コンテンツにスキップ

プラクティス集@Kubernetes

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. リポジトリの編成規約

リポジトリ分割のメリット

リポジトリを分割することにより、以下のメリットがある。

  • 認可スコープをリポジトリ内に閉じられるため、運用チームを別に分けられる。


アプリと IaC を同じリポジトリで管理

アプリケーションと同じリポジトリにて、kubernetes ディレクトリを作成し、ここにマニフェストを配置する。

repository/
├── app/ # アプリケーション
├── manifests/
│   └── kubernetes/
│       ├── foo/
│       │   ├── deployment.yaml
│       │   ├── service.yaml
│       │   ├── persistent-volume.yaml
│       │   └── persistent-volume-claim.yaml
│       │
...


アプリと IaC を異なるリポジトリで管理 (推奨)

▼ 各マイクロサービスを同じリポジトリで管理

repository/
├── foo/ # foo サービス
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── persistent-volume.yaml
│   └── persistent-volume-claim.yaml

├── bar/ # bar サービス
└── baz/ # baz サービス

▼ 各マイクロサービスを異なるリポジトリで管理

repository/ # foo サービス
├── deployment.yaml
...
repository/ # bar サービス
├── deployment.yaml
...
repository/ # baz サービス
├── deployment.yaml
...


01-02. ディレクトリ構成規約

ディレクトリ/ファイルの構成

▼ マイクロサービス別

マイクロサービス別にディレクトリを作成し、Kubernetes リソースごとに異なるマニフェストを定義する。

kubectl コマンドの実行時にマニフェストの送信の順番を制御しにくいデメリットがある。

repository/
├── foo/ # foo サービス
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── persistent-volume.yaml
│   └── persistent-volume-claim.yaml

├── bar/ # bar サービス
└── baz/ # baz サービス

加えて、実行環境やコンポーネント (app、db) 別に分割してもよい。

repository/
└── foo/ # foo サービス
    ├── tes # テスト環境
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── persistent-volume.yaml
    │   └── persistent-volume-claim.yaml
    
    ├── prd # 本番環境
    └── stg # ステージング環境
repository/
└── foo/ # foo サービス
    ├── app/ # app コンポーネント
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── persistent-volume.yaml
    │   └── persistent-volume-claim.yaml
    
    └── db/ # db コンポーネント
        ├── stateful-set.yaml
        ├── service.yaml
        ├── persistent-volume.yaml
        └── persistent-volume-claim.yaml

▼ ディレクトリ無し

ディレクトリを作成しない。

代わりに、マイクロサービス別にマニフェストを定義し、関連するすべての Kubernetes リソースをこのなかで定義する。

repository/
├── foo.yaml # foo サービス (Deployment、Service、PersistentVolume、...)
├── bar.yaml # bar サービス
└── baz.yaml # baz サービス


02. 命名規則

Namespace の粒度

application フロントエンドアプリケーション、各種マイクロサービスを置く
batch バッチサービスを置く
system 監視サービスなどを置く


リソース名

▼ 冗長な名前が嫌いな場合

冗長な名前が嫌いな場合は <マイクロサービス名> とする。

基本はこれを使用する。

ケバブケースとする。

Kubernetes リソース
Service foo
Deployment foo
PersistentVolume foo
... ...

▼ 冗長な名前が嫌いでない場合

嫌いでない場合は <マイクロサービス名>-<Kubernetesリソース名> とする。

ケバブケースとする。

Kubernetes リソース
Service foo-service
Deployment foo-pod
PersistentVolume foo-persistent-volume
... ...


マニフェストのファイル名

▼ 重複しない場合

ファイル名は、Kubernetes リソース名 (例:deployment.yaml ファイル) と同じにする。

基本的にはこれを使用する。

ケバブケースとする。

GitHub の公式チャートを見ると、命名方法が参考になる。

repository/
├── deployment.yaml
├── service.yaml
├── persistent-volume.yaml
└── persistent-volume-claim.yaml

▼ ファイル名重複する場合

1 個のディレクトリ内で Kubernetes リソースが重複する場合、Kubernetes リソース名をつけることができない。

