--- title: Pivotal Container Service (PKS)でPrometheus Operatorを使うメモ tags: ["Kubernetes", "PKS", "Micrometer", "Prometheus", "BOSH", "CFCR"] categories: ["Dev", "CaaS", "Kubernetes", "PKS"] date: 2018-10-15T08:16:38Z updated: 2018-11-24T13:01:02Z --- PKSで[Prometheus Operator](https://github.com/coreos/prometheus-operator)を使うメモです。 普通にPrometheusをデプロイするmanifestを書くのではなくPrometheus Operatorを使う理由は * ConfigMapまたはSecretで`prometheus.yml`をざっくり管理するのではなく、Custom Resource Definition(CRD)でKuberntes NativeなPrometheusのConfigurationができる。 * [kube-prometheus](https://github.com/coreos/prometheus-operator/tree/master/contrib/kube-prometheus)でOpinionatedなPrometheus/AlertManager/Grafanaをインストールできる。 個人手にHelm Chartは嫌いなので検討対象外です。 CRDを使うことには少し抵抗がありましたが、CRDはこれから一般的になっていくことが推測されるのと、 Prometheus Operatorは[Operatorの代表例](https://github.com/operator-framework/awesome-operators)にもなっていますし野良CRDよりも信用できるので、Kubernetes Nativeなやり方に慣れてみることにしました。 PCFではPrometheusは[BOSH Release](https://github.com/bosh-prometheus/prometheus-boshrelease)を使ってインストールするのが一般的ですが、 この場合はモニタリングはk8sの外から行うことになります。個人的にはモニタリングは外から行うべきだと思いますが、Servivce Discoveryを使ってコンテナにアクセスしてscrapeするにはPrometheusをk8sの中に配置する必要があります。そのため、 * VMレベルのモニタリング(BOSH Exporter, Node Exporter) => Prometheus BOSH Release * コンテナ/アプリレベルのモニタリング => Prometheus Operator で使い分けます。BOSH Exporterのインストール方法は[こちら](https://github.com/pivotal-cf/pcf-prometheus-pipeline)を参照してください。 > 本記事の内容を[`kustomize`](https://github.com/kubernetes-sigs/kustomize)で管理する方法は[こちら](https://github.com/making/prometheus-kustomize) ### PKS側の設定 Prometheus Operatorが用意するmanifestは`securityContent.runAsUser`が設定されています。本稿執筆時点でのPKS最新バージョンである1.2が内包するCloud Foundry Container Runtime(CFCR, formerly known as Kubo) 0.21.0ではPrivileged Containersを無効(デフォルト、推奨)にすると、[`SecurityContextDeny`が設定されてしまう](https://github.com/cloudfoundry-incubator/kubo-release/issues/231)ため、Prometheus Operatorのmanifestを変更せずに使うには不本意ながら"Enable Privileged Containers - Use with caution"にチェックを入れてインストールする必要があります。 ![image](https://user-images.githubusercontent.com/106908/46909116-54bcae00-cf68-11e8-8e2e-c806d3108329.png) > この制約は[CFCR 0.22.0](https://docs-cfcr.cfapps.io/overview/release-notes/#v0220)で修正されたため、おそらくPKS 1.3では修正されると思います。 ### Kubernetesクラスタの作成 PKSはインストールされている前提です。Privileged Containersが有効になっているplanで普通にクラスタを作成してください。 ``` pks create-cluster demo -e demo.pks.bosh.tokyo -p small -u admin ``` しばらくするとクラスタができます。(PKS 1.2では30分くらいかかります...我慢) ``` $ pks cluster demo Name: demo Plan Name: small UUID: ca28e2f6-1b90-4929-80cc-8949143c757b Last Action: CREATE Last Action State: succeeded Last Action Description: Instance provisioning completed Kubernetes Master Host: demo.pks.bosh.tokyo Kubernetes Master Port: 8443 Worker Nodes: 1 Kubernetes Master IP(s): 10.0.8.4 $ pks get-credentials demo ``` ### Prometheus Operatorのインストール 本稿ではPrometheus Operator 0.24.0をインストールします。 ``` git clone https://github.com/coreos/prometheus-operator.git cd prometheus-operator git checkout v0.24.0 ``` [`contrib/kube-prometheus/manifests`](https://github.com/coreos/prometheus-operator/tree/master/contrib/kube-prometheus/manifests)以下に含まれるmanifestを使って、CRDのインストールおよび、OpinionatedなPrometheus / AlertManager / Grafanaをインストールします。 このmanifestではNode Exporterもインストールされてしまうのですが、Node Exporterは[BOSH addon](https://bosh.io/docs/runtime-config/)としてインストールした方が * PKS管理の全k8sクラスタにまとめてインストールできる * k8s以外のVM(PKS APIなど)のモニタリングもできる * k8s自体がダウンしてもnode-exporterに影響がない という点で良いのでここではインストール対象から除外します。(というか何らかの制約でインストールできません) Node Exporterのインストールは後述します。 ``` for f in $(ls contrib/kube-prometheus/manifests/node-exporter-*);do mv $f $f.bak done ``` これで`kubectly apply`でインストールします。デフォルトでPrometheusとAlertManagerが冗長な設定になっていますが、ここでは1 Podに減らします。 ``` kubectl apply -f contrib/kube-prometheus/manifests/ kubectl patch -n monitoring alertmanager main --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value": 1 }]' kubectl patch -n monitoring prometheus k8s --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value": 1 }]' ``` インストールできたらPod一覧は次のようになります。`monitoring` Namespaceに各種Podができていることを確認してください。 ``` $ kubectl get pod --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system heapster-6d5f964dbd-kqnps 1/1 Running 0 28m kube-system kube-dns-6b697fcdbd-2tjhz 3/3 Running 0 29m kube-system kubernetes-dashboard-785584f46b-vxkgn 1/1 Running 0 28m kube-system metrics-server-5f68584c5b-lkx2w 1/1 Running 0 28m kube-system monitoring-influxdb-54759946d4-8rpn4 1/1 Running 0 28m kube-system telemetry-agent-b8957f99-wjsst 1/1 Running 0 22m monitoring alertmanager-main-0 2/2 Running 0 12s monitoring grafana-566fcc7956-7fb8f 1/1 Running 0 3m monitoring kube-state-metrics-65bf5c56b6-2dbrk 4/4 Running 0 3m monitoring prometheus-k8s-0 3/3 Running 1 2m monitoring prometheus-operator-6694d94d6b-7r2bw 1/1 Running 0 3m pks-system fluent-bit-m9pp8 1/1 Running 0 28m pks-system sink-controller-578859d5f-7lfjd 1/1 Running 0 28m ``` Custom Resource Definition一覧も確認してください。 ``` $ kubectl get crd NAME CREATED AT alertmanagers.monitoring.coreos.com 2018-10-13T19:26:15Z prometheuses.monitoring.coreos.com 2018-10-13T19:26:15Z prometheusrules.monitoring.coreos.com 2018-10-13T19:26:16Z servicemonitors.monitoring.coreos.com 2018-10-13T19:26:16Z sinks.apps.pivotal.io 2018-10-13T19:00:48Z ``` Prometheusにアクセスします。 ``` kubectl port-forward -n monitoring $(kubectl get pod -n monitoring -l app=prometheus -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}') 9090:9090 ``` ![image](https://user-images.githubusercontent.com/106908/46909659-fe07a200-cf70-11e8-9b52-0709555ec429.png) Configurationで複数のScrape Configが設定されていることを確認してください。 ![image](https://user-images.githubusercontent.com/106908/46909667-1c6d9d80-cf71-11e8-96b7-2b57f9385452.png) Grafanaにアクセスします。 ``` kubectl port-forward -n monitoring $(kubectl get pod -n monitoring -l app=grafana -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}') 3000:3000 ``` `admin`/`admin`でログインしたのちパスワード変更を求められます。 ![image](https://user-images.githubusercontent.com/106908/46909301-fe04a380-cf6a-11e8-9c07-f48d593c23b2.png) あらかじめDashboardが用意されています。 ![image](https://user-images.githubusercontent.com/106908/46909319-5d62b380-cf6b-11e8-9a45-8289a71e6575.png) Namespace毎のメトリクス ![image](https://user-images.githubusercontent.com/106908/46909333-82572680-cf6b-11e8-8fd1-e256a83a4700.png) Pod毎のメトリクス ![image](https://user-images.githubusercontent.com/106908/46909351-c9ddb280-cf6b-11e8-8bd2-d5c786a53bed.png) Node ExporterはインストールしていないのでNode毎のメトリクスやClusterのメトリクスは"No data points"となります。 > TODO: Persistemt Volumeの設定がないので、Podが再作成されるとPrometheus, Grafana共にデータが消えます。Persistent Volumeの設定は後で書く。 ### Node Exporterのインストール 前述の通り、Node Exporterは[BOSH addon](https://bosh.io/docs/runtime-config/)としてインストールします。 `node-exporter.yml`に次の内容を記述してください。 ```yaml releases: - name: node-exporter version: 4.0.1 url: https://github.com/bosh-prometheus/node-exporter-boshrelease/releases/download/v4.0.1/node-exporter-4.0.1.tgz sha1: 8f00d257838f33d5022d6c356c35d2922e75c9b4 addons: - name: node-exporter jobs: - name: node_exporter release: node-exporter properties: {} include: stemcell: - os: ubuntu-trusty - os: ubuntu-xenial ``` 次のコマンドでBOSH Runtime Configを設定してください。 ``` bosh update-runtime-config --name=node-exporter node-exporter.yml ``` > `bosh`コマンドを使うにはOps ManagerのDirector TileのCredentialsから"BOSH Commandline Credentials"を参照し、 > ![image](https://user-images.githubusercontent.com/106908/46909822-adde0f00-cf73-11e8-9189-e9bc3b8021cf.png) > > 次のように環境変数を設定してください。 > > ```bash > export BOSH_CLIENT=ops_manager > export BOSH_CLIENT_SECRET=.... > export BOSH_CA_CERT=/var/tempest/workspaces/default/root_ca_certificate > export BOSH_ENVIRONMENT=.... > ``` > OpsManager VM上で作業するのが楽です。 Runtime Configを設定したのち、OpsManagerで"Apply Changes"をクリックしてください。"Update All Clusters"のErrandを有効にするのを忘れないでください。 Apply Changesが終わったら次のコマンドで確認してください。 ``` bosh instances --ps ``` 各VM上に`node_exporter`が起動していることがわかります。 ![image](https://user-images.githubusercontent.com/106908/46909953-0f06e200-cf76-11e8-887f-078c0282040a.png) 次に、Kubernetes上のPrometheusにNode Exporter用のscrape configを設定します。 Node ExporterのモニタリングはBOSH側のPrometheusで行えますが、ここではPrometheus Operatorの使用例として説明します。 Prometheus Operatorで監視対象を追加するにはCRDに追加された`ServiceMonitor`リソースを定義しますが、Prometheus Operator管理外のExporterをscrapeする場合は、 これもCRDで追加された`Prometheus`リソースの`spec/additionalScrapeConfigs`にscrape configを`Secret`リソース経由で渡します。 Node Exporter用のscrape configを作成するために、`prometheus-additional.yml`に次の内容を記述してください。NodeのIPアドレスはKubernetes Service Discoveryで取得可能です。 ```yaml - job_name: "node-exporter" kubernetes_sd_configs: - role: node bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - source_labels: [__meta_kubernetes_node_address_InternalIP] target_label: __address__ regex: (.*) replacement: $1:9100 ``` > この設定ではKubernetesのWorker NodeしかMonitoringできません。その他のVMのモニタリングもしたい場合は`static_configs`か`file_sd_configs`を使用してください。 PrometheusがNodeの情報を取得できるようにするために、`ClusterRole`を修正する必要があります。 ``` kubectl patch clusterrole prometheus-k8s --type='json' -p='[{"op": "add", "path": "/rules/0/resources/-", "value": "nodes"}, {"op": "add", "path": "/rules/0/verbs/-", "value": "list"}, {"op": "add", "path": "/rules/0/verbs/-", "value": "watch"}]' ``` `prometheus-additional.yml`を`Secret`として作成します。 ``` kubectl create -n monitoring secret generic additional-scrape-configs --from-file=prometheus-additional.yml --dry-run -oyaml > additional-scrape-configs.yml kubectl apply -f additional-scrape-configs.yml ``` この`Secret`の情報を`additionalScrapeConfigs`に設定します。 ``` kubectl patch -n monitoring prometheus k8s --type='json' -p='[{"op": "add", "path": "/spec/additionalScrapeConfigs", "value": {"name": "additional-scrape-configs", "key": "prometheus-additional.yml"}}]' ``` PrometheusのPodを再作成して設定を反映させる必要があります。ここでは雑にPodを一旦Deleteします。 ``` kubectl delete pod -n monitoring prometheus-k8s-0 ``` PrometheusのPodがrecreateされ、Targetsを確認すると、Node Exporterが追加されています。 ![image](https://user-images.githubusercontent.com/106908/46910554-6fe7e780-cf81-11e8-8c7c-c7be225837b9.png) Grafnaにアクセスすると、Nodeに関するメトリクスや ![image](https://user-images.githubusercontent.com/106908/46910561-9c9bff00-cf81-11e8-9679-3bce5123faee.png) Clusterに関するメトリクスが表示されます。 ![image](https://user-images.githubusercontent.com/106908/46910304-4af17580-cf7d-11e8-91c7-eec87fe7e079.png) ### モニタリング対象の追加 次に`ServiceMonitor`リソースを使って、モニタリング対象を追加します。対象のサンプルアプリケーションは[こちら](https://github.com/making/hello-pks/tree/0.0.2)です。 Spring Boot Actuatorと[Micrometer](https://micrometer.io/)を使って`/actuator/prometheus`エンドポイントでメトリクスをexportしています。 このアプリケーションを次のmanifestで`hello` Namespaceにデプロイします。`Service`のport定義に`name`をつけるのが重要です。 ```yaml apiVersion: v1 kind: Namespace metadata: name: hello --- apiVersion: apps/v1 kind: Deployment metadata: name: hello-pks namespace: hello spec: replicas: 1 selector: matchLabels: app: hello-pks template: metadata: labels: app: hello-pks spec: containers: - image: making/hello-pks:0.0.2 name: hello-pks ports: - containerPort: 8080 --- kind: Service apiVersion: v1 metadata: name: hello-pks-service namespace: hello labels: app: hello-pks spec: type: NodePort selector: app: hello-pks ports: - protocol: TCP port: 8080 name: http ``` `kubectl apply`でデプロイします。 ``` kubectl apply -f hello-pks.yml ``` Prometheus OperatorではNamespace毎に`Prometheus`リソースを作って個別にPrometheusを立ててもいいですが、 ここでは1クラスタ毎にテナントが用意されていて、Cluster Adminがもらえている前提とし、`monitoring` NamespaceのPrometheusにモニタリングを集約させます。 `monitoring` NamespaceのPrometheusが`hello` NamespaceのPod等の情報にアクセスすために、`monitoring` Namespaceの`prometheus-k8s` Service Accountに`Role`を追加する必要があります。 `ServiceMonitor`の定義と一緒に次の`hello-pks-monitor.yml`に`Role`と`RoleBinding`も作成します。 ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: labels: k8s-app: hello-pks name: hello-pks namespace: hello spec: endpoints: - interval: 30s port: http path: /actuator/prometheus namespaceSelector: matchNames: - hello selector: matchLabels: app: hello-pks --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: prometheus-k8s namespace: hello rules: - apiGroups: - "" resources: - nodes - services - endpoints - pods verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: prometheus-k8s namespace: hello roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: prometheus-k8s subjects: - kind: ServiceAccount name: prometheus-k8s namespace: monitoring ``` `kubectl apply`でデプロイします。 ``` kubectl apply -f hello-pks-monitor.yml ``` しばらくするとPrometheusのConfigurationがアップデートされます。 ![image](https://user-images.githubusercontent.com/106908/46910717-2fd63400-cf84-11e8-8881-5d76d946ba55.png) Targetに追加したアプリケーションが増えていることを確認してください。 ![image](https://user-images.githubusercontent.com/106908/46910821-42516d00-cf86-11e8-8f7d-9ea88b0fef24.png) `jvm_memory_used_bytes`などMicrometerで取得できるメトリクスを確認してください。 ![image](https://user-images.githubusercontent.com/106908/46910830-7fb5fa80-cf86-11e8-8dae-c4c76ef9e069.png) ### Grafanaダッシュボードの追加 次にGrafanaダッシュボードの追加方法を説明します。 Micrometer用のGrafanaダッシュボードを作成したので、[こちら](https://gist.github.com/making/05497ac18f7913e3a6495e2b9c15e6fe)からダウンロードして`micrometer.json`というファイル名をつけてください。 このJSONを`ConfigMap`リソースに登録します。 ``` kubectl create -n monitoring configmap grafana-dashboard-micrometer --from-file=micrometer.json --dry-run -oyaml > grafana-micrometer.yml kubectl apply -f grafana-micrometer.yml ``` `ConfigMap`をGrafanaのPodにMountして、自動読み込み対象に追加します。 ``` kubectl patch -n monitoring deployment grafana --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts/-", "value": {"mountPath": "/grafana-dashboard-definitions/0/micrometer", "name": "grafana-dashboard-micrometer", "readOnly": false}}, {"op": "add", "path": "/spec/template/spec/volumes/-", "value": {"configMap": {"name": "grafana-dashboard-micrometer"}, "name": "grafana-dashboard-micrometer"}}]' ``` GrafanaのPodが再作成されればDashboardが追加され、Micrometerに関連するメトリクスが表示されます。 ![image](https://user-images.githubusercontent.com/106908/46911043-0e794600-cf8c-11e8-8325-b45a79ee85e4.png) なお、ConfigMapを変更するだけだと、Podは自動で再作成されないので、JSONを更新したい場合は ``` kubectl delete pod -n monitoring -l app=grafana ``` も実行すると手っ取り早いです。 > ~~TODO: `kubectl patch`で差分適用すると、Prometheus Operatorをバージョンアップする際にリソースが一度パッチ適用前に戻ってしまう。[`bosh` CLI](https://bosh.io/docs/cli-v2-install/)の[ops-file](https://bosh.io/docs/cli-ops-files/)などを使って、YAMLをcompoeseする仕組みが必要。~~ > => 本記事の内容を[`kustomize`](https://github.com/kubernetes-sigs/kustomize)で管理する方法は[こちら](https://github.com/making/prometheus-kustomize) > TODO: AlertManagerの設定 > TODO: Prometheusのretention設定(デフォルト: 24h) --- Kubernetes結構大変じゃない...? PKSからOut of the boxなモニタリング機構が欲しい...