RaspberryPi で構築する Bare-Metal Kubernetes - エコシステム編
- Authors
- Name
- ごとれん
- X
- @ren510dev
目次
- 目次
- はじめに
- 全体の流れ
- エコシステム
- 1. モニタリング基盤の整備
- Kubernetes Metrics Server
- Kubernetes Dashboard
- kube-prometheus-stack
- 2. GitOps の整備
- ArgoCD
- まとめ
- 参考・引用

はじめに
このブログは『RaspberryPi で構築する Bare-Metal Kubernetes』のエコシステム編です。 準備編では、機器類の準備、セットアップ、各種 OSS の選定と全体設計について紹介しました。 また、構築編では Kubernetes クラスタを構築し、アプリケーションをデプロイして MetalLB で公開しました。
エコシステム編では、より本番環境に近い Kubernetes の運用を目指すべく、モニタリング基盤と ArgoCD による GitOps を整備したいと思います。
前回のブログは こちら から読めます。
全体の流れ
以下の流れで作業します。
【準備編】準備・設計
- 機器類の準備: RaspberryPi 等の必要機器を準備します。
- 技術選定:主に CRI / CNI / LB を選定します。
- ネットワーク設計:ネットワーク構成と IP アドレスレンジを決定します。
- RaspberryPi の初期設定:OS のインストールとホストマシンの基礎設定をします。

【構築編】クラスタ構築
- Kubernetes のインストール:依存パッケージの追加とカーネルパラメータを設定します。
- Kubernetes の初期設定:Control-Plane / Data-Plane を構築します。
- アプリケーションのデプロイ:アプリケーションを追加して MetaLB で公開します。
- 【番外編】MetalLB の仕組み:MetalLB の仕組みについて紹介します。

【エコシステム編】エコシステム整備 ⭐️ 本ブログ ⭐️
- モニタリング基盤の整備:クラスタメトリクスを収集して監視基盤を構築します。
- GitOps の整備:GitHub とベアメタル Kubernetes を接続します。

エコシステム
エコシステム とは、インフラプラットフォームと連携する様々なツール、アプリケーション、エクステンションの集合体を指します。 Kubernetes のエコシステムには、クラスタそのものを構成するツールから、DevOps に則ったアプリケーションの開発とコンテナのデプロイパイプライン、スケジューリング、また運用における監視基盤からセキュリティツールまで様々なものが存在します。 CNCF(Cloud Native Computing Foundation)は Kubernetes に統合できる様々な周辺エコシステムを提供しています。

Ecosystem components | Tool examples |
---|---|
Container Runtime | Docker, containerd, CRI-O |
Networking | Calico, flannel, Cilium, MetalLB, Kong, Envoy |
Scheduling & Orchestration | Kubernetes, Knative, Kubeflow, Docker Swarm, KEDA |
Service Mesh | Istio, Linkerd, ASM, App Mesh |
Service Discovery | CoreDNS, etcd, KubeBrain, Cloud Map |
Application Definition | Helm, Kustomize, Artifact Hub, KubeVirt, Backstage, Dapr |
Monitoring & Logging | metrics-server, Prometheus, Grafana, OpenTelemetry, Elasticsearch, Fluentd, Kibana |
CI/CD | GitHub, GitLab, Jenkins, Spinnaker, ArgoCD, PipeCD, flux, k6 |
Security | cert-manager, Falco, OPA, TUF, in-toto, keycloal, Dex, Sysdig, Trivy, Aqua, Twistlock |
Database | TiDB, TiKV, CockroachDB, YugabyteDB, Cassandra, InfluxDB, Vitess |
Storage | Rook, Ceph, CubeFS, Longhorn, Portworx |
構築編 で使用した containerd や flannel、マニフェスト管理に使用した Kustomize や Helm もエコシステムの一つです。
今回は、モニタリングに代表される Prometheus / Grafana を用いた監視基盤と、Kuberentes の主要な CD ツールである ArgoCD を用いた GitOps を整備することで Kubernetes の運用を強化します。
1. モニタリング基盤の整備
モニタリング(監視)は、サービスのパフォーマンスやリソース使用状況、健全性、全体的な動作状態を追跡して分析するプロセスを指します。
開発者は、例えばサービスサーバがリクエストを正常に裁けているか、過剰にリソースを消費していないか、クラスタのキャパシティは十分であるか等、潜在的なシステム状態を常に把握する必要があります。 これらを、複雑化したクラスタに対して CLI ベースで確認するのは困難です。 そこで、クラスタおよびサービスの統合的な監視システムを設けておくことで、Kubernetes 環境のパフォーマンスを最適化して安全に運用することができます。
Kubernetes には metrics-server と呼ばれる、内部のメトリクスを公開するための Extension API が用意されています。 metrics-server をインストールすることで、様々なメトリクス収集ツールおよび可視化ツールとも連携することが可能になります。
Kubernetes Metrics Server
metrics-server:
Metrics Server is a scalable, efficient source of container resource metrics for Kubernetes built-in autoscaling pipelines. Metrics Server collects resource metrics from Kubelets and exposes them in Kubernetes apiserver through Metrics API for use by Horizontal Pod Autoscaler and Vertical Pod Autoscaler. Metrics API can also be accessed by kubectl top, making it easier to debug autoscaling pipelines.
概要
metrics-server は、Kubernetes のノードおよび Pod のメトリクスを Kubernetes API として公開することができる Extension API Server です。 ここで、Extension API Server とは、Kubernetes API Server を拡張する外部の API サーバのことです。 Extension API Server を API Service リソースとして登録することで、所定のグループに対する API リクエストを Extension API Server で処理させることが可能になります。

