Closed18

Kubernetes完全ガイドをちゃんと理解するための個人雑メモ

ぱんだぱんだ

3章 kubernetes環境の選択肢

Minikube

  • シングルノード構成
  • ハイパーバイザーを必要とし、各ハイパーバイザーに応じたDriverを使用して操作する
# Minikubeの起動 driverの指定をしないと使用可能なDriverを選択する? -> デフォルトがdockerのよう
minikube start

docker desktop

  • kubernetesの設定を有効化することで使用できそう

kind

  • minikubeはシングルノードのためマルチノードクラスターをローカルで構築するにはkindを使用する。

playground

以下のリンクでブラウザからkubernetesの構築が試せるよう。

https://labs.play-with-k8s.com/

ぱんだぱんだ

4章 APIリソースとkubectl

  • kubectlはバージョンを気にしなければ以下brewでインストールできる。
brew install kubernetes-cli
  • シェル補完
echo 'source <(kubectl completion zsh)' >> ~/.zshrc
  • kubernetesはマスターノードとワーカーノードからなるマルチノードで構成されている。
  • マスターノードはAPIエンドポイントの提供、コンテナのスケジューリングやスケーリングを担うノード。
  • ワーカーノードは実際にコンテナが起動するノード。
  • kubernetesクラスタにはNamespaceが設定できるようだが、一つのクラスタを複数の目的で利用したり複雑なクラスタでなければデフォルトのNamespaceでリソースを作成して良さそう。
  • kubernetesの操作は全てマスターノードが提供するAPIを通して実行し、実際にはkubectlを使用する。
  • kubectlはkubeconfig(~/.kube/config)の情報をもとにkubernetesに接続する。
  • リソースの作成はkubectl createでも可能だがkubectl applyを使用したほうが良い。
  • 理由としては差分検知がうまく働かないことがあるため。applyを使用すれば確実。
  • kubectl createはgenerateNameを使用することでランダムな命名をするのに使えることもある。
  • kubectlの操作は全て非同期のため操作が完了してから何かしたい場合は--waitオプションを使用する。
  • アノテーションはEKSやGCEなどクラウドサービスごとの拡張機能などを使うための目印的な使い方がある
  • マニフェストから削除されたリソースをapply時に自動で削除するための--pruneオプションがある。
kubectl apply -f sample.yaml --prune
  • kubectl setコマンドでマニフェストを更新しなくてもリソースの変更ができるがマニフェストとリソースに差異が生まれるためあまり利用すべきでない。
  • kubectl diff -f sample-pod.yamlでマニフェストファイルと現状の変更差分を表示できる
  • kubectl api-resourcesでリソース一覧見れる
  • リソース情報の取得はyaml, json形式の他にカスタムで表示もできる
kubectl get pods -o custom-columns="IMAGE:{.spec.containers[0].image}" sample-pod
IMAGE
nginx:1.7.9
  • 全てのリソース一覧の取得
kubectl get $(kubectl api-resources --namespaced=true --verbs=list -o name | tr '\n' ',' | sed -e 's|,$||g')
  • pod内で実行されているコンテナ上でコマンドを実行するには以下のような感じ
    kubectl exec -it sample-pod -- /bin/bash
  • kubectl debugでpod内にデバッグ用のコンテナを起動させて任意のコマンドを実行したりもできる
  • kubectlを利用してpodにポートフォワードするには以下のような感じ
kubectl port-forward sample-pod 8080:80 // 8080 -> 80
  • kubectl logsでリソースのログを確認できる
  • OSSのSternを利用すると複数Podのログがより見やすい
brew install stern
  • ファイルのコピーはkubectl cpでできる
  • kubectlはサブコマンドを拡張することができ、プラグインの追加はkrewというプラグインマネージャーを使用することができる。インストールは以下。
    https://krew.sigs.k8s.io/docs/user-guide/setup/install/

kube-ps1

プロンプトに現在選択中のkubernetesクラスタとNamespaceを表示する。

brew update
brew install kube-ps1

# .zshrcに追加
source "/usr/local/opt/kube-ps1/share/kube-ps1.sh"
PS1='$(kube_ps1)'$PS1

source ~/.zshrc

[user@mba:~/work/kubernetes-lessones/4]
$
(⎈|minikube:default)

server side apply

kubectlによる差分計算によるリソース作成はclient applyであり、server side applyを使用することで変更の衝突を検知することができる。

# podの作成
kubectl apply -f sample-pod.yaml

# podの内容を変更
kubectl set image pod sample-pod sample-pod=nginx:1.17

# マニフェストの内容と現状の内容が相違しているのでエラーになる
kubectl apply -f sample-pod.yaml --server-side

# 強制適用
kubectl apply -f sample-pod.yaml --server-side --force-conflicts

変更の検知にはフィールドを管理することで実現し、各フィールドにはmanagerがkubectlでデフォルト設定される。もし、CIからkubectlで変更がある場合、ローカルでの変更と衝突してもmanager名がデフォルトのままだと検知できないため変更することが可能。

# マニフェストを変更