その場合、app.kubernetes.io キーの値 (例:<マイクロサービス名> または <マイクロサービス名>-<Kubernetesリソース名>) と同じにする。

# 全て Application
# 各 Application は、foo マイクロサービス、bar マイクロサービス、baz マイクロサービス、にデプロイする。
repository/
├── foo.yaml
├── bar.yaml
└── baz.yaml
# 全て Application
# 各 Application は、foo マイクロサービス、bar マイクロサービス、baz マイクロサービス、にデプロイする。
repository/
├── foo-application.yaml
├── bar-application.yaml
└── baz-application.yaml


拡張子

Kubernetes に関する開発プロジェクトを確認すると、そのほとんとで、yaml ファイルの拡張子を yml ではなく yaml に統一している。

そこで、Kubernetes や関連技術 (Istio、Helm、Skaffold、Envoy など) の yaml ファイルの拡張子を yaml で統一する。

repository/
├── foo/ # foo サービス
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── persistent-volume.yaml
│   └── persistent-volume-claim.yaml

├── bar/ # bar サービス
└── baz/ # baz サービス


マニフェストの粒度

1 個のマニフェストに、1 個の Kubernetes リソースを定義する。


03. 実行環境

開発環境

▼ Kubernetes の実行環境

開発環境で Kubernetes リソースの機能追加を検証するツールの例を記載する。

Minikube Docker for Desktop Kind クラウドプロバイダー (Amazon EKS、Google Cloud GKE など)
概要 カスタマイズ性が高いため、カスタマイズ次第で本番環境と開発環境の差異を小さくできる。2022 年 3 月の現在では、Kubernetes の開発環境として、ベタープラクティスである。 セットアップが非常に簡単 (有効化するだけ) なため、開発に取り掛かるまでが早い。 セットアップが簡単なため、開発に取り掛かるまでが早い 実行環境を開発環境としても使用する。開発者ごとに異なる Namespace を作成する。これを採用している企業が多い。
セットアップの難易度 簡単 非常に簡単 簡単 難しい
コンテナランタイム docker、containerd、cri-o docker containerd (ホスト OS の docker コンテナを作成し、このなかに containerd コンテナを作成する) docker、containerd
Kubernetes のバージョン 任意のバージョンを指定できる。 Docker for Desktop のバージョンごとに、Kubernetes のバージョンが固定される。 任意のバージョンを指定できる。 任意のバージョンを指定できる。
マルチ Node 可能 可能 可能 可能
Node のカスタマイズ性 高い 低い 高い 高い
料金 無料 無料 無料 非常に高い

▼ Kubernetes リソースの apply

Skaffold Telepresence
概要 CIOps によって、Kubernetes の開発環境に Kubernetes リソースを作成する。本番環境への CIOps は非推奨であるが、開発環境であれば問題ない。 ローカルマシンに対するリクエストを、リモートにある Kubernetes の実行環境にフォワーディングする。
https://thinkit.co.jp/article/17853


テスト環境、ステージング環境、本番環境

▼ Kubernetes の実行環境

開発環境で検証後、Kubernetes リソースの機能追加を検証するツールの例を記載する。

すべて自前 オンプレ クラウド
Kuberbetes オーケストレーションツール すべて自前なため、自由にカスタマイズできる。 Kubeadm、Rancher、Kops、Kubespray、ベアメタル (例;EKS Anywhere、Anthos on Baremetal)など Amazon EKS、Google Cloud GKE など
説明 オンプレミス上にコントロールプレーン Node やワーカーNode となる仮想サーバーを事前に作成しておく。ユーザー自身が、Cluster を作成し、仮想サーバーにコントロールプレーン Node あるいはワーカーNode としての役割を割り当てる。 オンプレミス上にコントロールプレーン Node やワーカーNode となる仮想サーバーを事前に作成しておく。ツールを使用して、仮想サーバーを Cluster に参加させ、仮想サーバーにコントロールプレーン Node あるいはワーカーNode としての役割を割り当てる。マニフェストの DB として KVS を使用する必要があるが、KVS 用クエリを RDB 用クエリに変換するツール (例:Kine) を使用すれば、RDB も使用できる。 セルフマネージドワーカーNode の場合は、ワーカーNode となる仮想サーバーを事前に作成しておく。コントロールプレーン Node は必ずマネージドになる。クラウドプロバイダーを使用して、仮想サーバーを Cluster に参加させ、仮想サーバーにコントロールプレーン Node あるいはワーカーNode としての役割を割り当てる。
メリット すべて自前なため、自由にカスタマイズできる。 カスタマイズ性が高い。 マネージドであるため、ユーザーが Kubernetes のワーカーNode を管理するコストが低い。執筆時点 (2022 年 3 月) では、Kubernetes の本番環境として、ベタープラクティスである。
デメリット ユーザーが Kubernetes のワーカーNode を管理するコストが高い。 ユーザーが Kubernetes のワーカーNode を管理するコストが高い。 カスタマイズ性が低い