metrics-server は、HPA(Horizontal Pod Autoscaler)/ VPA(Vertical Pod Autoscaler)を利用するためのデータソースとして利用される他、kubectl top
コマンドを通じてメトリクスデータを確認することができるようになります。 実際、HPA / VPA を使用するためには、metrics-server が必須であるため、実質的に Kubernetes のコアコンポーネントとなっています。 マネージド Kubernetes の場合、EKS は Addon として用意されており、GKE の場合はクラスタを作成した時点で予め追加されています。
アーキテクチャ

metrics-server は metrics.k8s.io
グループの Extension API Server として API Service に登録されます。 主に、kubelet API をコールして Data-Plane ノード(https://<host>:10250/metrics/resource
)からデフォルト 15 秒間隔でメトリクスを収集します。 kubelet にリクエストを送信する際は、Control-Plane ServiceAccount の認証情報(kubeconfig)を使用します。 取得したメトリクスはパースされ、Control-Plane 内のメモリにキャッシュされます。
実際の運用では、metrics-server が取得したメトリクスを、さらに別のスクレイパが取得して Data-Plane の PV(Persistent Volume)等に永続化します。
追加手順
こちら のマニフェストを適用して metrics-server をデプロイします。
$ cd ./k8s/manifests/platform/metrics-server/playground
$ kustomize build . --enable-helm | kubectl apply -f -
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server-aggregated-reader created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
先ほど説明した API Service を確認してみます。
### apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io を確認
$ kubectl get apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io -o yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apiregistration.k8s.io/v1","kind":"APIService","metadata":{"annotations":{},"labels":{"app.kubernetes.io/env":"playground","app.kubernetes.io/group":"monitoring","app.kubernetes.io/instance":"metrics-server","app.kubernetes.io/managed-by":"argocd","app.kubernetes.io/name":"metrics-server","app.kubernetes.io/owner":"cloud-platform","app.kubernetes.io/version":"0.7.2","argocd.argoproj.io/instance":"metrics-server","helm.sh/chart":"metrics-server-3.12.2"},"name":"v1beta1.metrics.k8s.io"},"spec":{"group":"metrics.k8s.io","groupPriorityMinimum":100,"insecureSkipTLSVerify":true,"service":{"name":"metrics-server","namespace":"kube-system","port":443},"version":"v1beta1","versionPriority":100}}
creationTimestamp: "2025-01-22T13:13:53Z"
labels:
app.kubernetes.io/env: playground
app.kubernetes.io/group: monitoring
app.kubernetes.io/instance: metrics-server
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/name: metrics-server
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/version: 0.7.2
argocd.argoproj.io/instance: metrics-server
helm.sh/chart: metrics-server-3.12.2
name: v1beta1.metrics.k8s.io
resourceVersion: "3036933"
uid: 472d1eaa-4ae8-4503-b603-bd7361d327b2
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
port: 443
version: v1beta1
versionPriority: 100
status:
conditions:
- lastTransitionTime: "2025-01-22T13:13:53Z"
message: all checks passed
reason: Passed
status: "True"
type: Available
metrics-server がデプロイされると、kubectl
コマンドを通じてノードのメトリクスを確認できるようになります。
### ノードのメトリクスを確認
$ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 223m 5% 2087Mi 27%
node01 135m 3% 1306Mi 16%
node02 80m 2% 1500Mi 19%
node03 99m 2% 1180Mi 15%
これでクラスタのシステムメトリクスを公開することができました。
Kubernetes Dashboard
metrics-server によって収集されるメトリクスは数値データであるため、人間が時系列でシステムの動向を把握することは困難です。
そこで、コミュニティが用意している ダッシュボード を利用することで、取得したメトリクスを直感的に把握することができます。 ダッシュボードは Web ベースのユーザインターフェースとなっており、GUI でアプリケーションのデプロイやリソースの管理が可能です。
kubernetes-dashboard:
Kubernetes Dashboard is a general purpose, web-based UI for Kubernetes clusters. It allows users to manage applications running in the cluster and troubleshoot them, as well as manage the cluster itself. As of version 7.0.0, we have dropped support for Manifest-based installation. Only Helm-based installation is supported now. Due to multi-container setup and hard dependency on Kong gateway API proxy it would not be feasible to easily support Manifest-based installation. Additionally, we have changed the versioning scheme and dropped appVersion from Helm chart. It is because, with a multi-container setup, every module is now versioned separately. Helm chart version can be considered an app version now.
こちら のマニフェストを適用して kubernetes-dashboard をデプロイします。
$ cd ./k8s/manifests/platform/kubernetes-dashboard/playground
$ kustomize build . --enable-helm | kubectl apply -f -
namespace/kubernetes-dashboard created
customresourcedefinition.apiextensions.k8s.io/ingressclassparameterses.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongclusterplugins.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongconsumergroups.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongconsumers.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongcustomentities.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongingresses.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/konglicenses.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongplugins.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongupstreampolicies.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/kongvaults.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/tcpingresses.configuration.konghq.com created
customresourcedefinition.apiextensions.k8s.io/udpingresses.configuration.konghq.com created
serviceaccount/admin-user created
serviceaccount/kubernetes-dashboard-api created
serviceaccount/kubernetes-dashboard-kong created
serviceaccount/kubernetes-dashboard-metrics-scraper created
serviceaccount/kubernetes-dashboard-web created
role.rbac.authorization.k8s.io/kubernetes-dashboard-api created
role.rbac.authorization.k8s.io/kubernetes-dashboard-web created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard-metrics-scraper created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard-api created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard-web created
clusterrolebinding.rbac.authorization.k8s.io/admin-user created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard-metrics-scraper created
configmap/kong-dbless-config created
configmap/kubernetes-dashboard-web-settings created
secret/admin-user created
secret/kubernetes-dashboard-csrf created
service/kubernetes-dashboard-api created
service/kubernetes-dashboard-auth created
service/kubernetes-dashboard-kong-proxy created
service/kubernetes-dashboard-metrics-scraper created
service/kubernetes-dashboard-web created
deployment.apps/kubernetes-dashboard-api created
deployment.apps/kubernetes-dashboard-auth created
deployment.apps/kubernetes-dashboard-kong created
deployment.apps/kubernetes-dashboard-metrics-scraper created
deployment.apps/kubernetes-dashboard-web created
デフォルトの Helm Chart を使用した場合、Kong をネットワークプロキシとして使用します。参考