# manager名を変更してapplyするとエラーになる
kubectl apply -f sample-pod.yaml --server-side --field-manager ci-tool
ぱんだぱんだ

5章 Workloads APIs

クラスタ上にコンテナを起動させるのに利用するリソース。全8種

  • Pod
  • ReplicationController
  • ReplicaSet
  • Deployment
  • DaemonSet
  • StatefulSet
  • Job
  • CronJob

Pod

  • Podは1つ以上のコンテナを含む。
  • コンテナはPodに割り当てられたIPアドレスを共有する。
  • コンテナ同士はlocalhost宛で通信することができる。

デザインパターン

  • サイドカーパターン

  • アンバサダーパターン

  • アダプターパターン

  • Dockerfileで言うところのENTRYPOINTをcommand, CMDをargsに記述できる。

  • デフォルトのdnsPolicyはクラスタ内のDNSに問い合わせを行い、解決できなかった場合はアップストリームに問い合わせをおこなう。

ReplicaSet/ReplicationController

指定のレプリカ数のPodを維持し続けるリソース。ReplicationControllerは今後廃止予定のためReplicaSetを使用しておけばok。ReplicaSetはPodがたとえ停止してしまったとしても指定されたレプリカ数を維持しようとする、いわゆるセルフヒーリングが働いている。レプリカ数の維持はPodのラベルを見ていていい感じにPodを削除・作成し数を調整してくれる。

Deployment

ReplicaSetの親リソース。ReplicaSetを管理することでローリングアップデートやロールバックを実現するためのリソース。ロールバックは古いマニフェストをapplyすることで戻すことができるのであまりロールバックコマンド自体は使わないかもしれない。アップデート戦略はローリングアップデート以外にもRecreateが選べたり、アップデート時にPodをどのように更新していくかは細かく設定することができる。

DaemonSet

ReplicaSetはどのノードにいくつPodが配置されるかがわからないが、DaemonSetは各ノードに必ず1つPodを作成する。そのため、レプリカ数の指定などはなく、Datadogなどのモニタリング用のPodなど必ず各ノード上に配置したいリソースの作成に使用される。

アップデート戦略はRollingUpdateOnDeleteの2種類がある。

StatefulSet

データを永続化することができる。

PersistentVolume

永続化領域。これはクラスタ外にある。

PersistentVolumeClaim

永続化要求。この要求によりクラス外のPersistentVolumeをPodにアタッチすることができる。

StatefulSetを削除するときは、PersistentVolumeは削除されないためもし永続化領域の削除をしたい場合はPersitentVolumeClaimとPersitentVolumeの削除が必要。

Job

処理を実行したら停止するPodを作成する。ReplicaSetなどとの違いは停止することを前提に作られること。restartPolicyを設定することができNeverOnFailureがある。違いは再起動時にPodを作り直すか再度同じPodを使用するかの違い。

Oneshot Task

1回のみ実行するタスク。completions=1 parallelism=1 backoffLimit=0

Multi Task

並列実行。例えば、completions=5 parallelism=3 backoffLimit=0 だと5回成功するまで3並列でタスクを実行する。3並列とはPodが3つ作成されるということ。

Multi WorkQueue

completionsを指定しないことで、処理を実行し続けることが可能。並列を指定することで大きな処理を並列で実行し続けるようなWorkQueue型のJobを実行することができる。一つでもPodが成功終了した場合、それ以降はPodは作成されない。Podが成功終了した時点で起動しているPodは正常終了されるまで停止されることはない。

WorkQueue型のJobを作成する場合なんらかのメッセージキューを使用することになる。

Single Worker Queue

上記Multi WorkerQueueの並列数を1にすることで1つずつWorkQueueを実行することができる。

CronJob

cronのようにスケジューリングすることができるJob。

ジョブの停止

kubectl patch cronjob sample-cronjob -p '{"spec": {"suspend": true}}'

任意のタイミングでの実行

kubectl create job sample-job-from-cronjob --from cronjob/sample-cronjob

同時実行に関するポリシー

  • Arrow(default) 同時実行に関して制御を行わない
  • Forbid 前のJobが終了していない場合、次のJobを実行しない(同時実行しない)
  • Replace 前のJobをキャンセルし、次のJobを実行する
ぱんだぱんだ

6章 Service APIs

クラスタ上のコンテナに対するエンドポイントの提供や、ラベルに一致するコンテナのディスカバリに利用されるリソース。

  • Service

    • ClusterIP
    • ExternalIP
    • NodePort
    • LoadBalancer
    • Headless
    • ExternalName
    • None-Selector
  • Ingerss

  • kubernetesクラスター内の各ノードはNode Networkでつながっている。

  • そして、ノード内の各PodはCNI(Container Network Interface)でつながっているためPod間の通信ができる。

  • なのでServiceがなくてもPod間通信はなりたつがServiceを利用することでロードバランシングやクラスタ内DNSなどのメリットがある。

  • Podに割り当てられるIPは作成するたびに変化する。

  • kubernetesではDNSを利用して名前解決をすることができるため変化するIPではなくドメイン名で解決するようにしたほうがよい。

