Назад | Перейти на главную страницу

kube-proxy не принимает соединения на некоторых узлах

Я попал в очень странную ситуацию, когда kube-proxy не принимает соединения на некоторых узлах, и, честно говоря, я в тупике.

Задний план:

Пример ниже. Оба узла находятся в одной зоне доступности.

Здоровый узел:

curl --connect-timeout 5 -sD - -k https://localhost:32028/healthz

HTTP/2 200
date: Sun, 13 Oct 2019 13:51:32 GMT
content-type: text/html
content-length: 0
sudo netstat -taupen | grep kube-proxy | grep LISTEN                                                                                       
tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      0          21284      3162/kube-proxy
tcp6       0      0 :::32618                :::*                    LISTEN      0          23820      3162/kube-proxy
tcp6       0      0 :::32012                :::*                    LISTEN      0          21359      3162/kube-proxy
tcp6       0      0 :::10256                :::*                    LISTEN      0          21280      3162/kube-proxy
tcp6       0      0 :::30259                :::*                    LISTEN      0          21358      3162/kube-proxy
tcp6       0      0 :::30844                :::*                    LISTEN      0          21361      3162/kube-proxy
tcp6       0      0 :::32028                :::*                    LISTEN      0          21360      3162/kube-proxy
tcp6       0      0 :::30048                :::*                    LISTEN      0          21357      3162/kube-proxy

Нездоровый узел:

curl -v --connect-timeout 5 -sD - -k https://localhost:32028/healthz'                                                                             

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connection timed out after 5001 milliseconds
* Curl_http_done: called premature == 1
* stopped the pause stream!
* Closing connection 0
sudo netstat -taupen | grep kube-proxy | grep LISTEN
tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      0          23611      2726/kube-proxy
tcp6       0      0 :::32618                :::*                    LISTEN      0          22662      2726/kube-proxy
tcp6       0      0 :::32012                :::*                    LISTEN      0          22654      2726/kube-proxy
tcp6       0      0 :::10256                :::*                    LISTEN      0          21872      2726/kube-proxy
tcp6       0      0 :::30259                :::*                    LISTEN      0          22653      2726/kube-proxy
tcp6       0      0 :::32028                :::*                    LISTEN      0          22656      2726/kube-proxy
tcp6       0      0 :::30844                :::*                    LISTEN      0          22655      2726/kube-proxy
tcp6       0      0 :::30048                :::*                    LISTEN      0          22652      2726/kube-proxy

Окружающая среда:

kubectl get services nginx-ingress
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP                                                                        PORT(S)                                   AGE
nginx-ingress   LoadBalancer   100.67.138.99   xxxx-yyyy.elb.eu-central-1.amazonaws.com   80:30259/TCP,443:32028/TCP,22:32012/TCP   47h


kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.1", GitCommit:"d647ddbd755faf07169599a625faf302ffc34458", GitTreeState:"clean", BuildDate:"2019-10-02T23:49:07Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.6", GitCommit:"96fac5cd13a5dc064f7d9f4f23030a6aeface6cc", GitTreeState:"clean", BuildDate:"2019-08-19T11:05:16Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}