Kong:
Kong or Kong API Gateway is a cloud-native, platform-agnostic, scalable API Gateway distinguished for its high performance and extensibility via plugins. It also provides advanced AI capabilities with multi-LLM support. By providing functionality for proxying, routing, load balancing, health checking, authentication (and more), Kong serves as the central layer for orchestrating microservices or conventional API traffic with ease.
今回は MetalLB で LAN IP 192.168.68.242 を Kong Proxy に払い出します。
### kong-proxy に接続
$ kubectl get -n kubernetes-dashboard svc/kubernetes-dashboard-kong-proxy
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard-kong-proxy LoadBalancer 10.1.13.156 192.168.68.242 443:32176/TCP 49m
以下の URL に HTTPS でアクセスします。


ログインの際は Bearer トークンでアクセスします。 前述のマニフェストでデプロイした場合、admin-user という管理用のサービスアカウントが作成されているため、以下のコマンドでトークンを取得します。
### サービスアカウント(admin-user)のトークンを取得
$ kubectl -n kubernetes-dashboard describe secret admin-user | grep "token:" | awk '{print $2}'
ログインすると、各ノードの CPU やメモリの使用状況、Pod のステータスを Web UI から確認することができます。

kube-prometheus-stack

kube-prometheus-stack:
Installs core components of the kube-prometheus stack, a collection of Kubernetes manifests, Grafana dashboards, and Prometheus rules combined with documentation and scripts to provide easy to operate end-to-end Kubernetes cluster monitoring with Prometheus using the Prometheus Operator.
kubernetes-dashboard は Kubernetes 全体のリソース管理と基本的な監視機能を提供しており、必要最低限のメトリクスを十分に確認することができます。 kubernetes-dashboard は Kubernetes SIGs によって提供されていますが、CNCF はより柔軟なカスタマイズを可能とする kube-prometheus-stack というツールを提供しています。
kube-prometheus-stack とは、Prometheus や Grafana、Thanos、各種メトリクスエクスポータツールをオールインワンでデプロイできる Kubernetes 用のモニタリングツールです。

