microk8sベースのクラスタにPrometheus/GrafanaとdashboardをデプロイしてNodePortでアクセスする
你好。
我是株式会社Class Act基础设施业务部的大塚。
今回はmicrok8sで構築したKubernetes環境にPrometheusとGrafanaをデプロイし、NodePortを使ってWebブラウザからアクセスしてみたいと思います。
他のWeb記事でもmicrok8sでPrometheus/Grafana環境をデプロイしているのを見るのですが、port-forwardでやっており。。。個人的な感覚で恐縮なのですがあまりport-forwardオプションが好きではなく。
そのため、NodePortで接続できる環境を作っていきます。
Prometheus是什么?
ざっくり調べてみた感じ、オープンソースのシステム監視・警告ツールの様です。
Zabbixと比較検討されているWeb記事を複数見ましたので「Zabbixみたいなツールなんだな」とでも思っておけばいいのかなと勝手に思っています。
CPUやMemoryに関するデータや死活監視等一般的な監視が可能みたいです。
このPrometheusは単一のコンポーネントではなく、複数のコンポーネントによって成り立っています。
監視対象から監視データをpullして、それをPrometheusサーバに蓄積。人間は蓄積されたデータをPrometheusが備えているWebインターフェースで見るか、Grafana等の別のインターフェースを導入してそっちで見るか、という流れの様です。
下の図で言うと、監視対象が左側や上部のk8s。Prometheusサーバが中央。人間が見るのが右側ですね。