▼ Kubernetes リソースの apply

CIOps GitOps
概要 CIOps によって、Kubernetes の本番環境に Kubernetes リソースを作成する。非推奨である。 GitOps によって、Kubernetes の本番環境に Kubernetes リソースを作成する。

▼ 実行環境の分割

Cluster の複数の実行環境 (dev-*stg-*prd-*) を用意したい場合、個人的にはその分 Cluster を増やすようにする。

実行環境が 5 個や 10 個となってくると、Cluster の分だけアップグレードや Sync 漏れ (手動の場合) が発生するため、運用コストが高くなるというデメリットはある。

一方で、Namespace を実行環境の粒度とすると、上記のデメリットは少ない。しかし、Namespace のプレフィクスに実行環境名を付与することになり、名前が長くなってしまう。

これらを比較して、より自身に合った方法を選ぶ。


04. バージョンの互換性

kube-apiserver

▼ kube-apiserver が冗長化されている場合

冗長化された kube-apiserver のバージョン差は、前方の 1 個のマイナーバージョン以内に収める必要がある。


kubectl

▼ kube-apiserver の場合

kubectl コマンドと kube-apiserver のバージョン差は、前方/後方の 1 個のマイナーバージョン以内に収める必要がある。


06. CIDR ブロックの設計

ワーカーNode の場合

Kubernetes では、稼働する可能性のある Pod 数から、ワーカーNode の CIDR ブロックを算出するとよい。

アプリケーションの Pod がスケーリングすることや、カスタムリソース (例:Istio、Linkerd) を導入することも考慮して、尤もらしい IP アドレス数を算出できる。

削除される Pod と作成される Pod の IP アドレスを変える (IP アドレスの再利用を防ぐ) ため、Pod の最大数の 2 倍の IP アドレスを持つ CIDR ブロックを設定するとよい。

Node 当たりの最大 Pod 数 ワーカーNode 当たりの CIDR ブロック IP アドレス数
1 /32 2
8 /28 16
916 /27 32
1732 /26 64
3364 /25 128
65110 /24 256


サブネットの場合

Amazon EKS での目安であるが、サブネットごとに /19/20 なるように設計するのが、個人的にはおすすめ。


07. 監視ポリシー

メトリクスエンドポイント

Kubernetes の以下のコンポーネントが、メトリクスエンドポイント (/metrics) を持つ。

  • kube-controller-manager
  • kube-proxy
  • kube-apiserver
  • kube-scheduler
  • kubelet


ハードウェアリソース系

▼ ハードウェアリソース系

ハードウェアリソースの性能指標に関するメトリクスである。

収集ツールとして、Node Exporter がある。

▼ Cluster

メトリクス 単位 説明 アラート条件例 (合致したら発火)
CPU % 同じ Cluster 内のワーカーNode の CPU 使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80
Memory % 同じ Cluster 内のワーカーNode のメモリ使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80

▼ Pod

メトリクス 単位 説明 アラート条件例 (合致したら発火)
CPU % Pod 全体の CPU 使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80
Memory % Pod 全体のメモリ使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80

▼ コンテナ

メトリクス 単位 説明 アラート条件例 (合致したら発火)
CPU % コンテナの CPU 使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80
Memory % コンテナのメモリ使用率をデータポイントとする。 ・統計 : 期間内平均使用率
・期間 : 5
・閾値 : >= 80