ClusterIP

クラスター内のみ疎通性のあるサービス。マニフェストでラベルを指定することで適切に紐づいたPodへのロードバランシングを実施する。ClusterIPの名前解決はDNS名ですべきだが、ClusterIPを指定することも可能。

ExternalIP

ClusterIPは外部疎通性がないが、ExternalIPはkubernetesノードのIPをを使用して外部疎通を確立することができるサービス。ただし、特別な理由がなければNode Port Serviceを検討したほうがよい。

また、ExternalIPはマニフェストにtype: ClusterIPを指定し、ExternalIPというtypeがあるわけではない。当然、ClusterIPが作成されるためマニフェストで指定したノードIPに外部からアクセスすると各Podに均等に割り振られる。

NodePort Service

ExternalIPは指定したnodeのIPとの外部疎通を確立していたが、NodePort Serviceは全てのノード(厳密には0.0.0.0:Portで外部との疎通を確立する)で受け付けることができる。typeはNodePortで指定。

マニフェストでは「全てのノードで受け付けるポート」「クラスターIPのポート」「割り振るPodのポート」を指定する。

NodePortで指定できるポートは30000~32767の範囲。

LoadBalancer Service

クラスタ外部にロードバランサー用のIPを払い出す。外部のロードバランサーを利用するのでGCPやAWSのロードバランサーに対して外部疎通性のあるIPを払い出すことになる。プロダクションとしてkubernetesを使用する時に一番実用的なサービス。

ExternalIPやNodePortはkubernetesノードのIPを指定するためそのノードIPが単一障害点になってしまう。一方、LoadBalancer Serviceは外部ロードバランサーを使用するためそのような心配はない。

マニフェストのtypeにはLoadBalancerを指定。

実際の運用ではロードバランサーのIPにドメインを割り当てる関係でIPを固定したい場合があると思うがその場合にはマニフェストでIPを指定することができる。

特に指定なく作成したロードバランサーは全公開になっているためアクセスを制限したい場合はマニフェストで指定することができる。

Headless Service(None)

対象となる個々のPodのIPが直接返ってくるサービス。サービス自体はIPを持たずDNSラウンドロビンを使ったエンドポイントを提供するため、複数のIPが返ってくる。

このサービスを作成するにはマニフェストでtypeにNoneを指定する。

ExternalName Service

サービスのドメインに外部ドメインを使用することができるサービス。外部ドメインを使用することでkubernetesへのアクセスに使用するドメインを疎結合に保つことができる。作成するにはマニフェストのtypeにExternalNameを指定する。

Non-Selector Service

ExternalName Serviceは外部のドメインに転送されていたが、Non-Selector Serviceの場合、サービス名で名前解決をすると自分で指定したメンバに対してロードバランシングを行う。基本的にはClusterIPによるクラスタ内ロードバランサで使用するのが大半。

Ingress

ロードバランシングを提供するサービスリソースがL4相当のロードバランサーであったのに対し、L7相当のロードバンサーとなるのがIngressである。Ingressはクラス外のロードバランサを利用したIngress(GKE Ingressなど)とクラスタ内にIngress用のPodをデプロイするIngress(Nginx Ingressなど)がある。

GKE Ingressを構築する場合は、クラスタ外部のL7相当ロードバランサからクラスタ内のNodePort Serviceを経由してPodに到達する。

Nginx Ingressの場合はL4相当のロードバランササービスを経由してNginx Ingress Podを経由してPodに到達する。

Ingressの作成はマニフェストのkindにIngressを指定して作成。GKE Ingressの場合は普通にルーティングルールを記述するだけでよく、Nginx Ingressの場合はアノテーションにNginxを指定する。

その他

  • セッションアフィニティ
  • 外部ロードバランサーを使用する場合、ノードに到達した際にもロードバランシングが行われノードをまたいで振り分けされるため、二段階振り分けみたいになる。これはマニフェストで無効にすることも可能。
  • リージョンやゾーンなどのトポロジを意識した振り分けも可能。
ぱんだぱんだ

Config & Storage

  • 機密情報はSecretリソース
  • 単純なKey-Valueの設定はConfigMapリソース

環境変数

  • マニフェストのenvに指定することでコンテナに環境変数を設定することができる。
  • Podに関する情報を参照する場合はfieldRefを使用することができる。
  • コンテナに関する情報はresourceFieldRefで参照することができる。
  • マニフェストのargsとcommandで環境変数を使用するには{}ではなく()を使用する
  • マニフェストのargsとcommandで使用できる環境変数はマニフェスト内で定義した環境変数のみ。OSに設定された環境変数などは参照できない。

Secret

Secretのtypeは以下の通り。

  • Opaque 一般的な汎用用途
  • kubernetes.io/tls TLS証明書
  • kubernetes.io/basic-auth Basic認証
  • kubernetes.io/dockerconfigjson Dockerレジストリの認証情報
  • kubernetes.io/ssh-auth SSHの認証情報
  • kubernetes.io/service-account-tokne Service Account のトークン
  • kubernetes.io/token Bootstrapトークン

