kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

kube-prometheusでKubernetesの監視環境をマルっと用意する③

f:id:kun432:20210124210855p:plain

前回、前々回でkube-prometheusの導入方法についてご紹介しました。

今回はカスタマイズです。

目次

設定とカスタマイズ

設定とカスタマイズについては以下に記載されていますが、たくさん項目があって英語でわかりにくいということもあると思うので、かいつまんで説明します。

GitHub - prometheus-operator/kube-prometheus: Use Prometheus to monitor Kubernetes and applications running on Kubernetes

オーケストレーションツールごとの設定

使用するオーケストレーションによってKubernetesクラスタの中身は微妙に違います。どのオーケストレーションツールを使っているかを設定することで、それぞれのツールに合わせてカスタマイズが行われるようですね。

Jsonnet設定ファイル(ここではbase.libsonnet)の冒頭部分を修正します。

kubeadmだとこうなります。

local kp =
  (import 'kube-prometheus/kube-prometheus.libsonnet') +
  (import 'kube-prometheus/kube-prometheus-kubeadm.libsonnet') +  // ここ
(snip)
  {

EKSだとこうなるみたいです。

local kp =
  (import 'kube-prometheus/kube-prometheus.libsonnet') +
  (import 'kube-prometheus/kube-prometheus-eks.libsonnet') +  // ここ
(snip)
  {

nodeport有効化

普通にやるとprometheus/alertmanager/grafanaのGUIはすべてClusterIPになり、公開するには、serviceを変更するなり、nginx-ingressを使うなりして、自分で設定しないといけません。これをnodeportにするaddonがあります。

local kp =
  (import 'kube-prometheus/kube-prometheus.libsonnet') +
  (import 'kube-prometheus/kube-prometheus-kubeadm.libsonnet') + 
  (import 'kube-prometheus/addons/node-ports.libsonnet') + // ここ
(snip)
  {

ingressで公開する

ingressを使って公開することもできます。まず最初にnginx-ingressを入れておきます。ローカル環境なのでnodeportに変更しておきます。ついでに30080ポートに固定します。

$ kubectl create ns monitoring
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm install default ingress-nginx/ingress-nginx -n monitoring
$ kubectl -n monitoring patch service default-ingress-nginx-controller -p '{"spec":{"type": "NodePort"}}'
$ kubectl -n monitoring patch service default-ingress-nginx-controller --type='json' -p='[{"op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080}]'

確認。404にはなっていますが一応応答していますね。

$ kubectl get service -n monitoring
NAME                                            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
default-ingress-nginx-controller             NodePort    10.108.194.110   <none>        80:30080/TCP,443:30030/TCP   19s
default-ingress-nginx-controller-admission   ClusterIP   10.110.178.130   <none>        443/TCP                      19s

$ curl http://10.240.0.21:30080
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

base.libsonnetの_config以下を修正します。以下の例はv1.18向けなので、apiVersionは 'networking.k8s.io/v1beta1' にしていますし、backendの指定もそれに合わせてます。v1.20でも同じ書き方で行けましたが、このあたりはバージョンによって修正が必要な場合もありますね。

(snip)
  {
    _config+:: {
      namespace: 'monitoring',
    },
    // 以下を追加
    prometheus+:: {
      prometheus+: {
        spec+: {
          externalUrl: 'http://prometheus.internal',
        },
      },
    },
    ingress+:: {
      'prometheus-k8s': {
        apiVersion: 'networking.k8s.io/v1beta1',
        kind: 'Ingress',
        metadata: {
          name: $.prometheus.prometheus.metadata.name,
          namespace: $.prometheus.prometheus.metadata.namespace,
          annotations: {
            'kubernetes.io/ingress.class': 'nginx',
          },
        },
        spec: {
          rules: [{
            host: 'prometheus.internal',
            http: {
              paths: [{
                backend: {
                  serviceName: $.prometheus.service.metadata.name,
                  servicePort: 'web',
                },
              }],
            },
          }],
        },
      },
    },
  };
(snip)

あと一番最後の行を修正します。

(snip)
{ ['prometheus-adapter-' + name]: kp.prometheusAdapter[name] for name in std.objectFields(kp.prometheusAdapter) } +
{ ['grafana-' + name]: kp.grafana[name] for name in std.objectFields(kp.grafana) } +  // "+"を追記
{ ['ingress-' + name]: kp.ingress[name] for name in std.objectFields(kp.ingress) }      // 追加

ビルドしてapplyするとこうなります。

$ kubectl -n monitoring get ingress
NAME   CLASS    HOSTS                 ADDRESS          PORTS   AGE
k8s    <none>   prometheus.internal   10.103.124.145   80      9m18s

$ curl  http://10.240.0.31:30080/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

$ curl -H 'host: prometheus.internal' http://10.240.0.31:30080/
<a href="/graph">Found</a>.

hostヘッダを付けないとアクセスできないということで、ちゃんとingressが応答しているのがわかります。

同様にして、alertmanagerとgrafanaもingressで公開します。同じような記載を追加すればいいだけですが、以下を参考に少し弄ってみます。

  {
    _config+:: {
      namespace: 'monitoring',
      grafana+:: {
        config+: {
          sections+: {
            server+: {
              root_url: 'http://grafana.internal/',
            },
          },
        },
      },
    },
    prometheus+:: {
      prometheus+: {
        spec+: {
          externalUrl: 'http://prometheus.internal',
        },
      },
    },
    alertmanager+:: {
      alertmanager+: {
        spec+: {
          externalUrl: 'http://alertmanager.internal',
        },
      },
    },
    ingress+:: {
      'prometheus-k8s': {
        apiVersion: 'networking.k8s.io/v1beta1',
        kind: 'Ingress',
        metadata: {
          name: $.prometheus.prometheus.metadata.name,
          namespace: $.prometheus.prometheus.metadata.namespace,
          annotations: {
            'kubernetes.io/ingress.class': 'nginx',
          },
        },
        spec: {
          rules: [{
            host: 'prometheus.internal',
            http: {
              paths: [{
                backend: {
                  serviceName: $.prometheus.service.metadata.name,
                  servicePort: 'web',
                },
              }],
            },
          }],
        },
      },
      'alertmanager-main': {
        apiVersion: 'networking.k8s.io/v1beta1',
        kind: 'Ingress',
        metadata: {
          name: $.alertmanager.alertmanager.metadata.name,
          namespace: $.alertmanager.alertmanager.metadata.namespace,
          annotations: {
            'kubernetes.io/ingress.class': 'nginx',
          },
        },
        spec: {
          rules: [{
            host: 'alertmanager.internal',
            http: {
              paths: [{
                backend: {
                  serviceName: $.alertmanager.service.metadata.name,
                  servicePort: 'web',
                },
              }],
            },
          }],
        },
      },
      'grafana': {
        apiVersion: 'networking.k8s.io/v1beta1',
        kind: 'Ingress',
        metadata: {
          name: 'grafana',
          namespace: 'monitoring',
          annotations: {
            'kubernetes.io/ingress.class': 'nginx',
          },
        },
        spec: {
          rules: [{
            host: 'grafana.internal',
            http: {
              paths: [{
                backend: {
                  serviceName: 'grafana',
                  servicePort: 'http',
                },
              }],
            },
          }],
        },
      },
    },
  };

多少冗長になっていますが、わかりやすさ優先で。alertmanagerはprometheusとほぼ同じです。クセがあるのがgrafanaで、設定を_config配下にしないといけないみたいです。で、その関係上、ingressの設定のところ、うまく変数的に指定できなかったのでとりあえず動くこと優先でハードコードしてます・・・

適用するとこんな感じです。

$ kubectl -n monitoring get ingress
NAME      CLASS    HOSTS                   ADDRESS        PORTS   AGE
grafana   <none>   grafana.internal        10.108.82.19   80      4m16s
k8s       <none>   prometheus.internal     10.108.82.19   80      4m16s
main      <none>   alertmanager.internal   10.108.82.19   80      4m16s

$ curl -H 'host: prometheus.internal' http://10.240.0.31:30080/
<a href="/graph">Found</a>.

$ curl -H 'host: grafana.internal' http://10.240.0.31:30080/
<a href="/login">Found</a>.

$ curl -H 'host: alertmanager.internal' http://10.240.0.31:30080/
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>Alertmanager</title>
(snip)

OKですね。

まとめ

kube-prometheus、難しい・・・。Jsonnetもよくわかってないのですが、REPL的なものはないのかなぁ・・・

まだもう少し追いかけます。