kubectl get deployment nginx-ingress -oyaml:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    checksum/config: 0f815cbf49129a18dacd05c1f35c0e2c0a36d0ad4f8f0272828a558c49c40aed
    configmap.reloader.stakater.com/reload: ingress-nginx,tcp-services,udp-services
    deployment.kubernetes.io/revision: "5"
  creationTimestamp: "2019-10-11T14:16:23Z"
  generation: 18
  labels:
    app: nginx-ingress
    chart: nginx-ingress-0.26.1
    heritage: Tiller
    k8s-addon: ingress-nginx.addons.k8s.io
    k8s-app: nginx-ingress-controller
    release: nginx-ingress-private
  name: nginx-ingress
  namespace: backend
  resourceVersion: "85333311"
  selfLink: /apis/extensions/v1beta1/namespaces/backend/deployments/nginx-ingress
  uid: b4a6f226-ec31-11e9-bd40-066623cdec10
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: nginx-ingress
      release: nginx-ingress-private
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
      creationTimestamp: null
      labels:
        app: nginx-ingress
        k8s-addon: ingress-nginx.addons.k8s.io
        k8s-app: nginx-ingress-controller
        release: nginx-ingress-private
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --logtostderr=true
        - --stderrthreshold=0
        - --http-port=80
        - --https-port=443
        - --healthz-port=10254
        - --default-backend-service=$(POD_NAMESPACE)/nginx-ingress-default
        - --configmap=$(POD_NAMESPACE)/ingress-nginx
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
        - --publish-service=$(POD_NAMESPACE)/nginx-ingress
        - --default-ssl-certificate=$(POD_NAMESPACE)/certs-tls
        - --ingress-class=private
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: STAKATER_TCP_SERVICES_CONFIGMAP
          value: 060d83d51ec7d01fe8af12484189acf792044690
        - name: STAKATER_UDP_SERVICES_CONFIGMAP
          value: da39a3ee5e6b4b0d3255bfef95601890afd80709
        - name: STAKATER_INGRESS_NGINX_CONFIGMAP
          value: 6a393dab54c63f4117785f635b7c00c64e140853
        image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        name: nginx-ingress
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            cpu: 250m
            memory: 512Mi
          requests:
            cpu: 10m
            memory: 50Mi
        securityContext:
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 33
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: nginx-ingress
      serviceAccountName: nginx-ingress
      terminationGracePeriodSeconds: 60
status:
  availableReplicas: 3
  conditions:
  - lastTransitionTime: "2019-10-11T14:16:24Z"
    lastUpdateTime: "2019-10-11T21:55:50Z"
    message: ReplicaSet "nginx-ingress-6d994d7b96" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  - lastTransitionTime: "2019-10-13T11:05:46Z"
    lastUpdateTime: "2019-10-13T11:05:46Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  observedGeneration: 18
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3

/etc/kubernetes/manifests/kube-proxy.manifest:

apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    k8s-app: kube-proxy
    tier: node
  name: kube-proxy
  namespace: kube-system
spec:
  containers:
  - command:
    - /bin/sh
    - -c
    - mkfifo /tmp/pipe; (tee -a /var/log/kube-proxy.log < /tmp/pipe & ) ; exec /usr/local/bin/kube-proxy
      --cluster-cidr=100.96.0.0/11 --conntrack-max-per-core=131072 --hostname-override=ip-aaa-bbb-ccc-ddd.eu-central-1.compute.internal
      --kubeconfig=/var/lib/kube-proxy/kubeconfig --master=https://api.xxx.yyy.zzz
      --oom-score-adj=-998 --resource-container="" --v=2 > /tmp/pipe 2>&1
    image: k8s.gcr.io/kube-proxy:v1.14.6
    name: kube-proxy
    resources:
      requests:
        cpu: 100m
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /var/lib/kube-proxy/kubeconfig
      name: kubeconfig
      readOnly: true
    - mountPath: /var/log/kube-proxy.log
      name: logfile
    - mountPath: /lib/modules
      name: modules
      readOnly: true
    - mountPath: /etc/ssl/certs
      name: ssl-certs-hosts
      readOnly: true
    - mountPath: /run/xtables.lock
      name: iptableslock
  hostNetwork: true
  priorityClassName: system-node-critical
  tolerations:
  - key: CriticalAddonsOnly
    operator: Exists
  volumes:
  - hostPath:
      path: /var/lib/kube-proxy/kubeconfig
    name: kubeconfig
  - hostPath:
      path: /var/log/kube-proxy.log
    name: logfile
  - hostPath:
      path: /lib/modules
    name: modules
  - hostPath:
      path: /usr/share/ca-certificates
    name: ssl-certs-hosts
  - hostPath:
      path: /run/xtables.lock
      type: FileOrCreate
    name: iptableslock
status: {}

kubectl get service nginx-ingress -oyaml:

apiVersion: v1
kind: Service
metadata:
  annotations:
    dns.alpha.kubernetes.io/internal: private.xxx.yyy.zzz
    external-dns.alpha.kubernetes.io/hostname: private.xxx.yyy.zzz
    kubernetes.io/ingress.class: private
    service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
    service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "false"
  creationTimestamp: "2019-10-11T14:16:23Z"
  labels:
    app: nginx-ingress
    chart: nginx-ingress-0.26.1
    heritage: Tiller
    k8s-addon: ingress-nginx.addons.k8s.io
    release: nginx-ingress-private
  name: nginx-ingress
  namespace: backend
  resourceVersion: "84591201"
  selfLink: /api/v1/namespaces/backend/services/nginx-ingress
  uid: b4a1b347-ec31-11e9-bd40-066623cdec10
