メインコンテンツへ移動

Kubernetes

運用プラットフォーム一式を監視対象の HAP/HDP Kubernetes クラスター内にデプロイします。Prometheus が ServiceAccount でクラスターを自動検出するため、Token や NodePort は不要です。

以下の手順には、Kubernetes 形態でのデプロイに必要な全工程が含まれます。

Kubernetes メトリクスの収集には監視対象クラスター内へのデプロイが必要

クラスター外にデプロイした場合はホストとミドルウェアのみを監視でき、Kubernetes 自体のノード/Pod/Deployment メトリクスを直接収集できません(1.5.3 以降、クラスター外からの収集方式は廃止されました)。

開始前の準備​

必要なもの

  • 正常稼働している HAP/HDP クラスター
  • 監視対象ミドルウェア(実際の構成に応じた MongoDB/MySQL/Redis/Kafka/Elasticsearch)にクラスター内からアクセスでき、デプロイ概要に従って読み取り専用アカウントを準備済みであること
  • Flink などの外部 Web UI は任意です。デプロイ後に「データソース」でカスタムページとして登録します。
  • kubectl で対象クラスターを操作できること。未準備の場合は付録 A:テストクラスターの構築を参照してください。

⬇ k8s-cluster.tar.gz をダウンロード(展開すると次のファイルが得られます):

00-namespace.yaml 11-configmap.yaml 30-stateful.yaml 50-daemonsets.yaml
10-secret.yaml.example 20-rbac.yaml 40-stateless.yaml

データ永続化方式の選択

ステートフルなコンポーネント(Prometheus/Grafana/ops-mongo)にはデータの永続化が必要です。次の 2 つから選択し、手順 2 の作業を決定します:

PVC(デフォルト、推奨)hostPath(代替)
保存先ストレージボリューム。ノード再作成でも保持特定ノードのローカルディレクトリ
使用するマニフェストk8s-cluster/ の分割ファイル単一の ops.yaml
前提デフォルトの StorageClass がある不要。ただしノード固定が必要
適した環境クラウド管理クラスター(TKE/ACK/EKS)、本番環境ノードが固定された自前クラスター、使用可能な StorageClass がない環境
クラウド管理クラスターでは PVC を使用してください

クラウドのノードは交換可能であり、自動復旧、スケーリング、バージョンアップ時に再作成されます。hostPath のデータは Pod とともに移動しません。 Prometheus の TSDB が失われるとメトリクス履歴の検索に影響し、ops-mongo が失われるとアラートルール、通知チャンネル、データソース設定、スロークエリ履歴がすべて失われます。

以下は PVC を中心に説明し、hostPath との差異を各手順に記載します。


手順 1:イメージの取得​

crictl pull registry.cn-hangzhou.aliyuncs.com/mdpublic/ops-allinone:1.5.12

ops-nodeagent は DaemonSet として実行されるため、全ノードにこのイメージが必要です。オフライン環境はオフラインパッケージを参照してください。

国境を越えるイメージ取得

異なる地域のクラスターで 2.16GB のイメージを取得するには十数分かかる場合があり、ノードごとの所要時間も異なります。 あるノードで処理が止まる場合は、そのノードに kubectl cordon を実行し、DaemonSet 以外の Pod を削除して、イメージをキャッシュ済みのノードに再スケジュールできます(DaemonSet は各ノードで取得完了を待つ必要があります)。海外では近隣のイメージレジストリへの事前同期を推奨します。


手順 2:永続化の準備​

PVC(推奨)​

デフォルトの StorageClass が必要です。次のコマンドで確認します:

kubectl get sc

出力に (default) の付いた StorageClass があることを確認します。ない場合は、以下のいずれかの方法で作成します。

クラウド管理クラスター(TKE/ACK/EKS)​

通常はクラウドプロバイダーがデフォルトの StorageClass を提供しますが、オンライン拡張に対応した StorageClass の作成を推奨します。PVC 作成後の StorageClass 変更には通常ディスク再作成が必要です。Tencent Cloud TKE の例:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cbs-expandable
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: com.tencent.cloud.csi.cbs
parameters:
diskType: CLOUD_PREMIUM # 明示指定。TKE のデフォルト SC の `type: cbs` は無効なパラメーターで、ドライバーのデフォルト値に依存
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true # TKE のデフォルト SC は通常この設定が無効。ドライバーはオンライン拡張に対応

作成後は元の StorageClass のデフォルト指定を解除し、デフォルトが 2 つ存在しないようにします:

kubectl patch sc <元のデフォルトSC名> -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
拡張時は PVC の capacity だけで判断しないでください

PVC.status.capacity は第 2 段階(ノード上の resize2fs)の完了後に更新されます。この段階には Pod によるマウントが必須です。未マウントの PVC は古い値のまま、condition が FileSystemResizePending になります。これは拡張失敗を意味せず、クラウドディスク自体の拡張は通常完了しています。

自前/単一ノードのテストクラスター​

クラウドディスクがない場合は local-path-provisioner を使用し、ノードのローカルディレクトリに保存できます:

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
kubectl patch sc local-path -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
単一ノードでは必ず先に PVC 容量を調整

30-stateful.yaml のデフォルト要求は、本番クラスター向けに prometheus 100Gi + ops-mongo 20Gi + grafana 10Gi = 130Gi です。

local-path-provisioner はディスク空き容量を検証しません。PVC が正常に Bound になっても、Prometheus がディスクを使い切ると no space left on device が発生し、サービス障害と誤認しやすくなります。テストマシンは通常 100G 程度のため、apply 前に調整してください:

# 30-stateful.yaml の 3 か所の volumeClaimTemplates
resources:
requests:
storage: 20Gi # ops-prometheus,テスト環境
# storage: 5Gi # ops-mongo
# storage: 5Gi # ops-grafana

また local-path はオンライン拡張非対応で、増量には PVC の再作成が必要です。本番では allowVolumeExpansion に対応するクラウドディスク SC を使用してください。

hostPath(代替)​

StorageClass を使用せず、ステートフルなコンポーネントを特定ノードに固定して、そのローカルディスクに保存します。対象ノードにラベルを付けます:

kubectl label node <ノード名> hap-ops=true

kubectl get node -o wide でノード名を確認します。データはそのノードの /data/mdis/ 以下に統一されます(prometheus/grafana/loki/tempo/mongo の各サブディレクトリ)。


手順 3:オブジェクトストレージの準備(任意)​

ログ(Loki)とトレース(Tempo)はデフォルトでローカルボリュームに保存されます。単一ノードのディスク容量に制限されず長期保持する場合はオブジェクトストレージを用意します。バケットは 2 つ必要です:

バケット用途推奨名
ログLoki ブロックストレージmdis-loki
トレースTempo ブロックストレージmdis-tempo

設定先は 2 か所に分かれます:

設定内容設定先説明
endpoint、AK/SK、path style10-secret.yaml の ENV_S3_*手順 4 で入力
バケット名30-stateful.yaml の ops-loki/ops-tempo それぞれの ENV_S3_BUCKET_LOKI/ENV_S3_BUCKET_TEMPO上表の名前が設定済み。同じ名前で作成すれば変更不要

⚠️ 2 コンポーネントは必ず別のバケットを使用してください。共通の ENV_S3_BUCKET だけを設定すると同じバケットに保存され、ディレクトリ構造を互いに上書きします(起動ログに警告が出ます)。各クラウドの endpoint と互換性はオブジェクトストレージを参照してください。

長期保持が不要なら、この手順はスキップし、後から設定できます。


手順 4:設定の入力​

# 1. 名前空間
kubectl apply -f 00-namespace.yaml

# 2. Secret:example をコピーして入力
cp 10-secret.yaml.example 10-secret.yaml

10-secret.yaml の以下 2 項目は必須です:

変数説明
ENV_OPS_TOKENログイントークン。強力なランダム文字列を指定
ENV_ALERT_CRYPTO_KEY32 文字の 16 進数。openssl rand -hex 16 で生成

手順 3 でオブジェクトストレージを準備した場合は、ENV_S3_ENDPOINT/ENV_S3_ACCESS_KEY/ENV_S3_SECRET_KEY/ENV_S3_FORCE_PATH_STYLE も入力します(バケット名は前の手順で設定)。

kubectl apply -f 10-secret.yaml

その他の調整項目(データ保持期間、コンポーネントのアドレスなど)は 11-configmap.yaml にあり、デフォルト値をそのまま使用できます。必要に応じて環境変数を参照してください。

shell heredoc で Secret を生成しないでください

kubectl create secret または YAML の直接記述を使用してください。heredoc のエスケープによって引用符が変数値に入り、ログイン認証に失敗して原因の特定が難しくなることがあります。

hostPath の場合:上記の分割マニフェストは使用せず、単一マニフェストをダウンロードして必要箇所を変更します。

