Webエンジニアのブログ

「Kubernetes 完全ガイド」を読んだので要約する


Kubernetesについて体系的な知識がなかったため、何を解決できるのか分からなかった。そんな課題を解決すべく「Kubernetes完全ガイド」を読んでみた。この本ではDockerの基本からKubernetesの運用方法が丁寧に紹介されている。Kubernetesを効率的に学びたい時、まずこの本を読むべきというレベルで良書だと感じた。

自分が気になっていた部分を、ここに一通りまとめておく。

4 APIリソースとkubectl

4.2 Kubernetesの基礎

Kubernetesは、Kubernetes MasterとKubernetes Nodeの2種類のノードから成り立つ。Kubernetes MasterはAPIエンドポイントの提供、コンテナのスケジューリングなどを担うノードである。Kubernetes Nodeは、Dockerホストであり、実際にコンテナが起動するノードである。

4.3 Kubernetesとリソース

Kubernetesでは「リソース」を登録することで、コンテナの実行やロードバランサの作成が非同期に行われる。リソースには次の5種類がある。

  • Workloadsリソース(コンテナの実行に関するもの)
  • Discovery & LBリソース(コンテナを外部公開するためのエンドポイント)
  • Config & Storageリソース(設定、機密情報、永続化ボリュームなど)
  • Clusterリソース(セキュリティなどのクラスタ自体の設定)
  • Metadataリソース(クラスタ内の他のリソースを操作する)

4.4 Namespaceによる仮想的なクラスタの分離

KubernetesにはNamespaceと呼ばれる仮想的なKubernetesクラスタの分離機能がある。これにより1つのクラスタを複数チームで運用したり、環境ごとに分割したりすることができる。初期状態では3つのNamespaceが作成されている。

  • kube-system(Kubernetesクラスタのコンポーネントやアドオンがデプロイされる)
  • kube-public(全ユーザが利用できるConfigMapなどを配置する)
  • default(デフォルトのNamespace)

RBAC(Role-Based Access Control)によってNamespaceごとの権限管理が可能。システムが複雑でない場合はdefaultのNamespaceを利用しても問題ない。

4.5 CLIツールとkubectl

Kubernetesでは、クラスタの操作は全てKubernetes MasterのAPIを介して行われる。手動で操作する場合はkubectlというCLIツールを利用することが一般的である。以下はkubectlのTips。

  • ContextやNamespaceの切り替えが面倒な場合はkubectxやkubensの利用を検討する
  • 基本的にkubectl createではなくkubectl applyを使用する(差分を考慮するため)
  • マニフェストファイルは1つのディレクトリにまとめる(大規模である場合は分割)

Kubernetesでは各リソースに対してアノテーションとラベルというメタデータを付与できる。アノテーションはシステム側の管理に使うメモ書きのようなものであり、Kubernetesが利用できない設定をアノテーションで制御することもある。ラベルは主にリソースをグルーピングし、各グループへオペレーションを行えるようにするために用いられる。レプリカ数の管理やLBの転送先決定にも使われているため、ラベル名の衝突には気をつける。

5 Workloadsリソース

Workloadsリソースは、クラスタ上にコンテナを起動させるためのリソースである。全部で8種類あり、Podを最小単位として、それらを管理する上位リソースがある関係になっている。

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

5.2 Pod

Podは1つ以上のコンテナから構成されている。Podのコンテナ同士はネットワーク的に隔離されておらず、IPアドレスを共有している。そのためlocalhost宛で通信することができる。

Podには大きく分けて3つのデザインパターンがある。

  • サイドカーパターン(メインコンテナに機能を追加する)
    • 例1: Gitリポジトリとローカルストレージを同期するコンテナ
    • 例2: アプリケーションのログファイルをオブジェクトストレージに転送するコンテナ
  • アンバサダーパターン(外部システムとのやり取りの代理を行う)
    • 例1: DBへの接続情報などを管理し、アプリケーション側をインフラと疎結合にする
  • アダプタパターン(外部からのアクセスのインターフェースとなる)
    • 例1: 監視ソフトウェアからのログ収集に対して、適切なフォーマットに変換する