kube-prometheus-stack は Helm Chart で提供されるオープンソースなので、高額な SaaS と比較して無料で利用することができます。(メトリクスの長期保存には別途ストレージコストが掛かります。)
また、セルフホスティングによる管理コストが生じるものの、メトリクス量に応じて基盤をスケールできるため、サービスに適した柔軟なモニタリングシステムを構築することができます。
こちら のマニフェストを適用して kube-prometheus-stack をデプロイします。
なお、kube-prometheus-stack の CRD には、metadata.annotations
が 262144 bytes(≒ 260 KB)を超えるリソースが含まれているため、Server-Side Apply でデプロイします。
$ cd ./k8s/manifests/platform/kube-prometheus-stack/playground
$ kustomize build . --enable-helm | kubectl apply -f - --server-side
namespace/monitoring created
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com created
serviceaccount/kube-prometheus-stack-admission created
serviceaccount/kube-prometheus-stack-alertmanager created
serviceaccount/kube-prometheus-stack-grafana created
serviceaccount/kube-prometheus-stack-kube-state-metrics created
serviceaccount/kube-prometheus-stack-operator created
serviceaccount/kube-prometheus-stack-prometheus created
serviceaccount/kube-prometheus-stack-prometheus-node-exporter created
role.rbac.authorization.k8s.io/kube-prometheus-stack-admission created
role.rbac.authorization.k8s.io/kube-prometheus-stack-grafana created
clusterrole.rbac.authorization.k8s.io/kube-prometheus-stack-admission created
clusterrole.rbac.authorization.k8s.io/kube-prometheus-stack-grafana-clusterrole created
clusterrole.rbac.authorization.k8s.io/kube-prometheus-stack-kube-state-metrics created
clusterrole.rbac.authorization.k8s.io/kube-prometheus-stack-operator created
clusterrole.rbac.authorization.k8s.io/kube-prometheus-stack-prometheus created
rolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-admission created
rolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-grafana created
clusterrolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-admission created
clusterrolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-grafana-clusterrolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-kube-state-metrics created
clusterrolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-operator created
clusterrolebinding.rbac.authorization.k8s.io/kube-prometheus-stack-prometheus created
configmap/kube-prometheus-stack-alertmanager-overview created
configmap/kube-prometheus-stack-apiserver created
configmap/kube-prometheus-stack-cluster-total created
configmap/kube-prometheus-stack-controller-manager created
configmap/kube-prometheus-stack-etcd created
configmap/kube-prometheus-stack-grafana created
configmap/kube-prometheus-stack-grafana-config-dashboards created
configmap/kube-prometheus-stack-grafana-datasource created
configmap/kube-prometheus-stack-grafana-overview created
configmap/kube-prometheus-stack-k8s-coredns created
configmap/kube-prometheus-stack-k8s-resources-cluster created
configmap/kube-prometheus-stack-k8s-resources-multicluster created
configmap/kube-prometheus-stack-k8s-resources-namespace created
configmap/kube-prometheus-stack-k8s-resources-node created
configmap/kube-prometheus-stack-k8s-resources-pod created
configmap/kube-prometheus-stack-k8s-resources-workload created
configmap/kube-prometheus-stack-k8s-resources-workloads-namespace created
configmap/kube-prometheus-stack-kubelet created
configmap/kube-prometheus-stack-namespace-by-pod created
configmap/kube-prometheus-stack-namespace-by-workload created
configmap/kube-prometheus-stack-node-cluster-rsrc-use created
configmap/kube-prometheus-stack-node-rsrc-use created
configmap/kube-prometheus-stack-nodes created
configmap/kube-prometheus-stack-nodes-darwin created
configmap/kube-prometheus-stack-persistentvolumesusage created
configmap/kube-prometheus-stack-pod-total created
configmap/kube-prometheus-stack-prometheus created
configmap/kube-prometheus-stack-proxy created
configmap/kube-prometheus-stack-scheduler created
configmap/kube-prometheus-stack-workload-total created
secret/alertmanager-kube-prometheus-stack-alertmanager created
secret/kube-prometheus-stack-grafana created
secret/kube-prometheus-stack-prometheus created
service/kube-prometheus-stack-coredns created
service/kube-prometheus-stack-kube-controller-manager created
service/kube-prometheus-stack-kube-etcd created
service/kube-prometheus-stack-kube-proxy created
service/kube-prometheus-stack-kube-scheduler created
service/kube-prometheus-stack-alertmanager created
service/kube-prometheus-stack-grafana created
service/kube-prometheus-stack-kube-state-metrics created
service/kube-prometheus-stack-operator created
service/kube-prometheus-stack-prometheus created
service/kube-prometheus-stack-prometheus-node-exporter created
deployment.apps/kube-prometheus-stack-grafana created
deployment.apps/kube-prometheus-stack-kube-state-metrics created
deployment.apps/kube-prometheus-stack-operator created
daemonset.apps/kube-prometheus-stack-prometheus-node-exporter created
job.batch/kube-prometheus-stack-admission-create created
job.batch/kube-prometheus-stack-admission-patch created
alertmanager.monitoring.coreos.com/kube-prometheus-stack-alertmanager created
prometheus.monitoring.coreos.com/kube-prometheus-stack-prometheus created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-alertmanager.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-config-reloaders created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-etcd created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-general.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-cpu-usage-seconds-tot created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-memory-cache created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-memory-rss created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-memory-swap created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-memory-working-set-by created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.container-resource created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-k8s.rules.pod-owner created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-apiserver-availability.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-apiserver-burnrate.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-apiserver-histogram.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-apiserver-slos created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-prometheus-general.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-prometheus-node-recording.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-scheduler.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kube-state-metrics created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubelet.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-apps created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-resources created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-storage created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system-apiserver created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system-controller-manager created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system-kube-proxy created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system-kubelet created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-kubernetes-system-scheduler created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-node-exporter created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-node-exporter.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-node-network created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-node.rules created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-prometheus created
prometheusrule.monitoring.coreos.com/kube-prometheus-stack-prometheus-operator created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-alertmanager created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-apiserver created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-coredns created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-grafana created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-controller-manager created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-etcd created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-proxy created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-scheduler created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-state-metrics created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kubelet created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-operator created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-prometheus created
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-prometheus-node-exporter created
mutatingwebhookconfiguration.admissionregistration.k8s.io/kube-prometheus-stack-admission created
validatingwebhookconfiguration.admissionregistration.k8s.io/kube-prometheus-stack-admission created
デプロイが完了したら、まず Prometheus が対象ノードのメトリクスを収集できる状態にあるか確認します。
### Prometheus ダッシュボードを確認
$ kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9091:9090