Opaque

  • 作成したSecretの値はbase64で難読化されている
  • Secretの作成は以下の4つの方法がある
  1. --from-file kubectlでファイルから値を参照する
  2. --from-env-file kubectlでenvファイルから値を参照する
  3. --from-literal kubectlで直接値を渡す
  4. マニフェストファイルを使用する

Secretの利用

containerからSecretを利用するには

  • 環境変数として渡す
  • Volumeとしてマウントする
    のどちらか

環境変数として渡す

secretKeyRefを使用して指定したSecretのKeyに対応する値を環境変数として設定する。Secret全てを渡す場合はenvFrom.secretRefでSecret名を指定することでSecretの全てのKey-Valueを環境変数として渡すことができる。また、Secret全てを渡す場合Keyが衝突する可能性があるのでprefixを設定することもできる。

Valueとしてマウントする

volumeとしてSecetをマニフェストで指定することでSecretの指定のKeyに対応した値をファイルとしてコンテナからマウントして参照することができる。環境変数として渡す時同様、Secret全てをマウントすることもできる。

動的にSecretを渡す

環境変数として渡す場合は、コンテナ起動時に環境変数として設定するため動的な対応はできないがValueとしてマウントしている場合は一定間隔で変更を検知しファイルを置き換えるため動的にSecretをコンテナに渡すことができる。

ConfigMap

Secret同様、ConfigMapの作成にはkubectlでファイルを渡す方法、kubectlで直接値を渡す方法、マニフェストで作成する方法がある。ConfigMapはKey-Valueの形式だがnginx.confのようなファイルをそのまま渡すこともできる。また、binaryDataを指定することでUTF-8以外のデータを含むバイナリデータを保存することもできる。つまり、画像データなどを保存しておける。保存した場合はbase64でエンコードされた状態で保存される。

ConfigMapの値をコンテナから使用するにはSecret同様、環境変数として渡すかValueとしてマウントする方法があり、個別で渡すこともConfigMapの全ての値を渡すこともできる。ただし、ConfigMapの値を全て環境変数として渡す場合は「.」や「-」みたいな記号を含むKeyの場合、うまく参照できない可能性があるのでファイルとしてマウントしたほうがよい。

Permissionについて

ConfigMapもSecretも値として保存したスクリプトをファイルとして実行する場合、適切な権限を設定することができる。デフォルトは644の権限でマウントされるので実行権限がない。なのでファイルとして実行したい場合などは適切な権限を付与する必要がある。また、マニフェストファイルでの指定は8進数表記の権限を10進数表記に変換したものを指定する。

設定値の変更を不可にする

ConfigMapとSecretの値はimmutable=trueにすることで後から変更不可にすることができる。

VolumeとPersistentVolumeとPersistentVolumeClaim

Volumeはホストなどにあらかじめ用意されてある利用可能なvolumeをマニフェストに指定することで使用する。PersistentVolumeは外部の永続ボリュームを提供するシステムと連携する。PersistentVolumeClaimはその名の通りPersistentVolumeをマニフェストに指定しても登録しか行われないので実際に要求するためのもの。

Volume

kubernetesではVolumeプラグインとして下記のようなものが用意されておりPodに対して静的に領域を指定する。

  • emptyDir
  • hostPath
  • downwardAPI
  • projected
  • nfs
  • iscsi
  • cephfs

emptyDir

Podの一時的なディスク領域として利用可能。PodがTerminateされると削除される。ホスト上の任意の領域をマウントできるわけではないし、ホスト上のファイルを参照することもできない。あくまで一時的な領域として使用される。

emptyDirはマニフェストでmedium=Memoryを指定することで高速なtmpfs領域を割り当てすることもできる。

hostPath

kubernetesノード上の領域をコンテナにマッピングすることができる。emptyDirとは異なりホスト上の任意の領域をマウントすることができるためPodがTerminateされても消えない。

downwardAPI

Podの情報などをファイルとして配置するためのプラグイン。環境変数のところで使用したfieldRefとresourceFieldRefと同じ使い方。

projected

Secret, ConfigMap, downwardAPI, serviceAccountTokenのボリュームマウントを1ヶ所のディレクトリに集約するプラグイン。

PersistentVolume

VolumeはPodの定義内に直接書き込む形で接続をしていたが、PersistentVolumeは完全に外部にリソースとして作成する。また、PersistentVolumeは厳密にはConfig & Storage リソースではなくClusterリソースに分類。

PersistentVolumeとして実際に使用できるのは

  • GCE Persistent Disk
  • AWS Elastic Block Store
  • Container Storage Interface (CSI)
    などがある。

Container Storage Interface(CSI)

このプラグインはkubernetesとストレージエンジンをつなぐためのインターフェイス仕様です。従来はさまざまなプラグインがkubernetes内に実装されてきたが、プロバイダ側のアップデートのたびにkubernetes内部のプラグイン実装まで変更する必要があるため、kubernetes側では抽象化したインターフェイスを参照するようにすることでさまざまなプラグインが疎結合に使用することができる。

PersistentVolumeClaim