個人的にはPrometheusのインターフェースはめちゃんこわかりにくいなと。。。
見ることあるんだろうか・・・?と思ってたりします。
Grafana是什么?
以下是引述的内容。
在上述说明中,“无论存储在哪里”一词是指Prometheus,在这里的工作是“让其可视化!”,而Grafana正是负责这项工作的工具。
Grafanaオープンソースは、オープンソースの可視化および分析ソフトウェアです。メトリクス、ログ、トレースがどこに保存されていても、クエリ、可視化、アラート、探索を行うことができます。時系列データベース(TSDB)データを洞察力のあるグラフやビジュアライゼーションに変換するためのツールを提供します。
建立
構築していきます。
なお、今回デプロイするサービスとデフォルトのポート番号とNodePortの関係性は以下とします。
DNS,Prometheus/Grafana,dashboardのenable
这一次我们采用了4台集群来构建。
root@k8s-master:~# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-worker03 Ready <none> 4m41s v1.26.4 192.168.2.33 <none> Ubuntu 22.04.2 LTS 5.15.0-72-generic containerd://1.6.15
k8s-master Ready <none> 2d3h v1.26.4 192.168.2.30 <none> Ubuntu 22.04.2 LTS 5.15.0-72-generic containerd://1.6.15
k8s-worker02 Ready <none> 2d3h v1.26.4 192.168.2.32 <none> Ubuntu 22.04.2 LTS 5.15.0-72-generic containerd://1.6.15
k8s-worker01 Ready <none> 2d3h v1.26.4 192.168.2.31 <none> Ubuntu 22.04.2 LTS 5.15.0-72-generic containerd://1.6.15
まず、microk8sのdns、dashboard、prometheusをenableにします。
恐らくGrafanaはPrometheusとセットになっているのかと。。。
root@k8s-master:~# microk8s enable prometheus dashboard dns
enableが正常終了すると、podやdeployment、serviceが色々デプロイされています。
root@k8s-master:~# kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system hostpath-provisioner-69cd9ff5b8-tcrcw 1/1 Running 0 4m15s 10.1.79.66 k8s-worker01 <none> <none>
observability kube-prom-stack-kube-prome-operator-79cbdd7979-xk852 1/1 Running 0 4m 10.1.69.194 k8s-worker02 <none> <none>
observability tempo-0 2/2 Running 0 2m47s 10.1.79.69 k8s-worker01 <none> <none>
observability kube-prom-stack-prometheus-node-exporter-rbdhm 1/1 Running 0 4m 192.168.2.30 k8s-master <none> <none>
kube-system calico-node-gjdxt 1/1 Running 0 2d3h 192.168.2.30 k8s-master <none> <none>
kube-system calico-kube-controllers-79568db7f8-8hgn9 1/1 Running 0 2d3h 10.1.235.193 k8s-master <none> <none>
observability loki-promtail-66tnc 1/1 Running 0 3m3s 10.1.235.196 k8s-master <none> <none>
observability kube-prom-stack-prometheus-node-exporter-2j8sd 1/1 Running 0 4m 192.168.2.31 k8s-worker01 <none> <none>
kube-system calico-node-cp8rh 1/1 Running 0 2d3h 192.168.2.31 k8s-worker01 <none> <none>
observability alertmanager-kube-prom-stack-kube-prome-alertmanager-0 2/2 Running 1 (3m26s ago) 3m39s 10.1.69.195 k8s-worker02 <none> <none>
observability loki-0 0/1 Running 0 3m3s 10.1.79.68 k8s-worker01 <none> <none>
observability kube-prom-stack-prometheus-node-exporter-f6tm2 1/1 Running 0 4m 192.168.2.32 k8s-worker02 <none> <none>
kube-system coredns-6f5f9b5d74-265dg 1/1 Running 0 5m35s 10.1.79.65 k8s-worker01 <none> <none>
observability loki-promtail-nl6wj 1/1 Running 0 3m3s 10.1.69.196 k8s-worker02 <none> <none>
observability prometheus-kube-prom-stack-kube-prome-prometheus-0 2/2 Running 0 3m38s 10.1.235.195 k8s-master <none> <none>
observability loki-promtail-428kg 1/1 Running 1 3m3s 10.1.79.67 k8s-worker01 <none> <none>
observability kube-prom-stack-prometheus-node-exporter-k28g4 1/1 Running 0 4m 192.168.2.33 k8s-worker03 <none> <none>
observability kube-prom-stack-kube-state-metrics-5bf874b44d-gl76c 1/1 Running 0 4m 10.1.39.193 k8s-worker03 <none> <none>
kube-system calico-node-dhzr9 1/1 Running 0 2d3h 192.168.2.32 k8s-worker02 <none> <none>
kube-system calico-node-2ljv4 1/1 Running 0 10m 192.168.2.33 k8s-worker03 <none> <none>
observability kube-prom-stack-grafana-79bff66ffb-m9f8m 3/3 Running 0 4m 10.1.39.194 k8s-worker03 <none> <none>
observability loki-promtail-mpf5s 1/1 Running 0 3m3s 10.1.39.195 k8s-worker03 <none> <none>
root@k8s-master:~# kubectl get deployment -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system calico-kube-controllers 1/1 1 1 2d4h
kube-system coredns 1/1 1 1 35m
observability kube-prom-stack-kube-prome-operator 1/1 1 1 34m
observability kube-prom-stack-kube-state-metrics 1/1 1 1 34m
observability kube-prom-stack-grafana 1/1 1 1 34m
kube-system dashboard-metrics-scraper 1/1 1 1 31m
kube-system kubernetes-dashboard 1/1 1 1 31m
kube-system metrics-server 1/1 1 1 31m
kube-system hostpath-provisioner 0/1 1 0 35m
root@k8s-master:~# kubectl get svc -A -o wide
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
default kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 2d3h <none>
kube-system kube-dns ClusterIP 10.152.183.10 <none> 53/UDP,53/TCP,9153/TCP 6m38s k8s-app=kube-dns
kube-system kube-prom-stack-kube-prome-kube-proxy ClusterIP None <none> 10249/TCP 5m4s <none>
kube-system kube-prom-stack-kube-prome-kube-controller-manager ClusterIP None <none> 10257/TCP 5m4s <none>
kube-system kube-prom-stack-kube-prome-coredns ClusterIP None <none> 9153/TCP 5m4s k8s-app=kube-dns
kube-system kube-prom-stack-kube-prome-kube-scheduler ClusterIP None <none> 10259/TCP 5m4s <none>
kube-system kube-prom-stack-kube-prome-kube-etcd ClusterIP None <none> 2381/TCP 5m4s component=etcd
observability kube-prom-stack-grafana ClusterIP 10.152.183.194 <none> 80/TCP 5m4s app.kubernetes.io/instance=kube-prom-stack,app.kubernetes.io/name=grafana
observability kube-prom-stack-kube-state-metrics ClusterIP 10.152.183.209 <none> 8080/TCP 5m4s app.kubernetes.io/instance=kube-prom-stack,app.kubernetes.io/name=kube-state-metrics
observability kube-prom-stack-kube-prome-prometheus ClusterIP 10.152.183.19 <none> 9090/TCP 5m4s app.kubernetes.io/name=prometheus,prometheus=kube-prom-stack-kube-prome-prometheus
observability kube-prom-stack-kube-prome-operator ClusterIP 10.152.183.58 <none> 443/TCP 5m4s app=kube-prometheus-stack-operator,release=kube-prom-stack
observability kube-prom-stack-kube-prome-alertmanager ClusterIP 10.152.183.98 <none> 9093/TCP 5m4s alertmanager=kube-prom-stack-kube-prome-alertmanager,app.kubernetes.io/name=alertmanager
observability kube-prom-stack-prometheus-node-exporter ClusterIP 10.152.183.92 <none> 9100/TCP 5m4s app.kubernetes.io/instance=kube-prom-stack,app.kubernetes.io/name=prometheus-node-exporter
kube-system kube-prom-stack-kube-prome-kubelet ClusterIP None <none> 10250/TCP,10255/TCP,4194/TCP 4m43s <none>
observability alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 4m43s app.kubernetes.io/name=alertmanager
observability prometheus-operated ClusterIP None <none> 9090/TCP 4m42s app.kubernetes.io/name=prometheus
observability loki-headless ClusterIP None <none> 3100/TCP 4m6s app=loki,release=loki
observability loki-memberlist ClusterIP None <none> 7946/TCP 4m6s app=loki,release=loki
observability loki ClusterIP 10.152.183.219 <none> 3100/TCP 4m6s app=loki,release=loki
observability tempo ClusterIP 10.152.183.34 <none> 3100/TCP,16687/TCP,16686/TCP,6831/UDP,6832/UDP,14268/TCP,14250/TCP,9411/TCP,55680/TCP,55681/TCP,4317/TCP,4318/TCP,55678/TCP 3m52s app.kubernetes.io/instance=tempo,app.kubernetes.io/name=tempo
kube-system metrics-server ClusterIP 10.152.183.158 <none> 443/TCP 2m44s k8s-app=metrics-server
kube-system kubernetes-dashboard ClusterIP 10.152.183.211 <none> 443/TCP 2m23s k8s-app=kubernetes-dashboard
kube-system dashboard-metrics-scraper ClusterIP 10.152.183.180 <none> 8000/TCP 2m12s k8s-app=dashboard-metrics-scraper
部署 Prometheus WebUI 的 NodePort 到 Prometheus WebUI。
Prometeus WebUIのNodePortをデプロイしていきます。
と書くのは簡単なのですが、どれがWebUIを提供しているpodなのか名前だけだとパッとわかりませんでした。
その為、そのpodをまずは特定します。
※deploymentベースでNodePortを作成出来ればいいのですが、podベースしかなさそうだったので今回はpodからNodePortを作成します。
Prometheus WebUIのデフォルトのポートは9090なので、それでListenしているserviceやpodを確認します。
svcでprometheus関連っぽいものを色々describeしてみると私の環境ではIPアドレス:10.1.235.195を持つpodがPrometheus WebUIを提供するpodっぽいことが分かります。
そのIPアドレスは”prometheus-kube-prom-stack-kube-prome-prometheus-0″という名前のpodでした。
root@k8s-master:~# kubectl describe svc -n observability kube-prom-stack-kube-prome-prometheus
Name: kube-prom-stack-kube-prome-prometheus
Namespace: observability
~中略~
Port: http-web 9090/TCP
TargetPort: 9090/TCP
Endpoints: 10.1.235.195:9090 ★10.1.235.195のIPを持つpodが9090ポートでlistenしている
Session Affinity: None
Events: <none>
root@k8s-master:~# kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
~中略~
observability prometheus-kube-prom-stack-kube-prome-prometheus-0 2/2 Running 0 58m 10.1.235.195 k8s-master <none> <none>
~中略~
このpod用のNodePortをデプロイする為にkubectl exposeからdry-runをしてyamlファイルを出力。
そのyamlファイルにNodePortを追記します。追記したらapplyを実行してsvcをデプロイします。
root@k8s-master:~# kubectl expose pod prometheus-kube-prom-stack-kube-prome-prometheus-0 -n observability --type=NodePort --dry-run=client -o yaml > kubernetes-prometheus.yaml
root@k8s-master:~# vi kubernetes-prometheus.yaml
root@k8s-master:~# kubectl apply -f kubernetes-prometheus.yaml
service/prometheus-kube-prom-stack-kube-prome-prometheus-0 created
root@k8s-master:~# kubectl get svc prometheus-kube-prom-stack-kube-prome-prometheus-0 -n observability
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus-kube-prom-stack-kube-prome-prometheus-0 NodePort 10.152.183.149 <none> 9090:30900/TCP,8080:30800/TCP 87s
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: kube-prom-stack-kube-prome-prometheus
app.kubernetes.io/managed-by: prometheus-operator
app.kubernetes.io/name: prometheus
app.kubernetes.io/version: 2.42.0
controller-revision-hash: prometheus-kube-prom-stack-kube-prome-prometheus-5cf8688487
operator.prometheus.io/name: kube-prom-stack-kube-prome-prometheus
operator.prometheus.io/shard: "0"
prometheus: kube-prom-stack-kube-prome-prometheus
statefulset.kubernetes.io/pod-name: prometheus-kube-prom-stack-kube-prome-prometheus-0
name: prometheus-kube-prom-stack-kube-prome-prometheus-0
namespace: observability
spec:
ports:
- name: port-1
port: 9090
protocol: TCP
targetPort: 9090
nodePort: 30900 ★追記した部分
- name: port-2
port: 8080
protocol: TCP
targetPort: 8080
nodePort: 30800 ★追記した部分(WebUIだけ使うのであれば不要です)
selector:
app.kubernetes.io/instance: kube-prom-stack-kube-prome-prometheus
app.kubernetes.io/managed-by: prometheus-operator
app.kubernetes.io/name: prometheus
app.kubernetes.io/version: 2.42.0
controller-revision-hash: prometheus-kube-prom-stack-kube-prome-prometheus-5cf8688487
operator.prometheus.io/name: kube-prom-stack-kube-prome-prometheus
operator.prometheus.io/shard: "0"
prometheus: kube-prom-stack-kube-prome-prometheus
statefulset.kubernetes.io/pod-name: prometheus-kube-prom-stack-kube-prome-prometheus-0
type: NodePort
status:
loadBalancer: {}