ネットワーク系

▼ ネットワーク系

ネットワークの性能指標に関するメトリクスである。

収集ツールとして、kuebelet に内蔵された cAdvisor がある。

メトリクス 単位 説明 アラート条件例 (合致したら発火)
container_network_receive_bytes_total カウント 同じ Cluster 内の受信したバイトの累積数をデータポイントとする。 記入中...
container_network_transmit_bytes_total カウント 同じ Cluster 内の送信したバイトの累積数をデータポイントとする。 記入中...


状態系

▼ 状態系

状態に関するメトリクスである。

収集ツールとして、kube-state-metrics がある。

▼ Cluster

Cluster をディメンションとしたメトリクスの監視ポリシーは以下の通りである。

メトリクス 単位 説明 アラート条件例 (合致したら発火)
Node の必要最低数 カウント 同じ Cluster 内のワーカーNode 数の必要最低数をデータポイントとする。 ・統計 : 期間内合計数
・期間 : 5
・閾値 : <= 2
Pod の必要最低数 カウント 同じ Cluster 内のワーカーNode の Pod 必要最低数をデータポイントとする。 ・統計 : 期間内合計数
・期間 : 5
・閾値 : <= 1


▼ Pod

Pod 全体をディメンションとしたメトリクスの監視ポリシーは以下の通りである。

メトリクス 単位 説明 アラート条件例 (合致したら発火)
Pod の最低必要数 カウント 同じ Deployment 内の Pod の必要最低数をデータポイントとする。 ・統計 : 期間内合計数
・期間 : 5
・閾値 : <= 2

▼ コンテナ

コンテナをディメンションとしたメトリクスの監視ポリシーは以下の通りである。

メトリクス 単位 説明 アラート条件例 (合致したら発火) 補足
ReadinessProbe ヘルスチェック カウント コンテナの ReadinessProbe ヘルスチェックの失敗数をデータポイントとする。 ・統計 : 期間内合計数
・期間 : 1
・閾値 : >= 2
ネットワーク由来の問題で発生することがあるため、連続的に発生したうえでアラートする。


08. デバッグ

便利なイメージ

▼ Deployment 系

Deployment が正常に Pod を作成できない場合、それだけで HelloWorld のアプリケーションを起動できるイメージがある。

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: paulbouwer/hello-kubernetes:1.10
      ports:
        - containerPort: 8080
          protocol: TCP

▼ ネットワーク系

ネットワークのトラブルシューティングに役立つツールがインストールされているイメージがある。

kubectl debug コマンドと組み合わせる。

$ kubectl debug node/<Node名> \
    -n default \
    -it \
    --image=praqma/network-multitool


09. CI パイプライン

マニフェストのホワイトボックステスト

▼ 静的解析