kube-prometheus-stack に含まれている Node exporter が Control-Plane および Data-Plane の各ノードの /metrics
にアクセスしてメトリクスを収集します。 なお、Node exporter はデフォルトで 9100 番ポートを使用します。
- http://192.168.68.200:9100/metrics
- http://192.168.68.201:9100/metrics
- http://192.168.68.202:9100/metrics
- http://192.168.68.203:9100/metrics
ターゲットのステートが UP となっていれば、正常にメトリクスをスクレイプできる状態にあります。
次に、取得したメトリクスを Grafana ダッシュボードから確認します。 今回は Grafana の Service に LAN IP 192.168.68.241 を払い出しているので、以下の URL で確認します。
Username :
admin
Password :prom-operator
例えば、『Compute Resources > Cluster』では Kubernetes クラスタ全体のリソース使用量を確認することができます。

パネルから vCPU 約 5% 程度(実際 0.4core / 12core)、メモリ 約 15% 程度(実際 1GiB / 24GiB)の使用率となっていることが分かります。
kube-prometheus-stack を使用すると、他にも様々な Grafana ダッシュボードがデフォルトで追加されるため、こちらを参考にカスタムダッシュボードを整備すると良いでしょう。

2. GitOps の整備

次にマニフェストを GitHub で宣言的に管理し、Kubernetes に対するデプロイフローを整備するべく、GitOps(GitHub based Operations) を整備していきます。
従来、ソフトウェア開発の多くが自動化される一方で、インフラ部門では大部分が専門チームの手を必要とするマニュアルプロセスによって管理されていることが一般的でした。 GitOps は、特にインフラストラクチャのプロビジョニングプロセスを自動化するために使用されるアプローチです。 Kubernetes はマニフェストによってリソースを定義しているため、個々の開発者がローカル環境から都度適用していたのでは、リソースの一意性を確保することができません。
そこで、GitOps 戦略では GitHub を 信頼できる唯一の情報源(SSOT:Single Source Of Truth) とします。 開発者はマニフェストを記述した後、GitHub のリポジトリに Push し、所定の CD ツールを用いて Kubernetes にデプロイします。 こうすることで、GitHub を確認すればどのようなマニフェストが Kuberentes に適用されているかを容易に把握することができます。 そのため、GitOps のアプローチは IaC(Infrastructure as Code) に基づいていると言えます。
また、アプリケーションのメンテナンスもマニフェストを変更することで実施できるため、Kubernetes クラスタ自体に触れる必要はなく、属人化の防止や Immutable Infrastructure の観点でも有用です。