部署Grafana WebUI的NodePort到Grafana平台用户界面中。
接下来,在Grafana WebUI上部署NodePort。与Prometheus不同的是,检查部署时只有一个相关的项,我们将以此为基础生成yaml文件。在生成的yaml中添加NodePort,并部署svc。
root@k8s-master:~# kubectl expose deployment/kube-prom-stack-grafana --type=NodePort --dry-run=client -o yaml -n observability > kubernetes-grafana.yaml
root@k8s-master:~# vi kubernetes-grafana.yaml
root@k8s-master:~# kubectl apply -f kubernetes-grafana.yaml
Warning: resource services/kube-prom-stack-grafana is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
service/kube-prom-stack-grafana configured
root@k8s-master:~# kubectl get svc kube-prom-stack-grafana -n observability
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-prom-stack-grafana NodePort 10.152.183.194 <none> 3000:30300/TCP,9094:31011/UDP,80:31541/TCP 76m
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: kube-prom-stack
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: grafana
app.kubernetes.io/version: 9.3.8
helm.sh/chart: grafana-6.51.2
name: kube-prom-stack-grafana
namespace: observability
spec:
ports:
- name: port-1
port: 3000
protocol: TCP
targetPort: 3000
nodePort: 30300 ★追記した部分
- name: port-2
port: 9094
protocol: UDP
targetPort: 9094
- name: port-3
port: 9094
protocol: UDP
targetPort: 9094
selector:
app.kubernetes.io/instance: kube-prom-stack
app.kubernetes.io/name: grafana
type: NodePort
status:
loadBalancer: {}