観点 説明 補足
マニフェストの API 仕様違反テスト 外部の API 仕様違反テストツール ( (例:kubeconform) を使用する。Kubernetes リソースのスキーマに基づいて、マニフェストの API 仕様違反を検証する。 https://mixi-developers.mixi.co.jp/kubeconform-2bb477371e06
マニフェストのコード規約違反 外部の Policy as Code ツール (例:conftest、Gatekeeper CLI の gator など) を使用する。ポリシー (rego など) の定義に基づいて、そのプロダクトのコード規約違反を検証する。 https://qiita.com/Udomomo/items/10ed2dbfef85812808da#conftest%E3%81%A7policy%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B
マニフェストのベストプラクティス違反テスト 外部のベストプラクティス違反テストツール (例:polaris、kubeconform など) を使用する。報告された CVE に基づいて、チャートの実装方法に起因する脆弱性を検証する。 https://gavin-zhou.medium.com/%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9%E3%81%A8%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEkubernetes-yaml%E3%81%AE%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3-%E7%AC%AC%E5%9B%9B%E7%AB%A0-bc00f1610a3
マニフェストのバージョンテスト 外部のバージョンテストツール (例:pluto、kubepug) を使用する。指定した Kubernetes のバージョンに基づいて、マニフェストのバージョン (apiVersion) を検証する。 https://zenn.dev/johnn26/articles/detect-kubernetes-deplicated-api-automatically
マニフェストの脆弱性診断 外部の脆弱性診断ツール (例:kics) を使用する。報告された CVE に基づいて、マニフェストの実装方法に起因する脆弱性を検証する。補足として、Kubernetes リソースのセキュリティスキャン (例:trivy) は、すでに作成された Kubernetes リソースに対する検証のため、ここには含めない。 https://blog.nflabs.jp/entry/2021/12/24/091803
https://weblog.grimoh.net/entry/2022/01/02/100000
https://zenn.dev/tayusa/articles/ad9fafa197888b


マニフェストのブラックボックステスト

▼ 結合テスト

テスト環境に対して kubectl apply コマンドを実行することで、追加/変更を含む複数のマニフェストを組み合わせた結合テストを実施する。

▼ システムテスト

テスト環境に対して kubectl apply コマンドを実行することで、既存機能/追加/変更を含むすべてのチャートを組み合わせたシステムテストを実施する。


09-02. CD パイプライン

マニフェストのホワイトボックステスト

▼ 静的解析

GitOps の場合、CI パイプライン上だけでなく、CD パイプライン上でもホワイトボックステストを実施できる。

ただし、kube-apiserver の validating-admission ステップ時にこれを実施する必要がある。

観点 説明 補足
マニフェストのコード規約違反 外部の Policy as Code ツール (例:Gatekeeper、Kyverno) を使用する。ポリシー (rego など) の定義に基づいて、そのプロダクトのコード規約違反を検証する。 https://qiita.com/Udomomo/items/10ed2dbfef85812808da#conftest%E3%81%A7policy%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B


デプロイ

▼ デプロイとは

本番環境に対して、ローカルマシンまたは CD ツールを使用して、マニフェストをデプロイする。

▼ インプレースデプロイメント (非推奨)

Kubernetes の Deployment の Replace 戦略を採用する。非推奨である。ダウンタイムが発生する。

▼ ローリングアップデート (推奨)

Kubernetes の Deployment の RollingUpdate 戦略を採用する。

▼ BG デプロイメント (推奨)

Kubernetes 自体はブルー/グリーンデプロイメントの能力を持たない。CD ツール (例:Argo Rollouts) の BG デプロイメント機能を採用する。

▼ カナリアリリース (推奨)

Kubernetes 自体はカナリアリリースの能力を持たない。CD ツール (例:Argo Rollouts) やサービスメッシュツール (例:Istio、Linkerd など) のカナリアリリース機能を採用する。

注意点として、サービスメッシュツールであると、重み付けの段階的な変更が手動になってしまう。

▼ Progressive Delivery (推奨)

Kubernetes 自体は Progressive Delivery の能力を持たない。CD ツール (例:Argo Rollouts) の Progressive Delivery 機能を採用する。


ロールバック

デプロイ方法の採用状況 方法 推奨/非推奨
Deployment の RollingUpdate 戦略を採用している場合 過去のリリースタグ (リビジョン) を再デプロイする。あるいは GitHub によるコミットのリバートを使用し、現在のコミットを打ち消すコミットを作成し、PR を作成する。 非推奨
CD ツールの BG デプロイメントを採用している場合 削除せずに残してある現環境に再ルーティングする。手順は、CD ツールによる。 推奨
CD ツールのカナリアリリースを採用している場合 現環境へのルーティングの重みづけを 100%にする。手順は、CD ツールによる。 推奨
CD ツールの Progressive Delivery を採用している場合 削除せずに残してある現環境に再ルーティングする。手順は CD ツールによる。 推奨


09-03. 事後処理

デプロイの通知

▼ Kubernetes を使用する場合

Kubernetes には通知能力がなく、手動で知らせる必要がある。

▼ Kubernetes 以外を使用する場合

CD ツールの通知機能 (例:ArgoCD Notification) を使用して、CD パイプラインの結果が通知されるようにする。

通知があることと品質を高めることは直接的には関係ないが、開発者の作業効率が上がるため、間接的に品質を高めることにつながる。