Podはクラスタ内DNSを使って名前解決を行い、クラスタ内DNSで解決できないドメインはアップストリームのDNSサーバに問い合わせる。これはspec.dnsConfigで変更することができ、またspec.hostAliasesによって/etc/hostsの書き換えが可能である。

5.3 ReplicaSet / ReplicationController

ReplicaSet / ReplicationControllerはPodのレプリカを作成し、指定した数のPodを維持し続けるリソースである。当初はReplicationControllerという名前だったが、現在ではReplicaSetになっており、基本的にReplicaSetと呼ぶ。

Podはなるべくノード間で分散されるように配置される。またノードやPodに障害が発生した場合でも、指定された数を満たすように別のノードでコンテナを起動してくれる。これは「セルフヒーリング」と呼ばれる。

5.4 Deployment

Deploymentは複数のReplicaSetを管理することで、ローリングアップデートやロールバックなどを実現するリソースである。DeploymentがReplicaSetを管理し、ReplicaSetがPodを管理する3層の親子関係になっている。ローリングアップデートは以下のようなフローを取る。

  1. 新しいReplicaSetを作成
  2. 新しいReplicaSet上のレプリカ数を徐々に増やす
  3. 古いReplicaSet上のレプリカ数を徐々に減らす
  4. (2、3を繰り返す)
  5. 古いReplicaSetはレプリカ数0で保持する

古いReplicaSetは削除されずレプリカ数0で保持される。残っている古いReplicaSetを指定することでロールバックを行える。

アップデート戦略はRecreateとRollingUpdateの2種類がある。Recreateは一度全てのPodを削除してから再度Podを作成する。そのためダウンタイムが発生するが、余剰なリソースを使わず、そして切り替え完了が早いといったメリットがある。RollingUpdateは不足Pod数や超過Pod数などを設定し、アップデート時の挙動を変えることができる。

5.5 DaemonSet

DaemonSetはReplicaSetとは違い、各Node上に1つずつ配置するリソースである。ログ収集のFluentdやモニタリングのDataDogなどを動作させたい場合に使う。

アップデート戦略はOnDeleteとRollingUpdateの2種類がある。OnDeleteはPodが何らかの要因で停止して再作成されない限りアップデートされないため、長期間古いバージョンが稼働し続けてしまう可能性がある。

5.6 StatefulSet

StatefulSetもReplicaSetとは違い、データベースなどステートフルなワークロードに対応するためのリソースとなる。Pod名のサフィックスは数字のインデックスが付与されたものとなり、そしてデータを永続化するための仕組みを有している。アップデート戦略はDaemonSetと同じく、OnDeleteとRollingUpdateの2種類がある。

5.7 Job

Jobとは、並列じ実行しながら指定した回数のコンテナの実行(正常終了)を保証するリソースである。

spec.restartPolicyにはOnFailureまたはNeverのどちらかを指定する必要がある。NeverはPod障害時に新規のPodが作成され、OnFailureの場合には再度同一のPodを利用してJobを再開する。completions(完了数)を指定しなかった場合は、ワークキューとして動作するようになる。

5.8 CronJob

CronJobは、Cronのようにスケジュールされた時間にJobを作成するリソースである。CronJobとJobは親子関係になっている。

6 Discovery & LBリソース

Discovery & LBリソースは、コンテナに対するエンドポイントの提供や、ラベルに一致するコンテナのディスカバリに利用されるリソースである。L4ロードバランシングを提供するServiceリソースと、L7ロードバランシングを提供するIngressリソースの2種類がある。

  • Service
    • ClusterIP
    • ExternalIP
    • NodePort
    • LoadBalancer
    • Headless
    • ExternalName
    • None-Selector
  • Ingress

6.2 KubernetesクラスタのネットワークとService

Serviceを利用することによって、「Pod宛トラフィックのロードバランシング」と「サービスディスカバリとクラスタ内DNS」の2つのメリットが得られる。