ArgoCD
Kubernetes の CD ツールとしては ArgoCD が現在の主流かと思います。

ArgoCD:
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
概要
ArgoCD は、Kubernetes にインストールすることで各リソースを Application というカスタムリソースで管理します。 Application CR には、GitHub のどのリポジトリのどのパスにマニフェストが存在するかが定義されており、継続的にウォッチします。
開発者がマニフェストを GitHub に Push し、既存のリソース状態と差分がある場合は、Kubernetes に自動的に適用します。 これにより、開発者は慣れ親しんだ GitHub を通じて、Kubernetes にリソースを適用したり削除したりすることができるため、kubectl
のようなコマンドを叩く必要がなくなります。
Kubernetes の CI/CD パイプラインの整備はリソースの一意性を確保する上でも欠かせない要素です。 ArgoCD は GitHub の他、GitLab や Jenkins、Bitbucket、TeamHub のようなバージョン管理システムもサポートしています。

追加手順
概要を押さえたところで、こちら のマニフェストを適用して ArgoCD(argocd) と ArgoCD Application(argocd-apps) の 2 種類をデプロイします。
前者は ArgoCD そのものを定義したマニフェストで、後者は ArgoCD で管理するプロジェクト(GitHub リポジトリ)を定義したマニフェストになります。
プロジェクトは以下のような YAML で定義されており、GitHub リポジトリと、リソースの適用先クラスタが指定されています。
projects:
bare-metal-kubernetes-playground:
namespace: argocd
description: bare-metal-kubernetes-playground
sourceRepos:
- [email protected]:GotoRen/bare-metal-kubernetes-playground.git
destinations:
- name: kubeadm-orenge-cloud-playground
namespace: '*'
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: '*'
kind: '*'
$ cd ./k8s/manifests/platform/argocd/playground
$ kustomize build . --enable-helm | kubectl apply -f -
namespace/argocd created
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io unchanged
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io unchanged
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io unchanged
serviceaccount/argocd-application-controller created
serviceaccount/argocd-applicationset-controller created
serviceaccount/argocd-dex-server created
serviceaccount/argocd-notifications-controller created
serviceaccount/argocd-redis-secret-init created
serviceaccount/argocd-repo-server created
serviceaccount/argocd-server created
role.rbac.authorization.k8s.io/argocd-application-controller created
role.rbac.authorization.k8s.io/argocd-applicationset-controller created
role.rbac.authorization.k8s.io/argocd-dex-server created
role.rbac.authorization.k8s.io/argocd-notifications-controller created
role.rbac.authorization.k8s.io/argocd-redis-secret-init created
role.rbac.authorization.k8s.io/argocd-repo-server created
role.rbac.authorization.k8s.io/argocd-server created
clusterrole.rbac.authorization.k8s.io/argocd-application-controller created
clusterrole.rbac.authorization.k8s.io/argocd-notifications-controller created
clusterrole.rbac.authorization.k8s.io/argocd-server created
rolebinding.rbac.authorization.k8s.io/argocd-application-controller created
rolebinding.rbac.authorization.k8s.io/argocd-applicationset-controller created
rolebinding.rbac.authorization.k8s.io/argocd-dex-server created
rolebinding.rbac.authorization.k8s.io/argocd-notifications-controller created
rolebinding.rbac.authorization.k8s.io/argocd-redis-secret-init created
rolebinding.rbac.authorization.k8s.io/argocd-repo-server created
rolebinding.rbac.authorization.k8s.io/argocd-server created
clusterrolebinding.rbac.authorization.k8s.io/argocd-application-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-notifications-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-server created
configmap/argocd-cm created
configmap/argocd-cmd-params-cm created
configmap/argocd-gpg-keys-cm created
configmap/argocd-notifications-cm created
configmap/argocd-rbac-cm created
configmap/argocd-redis-health-configmap created
configmap/argocd-ssh-known-hosts-cm created
configmap/argocd-tls-certs-cm created
secret/argocd-notifications-secret created
secret/argocd-secret created
service/argocd-applicationset-controller created
service/argocd-dex-server created
service/argocd-redis created
service/argocd-repo-server created
service/argocd-server created
deployment.apps/argocd-applicationset-controller created
deployment.apps/argocd-dex-server created
deployment.apps/argocd-notifications-controller created
deployment.apps/argocd-redis created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-server created
statefulset.apps/argocd-application-controller created
appproject.argoproj.io/bare-metal-kubernetes-playground created
job.batch/argocd-redis-secret-init created
デプロイが完了したら、ArgoCD のコンポーネントを確認します。
$ kubectl get pod -n argocd -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
argocd-application-controller-0 1/1 Running 0 31s 10.16.2.45 node02 <none> <none>
argocd-applicationset-controller-77789859bf-j76sg 1/1 Running 0 39s 10.16.3.54 node03 <none> <none>
argocd-dex-server-9b94988dd-x6wtx 1/1 Running 0 57m 10.16.3.46 node03 <none> <none>
argocd-notifications-controller-64d4ccc9cd-cqfvm 1/1 Running 0 57m 10.16.2.39 node02 <none> <none>
argocd-redis-7fb9cbbcdd-mvf9b 1/1 Running 0 57m 10.16.1.50 node01 <none> <none>
argocd-repo-server-bc97c8b76-glt8t 1/1 Running 0 44s 10.16.1.60 node01 <none> <none>
argocd-server-5c68b48f74-rfthr 1/1 Running 0 45s 10.16.3.53 node03 <none> <none>
コンポーネントの種類と機能概要は以下の通りです。
コンポーネント | 機能 |
---|---|
application-controller | Kubernetes クラスタにマニフェストを適用します。 |
applicationset-controller | 対象アプリケーション(ApplicationSet)を継続的に監視して差分を取得します。 |
dex-server | (SSO を採用する場合)OIDC による ID 認証とユーザマッピングを提供し、外部の IdP に対して認証を行います。 |
notifications-controller | Slack 等と連携してアプリケーションのステータス情報を通知します。 |
redis-server | application-controller の処理結果をキャッシュします。 |
repo-server | マニフェストおよび Helm Chart リポジトリのクローンを取得します。 |
argocd-server (argocd-apiserver) | ArgoCD の Web UI ダッシュボードや API を提供します。 |
ArgoCD の Web UI(argocd-server)には LAN IP 192.168.68.240 を払い出しているので、以下の URL で確認します。

