通过 Ingress Controller 公开 Elastic APM

Expose Elastic APM through Ingress Controller

我已经将弹性 APM 服务器部署到 kubernetes 中,并试图通过 nginx 入口控制器公开它。以下是我的配置:

---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: elastic
  name: apm-server-config
  labels:
    k8s-app: apm-server
data:
  apm-server.yml: |-
    apm-server:
      host: "0.0.0.0:8200"
    setup.kibana:
      enabled: "true"
      host: "kibana:5601"
    output.elasticsearch:
      hosts: ["elastic:9200"]
---
#Deployment Configuration
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    name: apm-server
    env: msprod
    state: common
  name: apm-server
  namespace: elastic
spec:
  replicas: 1
  minReadySeconds: 10
  selector:
    matchLabels:
      app: apm-server
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: apm-server
    spec:
      containers:
        - image: docker.elastic.co/apm/apm-server:7.12.1
          imagePullPolicy: Always
          env:
            - name: output.elasticsearch.hosts
              value: "http://elastic:9200"
          name: apm-server              
          ports:
          - name: liveness-port
            containerPort: 8200
          volumeMounts:
          - name: apm-server-config
            mountPath: /usr/share/apm-server/apm-server.yml
            readOnly: true
            subPath: apm-server.yml
          resources:
            limits:
              cpu: 250m
              memory: 1024Mi
            requests:
              cpu: 100m
              memory: 250Mi
      volumes:
      - name: apm-server-config
        configMap:
          name: apm-server-config
      nodeSelector:
        env: prod
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
---
#Service Configuration
apiVersion: v1
kind: Service
metadata:
  labels:
    app: apm-server
  name: apm-server
  namespace: elastic
spec:
  ports:
  - port: 8200
    targetPort: 8200
    name: http
    nodePort: 31000
  selector:
    app: apm-server
  sessionAffinity: None
  type: NodePort
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  namespace: elastic
  name: gateway-ingress-apm
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: my.domain.com
      http: 
        paths:
          - path: /apm
            backend:
              serviceName: apm-server
              servicePort: 8200

pod 是 运行,我可以使用 kubectl port-forward 访问 APM 服务器。

但是当我使用 https://my.domain.com/apm 访问 apm 服务器时,我在浏览器中收到页面未找到错误并在 APM pod 中出现以下错误:

{"log.level":"error","@timestamp":"2021-10-21T06:22:00.198Z","log.logger":"request","log.origin":{"file.name":"middleware/log_middleware.go","file.line":60},"message":"404 page not found","url.original":"/apm","http.request.method":"GET","user_agent.original":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36","source.address":"10.148.7.7","http.request.body.bytes":0,"http.request.id":"9294124a-5356-4b2c-ba8e-c0a589b23571","event.duration":110881,"http.response.status_code":404,"error.message":"404 page not found","ecs.version":"1.6.0"}

出现错误是因为APM 中没有配置上下文路径。我浏览了 APM 文档,但找不到在 apm 服务器中配置上下文路径的方法。请帮忙。

将此作为评论中的答案发布。


初始入口规则将相同路径 /apm 传递给 APM 服务,APM pod 日志中的错误确认了这一点 - "message":"404 page not found","url.original":"/apm"

要修复它,nginx ingress rewrite annotation。它的工作方式在 link 示例中进行了描述。

最终 ingress.yaml 应如下所示:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  namespace: elastic
  name: gateway-ingress-apm
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: / # adding captured group
spec:
  rules:
    - host: my.domain.com
      http: 
        paths:
          - path: /apm(/|$)(.*) # to have captured group works correctly
            backend:
              serviceName: apm-server
              servicePort: 8200

这里发生的是发送到 my.domain.com/apm 的请求转到 / 路径上的服务。

Captured group 允许保留正确的路径,例如,如果请求转到 my.domain.com/apm/something,ingress 会将其转换为 /something,然后传递给服务。