Pod宛トラフィックのロードバランシングは、外部のロードバランサが払い出す仮想IPアドレス(Virtual IPアドレス)や、クラスタ内でのみ利用可能な仮想IPアドレス(ClusterIP)などを提供している。サービスディスカバリは「環境変数」「DNS Aレコード」「DNS SRVレコード」を利用した3種類が用意されている。SRVレコードはPort名とProtocolを利用し、サービスを提供しているPort番号を含めたエンドポイントを解決できる仕組みである。

6.3 ClusterIP Service

ClusterIPは、Kubernetesクラスタ内からのみ疎通性があるプライベートな仮想IPが割り当てられる。ClusterIP宛の通信は、各ノード上で実行しているシステムコンポーネントのkube-proxyがPod向けに転送を行う。

6.4 ExternalIP Service

ExternalIPは、特定のNodeのIPアドレス:Portで受信したトラフィックを、コンテナに転送する形で外部疎通性を確立するServiceである。

6.5 NodePort Service

NodePortは、全てのNodeのIPアドレス:Portで受信したトラフィックをコンテナに転送する。厳密に言うとListenする際に0.0.0.0:Portを使用して全てのIPアドレスでBindする形になる。

6.6 LoadBalancer Service

LoadBalancerは、Kubernetesクラスタ外のLoadBalancerを利用してロードバランシングを行う。プロダクション環境では一番実用的とされている。外部のLoadBalancerを利用するためには、Kubernetesクラスタが構築されているインフラがこの仕組みに対応している必要がある。AWSやGCP、Azureなどは対応している。

6.7 Headless Service(None)

Headless Serviceは、DNS Roud Robin(DNS RR)を使ったエンドポイントを提供する。

6.8 ExternalName Service

ExternalNameは、Service名の名前解決に対して外部のドメイン宛のCNAMEを返す。

6.9 None-Selector Service

None-Selectorは、Service名で名前解決を行うと自分で指定したメンバに対してロードバランシングを行う。

6.10 Ingress

IngressはL7ロードバランシングを提供するリソースである。「Ingressリソース」はマニフェストで登録されるリソースを意味し、「Ingress Controller」はIngressリソースがKubernetesに登録された際に、何らかの処理を行うものを意味する。Ingressはクラスタ外のロードバランサを利用するものと、クラスタ内にIngress用のPodをデプロイする2種類に大別できる。

7 Config & Storageリソース

Config & Storageは、コンテナに対して設定ファイル、パスワードなどの機密情報などをインジェクトしたり、永続化ボリュームを提供したりするためのリソースである。

7.2 環境変数の利用

Kubernetesで環境変数を渡す際に、大きく分けて5つの情報源から渡すことができる。

  • 静的設定(マニフェストに直接記述)
  • Podの情報(Pod自身の情報から取得)
  • コンテナの情報(コンテナの情報から取得)
  • Secretリソースの機密情報(Secretリソースから参照)
  • ConfigMapリソースの設定値(ConfigMapリソースから参照)

7.3 Secret

Secretは、機密情報をコンテナに渡す際に使うリソースである。Secretはいくつかのタイプに分けられる。

  • Generic(スキーマレスなSecret)
  • TLS(証明書として利用するSecret)
  • Dockerレジストリ(プライベートリポジトリの認証時に利用するSecret)
  • Service Account(Service Accountのトークンや証明書をマウントするためのSecret)

Secretをコンテナから利用する場合は「環境変数として渡す」か「Volumeとしてマウントする」の2つがある。Volumeの場合は動的に値を更新することができる(デフォルトの更新間隔は60秒)。

Secretリソースはマニフェストにbase64エンコードした値をそのまま記述しているだけである。セキュアにするためにはkubesecというツールを使い、GnuPGやAWS KMSを用いた暗号化を行う必要がある。またSecretはetcdに保存されており、Node上にはtmpfs領域(メモリ上にある一時的なファイルシステム)に保持されるようになっている。

7.4 ConfigMap