Username :
admin
Password : 別途取得
### ArgoCD 初期パスワード
$ kubectl -n argocd get secret/argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
ログインできら ArgoCD のプロジェクトを確認します。
Settings > Projects > bare-metal-kubernetes-playground > SUMMARY
上で定義しているプロジェクトの設定が反映されていることが分かります。

GitHub との接続
次に、GitHub のリポジトリと ArgoCD のプロジェクトを紐付けます。
具体的には、GitHub に公開鍵を登録しておき、ArgoCD に秘密鍵を登録しておきます。 すると、ArgoCD Repo Server は対象マニフェストを GitHub からクローンして、Application Controller がクラスタにデプロイします。
- 管理用 PC(macOS)で ed25519 SSH 鍵を発行します。
$ cd ~/.ssh
$ ssh-keygen -t ed25519 -f bare-metal-argocd_id_ed25519
- 公開鍵を GitHub に登録します。
Settings > Deploy keys
### 公開鍵をコピー
$ cat ~/.ssh/bare-metal-argocd_id_ed25519.pub | pbcopy

- 秘密鍵を ArgoCD に登録します。
Settings > Repositories > CONNECT REPO
### 秘密鍵をコピー
$ cat ~/.ssh/bare-metal-argocd_id_ed25519 | pbcopy