永続化領域の要求を行うリソース。前述のPersistentVolumeリソースを作成しただけでは使用することはできないためこのPersistentVolumeClaim経由で利用することになる。PersistentVolumeClaimは指定された容量、ラベルなどの条件に当てはまるPersistenVolumeを割り当てる。

Dynamic Provisioning

上述のPersistentVolumeCaimの説明では事前にPersistentVolumeリソースを作成している必要が当然ある。また、要求のVolume容量に一番近いVolumeが割り当てられるため3GiBの要求なのに7GiBも多い10GiBのVolumeが割り当てられるみたいなこともある。

これらの問題を解決するのがDynamic Provisioning。これを使用するとPersistentVolumeClaimが作成されたタイミングで動的にPersistentVolumeを作成して、割り当てる。そのため事前にPersistentVolumeを作成する必要もないし、割り当ても無駄がない。

Dynamic Provisioninを利用するには事前にどういったPersistentVolumeを作成するかを定義したStorage Classリソースを作成する。

ぱんだぱんだ

8章 Cluster APIs & Metadata APIs

Cluster APIsに分類されるリソースはセキュリティ周りの設定などクラスタの挙動を制御するためのリソースで内部的に利用されているものを除いて利用者が直接利用するものは全部で10種類。

  • Node
  • Namespace
  • Persistent Volume
  • Resource Quota
  • ServiceAccount
  • Role
  • ClusterRole
  • RoleBinding
  • ClusterRoleBinding
  • NetworkPolicy

Metadata APIsに分類されるリソースはクラスタ上にコンテナを起動させるのに利用され、以下の4種類がある。

  • LimitRange
  • HorizontalPodAutoscaler
  • PodDisruptionBudget
  • CustomResourceDefinition
ぱんだぱんだ

9章 リソース管理とオートスケーリング

  • コンテナのリソースを制限することが可能。マニフェストで下限はrequestsに上限はlimitsにmemoryとcpuを設定できる。下限のみを設定すると上限に使用可能なリソースを名一杯使ってしまい、逆に上限のみの設定だと上限と同じ値が下限にも設定されてしまうので片方のみの設定は避け両方設定したほうがよい。
  • Ephemeral Storageの容量が圧迫された時PodはEvictされる。Ephemeral Storageとしてカウントしているのは以下の3つ。
  1. コンテナが出力するログ
  2. emptyDirに書き込まれたデータ
  3. コンテナの書き込み可能なレイヤに書き込まれたデータ
  • kubernetesクラスタ自体のオートスケーリング機能(Cluster Autoscaler)もあり、需要に応じてkubernetesノードを自動で追加してくれる。nodeの追加はPending状態のPodが作成されたタイミングで行われる。
  • これは、リソースの下限が高すぎると負荷がそうでもなにのにnodeの追加が行われてしまったり、逆にnodeの追加が行われないなどの予期せぬ挙動をしてしまう可能性がある。
  • ポイントは加減と上限に顕著な差をつけないことと下限を高くしすぎないこと。
  • リソースのRequestとLimitを設定しないと、無限にリソースを作り続けてしまうのでデフォルトのLimitRangeが用意されている環境もある。
  • LimitRangeリソースはtypeにcontainer, Pod, PersitentVolumeClaimなどを指定してそれらのリソースが作成されるときに制限をかけることができる。

QoS Class

PodにはRequest/Limitsの設定に応じて自動的にQoS Classの値が設定されるようになっている。QoS Classの値は手動で設定するものではなく自動で設定される。

割り当てられるQoS Class

  • BestEffort
  • Guaranteed
  • Burstable

このQoS Classはkubernetesがコンテナにたいしてoom scoreを設定するのに使用される。oom scoreはOOM Killerによってプロセスを停止される際の優先度の値。

ResourceQuota

リソース。作成可能なリソースの制限とリソース使用量の制限ができる。

HorizontalPodAutoscaler(HPA)

Deployment, ReplicaSetなどのオートスケーリング。HorizontalPodAutoscalerは30秒に1回オートスケーリングすべきかチェックしている。

VerticalPodAutoscaler(VPA)

リソース。PodのCPU/メモリのオートスケーリング。

ぱんだぱんだ

10章 ヘルスチェック

