フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

GKEでkube-dnsのメトリクスを取りたい話

f:id:lirlia:20211021235241p:plain

GCP上のkube-dnsはその裏側にdnsmasqskydnsが存在しています。

その二つの違いはRedHatの資料に詳しく書かれており

f:id:lirlia:20211021232207p:plain

上記のように紹介されています。GKEだと少し端折られてますね。

f:id:lirlia:20211021232231p:plain

どのメトリクスを見るべきなのか?

Prometheusを動かしメトリクスを集めるとDNSがつくメトリクスがこれだけあります。

metrics 意味
kubedns_dnsmasq_evictioins プロセス開始からDNSキャッシュが排除された回数
kubedns_dnsmasq_misses プロセス開始からDNSキャッシュミスした回数
kubedns_dnsmasq_hists プロセス開始からDNSキャッシュにヒットした回数
kubedns_dnsmasq_insertions プロセス開始からDNSキャッシュに追加した回数
kubedns_dnsmasq_hists DNSキャッシュの最大サイズ
kubedns_dnsmasq_errors メトリックの取得中に発生したエラーの数
kubedns_probe_dnsmasq_errors dnsmasqでの名前解決の失敗回数
--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,SRVのように設定されており、この名前を5秒のインターバルで弾けるかチェックしている
kubedns_probe_dnsmasq_latency_ms_bucket latencyとあるがグラフを見ると積み上がってる・・謎。少なくともその時点のレイテンシーではなさそう。レイテンシーをずっと足し合わせている?
https://github.com/kubernetes/dns/blob/28b748057b41e2fb4b1872138f43957f265a59a3/pkg/sidecar/dnsprobe.go#L96
kubedns_probe_dnsmasq_latency_ms_count 同上
kubedns_probe_dnsmasq_latency_ms_sum 同上
kubedns_probe_kubedns_latency_ms_bucket latencyとあるがグラフを見ると積み上がってる・・謎。少なくともその時点のレイテンシーではなさそう。レイテンシーをずっと足し合わせている?
https://github.com/kubernetes/dns/blob/28b748057b41e2fb4b1872138f43957f265a59a3/pkg/sidecar/dnsprobe.go#L96
kubedns_probe_kubedns_latency_ms_count 同上
kubedns_probe_kubedns_latency_ms_sum 同上
prometheus_sd_dns_lookup_failures_total DNS-ServiceDiscovery ルックアップ失敗回数 https://github.com/prometheus/prometheus/blob/c0c22ed04200a8d24d1d5719f605c85710f0d008/discovery/dns/dns.go#L55
prometheus_sd_dns_lookups_total DNS-ServiceDiscovery ルックアップ回数

ただすぐに思いつくクエリ/secや、失敗率が存在していません。。。どうするんだ。 どうやらskyDNSの方のメトリクスを集めれば良いようです。

   requestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
        Namespace: Namespace,
        Subsystem: Subsystem,
        Name:      "dns_request_count_total",
        Help:      "Counter of DNS requests made.",
    }, []string{"system"})


    requestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
        Namespace: Namespace,
        Subsystem: Subsystem,
        Name:      "dns_request_duration_seconds",
        Help:      "Histogram of the time (in seconds) each request took to resolve.",
        Buckets:   append([]float64{0.001, 0.003}, prometheus.DefBuckets...),
    }, []string{"system"})


    responseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
        Namespace: Namespace,
        Subsystem: Subsystem,
        Name:      "dns_response_size_bytes",
        Help:      "Size of the returns response in bytes.",
        Buckets: []float64{0, 512, 1024, 1500, 2048, 4096,
            8192, 12288, 16384, 20480, 24576, 28672, 32768, 36864,
            40960, 45056, 49152, 53248, 57344, 61440, 65536,
        },
    }, []string{"system"})


    errorCount = prometheus.NewCounterVec(prometheus.CounterOpts{
        Namespace: Namespace,
        Subsystem: Subsystem,
        Name:      "dns_error_count_total",
        Help:      "Counter of DNS requests resulting in an error.",
    }, []string{"system", "cause"})


    cacheMiss = prometheus.NewCounterVec(prometheus.CounterOpts{
        Namespace: Namespace,
        Subsystem: Subsystem,
        Name:      "dns_cachemiss_count_total",
        Help:      "Counter of DNS requests that result in a cache miss.",
    }, []string{"cache"})