環境を探ってみると、どうやらパスワードはSecretに格納されているようです。
恐らく”kube-prom-stack-grafana”という名前のsecretがあるかと思います。
describeして中を見ると、admin-passwordという名前のDataがあることが分かります。
root@k8s-master:~# kubectl get secret -A
NAMESPACE NAME TYPE DATA AGE
observability kube-prom-stack-grafana Opaque 3 12h
root@k8s-master:~# kubectl describe secret kube-prom-stack-grafana -n observability
Name: kube-prom-stack-grafana
Namespace: observability
Labels: app.kubernetes.io/instance=kube-prom-stack
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=grafana
app.kubernetes.io/version=9.3.8
helm.sh/chart=grafana-6.51.2
Annotations: meta.helm.sh/release-name: kube-prom-stack
meta.helm.sh/release-namespace: observability
Type: Opaque
Data
====
admin-password: 13 bytes
admin-user: 5 bytes
ldap-toml: 0 bytes
admin-passwordをbase64でデコードして取り出します。どうも”prom-operator”の様です。
root@k8s-master:~# kubectl get secret --namespace observability kube-prom-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
prom-operator

DashboardへのNodePortをデプロイ
他2つと手順は同じです。dashboardのdeploymentからdry-runをしてyamlファイルを生成。
NodePortを追記してsvcをデプロイします。
root@k8s-master:~# kubectl expose deployment/kubernetes-dashboard --type=NodePort --dry-run=client -o yaml -n kube-system > kubernetes-dashboard-nodeport.yaml
root@k8s-master:~# vi kubernetes-dashboard-nodeport.yaml
root@k8s-master:~# kubectl apply -f kubernetes-dashboard-nodeport.yaml
service/kubernetes-dashboard configured
root@k8s-master:~# kubectl get svc kubernetes-dashboard -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard NodePort 10.152.183.211 <none> 8443:30080/TCP 45m
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
spec:
ports:
- port: 8443
protocol: TCP
targetPort: 8443
nodePort: 30080 ★追記した部分
selector:
k8s-app: kubernetes-dashboard
type: NodePort
status:
loadBalancer: {}
您可以通过以下方式确认登录到仪表板的令牌。
root@k8s-master:~# kubectl create token default
eyJhbGciOiJSUzI1NiIsImtpZCI6IktlbFlLQmE3U2VuMmx2Vk5mcEZHU0M2Vm0xTjlRRk5kWDlza3lOS1lrTTQifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIl0sImV4cCI6MTY4NTY3MDA3NiwiaWF0IjoxNjg1NjY2NDc2LCJpc3MiOiJodHRwczovL2t1YmVybmV0ZXMuZGVmYXVsdC5zdmMiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImRlZmF1bHQiLCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjhiMWIwYjc3LWQ1OWMtNGY0My05YmVkLTAyNDZkNTkyYWI3OCJ9fSwibmJmIjoxNjg1NjY2NDc2LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.erv6pBJMRtsPDtyWc__15wTQMy9wtHibNPiwpjG-YGxa5y21gYYKhG-MScfA6RaKzAPUbFJ_hwfYN9FHZQ_G9jme8d5ckCHm4sZpatiJwFYFnfl8sXjAaSaQ6cKEpyqUKphfHIURQOzO5lKDrmlFkTgo4VcIA7mdfacAt9IPXCoFNe3mUmfskPLQdw7qfruKcn-lK62AgjuNHZf-z241m3ht2Y0kGz-jg3c0IJjDo7fHnzBuKAyyKUHMffgfxG5ANcKIPZge8NY_7Dxt-Hpurl8KOe_e8GsfjsMMN_3CeKlPa24OVSW1PIT9qMYpPNH98TuO4kgWEoGPtArw5bimaw