ConfigMapは、設定情報などのKey-Valueで保持できるデータを保存しておくリソースである。nginx.confやhttpd.confのような設定ファイルも保存が可能になっている。ConfigMapも「環境変数として渡す」か「Volumeとしてマウントする」の2つがある。

7.5 PersistentVolumeClaim

VolumeとPersistentVolueとPersistentVolumeClaimの違いを説明する。

Volumeはあらかじめ用意された利用可能なボリューム(ホストの領域やNFS)をマニフェストに指定することで利用可能にするものである。PersistentVolumeは、外部の永続ボリュームを提供するシステムと連携して、新規のボリュームの作成や削除を行うことが可能である。具体的にはPersistentVolumeリソースを用いる。PersistentVolumeClaimは、PersistentVolumeからリソースをアサインするためのものとなっている。

7.6 Volume

Volumeには以下のようなプラグインがある。

  • emptyDir(ホストのコンテナ用の一時領域をコンテナ上にマッピングする)
  • hostPath(ホスト上の領域をコンテナ上にマッピングする
  • downwardAPI(Podの情報をファイルとして配置する)
  • projected(SecretやConfigMapのマウントを1つのディレクトリに集約する)
  • nfs
  • iscsi
  • cephfs

7.7 PersistentVolume(PV)

PVは、永続化領域として確保されるVolumeであり、基本的にネットワーク越しにディスクをアタッチするタイプとなる。PVには以下のようなものがある。

  • GCE Persistent Disk
  • AWS Elastic Block Store
  • NFS
  • iSCSI
  • Ceph
  • OpenStack Cinder
  • GlusterFS

PVは3つのアクセスモードがある。

  • ReadWriteOnce(RWO、単一ノードからRead/Writeが可能)
  • ReadOnlyMane(ROX、複数ノードからReadが可能)
  • ReadWriteMany(RWX、複数ノードからRead/Writeが可能)

Reclaim Policyを設定すれば、PVCが削除された際のPVの実体の挙動を制御できる。

  • Delete(PVの実体が削除される)
  • Retain(PVの実体を消さずに保持する)
  • Recycle(PVのデータをrm -rfで削除し、再利用可能な状態にする)
    • Recycleは現在では推奨されておらず、後述するDynamic Provisioningで動的な新しいディスクの作成と削除が実現されている。

7.8 PersistentVolumeClaim(PVC)

PVCは、PVへ永続化領域の要求を行うリソースである。PVCでは事前にPVを作成し、PVCの要求を元に割り当てるといった順序を取っていたが、作成の手間や効率的にVolumeを割り当てられないという問題があった。そこでDynamic Provisioningが登場し、動的にPVを作成して割り当てることができる。ただ一方で一部のアクセスモードしかサポートしていないことが多い。

8 ClusterリソースとMetadataリソース

Clusterリソースは、セキュリティ周りの設定やクォータ設定など、クラスタの挙動を制御するためのリソースである。Clusterリソースには以下のようなものがある。

  • Node
  • Namespace
  • PersistentVolume
  • ResourceQuota
  • ServiceAccount
  • Role
  • ClusterRole
  • RoleBinding
  • ClusterRoleBinding
  • NetworkPolicy

Metadataリソースは、クラスタ上にコンテナを起動させるのに利用するリソースである。Metadataリソースには以下のようなものがある。

  • LimitRange
  • HorizontalPodAutoscaler
  • PodDisruptionBudget
  • CustomResourceDefinition

8.2 Node

NodeはKubernetes上にリソースとして登録されている。ユーザーが作成や削除を行うリソースではないが、NodeのIPアドレスやホスト名などを取得するためによく意識するものである。

8.3 Namespace

Namespaceは、リソースのクォータ(割り当て)を設定するResourceQuotaや、認可を行うRBAC(Role Based Access Control)で利用可能である。

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

Kubernetesでは、コンテナ単位にリソースの制限を行うことが可能である。制限をかけられるリソースはCPUとメモリだが、DevicePluginsを利用すればGPUなどにも制限をかけられるようになる。CPUは1vCPU(仮想CPU)を1000millicores(m)とする単位で指定する。

リソースの制御はPodのコンテナ定義の部分に記載し、RequestsとLimitsを指定できる。Requestsは使用するリソースの下限を指定する。ノードに空きリソースが無い場合はスケジューリングされない。一方でLimitsは使用するリソースの上限を指定する。ノードのLimitsで指定されたリソースが残っていなくてもスケジューリングされるため、Requestsとの差が大きすぎるとクラスタ全体の負荷が高くなってしまう。

9.2 Cluster Autoscalerとリソース不足

Kubernetesでは、Cluster Autoscalerによってクラスタ自体のオートスケーリングを行い、需要に応じてKubernetes Nodeを自動的に増減させる。基本的にリソースによるスケジューリングはRequests(下限)を基準に行われる。そのため実際のロードアベレージ(CPU使用率など)は低いのにスケールアウトしたり、高いのにスケールアウトされないといった状況が起こりうる。これを防ぐには「RequestsとLimitsに顕著な差をつけないこと」「Requestsを大きくし過ぎないこと」の2つを心がける必要がある。

9.3 LimitRangeによるリソース制限

LimitRangeを利用すると、Pod、Container、PVCに対してリソースの最小値や最大値、デフォルト値を設定することができる。LimitRangeは各Namespaceごとに設定が必要になる。

9.4 QoS Class

Qos Classは、KubernetesがPodを停止する際に参考する設定である。Qos Classは下記の条件を元に自動で設定される。

  • BestEffort(Requests,Limitsがどちらも未指定、優先度3)
  • Guaranteed(Requests,Limitsが同じでCPUとメモリの両方が指定されている、優先度1)
  • Burstable(Guaranteedを満たさず、1つ以上のRequests,Limitsが設定されている、優先度2)

例えばOOM KillerによってPodを停止する際、上記の優先度が高い順で停止される。

9.5 ResourceQuotaによるNamespaceのリソースクォータ制限

ResourceQuotaを利用することで各Namespaceごとに理想可能なリソースを制限することができる。大きく分けて「作成可能なリソース数の制限」と「リソース使用量の制限」の2種類がある。

9.6 HorizontalPodAutoscaler(HPA)

HPAは、Deployment、ReplicaSetのレプリカ数をCPU不可などに応じて自動的にスケールさせるリソースである。必要なレプリカ数はceil(sum(Podの現在のCPU使用率 / targetAverageUtilization))で求められる(ceil()は切り上げを行う関数)。最大で3分に1回スケールアウトを行い、5分に1回スケールインを行う。

9.7 VerticalPodAutoscaler(VPA)

VPAは、コンテナに割り当てるCPUやメモリのリソースを自動的にスケールさせるリソースである。Kubernetes v1.11ではまだAlphaとして扱われている。

10 ヘルスチェックとコンテナのライフサイクル

10.1 ヘルスチェック

Kubernetesでは、標準でヘルスチェックが行われており、詳細な条件で行うこともできる。Kubernetesには、Liveness ProbeとReadiness Probeという2種類のヘルスチェック機構が用意されている。Liveness ProbeはPodが正常に動作していることを確認するためのヘルスチェックである。ヘルチェック失敗時はPodを再起動する。Readiness ProbeはPodがサービスインする準備ができているか確認するためのヘルスチェックである。ヘルスチェック失敗時はPodの再起動を行わず、再度サービスイン出来る状態になるのを待つ。

ヘルスチェック方式には以下の3つがある。

  • exec(コマンドを実行し、終了コードが0でなければ失敗)
  • httpGet(HTTP GETリクエストのStatus Codeが200~399でなければ失敗)
  • tcpSocket(TCPセッションが確立できなければ失敗)

10.2 コンテナのライフサイクルと再始動(restartPolicy)

コンテナのプロセス停止時やヘルスチェック失敗時に、コンテナを再起動するかどうかはspec.restartPolicyで指定できる。

  • always(Podが停止すると、常にPodを再起動する)
  • OnFailure(Podの停止が終了コード0以外の場合、Podを再起動する)
  • Never(Podが停止しても、Podを再起動させない)

10.3 Init Containers

Init Containersとは、Pod内でメインとなるコンテナを起動する前に別のコンテナを起動するための機能である。複数指定することもでき、その場合は上から1つずつコンテナが起動される。

10.4 起動時と終了時に任意のコマンドを実行する(postStart / preStop)

Kubernetesでは、コンテナの起動後と停止直前に任意のコマンドを実行することができる。Entrypointが実行されるより前にpostStartが実行される可能性もある。

10.5 Podの安全な停止とタイミング

起動中のPodの削除要求がKubernetes APIサーバーに届くと、非同期に「preStop処理+SIGTERM処理」と「Serviceからの除外設定」が行われる。この2つは厳密には同時に行われない。そのため「Serviceからの除外設定」が完了する前、すなわちリクエストが届かなくなる前に「preStop処理+SIGTERM処理」でプロセスを停止してしまうと、一部のリクエストでエラーが発生してしまう。これを防ぐにはServiceの除外処理が終わるであろう数秒間を「preStop処理+SIGTERM処理」で待機するのが効果的である。

Podにはspec.terminationGrancePeriodSeconds(デフォルト値は30秒)という設定が用意されており、この期間内に「preStop処理+SIGTERM処理」を終わらせる必要がある。この時間に達するとSIGKILLシグナルがコンテナに送られて強制終了される。

10.6 リソースを削除した時の挙動

KubernetesではReplicaSetなどの親リソースが削除された際には、子のPodなどを削除するためにガベージコレクションを行う。ReplicaSetを削除したときの挙動は下記の3パターンがある。

  • Background(ReplicaSetを直ちに削除し、Podはガベージコレクタが非同期に削除)
  • Foreground(ガベージコレクタがPodを削除してから、ReplicaSetを削除)
  • Orphan(Replicaset削除時にPodの削除を行わない)

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

Kubernetesのノードをメンテナンス等で停止する際には、Podを停止する必要がある。

KubernetesのノードはSchedulingEnabledとSchedulingDisabledのどちらかのステータスを持つ。ステータスがSchedulingDisabledになったノードにはPodが新規に作成されなくなるが、実行中のPodは停止されない。Podを退避させるにはkubectl drainを利用する。ダウンタイムを発生させないためにはspec.minAvailablespec.maxUnavailableにPodの個数やパーセンテージを指定する。

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

Kubernetesのスケジューリングでは、よくAffinityとAnti-Affinityの考え方を用いる。Affinityは特定の条件に一致するところにスケジューリングすることを意味し、Anti-Affinityは特定の条件に一致しないところにスケジューリングすることを意味する。

Kubernetesのスケジューリングには大きく分けて「Podのスケジューリング時に特定のNodeを選択する方法」と「Nodeに対して汚れ(Taints)をつけておき、それを許容(Tolerations)できるPodのみスケジューリングを許可する方法」の2種類がある。前者には大きく分けて下記の5つがある。

  • nodeSelector(簡易的なNode Affinity機能)
  • Node Affinity(特定のノード上だけで実行する)
  • Node Anti-Affinity(特定のノード以外で実行する)
  • Inter-Pod Affinity(特定のPodがいるドメイン(ノード、ゾーン、etc)上で実行する)
  • Inter-Pod Anti-Affinity(特定のPodがいないドメイン上で実行する)

12.2 ビルトインノードラベルとラベルの追加

Nodeにはあらかじめビルトインノードラベルが付与されており、ホスト名、OS、アーキテクチャ、インスタンスタイプ、リージョン、ゾーンといった情報が付与されている。手動でラベルを付与することも可能である。

13 セキュリティ

Kubernetesではユーザに似たコンセプトとして、UserAccountとServiceAccountがある。

UserAccountはEKSではIAMとリンクしており、Kubernetesの管理対象ではない。またUserAccountはその特性上クラスタレベルの存在となり、Namespaceの影響を受けない。一方でServiceAccountはKubernetes内で完結するものであり、Podで実行されるプロセスには必ず割り当てられる。

13.2 RBAC(Role Based Access Control)

RBACは、どういった操作を許可するのかを定めたRoleを作成し、ServiceAccountなどのUserに対してRoleを紐付けることで権限を管理する。AggregationRuleを利用することで、Roleが別のRoleを参照することができる。RBACには、NamespaceレベルのリソースとClusterレベルのリソースの2種類がある。具体的にはRoleとCluster Role、RoleBindingとClusterRoleBindingである。

13.3 Security Context

Security Contextは、個々のコンテナに対するセキュリティ設定である。privilegedやcapabilitiesなどを指定できる。

13.4 PodSecurityContext

PodSecurityContextは、Pod(全てのコンテナに)に対するセキュリティ設定である。実行するユーザやグループ、カーネルパラメータなどを指定できる。

13.5 PodSecurityPolicy

PodSecurityPolicyは、Kubernetesクラスタに対してセキュリティポリシーによる制限を行う機能である。例えばSecurityContextなどで設定した項目のデフォルト値や制限を行うことができる。

13.6 NetworkPolicy

NetworkPolicyは、Kubernetesクラスタ内でPod同士が通信する際のトラフィックルールを規定するものである。NetworkPolicyを利用すれば、Namespaceごとのトラフィック管理や、特定のPod同士のみ通信を許可するホワイトリスト方式にすることが可能になる。

13.7 認証/認可とAdmission Control

Admission Controlは、Kubernetes APIサーバにリクエスト制御を追加で行う仕組みである。KubernetesではAuthentication(認証)、Authorization(認可)、Admission Controlという順の流れで判断を行う。

13.8 PodPreset

PodPresetはAdmission Controllerの一つで、Podを作成する際にデフォルト設定を埋め込むリソースである。具体的には、Config & Storageリソースのデフォルト値を埋め込める。特定のラベルが付与されているPodに対して、自動的に環境変数を埋め込むなどといったことが可能になる。

14 マニフェストの汎用化を行うオープンソフトウェア

KubernetesではYAML形式で書かれたマニフェストを作成し、kubectlで適用するのが最も簡単である。しかし大規模になるほど難しくなってくるため、マニフェストを汎用化する必要がある。

14.2 Helm

Helmは、Kubernetesのパッケージマネージャである。Red Hat系におけるYUMや、Debian系におけるAPTに該当する。HelmはOSSとして公開されており、様々なパッケージ(Chart)が用意されている。各Chartはそれぞれの成熟度に合わせてstableとincubatorに分かれており、GitHub(helm/charts)で管理されている。

HelmクライアントはHelmリポジトリからChartをダウンロードし、Tillerに送信する。Tiller側ではChartとvaluesの組み合わせをReleaseとして管理し、KubernetesのConfigMapとしてデータを保存している。登録されたReleaseはKubernetes APIに登録することで、DeploymentやServiceなどの各リソースが作成されるようになっている。

14.4 Kustomize

Kustomizeという類似ツールもある。Kutomizeは将来的にkubectlのサブコマンドとしてマージされることを目標に進められている。

15 モニタリング

Kubernetesでは、モニタリングにSaaSの「Datadog」もしくはOSSの「Prometheus」を用いることが一般的である。後者は無料だが、起動するマシンリソースが必要になる。

16 コンテナログの集約

コンテナ上で起動するアプリケーションは、基本的に標準出力と標準エラー出力にログを出力するようにする。そうすることでログの扱いを抽象化することができる。

16.2 Fluentdによるログ集約

KubernetesではFluentdを使ってクラスタ外部に転送する構成がおすすめである。Fluentdは、DaemonSetを利用して各ノードに一つずつ起動し、そしてFluentd Podが同じノード上に起動している全コンテナのログを取得して転送する。実際には、Dockerコンテナの標準出力のログがノード上の/var/log/containers/に出力され、そのログファイルをFluentd Podがtailプラグインを使って読み出し、転送している。

17 Kubernetes環境でのCI/CD

17.2 Spinnaker

Spinnakerは、Netflixが開発しているOSSで、継続的デリバリを実現するものである。Spinnakerには以下のような機能がある。

  • カナリアリリース
  • Blue/Greenデプロイメント
  • ロールバック
  • Slackやメールなどの通知機能

17.3 Skaffold

Skaffoldは、Googleが開発したOSSで、Kubernetes向けのビルドとデプロイを自動化するものである。Skaffoldではソースコードが変更されたことを検知すると、Dockerイメージのビルド、プッシュ、デプロイを一元的に行うことが可能である。また開発段階向けとしてイメージをプッシュすることなくクラスタへデプロイすることも可能である。

18 マイクロサービスアーキテクチャとサービスメッシュ

マイクロサービスアーキテクチャは、システムの個々の機能をサービスとして切り出し、サービス同士がgRPCやRESTful APIなどで連携することでシステム全体を構成する疎結合なアーキテクチャである。

18.2 サービスメッシュとは

サービスメッシュとは、マイクロサービス間に張り巡らされたメッシュ状の通信やその通路を制御する考え方である。サービスメッシュを実現するためのOSSとしてはIstioやConduit、Linkerdなどが有名である。これらの基本的な仕組みは、Pod間の通信経路にプロキシを挟むことで、トラフィックのモニタリングやトラフィックコントロールを行うというものである。

Circuit Breakerという機能は、転送先のマイクロサービスに問題がある場合、アクセスを遮断してすぐにリクエストエラーを返すようにする。こうすることでタイムアウトを待つ必要がなく、障害が連鎖することを防げる。他にもリクエスト数を制限するRate Limit機能や、リクエスト失敗時のRetry処理機能などもサービスメッシュに任せることができる。

19 Kubernetesのアーキテクチャを知る

Kubernetesクラスタは、下記の7つのコンポーネントから構成され、kube-apiserverを中心とした分散システムとなっている。

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

19.2 etcd

etcdは、OSSの分散Key-Value Store(KVS)である。etcdは冗長性を担保するためにクラスタを組むことが可能であり、分散合意アルゴリズム(Raft)が使われている。etcdクラスタには単一のリーダーが存在し、リーダーが動作しなくなった場合には、自動的に新しいリーダーが選出される。

etcdにはKubernetesクラスタに登録される全ての情報が保存されるため、etcdのデータを守ることが最も大切である。また単一障害点にならないようにクラスタを組むべきである。

19.3 kube-apiserver

kube-apiserverは、Kubernetes APIを提供するコンポーネントである。kubectlはkube-apiserverに対してリクエストを送ることで、リソースの作成や削除を行う。kube-apiserverは受け取ったリクエストをetcdに保存する。そしてkube-schedulerが起動するノード情報が未割り当てのPodを検知し、kube-apiserverにスケジューリングのリクエストを送信する。

19.5 kube-controller-manager

kube-controller-managerは、様々なコントローラを実行するコンポーネントである。Deployment ControllerやReplicaSet Controllerでは、DeploymentやReplicaSetの状態を監視しながら必要に応じてリソースを作成する。

19.6 kubelet

kubeletは、各Kubernetes Node上で動作するコンポーネントである。Dockerなどのコンテナランタイムと連携し、実際にコンテナの起動や停止などの管理を行う。

19.7 kube-proxy

kube-proxyも、各Kubernetes Node上で動作するコンポーネントである。Serviceリソースが作られた際にClusterIPやNodePort宛のトラフィックがPodに正常に転送されるようにする。転送方式はユーザー空間上のプロセスやiptablesによるものがあるが、現在はIPVS(IP Virtual Server)が主に用いられている。IPVSはL4ロードバランシング機能などを提供している。

19.8 kube-dns(CoreDNS)

kube-dnsは、Kubernetesクラスタ内部の名前解決やサービスディスカバリに利用されているクラスタ内DNSサーバである。最近ではkube-dnsの光景としてCoreDNSが登場した。CoreDNSは単一のGoバイナリで動作する軽量かつ高速なDNSサーバである。


{ "name": "hareku", "job": "Software Engineer" }