ただGKEのkube-dnsではAnnotationにでdnsmasqのポートしか指定されていないのでこれを集められていません。 ということで自前で管理しましょう。(これは運用が面倒になるので微妙だと思いますが)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: DNS_DEPLOYMENT_NAME
  namespace: kube-system
  annotations:
    prometheus.io/port: 10054
    prometheus.io/port2: 10055  <- ⭐️もうひとつつける
    prometheus.io/scrape: true
    deployment.kubernetes.io/revision: "1"
    k8s-app: kube-dns
spec:
  selector:
    matchLabels:
      k8s-app: kube-dns
  strategy:
    rollingUpdate:
      maxSurge: 10%
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        k8s-app: kube-dns
    spec:
      containers:
      - name: kubedns
        image: k8s.gcr.io/dns/k8s-dns-kube-dns:1.17.3
        resources:
          limits:
            memory: '170Mi'
          requests:
            cpu: 100m
            memory: '70Mi'
        livenessProbe:
          httpGet:
            path: /healthcheck/kubedns
            port: 10054
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /readiness
            port: 8081
            scheme: HTTP
          initialDelaySeconds: 3
          timeoutSeconds: 5
        args:
        - --domain=cluster.local.
        - --dns-port=10053
        - --config-dir=/kube-dns-config
        - --v=2
        env:
        - name: PROMETHEUS_PORT
          value: "10055"
        ports:
        - containerPort: 10053
          name: dns-local
          protocol: UDP
        - containerPort: 10053
          name: dns-tcp-local
          protocol: TCP
        - containerPort: 10055
          name: metrics
          protocol: TCP
        volumeMounts:
        - name: kube-dns-config
          mountPath: /kube-dns-config
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsUser: 1001
          runAsGroup: 1001
      - name: dnsmasq
        image: k8s.gcr.io/dns/k8s-dns-dnsmasq-nanny:1.17.3
        livenessProbe:
          httpGet:
            path: /healthcheck/dnsmasq
            port: 10054
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        args:
        - -v=2
        - -logtostderr
        - -configDir=/etc/k8s/dns/dnsmasq-nanny
        - -restartDnsmasq=true
        - --
        - -k
        - --cache-size=1000
        - --no-negcache
        - --dns-forward-max=1500
        - --log-facility=-
        - --server=/cluster.local/127.0.0.1#10053
        - --server=/in-addr.arpa/127.0.0.1#10053
        - --server=/ip6.arpa/127.0.0.1#10053
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        resources:
          requests:
            cpu: 150m
            memory: 20Mi
        volumeMounts:
        - name: kube-dns-config
          mountPath: /etc/k8s/dns/dnsmasq-nanny
        securityContext:
          capabilities:
            drop:
            - all
            add:
            - NET_BIND_SERVICE
            - SETGID
      - name: sidecar
        image: k8s.gcr.io/dns/k8s-dns-sidecar:1.17.3
        livenessProbe:
          httpGet:
            path: /metrics
            port: 10054
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        args:
        - --v=2
        - --logtostderr
        - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,SRV
        - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,SRV
        ports:
        - containerPort: 10054
          name: metrics
          protocol: TCP
        resources:
          requests:
            memory: 20Mi
            cpu: 10m
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsUser: 1001
          runAsGroup: 1001
      dnsPolicy: Default
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: kube-dns
      serviceAccountName: kube-dns
      terminationGracePeriodSeconds: 30
      tolerations:
      - key: CriticalAddonsOnly
        operator: Exists
      volumes:
      - configMap:
          defaultMode: 420
          name: kube-dns
          optional: true
        name: kube-dns-config

なおこれ以外の方法としてCloudDNSを使う方法もあるので、こっちも検討すると良いかと思います。