spec:
  clusterIP: 100.xxx.yyy.zzz
  externalTrafficPolicy: Local
  healthCheckNodePort: 32618
  ports:
  - name: http
    nodePort: 30259
    port: 80
    protocol: TCP
    targetPort: http
  - name: https
    nodePort: 32028
    port: 443
    protocol: TCP
    targetPort: https
  - name: ssh
    nodePort: 32012
    port: 22
    protocol: TCP
    targetPort: 22
  selector:
    app: nginx-ingress
    release: nginx-ingress-private
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - hostname: xxx-yyy.elb.eu-central-1.amazonaws.com

kubectl get pods -n backend -o wide:

NAME                                    READY   STATUS    RESTARTS   AGE     IP              NODE                                              NOMINATED NODE   READINESS GATES
drone-drone-server-59586dd487-rmv9b     1/1     Running   0          2d10h   aaa.bbb.13.19    ip-172-xxx-yyy-180.eu-central-1.compute.internal   <none>           <none>
kube-slack-848c9646fd-8w5mw             1/1     Running   0          2d10h   aaa.bbb.13.10    ip-172-xxx-yyy-180.eu-central-1.compute.internal   <none>           <none>
nginx-ingress-5nlzg                     1/1     Running   0          9h      aaa.bbb.14.164   ip-172-xxx-yyy-201.eu-central-1.compute.internal   <none>           <none>
nginx-ingress-7xb54                     1/1     Running   0          9h      aaa.bbb.15.120   ip-172-xxx-yyy-156.eu-central-1.compute.internal   <none>           <none>
nginx-ingress-default-589975445-qdjvz   1/1     Running   0          9h      aaa.bbb.14.150   ip-172-xxx-yyy-201.eu-central-1.compute.internal   <none>           <none>
nginx-ingress-jqtd6                     1/1     Running   0          9h      aaa.bbb.12.84    ip-172-xxx-yyy-29.eu-central-1.compute.internal    <none>           <none>
nginx-ingress-z9nt8                     1/1     Running   0          9h      aaa.bbb.13.57    ip-172-xxx-yyy-180.eu-central-1.compute.internal   <none>           <none>
sonarqube-sonarqube-746cbc858b-ks87c    1/1     Running   0          2d10h   aaa.bbb.12.13    ip-172-xxx-yyy-29.eu-central-1.compute.internal    <none>           <none>
youtrack-0                              1/1     Running   0          2d10h   aaa.bbb.12.52    ip-172-xxx-yyy-29.eu-central-1.compute.internal    <none>           <none>

Мы будем очень благодарны за любые идеи о том, что может быть не так или как отладить проблему в дальнейшем.

ОБНОВИТЬ: Видит, что «нездоровые» / неработающие узлы - это только узлы, на которых находится nginx. не развернут. Развертывание модулей nginx как DeamonSet вместо того Deployment решает вопрос. Это все еще не дает ответа на вопрос, почему эта проблема возникает только при строго определенных условиях (не простой порт HTTP + внутренний балансировщик нагрузки) и как ее решить.

Я бы сказал, что все работает так, как задумано.

Обратите внимание, что, указав в службе nginx-ingress (LB) Ingress Controller следующую аннотацию:

 externalTrafficPolicy: Local

вы обеспечиваете входящий трафик, который будет обслуживаться только этими модулями (репликами Ingress Controller), которые являются локальными для узла. В AWS NLB не знает, какие узлы (зарегистрированные цели Load Balancer) не владеют собственной репликой Nginx-Ingress Controller, поэтому иногда распределенный трафик LB дает сбой.
Чтобы избежать такого поведения, вам необходимо вручную удалить эти узлы из зондов LB healthcheck.

Почему переход с «Развертывания» на «DeamonSet» решает проблему в вашем случае? Потому что это гарантирует, что каждый узел запускает копию Ingress Controller Pod.

Обратите внимание, что это поведение Load Balancer, зависящее от облачного провайдера, задокументировано. Вот.

если вы не заботитесь о сохранении исходных IP-адресов клиентов, просто измените 'externalTrafficPolicy' из 'Local'к'Cluster'чтобы решить вашу проблему.