コンテンツにスキップ

プラクティス集@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. 命名規則

リソース名

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

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

基本はこれを使用する。

ケバブケースとする。

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 クラウドプロバイダー (AWS 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)など AWS 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


サブネットの場合

AWS 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パイプライン

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

▼ 静的解析

観点 説明 補足
マニフェストの文法の誤りテスト 外部の文法の誤りテストツール ( (例:kubeconform) を使用する。Kubernetesリソースのスキーマに基づいて、マニフェストの文法の誤りを検証する。 https://mixi-developers.mixi.co.jp/kubeconform-2bb477371e06
マニフェストのコード規約違反 外部のPaCツール (例:conftest、GatekeeperCLIの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) を使用する。指定した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ステップ時にこれを実施する必要がある。

観点 説明 補足
マニフェストのコード規約違反 外部のPaCツール (例: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パイプラインの結果が通知されるようにする。

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