追加事項:修改NodePort.yaml文件。
因为上述信息中有不必要的内容,所以已经将其删除。
apiVersion: v1
kind: Service
metadata:
name: self-prometheus-nodeport
namespace: observability
spec:
ports:
- name: port-1
port: 9090
protocol: TCP
targetPort: 9090
nodePort: 30900
selector:
app.kubernetes.io/instance: kube-prom-stack-kube-prome-prometheus
app.kubernetes.io/managed-by: prometheus-operator
app.kubernetes.io/name: prometheus
app.kubernetes.io/version: 2.42.0
controller-revision-hash: prometheus-kube-prom-stack-kube-prome-prometheus-5cf8688487
operator.prometheus.io/name: kube-prom-stack-kube-prome-prometheus
operator.prometheus.io/shard: "0"
prometheus: kube-prom-stack-kube-prome-prometheus
statefulset.kubernetes.io/pod-name: prometheus-kube-prom-stack-kube-prome-prometheus-0
type: NodePort
apiVersion: v1
kind: Service
metadata:
name: self-grafana-nodeport
namespace: observability
spec:
ports:
- name: port-1
port: 3000
protocol: TCP
targetPort: 3000
nodePort: 30300
selector:
app.kubernetes.io/instance: kube-prom-stack
app.kubernetes.io/name: grafana
type: NodePort
apiVersion: v1
kind: Service
metadata:
name: self-kubernetes-dashboard-nodeport
namespace: kube-system
spec:
ports:
- port: 8443
protocol: TCP
targetPort: 8443
nodePort: 30443
selector:
k8s-app: kubernetes-dashboard
type: NodePort