Prove 役割 失敗時の挙動
Liveness Prove Pod内のコンテナが正常に起動しているどうか Podは再起動する
Readiness Prove Podがリクエストを受け付けられるかどうか トラフィックを流さない(Podは再起動しない
Startup Prove Podの初期起動が完了したかどうか 他のProveは起動しない

コンテナの初期起動に時間がかかる場合に十分に時間を確保していないとヘルスチェックが失敗し続けてしまうなどの問題があったためStartup Proveが登場した。Startup ProveはPod起動時に1回だけ実行され、問題なかった場合に他のProveを実施する。

ヘルスチェックの方式は以下の3種

  • exec コマンドを実行し終了コード0でなければ失敗
  • httpGet ステータスコード200 ~ 399でなければ失敗
  • tcpSocket TCPセッションが確立できなければ失敗

gRPCのヘルスチェックにはgRPC用のヘルスチェックがもともと用意されており、grpc_health_proveが使用できる。事前にコンテナイメージにgrpc_health_proveを用意しておきコマンド実行でヘルスチェックする。

ライフサイクル

Init Containers

Pod内でメインとなるコンテナを起動する前に、初期化処理を別のコンテナを起動して実行することで初期化処理を分離することができる。Init Containersは複数設定することができ、マニフェストに書いた順番通りに実行されるため順序性が必要な処理なども実行できる。

postStart / preStop

コンテナの起動後、終了直前に処理を実行することができる。注意点としてpostStartとpreStopは複数回実行される可能性があるため、1回のみ実行してほしい処理は書かないほうがいい。

ぱんだぱんだ

11章 メンテナンスとノードの停止

  • ノードにはSchedulingEnabledとScheduleDisabledのステータスがあり、ScheduleDisabledのステータスのノードでは新たにPodの作成は行われない。既に実行中のpodには影響はない。ステータスの変更はkubectl cordonkubectl uncordonで変更する。
  • ノード上で起動しているPodを退避させるにはkubectl drainを使用する。
  • kubernetesではあるノードにPodが偏って起動している状況などもありえるため、その状態でPodの退避を実行するとサービスの瞬断が発生してしまう。そのため、対象のPodを最低限起動させておく制約などをPodDistributionBudget(PDB)リソースで作成することができる。大規模なkubernetesの運用の場合、PDBなしにPodの退避をするのは難しい。
ぱんだぱんだ

12章 高度で柔軟なスケジューリング

  • マニフェストで指定できるスケジューリングには「配置したいnodeを指定する方法」と「配置したくないnodeを指定する方法」の2種類がある。

配置したいノードを選択する

  • nodeSelector 簡易的なNodeAffinity

  • NodeAffinity 特定なNode上だけで実行する

  • Node Anti-Affinity 特定のNode以外で実行

  • Inter-Pod Affinity 特定のPodがいるドメイン上で実行する

  • Inter-Pod Affinity 特定のPodがいないドメイン上で実行する

  • トポロジ均衡

  • TaintsとTolerations

kubernetesのスケジューラーは基本なもので十分だが機能が不足しているときに自作できるようになっている。

(後半の既存のPodに影響与えるスケジューリングのところだいぶ流し読みしてしまった.)

ぱんだぱんだ

13章 セキュリティ

ServiceAccount

  • kubernetesにはUserAccountとServiceAccountの2種類がある。
  • UserAccountはGKEではGoogleアカウントだったり、EKSではIAMだったりと紐づいていてkubernetesの管理対象ではない。
  • また、UserAccountはクラスタレベルのものなのでNamespaceの影響は受けない。
  • 一方、ServiceAccountはPodで実行されるプロセスのために割り当てるものでNamespaceに紐づく。
  • 指定しなかった場合はdefaultのServiceAccountが割り当てられる。
  • 例えば、Dockerレジストリの認証情報を指定したServiceAccountを作成し、containerに割り当てるなどして使う。
  • 作成したServiceAccountの認証情報はSecretリソースとしてPodに割り当てられる。

RBAC(Role Based Access Control)

  • どういった操作を許可するのかを定めたRoleをServiceAccountなどのUserに対して紐づけることで権限管理する。
  • 複数のRoleを集約したRole(AggregationRole)を利用することもできる。
  • RoleとRoleBindingにはNamespaceとClusterレベルの2種類がある。

SecurityContext

SecurityContextは個々のコンテナに対するセキュリティ設定。

  • privileged 特権コンテナ。コンテナ内で起動するプロセスのLinux Capabilitiesがホストと同等の権限。
  • capabilities より細かく権限を付与。
  • readOnlyRootFilesystem コンテナイメージに含まれているファイルなどをReadOnlyに

PodSecurityContext

Podに対するセキュリティ設定。

  • runAsUser/runAsGroup/runAsNonRoot 実行ユーザー、グループを変更する。セキュリティの観点からrootユーザー以外で実行するように変更したほうがよい。
  • fsGroup 通常マウントしたボリュームのオーナーとグループはroot:rootになっているため、コンテナんの事項ユーザを変更しているとマウントしたボリュームに対する権限がない場合がある。そういった時にマウントするボリュームのグループを変更できる。
  • sysctl カーネルパラメーターを変更。カーネルパラメーターにはsafeとunsafeなものがありたいていunsafe。unsafeなパラメーターを変更した場合、kubernetesクラスタの提供者が明示的に許可していないとPodの起動に失敗する。マネージドなクラスタの場合変更するのは難しいかもしれない。InitContaienrsで特権コンテナとして変更する方法もある。

PodSecurityPolicy

kubernetesクラスタに対してセキュリティーポリシーによる制限を行うリソース。PodSecurityPolicyはホワイトリスト形式のため適切なポリシーを作成しないとリソースが作成できなくなる。

ReplicaSetなどを実行するとき、ReplicaSetの例で言うとReplicaSet Controllerと呼ばれるシステムコンポーネントがPodを作成するためPodを作成するときの権限はReplicaSetを作成したときの権限は使用されない。kube-system内にある権限を変更したくなるがPodに割り当てたServiceAccountが適切なPodSecurityPolicyを持っていればPodを作成できるようになっている。

NetworkPolicy

kubernetesクラスタ内でPod同士が通信する際のトラフィックルールを規定するもの。NetworkPolicyを利用しない場合、クラスタ内のすべてのPod同士で通信できる。Namespaceごとにトラフィックを転送しないようにしたり、全ての通信を遮断してホワイトリスト形式で利用したりできる。

NetworkPolicyはインバウンドのIngressとアウトバウンドのEgressで構成される。

認証/認可 Admission Control

Admission Controlはkubernetes APIサーバーにリクエスト制御を追加で行う仕組み。kubernetesではAuthentication/Authorization/Admission Controlの3つのフェーズを通ってリソースが登録される。

Authenticationは認証。Authorizationは認可。Admission Controlは別途そのリクエストの内容を許可するかどうかの判断や追加の柔軟なチェックなどが行える。Admission Controlはプラグイン形式になっている。

PodPreset

Admission Controllerの1種。リソース。Podの起動前に環境変数を割り当てたり、volumeやPersistentVolumeを割り当てたりといった設定を追加できるため、Podの定義と疎結合に分離できる。また、PodPresetが衝突すると適用されなくなってしまうためなるべくPodPresetは分割して局所的に管理したほうがよい。

Secret

マニフェストは通常GitHubなどでバージョン管理するがSecretの値はbase64で難読化されているだけなのでセキュリティ的にそのままあげることはできない。

kubesec

GCPのKMSやAWSのKMSを使用して安全にSecretを管理するためのOSS。kubesecはファイル全体を暗号化するのではなくSecretの構造を保ったまま値だけ暗号化するので可読性に優れている。

インストール

curl -sSL https://github.com/shyiko/kubesec/releases/download/0.9.2/kubesec-0.9.2-darwin-amd64 \
  -o kubesec && chmod a+x kubesec && sudo mv kubesec /usr/local/bin/  

補完機能

source <(kubesec completion bash)

GCPのKMSの例で言うと、生成した共通鍵を利用してSecretの内容を暗号化・複合化をすることができ、その共通鍵をKMSで厳重に管理するようなフロー。

SealedSecret

kubesecとは異なり暗号化された独自のSealedSecretリソースをクラスタ上に作成し、クラスタ内部でSealedSecretからSecretリソースを作成する。秘密鍵も公開鍵もクラスタ内部に閉じ込められており、クラスタ内部の鍵を使用して暗号化、複合化する。

インストール

brew install kubeseal

// コントローラーのインストール

ExternalSecret

SealedSecret同様、リソースを作成するタイプ。ExternalSecretリソースをクラスタに登録しておくとクラスタ内部でExternalSecretからSecretに変換することができる。SealedSecretではクラスタ内で秘密鍵などを管理していたが、ExternalSecretでは外部のSecretManager(AWSやGCPなど)の参照情報を保持している。

インストール
https://external-secrets.io/v0.8.3/introduction/getting-started/

ぱんだぱんだ

Helm

インストール

brew install helm

補完

source <(helm completation bash)

Helmではチャートと呼ばれるパッケージが多く存在している。

https://artifacthub.io/

チャートリポジトリを初期化

helm repo add stable https://charts.helm.sh/stable

チャートを検索

helm search repo wordpress

NAME            	CHART VERSION	APP VERSION	DESCRIPTION
stable/wordpress	9.0.3        	5.3.2      	DEPRECATED Web publishing platform for building...

HelmリポジトリだけでなくHelm Hubからチャートを検索することもできる

helm search hub wordpress

チャートのインストール

インストール時に指定するパラメーターは直接コマンドオプションで指定するかvaluesファイルを作成し読み込むかのどちらか。

テンプレート

helm templateを利用することでテンプレートファイルからマニフェストファイルを出力することのみが可能。これを利用してGitOpsのようなCI/CDでhelm templateでマニフェストを出力し、applyするといったフローも可能。

独自チャートの作成

独自のチャートを作成するにはhelm createを実行する。

ぱんだぱんだ

15章 モニタリング

DataDog

helmでチャートが用意されているので使用するとよさげ。

Prometheus

ぱんだぱんだ

16章 コンテナログの集約

Fluented

kubernetesでは標準出力、エラー出力でログを出力するのが推奨されているが、Fluentedを使用することでクラスタ外部に転送するような構成が作れる。

DataDog

Datadogのエージェント経由でも可能。

Grafana Loki

Prometheusと相性がいい。

何にせよDamonSetでPodに常駐させてログを取集する。

ぱんだぱんだ

17章 CI/CD

GitOps

Gitを用いたCI/CDの手法の一つ。アプリケーションのCI/CDでよく見るようなCIツールを使用してkubectlでapplyする方法もあるがCIツールがkubernetesクラスタに対して強い権限を持ってしまったり依存関係が強くなってしまったりといった問題もあるがGitOpsを採用することでこういった問題を軽減できる。

CIツール

Tekton + Kanikoを組み合わせて実現したりできる。以下のCIで実行したいようなツールたちをパイプラインに乗せるのに導入する必要がありそう。

kubeval

マニフェストファイルのYAML構造がAPIバージョンに準拠しているかをチェックできるためCIに組み込んで使用できる。

Conftest

マニフェストファイルのユニットテストを実施できるため、これもCIに組み込んで使用できる。

Open Policy Agent

ポリシーチェックを実行できる。kubernetestと連携するGatekeeperと組み合わせることでマニフェストが適用されたポリシーチェックを実施することができる。kubernetesのAdmin Controllerとして動作するのでリソース作成時に検知する感じになる。

CDツール

前述したようにGitOpsを実現するにはCIツールではなくCDツールを採用したほうがええ。とりあえずArgoCDを使うのがベターそう。

ArgoCD

  • 指定したリポジトリを監視し、マニフェストをクラスタに適用する。
  • GitOpsで言うところのDeploy Agentに該当する。

install

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

https://argo-cd.readthedocs.io/en/stable/

  • ArgoCDではApplicationリソースを作成することで特定のリポジトリの特定のパスにあるファイルをkubernetestクラスタに適用する。
  • KustomizeやHelmにも対応しているため現状GitOpsを始めるのに最も適したツール。
  • ArgoCDは WebUIが用意されている。

開発環境を整えるツール

Telepresence

リモートのkubernetesクラスタを利用してローカル開発を実現するもの。大規模なkubernetesクラスタになると全てのコンポーネントをローカルで起動させるのは難しい。

Telepresenceはリモートで動いているkubernetesコンポーネントを使用し、一部をローカルで動作させる。ローカルのコンポーネントとkubernetesコンポーネントは疎通性があるので手元で起動したコンテナからリモートのkubernetes上のPodネットワークに接続することができる。

Skaffold

dockerおよびkubernetes向けのビルドとデプロイを自動化する。利用にはYAML形式のConfigリソースを作成して設定する。

ぱんだぱんだ

19章 kubernetesのアーキテクチャ

kubernetesクラスタは下記8つのコンポーネントから構成されている。

etcd

分散Key-Value Store。etcdにはkubernetesクラスタに登録されるすべての情報が保存されるためetcdのデータを守ることが最も重要。そのため、単一障害点とならないようクラスタ構成を組む必要がある。

kube-apiserver

kubernetes APIを提供するコンポーネント。kubectlでリクエストを送ることでリソースの操作を行う。kube-scheduler, kube-controller-manager, kubeletなどもこのkube-apiserverに対してリクエストを送る。

Podの例で言うとkubectlでPodの作成を実行するとkube-apiserverでリクエストを受け取り、Pod情報をetcdに登録する。kube-schedulerはノード未割り当てのPodのノード情報をkube-apiserverにリクエストすることで割り当てるノードを登録する。実際に起動するのはkubeletの役目。このようにkube-apiserver以外のすべてのコンポーネントはkube-apiserverを中心にして分散システムとして動作している。

kube-scheduler

上述したようにkube-schedulerはノード未割り当てのPodを検知し割り当てするノード情報を登録する。

kube-controller-manager

さまざまなコントローラーを実行するコンポーネント。Deployment ControllerやReplicaSet Controllerはリソースの情報を監視し、必要な操作をkube-apiserverに対して実行する。

kubelet

上述したようにkubeletはkubernetesノード上に存在し、Podの起動、停止の操作を実行する。

kubeletはCRIによってcontainerdなどの高レイヤコンテナランタイムに命令を送り、高レイヤコンテナランタイムはOCIの形式に準拠した形でruncのような低レイヤコンテナランタイムに命令を送るようになってる。

このようにCRIやOCIといった標準化が進んでいるためその形式に準拠した形であれば何でもしようできるようになっている。

kube-proxy

kube-proxyもkubelet同様、ノード上で動作する。Serviceリソースが作られた際にClusterIPやNodePort宛のトラフィックがPodに正常に転送されるようにする。

転送方式

  • userspaceモード
  • iptablesモード
  • ipvsモード

CNI(Container Network Interface) Plugin

複数のkubernetesノードはPod間の疎通性を確保するためにクラスタ内に分散配置されたPodが相互に疎通う可能なネットワークを作成する必要があり、この部分を担当するのがCNI。

kube-dns(CoreDNS)

kubernetesクラスタ内部の名前解決をする。

cloud-controller-manager

kubernetesクラスタが各種クラウドプロバイダと連携するためのコンポーネント。

CustomResourceDefinitionとOperator

kubernetesでは独自リソースを容易に追加して、kubernetesを拡張することができるようになっている。独自リソースを定義するにはCustomResourceDefinitionリソースを定義し作成するだけでよい。実際は独自リソースが作成された際に何かしらの処理をおこなうOperator(カスタムコントローラー)を実装する必要がある。

もし、カスタムコントローラーを実装するのであればkubebuilderOperator Frameworkなどを使用すると楽に作成できる。

このスクラップは2023/06/12にクローズされました