CONNECT を押下して保存した後、CONNECTION STATUS が Successful になっていれば GitHub との連携が完了しています。

今回は直接 ArgoCD の Web UI から登録していますが、外部のシークレットプロバイダに秘密鍵を登録しておき、External Secrets Operator(ESO) 等で読み込ませることもできます。
Application CR の追加
構築編 でデプロイした Nginx を ArgoCD で管理します。
リソースを ArgoCD で管理させる場合、カスタムリソースとして追加されている kind: Application
を定義します。
$ sudo vim ./k8s/manifests/services/nginx/playground/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx
namespace: argocd
spec:
project: bare-metal-kubernetes-playground
destination:
namespace: nginx
server: https://kubernetes.default.svc
source:
repoURL: [email protected]:GotoRen/bare-metal-kubernetes-playground.git
path: k8s/manifests/services/nginx/playground ## マニフェストのパス
targetRevision: main
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: true
prune: true
Application を追加します。
$ kubectl apply -f k8s/manifests/services/nginx/playground/application.yaml
これにより、ArgoCD は GitHub のマニフェストをクローンして、クラスタに適用されているマニフェストと比較します。 もし、差分がある場合は ArgoCD Application Controller が再度 Apply します。

ArgoCD によって管理されているリソースは、Web UI の Applications タブから確認することができます。

ここで、各 Kubernetes リソースを視覚的に把握できます。 例えば、Nginx の場合は、Deployment が OwnerResource で、現在の Pod 数(Replica)は 1 であることが分かります。

また、トラフィックフローも確認することができます。 ここで、Nginx Pod は Cluster Service を通じて公開されており、IP アドレスは 192.168.68.230 であることが分かります。

Application を他のリソースに対しても定義していきます。

Application として ArgoCD に管理されているリソースは、例えば kubectl delete
コマンド等でクラスタのリソースが削除された場合も、GitHub のマニフェストに基づき Reconciliation されます。
以上のように ArgoCD を用いることで、クラスタのリソースを常に GitHub 上のマニフェストに揃えることができます。 そのため、複数人で開発を進める場合でも一意性を確保することが可能になります。
注意点
一度 Application を定義すると、そのリソースは ArgoCD によって完全に管理されます。 そのため、Web UI から DELETE を実行した場合、デプロイ済みのリソースは全て削除されます。
もし、ArgoCD の追跡対象から外したい場合は、Application マニフェストを最初に削除するようにして下さい。
まとめ

今回のブログでは、より本番環境に近い Kubernetes の運用を目指すべく、モニタリング基盤と ArgoCD による GitOps の整備について紹介しました。 Kubernetes には様々なエコシステムが用意されており、それらを活用することで充実したシステム運用を実現することができます。 特にモニタリング基盤は、Kubernetes のキャパシティを把握したり、アプリケーションのパフォーマンスを最大化するために無くてはならない要素です。
また、Kubernetes はマニフェストでアプリケーションを管理しますが、複数人の開発者が携わる環境では、各々がローカル上からマニフェストを適用することでリソースの一意性を確保することが困難になります。 GitOps のアプローチでは、このような課題に対して、GitHub にマニフェストを集約し、Kubernetes に CD することで、IaC に基づく宣言的なインフラストラクチャの運用を可能にします。
今回 Kubernetes における CD ツールとして、デファクトスタンダードとなっている ArgoCD を用いて GitOps を整備しました。 各リソースを ArgoCD に管理させることで、都度 kubectl
コマンドを実行する必要が無くなり、慣れ親しんだ GitHub をベースとした運用を実現することができます。
Kubernetes や周辺エコシステムは基本的に OSS で構築することができるため、ベアメタルでセルフホスティングした Kubernetes でも十分にサービスを展開することができます。