Kubernetesで実践するクラウドネイティブDevOps を読んだ
Kubernetesで実践するクラウドネイティブDevOps を読んだ。本番環境で Kubernetes クラスタを運用するために必要な知識が体系的かつコンパクトにまとまっていて、自分の知識のインデックスをさっと作るのにとても良い本だった。
少し個人的な経緯を記載しておく。全く知識のない状態で Kubernetes (GKE) を使うプロジェクトに入った際に、自分はまず CKAD を取得した。Udemy のコース を一通り見て概念を掴み、実際に 資格 の受験・取得まで行った。CKAD が良かったのは、具体的な目標とカリキュラムがあるので必要な情報をスピーディに学べることと、ハンズオン形式なので手を動かしながら理解を深められるのが非常に良かった。特に kubectl でのオペレーションなどはある程度手になじませたほうが良いので、実運用でもこの資格取得で得た知識が役に立った実感が多くあった。ちなみに CKA も同時に準備していたが、出産等で受験する時間がとれないまま今に至っている。ただマネージドの Kubernetes を運用するために必要な最低限の知識をまずざっと得るのには CKAD が良かったと今でも思う。
その後実際に運用しながら、知らないトピック (CKAD ではカバーされていなかったリソースや GKE 側の知識など。例えば PDB、HPA、Pod Anti-Affinity などは自分が受けたときの CKAD ではカバーされていなかったように記憶している) については都度公式ドキュメントを読みながら対応していた。このように必要な部分に対してドキュメントや Issue 読んでいくので良いのだが、だんだんと自分のプロジェクトで利用する部分だけに知識が偏っている感覚が増えてきた。また「X をしたい」という目標に対して、どのような方法をとればよいのかパッと出てこない状態になっていた。
こうしてそろそろ体系的に知識を整理し直したいと思っていたところに、この Kubernetesで実践するクラウドネイティブDevOps はぴったりの本だった。
まず “本番運用に必要な知識” にフォーカスして、必要以上に細部に立ち入らずに記載されているので、スピーディに読むことができた。運用のうえで必要になる概念だけに集中していることや、数多くあるツールの中で代表的なものを選択肢として提示してくれている。詳細は最新のドキュメントで確認したほうが良く、必要なのは脳内のインデックスだったので、本書のこの方針はまさに今の自分が求めているものだった。
また知っていた知識についても、その重要度がこの本を通して明確になった感覚がある。例えばコンテナリソースの requests, limits はもちろん知識としては知っていたが、どちらかというと単にスペックの中の一要素程度にしか認識していなかった。これが本書では “リソースの管理” の章のトップで扱われていて、確かに自分の認識よりも重要なパラメータだということが理解でき、知識の補正になったと思う。
オブザーバビリティについてもカバーしている。個人的になかなかとらえどころのない概念でよく理解できていなかったのだが、「分散システムの性能はグラデーション的で、普段から常にどこかデグレしている」という前提にたっているという説明がわかりやすかった。とはいえかなり短い紙面しかないので、Observability Engineering あたりは読んでみたい気になった (以前無料公開されていた PDF が積んである)。
問題があるとすると原著が 2019 年刊行なので、Kubernetes の変化のスピードに対しては少し古くなりつつあると思う。基本的な概念は変わっていないが、紹介されているツールや SaaS 等が一部古くなっているように見えた。間は自分で埋める必要がある。
以下読書メモ。
3. Kubernetes 環境の選択
- k8s 環境を準備するにあたって、マネージドサービス、ターンキー方式(コントロールプレーンはマネージドでワーカーノードは自前)、セルフホスティング(その際に有用な kops といったツールの紹介)という方式に大別して、それぞれの特徴や代表的なサービスを検討
- その上で可能な限りはマネージドサービスを利用することを強く推奨している
- k8s をスクラッチから本番運用できる状態にするにはエンジニアの給与で 100 万ドルかかるという経験則がある
- 例えばセットアップは kubeadm といった便利なツールがあるが、運用上のハードで難しい部分を解決してくれるツールは無い
5. リソースの管理
- 最も基礎となる情報として、コンテナのリソースの要求
spec.containers[].resources.requests
と制限spec.containers[].resources.limits
がある- 原則どちらも設定されているのが望ましい
- また健全性、準備完了の判定として Liveness, Readiness probe がある
- Liveness probeに失敗した場合 pod は再起動を試みる。Readiness probeに失敗している場合は Service配下に入らない
- PodDisruptionBudget でpod の eviction が多すぎないよう、一定の pod を確保するように指定できる
- プリエンプティブノードを使う場合は Node affinity などを利用して容易に再起動すると困る pod がスケジュールされないようにする
- ノードのマシンタイプを決めるための経験則として、1 ノードあたり典型的な pod を最低 5 つ起動でき、かつ取り残されたリソース (小さすぎて新しい pod をスケジュールできない余りリソース) が 10 % 以下になるようにするとよい
- ノードのスペックが高い方が費用対効果が良いが一台の退役の可用性への影響が大きくなり、スペックが低いと取り残されたリソースが多くなり費用対効果が悪化する
6. クラスタの運用
- クラスタのサイジングは難しい問題で、運用しながら調節していくしかない
- Cluster autoscaler は需要に合わせてクラスタを伸縮させる
- スパイクの激しく無いサービスでは、利用せず手動でのクラスタ調整で十分なことも多い
7. Kubernetes の強力なツール
- マニフェストのヘルプは
kubectl explain
--watch
でオブジェクトの監視kubectl logs --timestamps
でタイムスタンプ付与- デバッグ用の一時的な使い捨て busybox コンテナを起動する例
kubectl run nslookup --image=busybox:1.28 --rm -it --restart=Never --command -- nslookup demo
COPY --from=busybox:1.28 /bin/busybox
のようにしてイメージ作成時に最低限のシェルやツールを入れることができる- 1MB くらい
kubectl completion -h
でシェル自動補完を導入するガイドが表示される- kubectl に
k
などのエイリアスを設定している場合はcomplete -o default -F __start_kubectl k
が必要
- kubectl に
8. コンテナの実行
- コンテナランタイムを学習のため Go で自作する
- imagePullPolicy でイメージをプルする際の挙動を指定できる
- Always, IfNotPresent, Never
- restartPolicy でコンテナの再起動ポリシーを指定できる
- Always がデフォルトで OnFailure, Never
9. Podの管理
- Node Affinity の
requiredDuringSchedulingIgnoredDuringExecution
とpreferredDuringSchedulingIgnoredDuringExecution
はそれぞれ “ハード”・”ソフト”アフィニティと考えると覚えやすい - k8s のスケジューラはデフォルトではノード間に pod を分散させる力学はなく、必要なら Pod Anti-Affinity を使う
- Taint, Toleration は Affinity とは反対に特定のノードに Pod がスケジュールされないことを設定する
- 各 Affinity など、いずれもスケジューラの最適化を多少なりとも妨げる動きになるので、運用上必要な微調整で切り札的に指定するイメージがよい
- ざっくり、Pod をどのノードに割り当てるかを決めるのがスケジューラで、Pod のライフサイクルを管理するのが Pod コントローラと考えると理解しやすい。以下はコントローラの一部
- DaemonSet はノードごとに 1 つだけの Pod をデーモン的に起動する
- StatefulSet は Pod のレプリカを特定の順序で起動・終了する
- Headless Service (clusterIP のタイプが None な Service) で特定のレプリカを指定してアクセスできるので、組み合わせて使うことが多い
- Job は一度きり (または指定された回数) Pod を実行する
- Horizontal Pod Autoscaler (HPA) は Pod を水平にスケーリングさせる
10. 設定と機密情報
- ConfigMap を更新した際の Pod の再起動について。Deployment はあくまで自身のスペックが更新されないと再起動しないので、例えば ConfigMap 更新時に Deployment のスペックのアノテーションを更新するといたテクニックが必要になる
- 機密情報の管理はマネージドサービス (Hashicorp Vault や AWS Secret Manager 等) を使うのが良いが、小さいチームでは暗号化した情報をリポジトリにコミットする方法も簡便で良い
- その場合、フレームワーク等に依存しないライブラリとして mozilla/sops がある
- 全体を暗号化するのではなく
user: ENC[AES256_GCM,data:CwE4O1s=,iv:2k=,aad:o=,tag:w==]
のようになり、どのようなキーが方式で暗号化されているのかレビューしやすくなっていたり、暗号化処理や保存場所のバックエンドには各種サービスやライブラリに対応していたりと、運用が意識されたよくできたソフトウェアに見えた
- 全体を暗号化するのではなく
11. セキュリティとバックアップ
- Kubernetes Security [Book] を読むのがよい
12. Kubernetesアプリケーションのデプロイ
- マニフェストのバリデーションを行う instrumenta/kubeval (yannh/kubeconform) やマニフェストのテストが書ける open-policy-agent/conftest といったツールがある
13. 開発ワークフロー
- ローリングアップデート中に停止・起動する pod 数の調整には maxSurge, maxUnavailable を使う
- カナリアデプロイの手順の説明が 公式ドキュメントにある
15. オブザーバビリティと監視
- 分散システムにおいては、サービスがアップ・ダウンどちらなのかを単純に 2 値に分類できない
- 平時から常にどこかがデグレして動いている可能性が高く、またそれでもユーザー影響のないサービスが提供できていれば良い
- Ops: It’s everyone’s job now | Opensource.com
- Gray failure: the Achilles’ heel of cloud-scale systems | the morning paper
- オブザーバビリティはこうした背景を受けて現れた概念で、監視アラートの “ダウン” の判定を複雑高度化していくアプローチではなく、各種のメトリクスを常時取得・適切に可視化しておき、問題の事前検知や発生時の原因究明を科学的に進めやすくするといった活動を行うこと (私個人の理解)
16. Kubernetesにおけるメトリクス
- メトリクスは大量にあり、必要なものにフォーカスすることがまず重要になる
- 代表的な指針として RED (リクエスト、エラー、持続時間) や USE (使用率、飽和度、エラー) がある
- 前者は API 志向、後者はミドルウェア志向なイメージ
- Kubernetes での有用なメトリクスの例
- クラスタ
- ノード数、ノードあたりの Pod 数、ノードのリソース使用率
- Deployment
- Deployment 数、Deployment あたりの Pod レプリカ数、利用できないレプリカ
- コンテナ
- リソース使用率、Liveness/Readiness Probe 状態、再起動回数、ネットワークトラフィック、ネットワークエラー
- クラスタ
- サービスが複数ある場合は、ダッシュボードのフォーマットも揃えた方が良い
- Pager 対応もトラッキングして適時レビューすると良い
- Prometheus は Borgmon にインスパイアされたソフトウェア