⬇ ops.yaml をダウンロード

全コンポーネント(ゲートウェイ、Prometheus、Grafana、Loki、Tempo、Alloy、MongoDB、ミドルウェア exporter、node-exporter)と Service 定義を含み、名前空間は hap-ops です。ダウンロード後、ENV_OPS_TOKEN、ENV_ALERT_CRYPTO_KEY、イメージ tag、ノードラベルを変更してください。

Kubernetes パネルはデプロイ時に自動有効化

マニフェストには Prometheus の ServiceAccount/ClusterRole と kube-state-metrics が含まれます。運用プラットフォームは監視対象クラスター内で動作し、PVC 構成と同様にデプロイ完了後からクラスターを収集できます。

k8s-addons を追加デプロイしないでください。これは運用プラットフォームが監視対象クラスターの外にある場合の収集コンポーネントで、別の名前空間を作成して本マニフェストと併存します。現在の運用プラットフォームで別のクラスターを管理する場合のみ必要です。Kubernetes クラスター監視を参照してください。

v1.5.7 より前のマニフェストには RBAC と kube-state-metrics がなく、デプロイ後の Kubernetes パネルにデータが表示されません。旧版からアップグレードする場合は再ダウンロードし、上書きで apply してください。


手順 5:起動​

kubectl apply -f 11-configmap.yaml -f 20-rbac.yaml \
-f 30-stateful.yaml -f 40-stateless.yaml -f 50-daemonsets.yaml

# 準備完了を待機(初回は 2.16GB のイメージ取得が必要。国境を越えるネットワークでは十数分かかる場合あり)
kubectl get pods -n hap-ops -w

hostPath の場合:kubectl apply -f ops.yaml(hap-ops 名前空間を含む)で起動し、kubectl delete -f ops.yaml で停止します。両構成とも名前空間は hap-ops で、以降の検証コマンドは共通です。

すべて Running になったら、アラートサブシステムのマウントを確認します:

kubectl logs deploy/ops-gateway -n hap-ops | grep 告警子系统
# 期待値:[alert] 告警子系统已挂载 /api/alert/
gateway は ops-mongo より先に起動しても問題ありません

Kubernetes には compose の depends_on がないため、イメージ取得の時間差で gateway が先に Running になる場合があります。1.4.5 以降、ops-server が ops-mongo に接続できない場合はバックグラウンドで 3s/6s/12s と間隔を延ばしながら再試行し、mongo の準備完了後に自動的にアラートサブシステムをマウントします。手動再起動は不要です。最終的に上記ログが出れば正常です。


手順 6:外部公開とアクセス​

ops-gateway-ui は NodePort 30881 で公開されます。クラスター外では nginx をリバースプロキシとして使用します:

upstream hap-ops {
server <node1>:30881 max_fails=0;
server <node2>:30881 max_fails=0;
server <node3>:30881 max_fails=0;
}

location /mdis/ {
allow <運用側の送信元IP>;
deny all;
proxy_pass http://hap-ops;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
}

ConfigMap には ENV_OPS_SUB_PATH=/mdis があるため、/mdis/ をそのまま転送し、rewrite は不要です。https://ドメイン/mdis/web/ にアクセスします。ログイン Token は ENV_OPS_TOKEN です。

セキュリティ境界は IP 許可リスト + 運用プラットフォームの 32 文字 Token + セッション Cookie で構成され、追加の Basic Auth は不要です。

Service を分割する理由

type: NodePort は Service のすべてのポートに NodePort を割り当てます。そのため 8081(クラスター内の Prometheus のサービスディスカバリー専用である ops-server 内部 API)まで外部公開されてしまいます。UI は NodePort、内部 API は ClusterIP のみとします。


手順 7:検証​

pip install playwright && playwright install chromium
python3 mdis_regression.py --base http://<ノードIP>:30881 --token <ENV_OPS_TOKEN>

終了コード 0 は全項目成功です。特定ミドルウェアのパネルにデータがない場合は、まず「データソース」の収集状態を確認します。赤い状態にカーソルを合わせると失敗理由が表示され、多くの問題を特定できます。その他はよくある質問を参照してください。


デプロイ後の連携​

完了後、監視対象を接続します:

  • データソース:ホストとミドルウェアを登録。収集設定は ConfigMap ではなく UI のみで行います。
  • Kubernetes クラスター:ノード/コンテナ/クラスターオブジェクト状態を収集
  • Node Exporter:クラスター外部のサーバーを監視(内部ノードは ops-nodeagent が監視)
  • サービスログ:HAP/HDP マイクロサービスのログを運用プラットフォームに送信
  • トレース:業務システムからトレースを送信

付録 A:テストクラスターの構築​

既存クラスターがある場合はスキップできます。以下は Debian 12 で kubeadm を使う最小手順で、テスト環境の参考用です。本番は Kubernetes 公式ドキュメントに従ってください。

# 1. swap を無効化(kubelet はデフォルトで swap 無効化が必要)
swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab

# 2. カーネルモジュールとネットワーク設定
cat > /etc/modules-load.d/k8s.conf <<'EOF'
overlay
br_netfilter
EOF
modprobe overlay && modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

# 3. containerd(必ず SystemdCgroup を有効化。無効だと kubelet が繰り返し再起動)
apt-get update && apt-get install -y containerd
mkdir -p /etc/containerd && containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd && systemctl enable containerd

# 4. kubeadm / kubelet / kubectl
apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key \
| gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' \
> /etc/apt/sources.list.d/kubernetes.list
apt-get update && apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

コントロールプレーンを初期化します:

kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--image-repository registry.aliyuncs.com/google_containers

export KUBECONFIG=/etc/kubernetes/admin.conf
echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
中国本土ではイメージ取得先の設定が必要です

kubeadm init はデフォルトで registry.k8s.io からコントロールプレーンのイメージを取得しますが、中国本土からのアクセスは制限されます。[preflight] Pulling images のままタイムアウトするため、--image-repository registry.aliyuncs.com/google_containers が必要です。kubeadm config images pull でも同じ引数を指定しないと事前取得に失敗します。

CNI をインストールします(未インストールの場合はノードが NotReady のままになります):

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

単一ノードクラスターではコントロールプレーンの taint も削除しないと、業務 Pod をスケジュールできません:

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

検証:

kubectl get nodes # Ready であること
kubectl get pods -A # すべて Running であること

付録 B:複数ノードと監視専用ノード​

簡易版と標準版は同じマニフェストを使用します。複数ノードクラスターでは以下を確認してください:

  1. 監視専用ノード(任意):ノードに taint を付け、各ワークロードに toleration を追加します:
    kubectl taint nodes <ノード名> hap-ops=true:NoSchedule
    # spec.template.spec に追加
    tolerations:
    - { key: "hap-ops", operator: "Equal", value: "true", effect: "NoSchedule" }
  2. 複数ミドルウェアの収集:標準クラスターには複数の mongo/kafka/es があることがあります。複数の agent は不要です。1.3.0 以降は単一の ops-agent で複数対象を監視でき(ポートは自動割り当て)、「データソース」に複数登録するだけです。
  3. ノードメトリクス:ops-nodeagent は DaemonSet として全ノードを自動的に監視し、個別設定は不要です。クラスター外部のサーバーは対象上に Node Exporter を個別デプロイしてください。

付録 C:スタンドアロンとの 3 つの構造上の違い​

以下はクラスターモード固有の設定です。スタンドアロンの Compose 設定をそのまま流用しないでください。

1. ops-agent の Service は headless(clusterIP: None)が必須

ops-agent は各データソースインスタンスに exporter を動的起動し、ポートを動的割り当てします:

mongodb → 19400, 19401, 19402 … MongoDB インスタンスごとにポートを追加
kafka → 19500, 19501 …
mysql → 19100 …

通常の ClusterIP Service は ports に列挙したポートのみ転送します。動的ポートはすべて connection refused となり、Prometheus はすべてのミドルウェア target を DOWN と表示します。headless Service の DNS は Pod IP を直接返すため、列挙せずに任意のポートへ接続できます。

2. コンテナログには alloy-logs DaemonSet が必要

ops-alloy(ROLE=alloy)は docker.sock でログを収集しますが、Kubernetes は containerd を使うため、Kubernetes 上ではコンテナログを収集できません(docker.sock 接続エラーが定期的に出ますが、想定内の通知で無視できます。Kubernetes 上では OTLP 受信を担当します)。50-daemonsets.yaml の alloy-logs が Kubernetes API で Pod ログを読み取り、コンテナログを収集します。

3. ステートフルコンポーネントは Deployment ではなく StatefulSet

Deployment のデフォルトのローリング更新では、新旧 Pod が同じディスクを同時にマウントします(このため hostPath では strategy: Recreate が必要です)。単一レプリカの StatefulSet は「先に削除してから作成」するため、この問題を回避できます。