Atsushi2022の日記

データエンジニアリングに関連する記事を投稿してます

【学習】Kubernetes Udemy CKA講座

目次

概要

  • Kubernetesの試験の1つであるCertified Kubernetes Administrator (CKA)を勉強中。
  • Udemyで「Certified Kubernetes Administrator (CKA) with Practice Tests」を受講。
  • 忘備のため勉強した内容をメモする

講座の構成

GitHub - kodekloudhub/certified-kubernetes-administrator-course: Certified Kubernetes Administrator - CKA Course

  1. Introduction
  2. Core Concepts
  3. Scheduling
  4. Logging & Monitoring
  5. Application Lifecycle Management
  6. Cluster Maintenance
  7. Security
  8. Storage
  9. Networking
  10. Design and Install Kubernetes
  11. Install "Kubernetes the kubeadm way"
  12. End to End Tests on Kubernetes Cluster
  13. Troubleshooting
  14. Other Topics
  15. Lightning Labs
  16. Mock Exams
  17. Course Conclusion

講座構成順に重要と思われるところをメモしていく。

1. Introduction

スキップ。

2. Core Concepts

  • Cluster Architecture
    • Master Node
    • ETCD
    • Kube-API Server
    • Kube Controller Manager
    • Kube Scheduler
    • ReplicaSet
    • Deployment
    • Namespace
    • Service
  • Woker Node
    • Kubelet
    • Pod
    • Kube Proxy

↑のうち、いくつかの役割を簡単にメモ。

Master Node

Kuberntesクラスタの管理やインターフェースを司るノード

Woker Node

Kuberntesクラスタでアプリケーション処理を行うノード

ETCD

ETCD自体は分散型のKey-Valueストア。KubernetesではPodやNodeなどの情報をETCD上に保管している。kubectl getコマンドによる情報取得元はすべてETCDサーバ。

Kube-API Server

Kubernetesリソース間でやり取りを行うためにAPIインターフェースを提供するサーバ。いまいちKube-APIが何をしているのかわかりにくいので、Pod作成時のKube-APIサーバの動きを見てみる。

・Kube-API Serverの動作~Pod作成

  1. Pod作成のAPIリクエストを受信。ユーザ認証する
  2. APIリクエストのバリデーション
  3. Pod作成 ※Kube-APIサーバがPodを作成する。ここでは未だNodeはアサインしない
  4. ETCDサーバにPod作成を通知。ETCDサーバがデータ更新。Kube-APIサーバがPod作成をユーザに通知
  5. Kube Schedulerが定期的にKube-APIサーバをモニタしていて、新たなPodにNodeがアサインされていないことに気づく。で、Kube SchedulerがPodをどのNodeに配置するか決定し、Kube-APIサーバに通知。
  6. Kube-APIサーバがPodがどのNodeに配置されるか決定されたことをETCDサーバに通知。
  7. さらにKube-APIサーバはPod配置先のNodeにいるKubeletにPodの配置を伝える。
  8. KubeletはPodをNode上に作成し、コンテナランタイム(Docker)にアプリケーションイメージをデプロイするよう指示する。
  9. それが完了したら、KubeletはKube-APIサーバにPodが配置されたことを通知。それを受けて、Kube-APIサーバがETCDサーバに通知。ETCDサーバがデータ更新。

Kube Controller Manager

コンテナコントローラーやノードコントローラといった複数のコントローラーを管理するサーバ。コントローラ自体は、①継続的にステータスをチェックして、②復旧措置を行う。

・コントローラの一例~Node-Controllerの動作

Node-Controllerは、例えばノードの状態を5秒毎に確認する。ノードからのハートビートが40秒間止まりっぱなしだとノードをUnrechableとしてマークする。Unrechableの状態が5分間治らない場合、そのノードに配置していたPodを削除して正常なノードに配置する。

Kube Scheduler

PodをどのNodeに配置するかを決定するサーバ。※Node上にPodを配置するのはKubeletの役目。

Kube-Proxy

KubernetesクラスタではすべてのPodが他のすべてのPodに到達可能だけれど、これはPod間ネットワークがあるため。Pod間ネットワークはすべてのノード間にわたる仮想ネットワーク。Kube-proxyは各Node上で稼働しているプロセスで新たなServiceが作成される度に他のノードに転送するためのルール(IPテーブルなど)を作成する。

3. Scheduling

Kube SchedulerはPodをどのNodeに配置するかを決定するサーバ。※Node上にPodを配置するのはKubeletの役目。ではどうやってPodの配置を決定するのか。以下の仕組みでスケジューリングを行う。1つずつ概要をメモしていく。

  • Taints & Tolerations
  • Node Selectors
  • Node Affinity
  • Resource Requirements & Resource Limits
  • 特殊な例
    • Daemonsets
    • Static Pod
    • Multiple Scheduler

Taints & Tolerations

TaintとToleration | Kubernetes

英語でTaintsは「汚れ」、Tolerationsは「寛容」という意味。だが、それだとちょっとわかりにくい。「虫よけスプレー」と「防護マスク」に例えるとわかりやすい。

Nodeに「Taints」という虫よけスプレーを振りかける。すると「虫=Pod」はNodeに近づけない=配置されない。でも虫よけスプレー(Taints)に耐えられるようPodに「防護マスク」をつけてやる(虫に防護マスクなんてつけられないけどそこは気にしないでください)。そうするとPodはNodeに近づける=Nodeに配置可能になる。

  • Taints:Node側の設定
kubectl taint nodes <ノード名> app=batch:NoSchedule # Taintsを設定
kubectl taint nodes <ノード名> app=batch:NoSchedule- # Taintsを解除
  • Tolerations:Pod側の設定
spec:
  tolerations:
  - key: "app"
    operator: "Equal"
    value: "batch"
    effect: "NoSchedule"

これでTolerationsで指定していないPodはNodeに配置されなくなる。

エフェクトにはNoScheduleも含め3種類ある。PreferNoScheduleは要件を満たすNodeが他になければ、Podを配置可能。NoExecuteは既にNodeにスケジュールされているPodであっても、PodにTolerationsが設定されてない限りNodeから削除される。

  • NoSchedule
  • PreferNoSchedule
  • NoExecute

Node Selectors

Node上へのPodのスケジューリング | Kubernetes

Taints & Tolerationsは、Podが特定のNodeに配置されないよう指定する仕組みだったのに対し、Node SelectorsはPodを特定のNodeに配置する仕組みである。Labels & Selectorsを使ってPodを配置するNodeを指定する。NodeのLabels設定でKey-Valueを指定し、PodのSelectors設定でNodeに設定したKey-Valueを指定してやる。

  • Lables:Node側の設定
kubectl label nodes <ノード名> Size=Large
  • Selectors:Pod側の設定
spec:
  nodeSelector:
    Size: Large

これで指定したNodeにのみPodが配置される。

Node Affinity

Node上へのPodのスケジューリング | Kubernetes

Node AffinityはNode Selectorsと同じくPodを特定のNodeに配置する仕組みである。違いは、より複雑な配置ルールを作成できる点である。例えばNOTやORといった条件を指定できる。

  • Lables:Node側の設定
kubectl label nodes <ノード名> Size=Large
  • nodeAffinity:Pod側の設定
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: Size
            operator: In
            values:
            - Large
            - Small

これで条件に該当するNodeにのみPodが配置される。

Node Affinity Typesには「requiredDuringSchedulingIgnoredDuringExecution」含め3種類存在する。

  • requiredDuringSchedulingIgnoredDuringExecution
  • preferredDuringSchedulingIgnoredDuringExecution
  • requiredDuringSchedulingRequiredDuringExecution

Resource Requirements & Resource Limits

Resource RequirementsではPodが必要とするリソース(CPU、メモリ)をYAMLファイルで設定することによりリソースを確保したNodeにのみPodが配置されるようになる。一方、Resource LimitsはPodが使用するリソースの上限値を設定しPodによるリソースの占有を防ぐことができる。CPUをResource Limitsを超えて利用しようとした場合にはスロットルされる。一方、メモリをLimitsを超えて継続的に利用しようとした場合にはPodは削除される。

  • Resource Requirements & Resource Limits:Pod側の設定
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Daemonsets

DaemonSet | Kubernetes

Daemonsetsは新たなNodeが追加される度に自動でPodを配置する。DaemonsetsはすべてのNodeに1つずつPodを配置する。DaemonsetsのユースケースとしてはNodeの監視などが考えられる。各Nodeに配置されたDaemonsets PodによってNodeを監視する。Daemonsetsを利用すれば、NodeにPodを配置する、あるいはNodeからPodを削除することを気にしないでよい。ほかにもKube Proxyを各Nodeに配置することも1つのユースケースとして考えられる。

Daemonsets

DaemonsetsのYAML定義ファイルはReplicasetsに似ている。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2

DaemonsetsでどのようにPodをNodeに配置しているのだろうか。Nodeの配置には現在Node AffinityとデフォルトのKube Schedulerを利用している。詳細は割愛。

Static Pod

static Podを作成する | Kubernetes

Masterノードで稼働しているKube APIサーバ、Kube Scheduler、Kube Controller、ETCDクラスタがすべて無くなってしまった(存在しない)状況を想定する。つまり、Worker NodeとWorker Node上に存在するKubelet、Dockerコンテナ(あるいは他のコンテナランタイム)しか存在してないとする。その場合PodをNode上で稼働させることは可能だろうか。実はその状況でもPodを稼働させるができる。そのようなPodをStatic Podと呼ぶ。

Kube APIサーバがないので、当然APIでPodを作成することはできない。では、どうするのか。PodのYAML定義ファイルをWorker Node上の指定されたフォルダに入れてあげればよい。Kubeletは定期的にフォルダを見に行って、Podの定義ファイルが存在したらそれに基づいてPodを作成する。もちろんこのやり方ではReplicasetsやDeploymentsは作成することはできない(Replication-ControllerやDeployment-Controllerが存在しないため)。

Kubeletにコマンドでフォルダの場所を知らせるので、フォルダは任意の場所でよい。

フォルダの居場所を調べるにはps -ef | grep kubeletというコマンドを使うとよい。

ユースケースとしてはStatic Podを使って、Kube APIサーバやETCDクラスタをMaster Nodeに配置することが考えられる。実際KubeadmではそのようにPodを配置している。

Static Podはkubectl get podsで確認することができるがkubectlで削除やエディットはできないことに注意。

Multiple Scheduler

Configure Multiple Schedulers | Kubernetes

Kubernetesでは独自のカスタムSchedulerを作成することができる。カスタムSchedulerはデフォルトのSchedulerと一緒に稼働することができる。

Kube Schedulerのバイナリをダウンロードしてオプションで独自の--scheduler-nameを設定すれば、カスタムスケジューラを作成することができる。

Kubeadmの場合だと、PodとしてKube Schedulerを稼働させている。Podの- command:欄で下記3点を指定してあげればよい。

  - --leader-elect=true
  - --scheduler-name=my-custom-scheduler
  - --lock-object-name=my-custom-scheduler

マルチマスタ構成でない場合は--leader-elect=falseとする。一方、マルチマスタ構成の場合は--leader-elect=trueとして--lock-object-name=my-custom-schedulerも設定する。


  • Scheduler用のPod設定
apiVersion: v1
kind: Pod
metadata:
  name: my-custom-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --address=127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
    - --scheduler-name=my-custom-scheduler
    - --lock-object-name=my-custom-scheduler
    image: k8s.gcr.io/kube-scheduler-amd64:v1.11.3
    name: kube-scheduler
  • スケジュールされる側のPod設定

schedulerNameでカスタムスケジューラ名を設定してやる。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
  schedulerName: my-custom-scheduler

4. Logging & Monitoring

Monitoring

2018年時点でビルトインのモニタリングツールはK8sにはない。代わりにオープンソースのモニタリングソースが色々ある。例えば、PrometheusやElastic Stack、DATADOG、dynatraceなど。メトリクスサーバはその1つ。

Resource metrics pipeline | Kubernetes

メトリクスサーバではノードやポッドからメトリクスを収集しアグリゲートする。クラスターあたり1つのメトリクスサーバが設定可能。

メトリクスサーバではKubelet内にcAdvisor=Container Advisorを設置する。cAdvisorがPodからパフォーマンスデータを集めてKube-APIを通じてメトリクスサーバに渡す。メトリクスサーバはインメモリに収集したメトリクスのデータを保管する。なので、デスクトップに保存したい場合はメトリクスサーバ以外のソリューションを利用しなければならない。

メトリクスサーバの導入手順

  1. gitからクローンして、kubectl createコマンドでメトリクスサーバを作成(DeploymentやService、clusterroleなどが稼働)
  2. kubectl top node、またはkubectl top podコマンドでCPU・メモリ使用率を確認
git clone https://github.com/kodekloudhub/kubernetes-metrics-server.git
cd kubernetes-metrics-server/
kubectl create -f .
kubectl top node

Logging

kubectl logs -f <pod名> <コンテナ名>でライブストリームログが見られる

5. Application Lifecycle Management

Rollout and Rollback

Rollout

Deployment | Kubernetes

RolloutはDeploymentのコンテナイメージをバージョンアップすること。Rolloutするたびに新たなDeployment Revisionが作成される。

Deploymentの方法(Deployment Strategy)は2種類ある。

  • Recreate
  • Rolling Update

RecreateはいったんPodをすべて削除し、その後Podを作成する。そのためApplicationのダウンタイムが発生する。一方Rolling Updateは1つのPodを削除し代わりに新たなPodを1つ作成してから次のPodに移るのでダウンタイムが発生しない。デフォルトはRolling Update。

Deployment Strategyはkubectl describe deploymentコマンドで確認できる。StrategyType:RecreateあるいはRollingUpdateと表示される。

Rolling Updateは、DeploymentのYAML定義ファイルでコンテナイメージの新バージョンを設定して、下記コマンドを実行することで開始される。

kubectl apply -f <YAMLファイル>

他の方法として、下記コマンドでも同様にRolloing Updateが行われる。

kubectl set image deployment/<デプロイメント名> <コンテナ名>=nginx:1.9.1

Deploymentの進捗および履歴は下記コマンドで確認できる。

  • DeploymentのRollout状況確認(m個中l個のReplicaがアップデートされた)
kubectl rollout status deployment/myapp-deployment
  • Revisionの変更履歴確認
kubectl rollout history deployment/myapp-deployment

Rollback

Deployment | Kubernetes

新たなRevisionに問題があった場合にはRollbackすることができる。下記コマンドで以前のRevisionにただちにRollbackできる。

kubectl rollout undo deployment/myapp-deployment

Configure Applications

  • Configuring Command and Arguments on applications
  • Configuring Environment Variables

Commands and Arguments

Define a Command and Arguments for a Container | Kubernetes

Pod YAML定義ファイルでcommand:欄にJson配列フォーマットでコンテナ起動時に実行する(エントリポイント)コマンドを記述できる。args:欄で実行するコマンドの引数を指定できる。

spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper
      command: ["sleep"]
      args: ["10"]

Environment Variables

環境変数の設定は3種類の方法がある。

  • Plain Environment Variables
  • ConfigMaps
  • Secrets

Plain Environment Variables

コンテナの環境変数の定義 | Kubernetes

env:フィールドで環境変数を定義できる。

spec:
  containers:
  - name:
    image:
    env:
    - name:
      value:

ConfigMaps

ConfigMap | Kubernetes

CongigMapとしてまとめて環境変数を扱えるようにして、管理を楽にする。次の2ステップでConfigMapをPodに適用する。

  1. ConfigMap作成
  2. Pod設定でConfigMapを割り当て
ConfigMap作成

3つのやり方がある。

①Key-Valueからコンフィグマップを作成する。

kubectl create configmap \
  <コンフィグマップ名> --from-literal=<キー>=<バリュー>

②ファイルをもとにコンフィグマップを作成する。

kubectl create configmap \
  <コンフィグマップ名> --from-file=<ファイルのパス>

ファイルは下記のフォーマットで作成しておく。

APP_COLOR: blue
APP_MODE: prod

YAMLでConfigMapの定義ファイルを作成し、コンフィグマップを作成。

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_COLOR: blue
  APP_MODE: prod

YAML定義ファイルをもとにコンフィグマップを作成。

kubectl create -f config-map.yaml
Pod設定でConfigMapを割り当て

PodでConfigMapを指定してやる。これでコンフィグマップで定義した環境変数を扱えるようになる。

spec:
  containers:
  - name:
     image:
     envFrom:
     - configMapRef:
          name:

configMapRef:で指定する以外にも、ほかに2つの方法がある。

env:
  -name : APP_COLOR
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: APP_COLOR
volumes:
- name : app-config-volume
  configMap:
    name: app-config

Secrets

Secret | Kubernetes

ConfigMapにパスワードなどのクレデンシャルを保存するのはよろしくない。そこで出てくるのがSecrets。Secretsは環境変数の値をBase64エンコーディングして保管する。

2つのステップでSecretsを利用できる。

  1. Secretsを作成し、
  2. PodでSecretsを指定する
Secretsの作成

①Key-Valueからシークレットを作成する。

kubectl create secret generic \
  <シークレット名> --from-literal=<キー>=<バリュー>

※バリューはハッシュ化されていない平文でよい。

②ファイルをもとにシークレットを作成する。

kubectl create secret generic \
  <シークレット名> --from-file=<ファイルのパス>

YAMLでSecretの定義ファイルを作成し、それをもとにシークレットを作成。

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
data:
  User: bxlZC=
  Password: cm9vDa=

環境変数の値にはBase64エンコーディングした値を入れる。 でも、Base64エンコーディングされた値ってだけじゃ全然安全じゃない。。(より安全な方法については後述)

echo -n 'test' | base64

YAMLファイルをもとにシークレットを作成。

kubectl create -f secret.yaml
Pod設定でSecretを割り当て
spec:
  containers:
  - name:
    image:
    envFrom:
      - secretRef:
          name: app-secret
シークレットのリスクについて

シークレットは暗号化されていないため全然安全ではない。

とはいっても、シークレットをより安全に利用するベストプラクティスがある。

  • Not checking-in secret object definition files to source code repositories.
  • Enabling Encryption at Rest for Secrets so they are stored encrypted in ETCD.

K8sのSecretにおけるリスク

Scale Applications

前述したので割愛

Multi Container Pods

Podの中に複数のコンテナを入れる。Webサーバとログ取得の機能をそれぞれ別々に開発し、セットでデプロイしたいということがあるが、そういったユースケースで利用される。Pod内ではネットワークとストレージを共用するのでServiceなどの追加は不要。

spec:
  containers:
  - name:
    image:
  - name
    image:

Multi Container Pods Design Patterns

CKADの範囲なので割愛

  • サイドカー
  • アダプター
  • アンバサダー の3種類がある。

Init Containers

コンテナで利用するコードやバイナリファイルを事前に取得しておきたいということがある。本命のコンテナが稼働する前に、別のコンテナを起動して処理を行う。 そのコンテナがInit Container。

initContainersが複数ある場合には、記述された順に処理を行う。initConainersのうち1つでも完了できなかった場合には、Podをリスタートする。

spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

Self Healing Applications

CKADの範囲なので割愛

6. Cluster Maintenance

OS Upgrades

OSをアップグレードする、あるいはセキュリティなどのパッチをあてる際にはノードがオフラインになる。

ノードがオフラインになった場合、マスターノードはデフォルトで5分間待機する。この待機時間をPod eviction timeoutという。5分間経ってもノードがオンラインにならない場合はノードが死んだと考え、PodがReplicasetの一部である場合には別のノードにPodを再配置する。5分経過後にノードがオンラインになったとしても、Podをそのノードに再配置することはしない。PodがReplicasetの一部でない場合にはPodは別のノードに作成されることはなく、ただ削除されたままの状態になる。

上記の影響があったも問題ない場合には特になにも対策せずに、OSをアップグレードして大丈夫。でも、上記の影響を避けたい場合にはOSをアップグレードする前にPodを退避してあげる必要がある。

下記コマンドでノードに配置されていたPodを削除して別のノードに再配置する。drainされたノードはUnschedulableになり、drainが解除されるまでPodが配置されることはなくなる。

kubectl drain <ノード名>

同様に新たなPodがスケジュールされないようノードをUnschedulableに設定できる。但し、ノード上で稼働していたPodは単に削除されるだけで別のノードに再配置されない点に注意。

kubectl cordon ノード名

drain/cordonによってUnschedulableになったノードのUnschedulable状態を解除する。解除しても他のノードに配置されたPodが再配置されるわけではない。

kubectl uncordon <ノード名>

Kubernetes Software Versions

kubernetes自体のバージョン管理について。Kubernetesのバージョンは3つからなる。

v1.12.0

左から

  • Major version
  • Minor version
  • Patch

である。Minor versionでは機能やフィーチャーが追加される。Patchはバグフィックス

Cluster Upgrade Process

Upgrading kubeadm clusters | Kubernetes

Kubernetesクラスタのバージョンアップをするためには、各コンポーネントのバージョン互換ルールに注意しなければならない。

K8sバージョン互換ルール

  • 基本的に、Kube APIサーバより新しいバージョンだとダメ。同じバージョンか1つ古いマイナーバージョンである必要がある。
  • KubeletとKube Proxyは2つ前のマイナーバージョンでもOK。
  • kubectlは1つ新しいマイナーバージョンでもOK。同じバージョン、1つ古いのバージョンもOK。
  • Kubernetesは直近3つのマイナーバージョンしかサポートしない。
  • マイナーバージョンのアップグレードは、飛び級せずに1つずつバージョンを上げていくことが推奨されている。

Kubernetesのアップグレードは、クラスタのデプロイ方法により3つの方法に分かれる。

  1. パブリッククラウド
  2. Kubeadm
  3. クラッチからクラスタデプロイ

パブリッククラウドの場合は数クリックでアップグレードできる。スクラッチからクラスタデプロイするケースは割愛する。

ここではKubeadmのケースを扱う。

マスターノード、ワーカーノードの順でアップグレードを行う。

マスターノードをアップグレード中もワーカーノードは稼働し続けるのでユーザ影響はない。ただ、マスターがオフラインなのでPod作成や編集ができない。またワーカーノード上で稼働しているPodが落ちても復旧できない。

ワーカーノードのアップグレード方法は3つある。

  1. すべてのノードをいっぺんにアップグレードする方法。このやり方だとユーザがアクセスできず影響がでる。
  2. ノード毎にアップグレードする。1つノードをオフラインにして、そこにいたPodを別のノードで稼働させる。アップグレードが終わったら別のノードをオフラインにしてアップグレードする。
  3. 新しいバージョンの新しいノードを追加する。そしてノードを1つずつアップグレードしていく。

アップグレード手順

事前にマスターノードのアップグレードに関する情報を確認しておく。

kubeadm upgrade plan

マスターノードのバージョンアップ。マスターノード上の各コンポーネントをアップグレードする。

kubeadm upgrade apply v1.12.0

Kubeletがマスターノード上に存在する場合はKubeletをアップグレードしてやる。Kubeletのアップグレードは行えないためマニュアルでアップグレードする必要あり。

apt-get upgrade -y kubelet=1.12.0-00
systemctl restart kubelet

これでマスターノードのコントロールプレーンおよびKubeletがアップグレードされた。

次に、Worker NodeのKubeletアップグレードを行う。アップグレードするワーカーノードからPodを削除して別のノードに再作成しておく。

kubectl drain node01

Kubeadm、Kubelet、Nodeをアップグレードし、Kubeletをリスタートする。

apt-get upgrade -y kubeadm=1.12.0-00
apt-get upgrade -y kubelet=1.12.0-00
kubeadm upgrade node config --kubelet-version v1.12.0
systemctl restart kubelet

これでWorker Nodeが新しいバージョンでアップしてくる。

ノードのUnschedulable状態を解除するのを忘れずに。

kubectl uncordon node01

Backup and Restore Methods

バックアップ方法は3種類ある。

  • リソースコンフィグのバックアップ
  • ETCDクラスタのバックアップ
  • パーシステントボリュームのバックアップ

K8sリソースコンフィグのバックアップ

K8sリソースコンフィグのバックアップを取得する。

kubectl get all --all-namespaces -o yaml > all-deploy-services.yaml

上のコマンドで取得できないリソースも存在する。VELEROを使えばK8sクラスタのバックアップを取得できる。

thinkit.co.jp

ETCDクラスタのバックアップ

Operating etcd clusters for Kubernetes | Kubernetes

ETCDクラスタは、K8sクラスタのステート情報を保管している。ETCDのデータはすべて特定のフォルダに保管されているのでそのフォルダをバックアップしてもいいが、以下ではスナップショットを作成する方法を紹介する。

スナップショット取得

ETCDCTL_API=3 etcdctl snapshot save shapshot.db \
--endpoints=https://[127.0.0.1]:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key  

エンドポイントなどを指定する必要がある。

スナップショットの中身を確認

etcdctl snapshot status shapshot.db

次に、ETCDクラスタのスナップショットから復元していく。

まずはkube APIサーバを停止

service kube-apiserver stop

で、リストア。

etcdctl snapshot restore snapshot.db --data-dir /var/lib/etcd-from-backup

「/var/lib/etcd-from-backup」は新たなデータディレクトリ。

そして、リスタート。

systemctl daemon-reload
service etcd restart
service kube-apiserver start

これでETCDクラスタのスナップショットから復元完了。

マネージドK8sサービスを使っている場合にはETCDクラスタにアクセスできないので、Kube-APIサーバでK8sリソースコンフィグのバックアップを取ることになるらしい。

7. Security

Authentication

認証を使って、どのようにクラスタをセキュアに保つかについて見ていく。

Accounts

アカウントは大きく分けて2種類ある。 User: クラスタを操作する人(アドミン、開発者) Service accounts: 外部アプリケーションなどでクラスタにアクセスが必要なもの

K8sは基本的にアカウント管理を行わない。ユーザリストなどの外部ソース(ファイル)を利用する。

つまり、kubectlコマンドでUserアカウントを作成できない。 一方、以下のようにService Accountは作成できる。

kubectl create serviceaccount sa1
kubectl get serviceaccount

Service Accountについては後述する。ここではUserについてさらに見ていく。

Userのアクセスはkube-apiサーバによって認証(Authenticate)される。

認証方法は以下の3つ。

  • Static Password File
  • Static Token File
  • Certificates
  • External Identity Services (LDAP)

Static Password File

  • Kube-apiサーバ側設定 パスワード、ユーザ名、ユーザIDを記載したファイルを用意し、それをKube-apiサーバのオプションで参照する。

  • ユーザ側 ユーザ名とパスワードを指定して、APIリクエストをKube-apiサーバに投げる。

curl -v -k https://master-node-ip:6443/api/v1/pods -u "user1:password123"

※この認証方法は推奨でないことに注意。TLS Certificatesの利用が推奨されている。TLS Certificatesを使用した認証については後述

Static Token File

認証 | Kubernetes

  • Kube-apiサーバ側設定 トークン、パスワード、ユーザ名、ユーザID、グループ名(任意)を記載したファイルを用意し、それをKube-apiサーバのオプションで参照する。

  • ユーザ側 HTTPヘッダでトークンを指定して、APIリクエストをKube-apiサーバに投げる。

curl -v -k https://master-node-ip:6443/api/v1/pods -u --header "Authorization: Bearer <トークン>"

※この認証方法は推奨でないことに注意。TLS Certificatesの利用が推奨されている。TLS Certificatesを使用した認証については後述

TLS Basics

PKI (Public Key Infrastructure)の概要を押さえておくこと。

PKI概要

目的

サーバークライアント間で暗号化した通信を行いたい

実現方法

サーバ自身が、自分が偽のサーバでないことをクライアントに対して証明する。 クライアントが生成した対称鍵を、クライアントーサーバ間で交換する。

手順

  • サーバが生成したサーバ秘密鍵とサーバ公開鍵のキーペアのうち、サーバ公開鍵をCSR(Certificate Signing Request)としてCA(Certification Authority)に送る。
  • CAはCA秘密鍵とCA公開鍵をもっている。CSRを受信したら、CA秘密鍵CSRを暗号化する。つまりCA公開鍵でのみ復号できるようにする。そして、CA秘密鍵で暗号化されたCSRをサーバに送り返す。
  • サーバは、CAから受信した「CA秘密鍵で暗号化されたCSR」をクライアントに送信する。
  • クライアントは、CA公開鍵をもっている。クライアントは、サーバから受信した「CA秘密鍵で暗号化されたCSR」をCA公開鍵で復号する。これでCSRが取り出される。さらにCSRの中に格納されているサーバ公開鍵を取り出す。
  • クライアントは対称鍵(Symmetric Key)を生成する。生成した対称鍵をサーバ公開鍵で暗号化する。そして、「サーバ公開鍵で暗号化した対称鍵」をサーバに送る。
  • サーバは、受信した「サーバ公開鍵で暗号化した対称鍵」をサーバ秘密鍵で復号し、対称鍵を取り出す。
  • これでクライアントーサーバ間で安全に対称鍵を交換できた。今後は対称鍵を使って、通信を暗号化する。

※ 前提として、秘密鍵で暗号化したものは公開鍵によってのみ復号化可能。反対に、公開鍵で暗号化したものは秘密鍵によってのみ復号化可能。

TLS in Kubernetes

前述のとおり証明書には以下の3種類がある。但し、以降証明書という呼び方は、証明書(=公開鍵)と秘密鍵のペアを指す。

証明書ファイルは、拡張子が.crt.pemになっている。 一方、秘密鍵ファイルは、.key-key.pemになっている。

Kubernetesクラスタ内のノード間通信、Kube-apiサーバとユーザとの通信、マスターノード内の通信はすべて暗号化される。 この要件を満たすためには、以下のように証明書を配置する必要がある。ややこしいのは、KubeletとKube-APIサーバがクライアント証明書とサーバ証明書を両方とも持っているところ。Kube-APIはクライアント証明書をETCD用とKubelet用にそれぞれ1つずつ持っているので、クライアント証明書2つにサーバ証明書1つの合計3つということになる。ややこしい。。。

さらに、上記の図には含まれていないが、最低1つのCAのサーバ証明書秘密鍵と公開鍵のペア)が存在する。

TLS in Kubernetes - Certificate Creation

Open SSLを使って、証明書を生成していく。

CAのルート証明書

まずはCAのルート証明書から。

1.秘密鍵 ca.keyを生成

openssl genrsa -out ca.key 2048

2.ca.keyと対になる公開鍵を含んだCSR ca.csrを生成

openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr

3.CSRに署名し、証明書 ca.crtを生成

openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt

これで、秘密鍵 ca.key、証明書(公開鍵) ca.crt が準備できた。

アドミンユーザのクライアント証明書生成

次に生成したCAのサーバ証明書を用いて、アドミンユーザのクライアント証明書を生成していく。

1.秘密鍵 admin.keyを生成

openssl genrsa -out admin.key 2048

2.admin.keyと対になる公開鍵を含んだCSR admin.csrを生成 ※アドミンユーザと他のユーザの区別は、Groupで行っている。 SYSTEM:MASTERSというグループを指定することで、アドミン権限をもつ。

openssl req -new -key admin.key -subj "/CN=kube-admin/O=system:masters" -out admin.csr

3.CAのキーペアを使ってCSRに署名し、証明書 admin.crtを生成

openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt

アドミンユーザとして、Kube-apiサーバにアクセスするには以下のようにオプションを指定すればよい。

curl https://kube-apiserver:6443/api/v1/pods \
--key admin.key \
--cert admin.crt \
--cacert ca.crt

kube-config.yamlでユーザを設定する場合には、以下のように設定する。

apiVersion: v1
clusters:
- cluster:
    certificate-authority: ca.crt
    server: https://kube-apiserver:6443
  name: kubernetes
kind: Config
users:
- name: kubernetes-admin
  user:
    client-certificate: admin.crt
    client-key: admin.key

他のクライアント証明書

同様にKube-Scheduler、Kube-controller-manager、Kube-proxyのクライアント証明書を作成していく。

サーバ証明書

次にサーバ証明書を見ていく。 (スキップ)

View Certificate Details

KubeadmでK8sクラスタをデプロイした場合の証明書の確認方法をみていく。

Kubeadmでデプロイした場合、Kube-apiサーバといったコントロールプレーンのコンポーネントはPodとしてデプロイされる。そのPodの定義ファイルは/etc/kubernetes/manifests/kube-apiserver.yamlに保存されている。このようなPodをStatic Podと呼ぶ(詳細後述)

(K8sコンフィグの保管場所) Implementation details | Kubernetes

YAMLファイルの証明書の設定に関する部分を抜きだしたものがこちら。

spec:
  containers:
  - command:
    - kube-apiserver
    - --authorization-mode=Node,RBAC
    - --advertise-address=172.17.0.32
    - --allow-privileged=true
    - --client-ca-file=/etc/kubernetes/pki/ca.crt #
    - --disable-admission-plugins=PersistentVolumeLabel 
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt #
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt #
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key #
    - --etcd-servers=https://127.0.0.1:2379
    - --insecure-port=0
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt #
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key #
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --secure-port=6443
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-cluster-ip-range=10.96.0.0/12
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt #
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key #

以下の証明書が設定されている。

試しにopenssl x509コマンドで/etc/kubernetes/pki/apiserver.crtの中身を見てみる。

  • 発行者
  • 期限
  • コモンネーム
  • オルタナティブネーム といった情報が記載されていることがわかる。

Serviceのログ確認

journalctl -u etcd.service -l

Podのログ確認

kubectl logs etcd-master

Dockerコンテナのログ確認

K8sがダウンした場合

docker ps -a
docker logs <コンテナ>

Certificates API

アドミンユーザとは別に新しいユーザを作成したい場合、以下の手順でCertificateを作成する。

  1. Create CertificateSingningRequest Object
  2. Review Requests
  3. Approve Requests
  4. Share Certs to Users

以下では、新しく「jane」というユーザを作成するケースを例として考える。

Create CertificateSingningRequest Object

Certificate Signing Requests | Kubernetes

まずjaneが「jane」用の秘密鍵CSRを作成する。

openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -subj "/CN=jane" -out jane.csr

janeのCSRをもとにCertificateSingningRequestオブジェクトを作成する。

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
name: jane
spec:
  signerName: kubernetes.io/kube-apiserver-client
  groups:
  - system: authenticated
  usages:
  - digital signature
  - key encipherment
  - client auth
  requests: <Base64エンコーディングしたCSR>

Kubernetes signers

Certificate Signing Requests | Kubernetes

K8sではカスタムsignerNameを作成できる。一方、K8sはビルトインのsignerを提供している。ビルトインのsignerは以下の種類がある。

  • kubernetes.io/kube-apiserver-client
  • kubernetes.io/kube-apiserver-client-kubelet
  • kubernetes.io/kubelet-serving
  • kubernetes.io/legacy-unknown

kubernetes.io/kube-apiserver-client-kubeletだけkube-controller-managerによって自動で承認される可能性がある。他は自動で承認されることはない。

signerの種類によっては、usages:に入れられるキーが限定される。

kubernetes.io/kube-apiserver-clientであれば、- client authはマスト。- digital signature- key enciphermentはオプションで追加できるが、それ以外(例えば- server auth)は不可。

kubernetes.io/kube-apiserver-client-kubeletの場合は、- client auth- digital signature- key enciphermentをすべて入れる必要がある。- server authは不可。

それ以外の詳細はK8sのサイトを確認。 Certificate Signing Requests | Kubernetes

Review Requests

作成したCertificateSingningRequestオブジェクトは以下のコマンドで確認できる。

kubectl get csr

Approve Requests

Certificate Signing Requests | Kubernetes

アドミニストレータがCertificateSingningRequestオブジェクトを承認する。

kubectl certificate approve jane

すると、KubernetesがCAキーペアを使って署名しCertificateを払い出す。

Share Certs to Users

Certificate Signing Requests | Kubernetes

Kubernetesによって払い出されたCertificateは、次のコマンドで表示できる。

kubectl get csr jane -o yaml

status: certificate:フィールドがBase64エンコーディングされたCertificate(公開鍵)になっている。

CSR-APPROVING、CSR-SIGNINGといったタスクは、Controller Managerが行っている。

KubeConfig

複数のクラスターへのアクセスを設定する | Kubernetes

KubeConfigファイルは、$HOME/.kube/configに保存されている。 クラスタが複数ある場合には、どのユーザがどのクラスタを使えるか定義する必要がある。それを$HOME/.kube/configで設定している。

$HOME/.kube/configの中身を以下のような感じ。kubectl createコマンドなどでオブジェクトを作成する必要はない。ファイルを書き換えると自動的に反映される。

apiVersion: v1
kind: Config

clusters:
- name: development
  cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://development-kubeapi-server:6443
  
contexts:
- name: dev-frontend
  context:
    cluster: development
    user: developer

users:
- name: developer
  user:
    client-certificate: /etc/kubernetes/pki/users/admin.crt
    client-key: /etc/kubernetes/pki/users/admin.key

以下のコマンドで$HOME/.kube/configの中身を見ることができる。

kubectl config view

KubeConfigファイルをデフォルトの$HOME/.kube/configではなく他のファイルを使う場合には、以下のようにオプションでKubeConfigファイルを指定する。

kubectl config view --kubeconfig=my-custom-config

複数のコンテキストが存在する場合には、次のコマンドで利用するコンテキストを指定できる。

kubectl config use-context dev-frontend

API Groups

APIのパスでグルーピングされている。例えば/appsなど。さらにその配下にAPIリソース、Verbが定義されている。 これらのAPIグループを使って、認可(Authorization )を行う。

Authorization

認証は本人であることを確認すること。一方、認可(Authorization )は特定の権限のみを与えること。

Authorization には次の4つがある。

  • Node
  • ABAC
  • RBAC
  • Webhook
  • AlwaysDeny
  • AlwaysAllow

Node

Worker node(Kubelet)がMaster nodeにアクセスするのを許可する。

ABAC (Attribute-based access control)

ユーザ名などアトリビュート(属性値)ごとに権限を付与する方法。

RBAC(Role-based access control)

開発者やアドミンなどのロールごとに権限を付与する。

Webhook

代わりに認可機能を実施する外部のツールを使う。例えばOpen Policy Agentなど。

Authorization Mode

上記のAuthorization方法=Authorization Modeを複数利用することもできる。 その場合、順序性を持っているため、最初のAuthorization Mode認可されれば、権限が付与される。

RBAC詳細

RBAC認可を使用する | Kubernetes

Roleオブジェクト

RoleオブジェクトのYAMLファイルは以下。 resourceNamesを指定することでPod名を絞って指定することができる。 YAMLを作成したらkubectl create -fコマンドでRoleオブジェクトを作成する。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
  resourceNames: ["blue", "orange"]

RoleBindingオブジェクト

↑で作成したRoleをUserに紐づけるオブジェクト。 kubectl create -fコマンドでRoleBindingオブジェクトを作成する。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
subjects:
- kind: User
  name: dev-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

View RBAC

kubectl get roles
kubectl get rolebindings
kubectl describe role pod-reader
kubectl describe rolebinding read-pods

Check Access

Authorization Overview | Kubernetes

権限の有無を確認できる。以下の例ではユーザ「dave」がprodネームスペースにdeploymentを作成できるかを調べている。 権限を保有している場合は「yes」、権限を保有してない場合は「no」が応答される。

kubectl auth can-i create deployments --namespace prod --as dave

Cluster Roles and Cluster Role Bindings

Using RBAC Authorization | Kubernetes

ResourceにはNamespacedリソースと非Namespacedリソース(Cluster Scopedリソース)がある。NamespacedリソースにはPodsやDeploymentsが含まれる。一方、非NamespacedリソースにはNodesやNamespacesが含まれる。PodはNamespacesを指定して操作を行えるが、一方NodesはNamespaceは指定できないため、上記のようにNamespacedリソースと非Namespacedリソースという分類になる。

Namespacedリソース、非Namespacedリソースの一覧は下記コマンドで確認できる。

kubectl api-resources --namespaced=true

非Namespacedリソースの「Node」や「Namespace」といったリソースへのアクセス権限付与に用いるのが「ClusterRole」と「ClusterRoleBinding」である。

  • ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-administrator
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["create", "get", "list", "delete"]
  • ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-role-binding
subjects:
- kind: User
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-administrator
  apiGroup: rbac.authorization.k8s.io

ClusterRoleをnamespacedリソース(Podsなど)にも適用することもできる。そのClusterRoleをClusterRoleBindingによりUserに割当てた場合、UserはNamespaceを問わず全てのNamespacedリソース(Pods)にアクセスできる。

Service Accounts

Authenticating | Kubernetes

Accountには、User AccountとService Accountがある。PrometeheusがKuberntesクラスタ監視をする際にKuberntesクラスタのアカウントが必要。または、Jenkinsが自動デプロイする際にKuberntesクラスタアカウントが必要。そういったときに使われるのがService Account。

Service Accountは下記コマンドで作成・確認できる。

kubectl create serviceaccount dashboard-sa
kubectl get serviceaccount

Service Accountを作成すると自動的にTokenが払い出される。Service AccountはTokenを利用してKuberntesクラスタにアクセスできる。但し、TokenはSecret Objectに入れられているので下記コマンドでTokenそのものは確認できない。

kubectl describe serviceaccount dashboard-sa

Tokenを見るには下記コマンドを実行する。

kubectl describe secret dashboard-sa

実際に上記コマンドでTokenを表示させてみる。

$ kubectl describe secret ray-operator-serviceaccount-token-cvl29
Name:         ray-operator-serviceaccount-token-cvl29
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: ray-operator-serviceaccount
              kubernetes.io/service-account.uid: 50f1e4f3-5b00-4249-9ef3-4466a3c0476f

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXkU8A

Kube APIを呼ぶときに上記TokenをAuthorization Bearer Headerに指定することで、Kuberntesクラスタへのアクセスが許可される。

curl https://kube-apiserver:6443/api -insecure --header "Authorization: Bearer eyJhbGci"

実はデフォルトで、すべてのNamespaceでdefaultという名前のService Accountが作成されている。

実はPodを作成すると、このdefault ServiceAccountがPodにマウントされている。なぜかというとPodにKube APIを呼ぶ権限を与えるため。但し、default Service Accountで呼べるのは基本的なAPIだけに限られる。Podのマウントは下記コマンドで確認できる。

kubectl describe pod my-kubernetes-dashboard

まずPodにマウントされているService Accountのディレクトリを確認する。

$ kubectl describe pod ray-operator-5b985c9d77-t2hlc

Name:         ray-operator-5b985c9d77-t2hlc
Namespace:    default
Containers:
  ray:
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-f2z8h (ro)

Podの中に入る。

$ kubectl exec -it ray-operator-5b985c9d77-t2hlc -- bash

Tokenの中身を見てみる。

$ cat  /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXkU8A

PodにデフォルトでないService Accountを割り当てるには、PodのYAMLファイルのspec:serviceAccountNameを追記する。

デフォルトのService AccountをPodにマウントしたくない場合は、PodのYAMLファイルのspec:autoMountServiceAccountToken: falseを記載する。

Image Security

Pull an Image from a Private Registry | Kubernetes

  • Dockerイメージをセキュアなリポジトリに保管し、
  • セキュアなレポジトリからイメージをプルする方法。

image: nginxと記述するが、これはレジストリとアカウントが省略されている。正式には、image: docker.io/library/nginxである。 docker.ioレジストリを表しており、libraryがアカウントを表している。

Podが、Docker Hub上にあるプライベートレジストリからイメージをプルしたい場合には

  1. プライベートDockerリポジトリのクレデンシャルをもとにSecret Objectを作成し、
  2. Pod YAMLファイルのimagePullSecrets:でSecret Objectを指定する

①プライベートDockerリポジトリのクレデンシャルをもとにSecret Objectを作成

kubectl create secret docker-registry regcred \
    --docker-server=<your-registry-server> \
    --docker-username=<your-name> \
    --docker-password=<your-pword> \
    --docker-email=<your-email>

②Pod YAMLファイルのimagePullSecrets:でSecret Objectを指定する

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec:
  containers:
  - name: private-reg-container
    image: <your-private-image>
  imagePullSecrets:
  - name: regcred

Security Contexts

Configure a Security Context for a Pod or Container | Kubernetes

Pod YAMLファイルのspec:配下、またはspec: containers:配下にsecurityContextを設定して、Podを操作するユーザID runAsUser:と実行できる操作 "ケーパビリティ" capabilities: add: ["user"]を限定することができる。

ケーパビリティの設定は、spec: containers:配下の場合のみ。spec:配下では設定できない。

ケーパビリティは、例えばLinux capabilitiesがある。 capabilities(7) - Linux manual page

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      capabilities:
        runAsUser: <User ID>
        add: ["NET_ADMIN", "SYS_TIME"]

Network Policy

ネットワークポリシー | Kubernetes

Kubenetesクラスタの仮想ネットワークは、デフォルトでAll Allowになっており、クラスタ内のPod/Serviceから任意のPod/Serviceにアクセスできる。

Podにネットワークポリシーを適用するには、NetworkPolicyオブジェクトを作成し、podSelector:で該当するLabelを持つPodにネットワークポリシーを紐づける。

具体例をみていく。

role: dbというラベルを持つPodがあるとする。そのPodに「role: api-podというラベルを持つPodからの3306ポート宛てのTCPトラヒックを許可する」というネットワークポリシーを割り当てる。その場合のNetworkPolicyオブジェクトは以下のようになる。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api-pod
    ports:
    - protocol: TCP
      port: 3306

すべてのNetwork SolutionがNetworkPolicyオブジェクトをサポートしているわけではないことに注意!

NetworkPolicyオブジェクトをサポートしている

  • Kube-router
  • Calico
  • Romana
  • Weave-net

NetworkPolicyオブジェクトをサポートしてない

  • Flannel

8. Storage

Storage in Docker

(Skip)

Volume Driver Plugin in Docker

ストレージドライバーについて | Docker ドキュメント

ストレージドライバー vs. Docker ボリューム🔗

Docker uses storage drivers to store image layers, and to store data in the writable layer of a container. The container’s writable layer does not persist after the container is deleted, but is suitable for storing ephemeral data that is generated at runtime. Storage drivers are optimized for space efficiency, but (depending on the storage driver) write speeds are lower than native file system performance, especially for storage drivers that use a copy-on-write filesystem. Write-intensive applications, such as database storage, are impacted by a performance overhead, particularly if pre-existing data exists in the read-only layer.

Use Docker volumes for write-intensive data, data that must persist beyond the container’s lifespan, and data that must be shared between containers. Refer to the volumes section to learn how to use volumes to persist data and improve performance.

Container Storage Interface (CSI)

(Skip)

Volume

Volumes | Kubernetes

コンテナが消えると、コンテナで扱っていたデータが消えてしまう。そこで、コンテナ上でVolumeを作ってそれをホストのディレクトリにマウントする。

hostPath

※hostPathはセキュリティ的に非推奨。

apiVersion: v1
kind: Pod
metadata:
  name: pv-recycler
spec:
  volumes:
  - name: vol
    hostPath:
      path: /any/path/it/will/be/replaced
  containers:
  - name: pv-recycler
    image: "k8s.gcr.io/busybox"
    volumeMounts:
    - name: vol
      mountPath: /scrub

シングルノードの場合はhostPathでいいが、マルチノードの場合は無理。そこでNFS, GlusterFS, FlockerといったStorage Solutionを利用する。

AWS EBS

例えば、AWS EBSを利用する場合には以下のようになる。 ※EBS自体は別途AWS上で作成しておく必要がある。

apiVersion: v1
kind: Pod
metadata:
  name: test-ebs
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-ebs
      name: test-volume
  volumes:
  - name: test-volume
    # This AWS EBS volume must already exist.
    awsElasticBlockStore:
      volumeID: "<volume id>"
      fsType: ext4

Persistent Volumes

永続ボリューム | Kubernetes

いちいちPod定義のYAMLファイルにVolumeを記載するのは面倒なので、別のやり方を考えたい。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 5Gi
  awsElasticBlockStore:
    volumeID: "<volume id>"
    fsType: ext4
  persistentVolumeReclaimPolicy: Retain

Persistent Volume Claim

Persistent Volumeの要求。要求を満たすPersistent Volumeがあれば、PVCのステータスがPendingからBoundになる。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi

View PVC

kubectl get persistentvolumeclaim

Delete PVC

kubectl delete persistentvolumeclaim myclaim

persistentVolumeReclaimPolicy: Retainとなっている場合には、PVCを削除してもPersintent Volumeは削除されず、また使いまわすこともできない。

persistentVolumeReclaimPolicy: Deleteとなっている場合には、PVCを削除するとPersintent Volumeも削除される。そして、エンドストレージデバイスも空になる。

persistentVolumeReclaimPolicy: Recycleとなっている場合には、PVCを削除するとPersintent Volumeの中身が空になり、他のPVCで利用できるようになる。

Using PVC in Pod

spec: volumes:配下で、persistentVolumeClaim:を設定する。

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

Storage Class

Storage Classes | Kubernetes

PVを作成する前に、マニュアルでAWS上にEBSを作成する必要があった。 Storage Classを利用することで、自動でAWSなどのクラウド上にストレージをプロビジョニングしてくれる。

  • Storage Class
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: aws-ebs-storage
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
  fsType: ext4
  • PersistentVolumeClaim

Storage Classを利用する場合は、storageClassName:にStoragClass名を入れる。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: foo-pvc
  namespace: foo
spec:
  storageClassName: aws-ebs-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  • Pod

Storage Classを利用する場合でも、Podはこれまで同様persistentVolumeClaim:でPVCを指定してあげればよい。

9. Networking

 DNS on Linux

K8sではなく、まずLinuxでのDNSについて再確認していく。

 Name resolution

/etc/hostsにホスト名とIPアドレスを記載することで、Linuxでホスト名をIPアドレスに変更できるようになる。

/etc/hostsファイル

192.168.1.11       db

ping dbとすると、ping 192.168.1.11となる。

 DNS

/etc/resolv.confDNSサーバのIPを入れておく。そうすることでping <ホスト名>としたときに、DNSに名前解決しにいく。

/etc/resolv.confファイル

nameserver    192.168.1.100
nameserver     8.8.8.8

8.8.8.8は、Googleが無償で提供している「Google Public DNS」のIPアドレス

/etc/hosts/etc/resolv.confどちらとも設定してある場合、つまりLinuxローカルにホスト名も登録しているけど、DNSも設定している場合には、/etc/nsswitch.confに記載されている順番で名前解決を行う。

以下の例だと、まずは/etc/hostsでローカルに登録しているホスト名を見に行く。そこになければ、DNSサーバに名前解決にいく。

/etc/nsswitch.confファイル

hosts:     files dns

但し、nslookupDNSサーバにしか名前解決しにいかないので注意。/etc/hostsファイルにホスト名を登録していても意味ない。dignslookupより詳しい応答を返してくれる。

ドメイン名を省略したい場合には/etc/resolv.confsearchを利用する。

/etc/resolv.confsearchファイル

search     mycompany.com

こうすると、ping webとしたときにping web.mycompany.comとインテリジェントに解釈してくれる。

Core DNS

サービスディスカバリーにCoreDNSを使用する | Kubernetes

CoreDNS は CNCF によってホストされている OSSDNS サーバ。

設定手順

  • GithubなどからCoreDNSバイナリをダウンロードし、解凍して実行
  • CorefileにIPアドレスFQDNのペアを記載

ちょっと便利に使う CoreDNS - Retty Tech Blog

Pre-requisite - Network Namespace

Create Network Namespace on Linux

# Network Namespaceの作成
ip netns add red
ip netns add blue

# 作成したNamespaceの確認
ip netns

# "red" Namespace上でのip link/arp/の確認
ip netns exec red ip link
ip netns exec red ip arp

# IPリンクの作成
ip link add veth-red type veth peer name beth-blue

# 作成したIPリンクをNamespaceにアタッチ
ip link set veth-red netns red
ip link set veth-blue netns blue

# IPアドレスを割り当てる
ip -n red addr add 192.168.15.1 dev veth-red
ip -n blue addr add 192.168.15.1 dev veth-blue

# IPリンクをUpにする
ip -n red link set veth-red up
ip -n blue link set veth-blue up

# "red" Namespaceからveth-blueにping
ip netns exec red ping 192.168.15.2

# "red" Namespaceからarp
ip netns exec red arp

Linux Bridge

仮想的なスイッチを作成し、Namespaceにアタッチしていく。 仮想的なスイッチを作成できるソリューションは色々あるが、ここではネイティブのLinux Bridgeを使う。

# 新しいIFの作成
ip link add v-net-0 type bridge

# IPリンクをUpにする
ip link set dev v-net-0 up

# スイッチにNamespaceをアタッチしていくので、いったん作成済みのリンクを削除する
ip -n red link del veth-red

# リンクを作成する
ip link add veth-red type veth peer name veth-red-br
ip link add veth-blue type veth peer name veth-blue-br

# 作成したリンクをNamespaceにアタッチする
ip link set veth-red netns red
ip link set veth-red-br netns master v-net-0

ip link set veth-blue netns blue
ip link set veth-blue-br netns master v-net-0

# IPアドレスを割り当てる
ip -n red addr add 192.168.15.1 dev veth-red
ip -n blue addr add 192.168.15.1 dev veth-blue
ip addr add 192.168.15.5/24 dev v-net-0

# IPリンクをUpにする
ip -n red link set veth-red up
ip -n blue link set veth-blue up

Pre-requisite - Docker Networking

(Skip)

Pre-requisite - CNI (Container Network Interface)

これはコンテナランタイム間のネットワーク設定の差異を乗り越えるためのコンテナ標準NW IF。

Cluster Networking

Ports and Protocols | Kubernetes

ポート番号

  • Kube-API: 6443
  • ETCD Server: 2379
  • ETCD Client: 2380
  • Kubelet: 10250
  • Kube-scheduler: 10251
  • Kube-controller-manager: 10252
  • Services: 30000 - 32767

Important Note about CNI and CKA Exam

Weave-netプラグインのイントール方法がK8s公式に記載されていたが今は無くなっている。曰く、「If you have a question to install it, they will provide a link to it.」とのこと。 Hi all, Currently I'm going through the CKA exam prep and in the installing netw . . . - Kubernetes-Slack Discussions - KodeKloud - DevOps Learning Community

Ciliumのインストール方法がK8s公式にあったので、一応ブックマークしておいたほうが良さそう。 Use Cilium for NetworkPolicy | Kubernetes

Pod Networking

CNI in Kubernetes

Network Plugins | Kubernetes

KubeletがどのNetwork Solutionを利用しているかは/etc/cni/net.d配下のファイルをみればわかる。

ps -aux | grep kubelet
ls /opt/cni/bin
ls /etc/cni/net.d
cat /etc/cni/net.d/10-bridge.conf

Practice Test - Deploy Network Solution

https://uklabs.kodekloud.com/topic/practice-test-deploy-network-solution-2/

IP Address Management (IPAM)

Network Plugins | Kubernetes

/etc/cni/net.d/net-script.confで、type": "host-local" とすると、ローカルホストでIPアドレスアサインを管理 WeaveのデフォルトIPレンジは10.32.0.0/12で、アサインすることができるアドレスは10.32.0.1 ~ 10.47.255.254 このアドレスレンジをノード数分に等しく分割して、それぞれのレンジ内でIPをアサインする。

{
  "name": "k8s-pod-network",
  "cniVersion": "0.3.0",
  "type": "net-script",
  "bridge": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/16",
    "routes": [
      {"dst": "0.0.0.0/0"}
    ]
  }
}

Service Networking

Serviceはプロセスでもネームスペースでもインターフェースでもなく、仮想的なオブジェクト。 クラスタは特定のノードに存在するわけではなく、クラスタ内の全ノードにわたって仮想的に存在している。

Serviceが新しく作成されたらKube-Proxyが認識し、まず事前に定義されたIPレンジからServiceにIPを割り当てる。そして、フォワーディングルールを作成する。このルールにより、Serviceに割当てられたIPにきたパケットをPodに転送する。これによってServiceにアクセスすることで、Podにアクセス可能になる。

ではどのようにフォワーディングルールを作成するか。3種類のやり方=Proxy-modeがある。

kube-proxy --proxy-mode [ userspace | iptables | ipvs ]

デフォルトはiptables。Kube-Proxyにより、作成されたIP tableは以下で確認できる。

iptables -L -t nat | grep db-service

また、/var/log/kube-proxy.logでNATが登録されていることを確認できる。

Serviceには3種類ある。

 DNS in kubernetes

K8sではデフォルトでビルトインのDNSサーバをデプロイする。これによりクラスタ内で、PodやServiceの名前解決ができる。

Serviceが作成されると、Kuberntes DNSはServiceのホスト名とIPのマッピングを登録する。これによりService名でアクセス可能になる。

仮にアクセス先のServiceが、アクセス元とは別のNamespaceであった場合、<Service名>.<Namespace>という形式でアクセス可能。

各Namespaceに対し、DNSサーバはサブドメインを作成する。すべてのServiceはsvcというサブドメインにグループ化される。さらに、すべてServiceとPodはcluster.localというルートドメインとしてグループ化される。

つまり、DNSに登録されるServiceのAレコードは、 <Service名>.<Namespace>.svc.cluster.local となる。

Podの場合は、 <PodのIPアドレス*1>.<Namespace>.pod.cluster.local である。

*1: PodのIPアドレスは、ドットをダッシュに変えたものになる。つまり、10.244.2.5であれば、10-244-2-5となる。

 CoreDNS in Kubernetes

サービスディスカバリーにCoreDNSを使用する | Kubernetes

CoreDNSは、PodやServiceが作成されたら自動でDNSにA/AAAAレコードを作成する。 CoreDNSはDeploymentとしてKube-systemネームスペースにデプロイされる。

CoreDNSのコンフィグファイルは、/etc/coredns/Corefile。Corefileの中身はこちら。 Customizing DNS Service | Kubernetes

このコンフィグファイルは、ConfigMapオブジェクトとして、Podに渡される。

CoreDNSがDeploymentとして作成される際に、デフォルトでkube-dnsという名前でServiceも作成される。新しくPodが作成されると、Pod内の/etc/resolve.confkube-dns ServiceのIPアドレスが登録される。これによって新規に作成されたPodが、名前解決のためにCoreDNSサーバにアクセスできる。

www.google.comといったウェブサイトの名前解決リクエストは、CoreDNS Pod内の/etc/resolbe.confファイルに記載されたネームサーバに転送される。

Ingress

URL Pathベースルーティングを提供するロードバランサ。TLS終端をサポート。

Ingress Controller

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

Ingress を作成したら、NodePortといったServiceと紐づける。

Ingressの転送先にはServiceを指定する。Service名とServiceで開けているポートを指定してやる。 Ingress | Kubernetes

IPアドレスレンジの確認方法

Node

ip addreth0に割当てられているアドレスレンジを確認する

Pod

ip addrでCNIプラグイン名のIFに割当てられているアドレスレンジを確認する または、ログ中のipalloc-range:を確認する。

kubectl logs <weave-pod-name> weave -n kube-system

Service

kube-apiサーバに割当てられているservice-cluster-ip-rangeを確認する。

cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep service-cluster-ip-range

Design and Install a Kubernetes Cluster

Design a Kubernetes Cluster

K8sで扱える最大容量 Considerations for large clusters | Kubernetes

Choosing Kubernetes Infrastructure

(Skip)

 Configure High Availability

Master Nodeの冗長化を考える。

その場合、Kube-APIは、Active-Activeでロードバランシングする。 一方、Controller ManagerとSchedulerは、Active-Standby構成

ETCDは2種類の冗長化方法がある。

1つがStacked Topology。他のMaster Nodeのコンポーネントと同じノードに、ETCDをデプロイする。 もう1つがExternal ETCD Topology。他のMaster Nodeとは別のノードにETCDをデプロイする。

ETCD in HA

分散データベース。すべてのノードで保管されているデータが一致。どのノードに対しても読み書きできる。

ノード間の差分がないので、どのノードに対しても読み込みができる。

Leader Election - RAFT

ETCDでは、RAFTプロトコルでLeaderとFollowerを決定する

それぞれのETCDサーバがランダムタイマー待機後に、リーダーになりたいというリクエストを送る。最初にリーダーのリクエストを送ったサーバがリーダーになる。

リーダーからの応答がなくなった場合には、残りのETCDサーバがリーダーを決定するために再度Electionを行う。

Leaderは書き込みを受け付けて、他のノードにも書き込みをリクエストする。他のノードから応答が帰ってきたら、書き込みを完了とする。もし、Followerが書き込みリクエストを受け付けた場合には、Leaderにリクエストを転送する。

Leaderからの書き込みリクエストに対して、他のノードから応答が返ってこない場合に、round(N/2+1)個のノードから応答が返ってくれば、書き込みが正常に完了したと判断する。

ノード数は奇数が望ましい。偶数の場合には冗長性がイマイチであるため。

Install Kubernetes the kubeadm way

Introduction to Deployment with Kubeadm

kubeadmを使用したクラスターの作成 | Kubernetes

Kubeadmを使用したK8sクラスタの設定手順

  1. Master node, Worker nodeを準備する
  2. Dockerコンテナランタイムをインストール
  3. kubeadmをインストール
  4. Master nodeを初期化
  5. ネットワークプラグインをインストール
  6. Worker nodeをjoinさせる

Deploy with Kubeadm - Provision VMs with Vagrant

(Skip)

Demo - Deployment with Kubeadm

(Skip)

End to End Tests on a Kubernetes cluster

(Skip) As per the CKA exam changes (effective September 2020), End to End tests is no longer part of the exam

Troubleshooting

トラブルシューティングのテクニックや手順の概要を示す。

Application Failure

アプリケーションのトラブルシューティング | Kubernetes

PodやServiceの接続図を描くとわかりやすくなる 仮にユーザからアプリケーションに接続できないと申告があった場合、

まず、アプリケーションのフロントエンドを調べる。 curl http://web-service-ip:node-port

Service

次にWebサービスのServiceを調べる。ServiceのSelector、PodのLabelが一致していることを確認する。 kubectl describe service web-service

Pod

次にPodがRunningステータスになっていることを確認する。 kubectl get pod

また、Podのイベントログを確認する。 kubectl describe pod web

さらにPodのログを調べる。 kubectl log web

Podがリスタートしてログが消えてしまう場合は、-fでリスタートしてもログが消えないようにするか、--previousで前回のログを確認する。

Controlplane Failure

Troubleshoot Clusters | Kubernetes

まずは、Nodeのステータスをチェック。 kubectl get nodes

KubeadmでK8sクラスタがデプロイされている場合、コントロールプレーンはPodとしてデプロイされている。なので、kube-system NamespaceのPodをチェックする。

kubectl get pods -n kube-system # Podのステータス確認
kubectl logs kube-apiserver-master -n kube-system # Podのログ確認

コントロールプレーンのコンポーネントがServiceとしてデプロイされている場合は、Serviceをチェックする。

service kube-apiserver status
service kube-controller-manager status
service kube-scheduler status
service kubelet status # Worker node
service kube-proxy status

Serviceの場合のログ確認は下記コマンドで行う。

sudo journalctl -u kube-apiserver

Workder Node Failure

まずはNodeのステータスをチェック。

kubectl get nodes

次にフラグを確認する。メモリ不足やディスク不足がわかる。 Master nodeに接続できない場合は、ステータスが「Unknown」になる。その場合、LastHeartbeatTimeでいつクラッシュしたかがわかる。

$ kubectl describe node ip-192-168-26-141.us-west-2.compute.internal
Name:               ip-192-168-26-141.us-west-2.compute.internal
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  MemoryPressure   False   Fri, 04 Mar 2022 10:32:12 +0900   Fri, 25 Feb 2022 13:22:28 +0900   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Fri, 04 Mar 2022 10:32:12 +0900   Fri, 25 Feb 2022 13:22:28 +0900   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Fri, 04 Mar 2022 10:32:12 +0900   Fri, 25 Feb 2022 13:22:28 +0900   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Fri, 04 Mar 2022 10:32:12 +0900   Fri, 25 Feb 2022 13:22:49 +0900   KubeletReady                 kubelet is posting ready status

Worker node上でCPU、メモリの使用状況をチェック

top     # CPUの使用状況
df -h   # メモリの使用状況

次に、Kubeletのステータスを調べる。 service kubelet status

さらにKubeletのログを調べる。 sudo journalctl -u kubelet

証明書が期限切れしてないかを確認する。 openssl x509 -in /var/lib/kubelet/worker-1.crt -text

Network Troubleshooting

Network Plugin in kubernetes

Kubernetes uses CNI plugins to setup network. The kubelet is responsible for executing plugins as we mention the following parameters in kubelet configuration.

  • cni-bin-dir: Kubelet probes this directory for plugins on startup
  • network-plugin: The network plugin to use from cni-bin-dir. It must match the name reported by a plugin probed from the plugin directory.

Note: If there are multiple CNI configuration files in the directory, the kubelet uses the configuration file that comes first by name in lexicographic order.

DNS in Kubernetes

Debugging DNS Resolution | Kubernetes

Kubernetes uses CoreDNS. CoreDNS is a flexible, extensible DNS server that can serve as the Kubernetes cluster DNS.

Troubleshooting issues related to coreDNS 1. If you find CoreDNS pods in pending state first check network plugin is installed. 2. coredns pods have CrashLoopBackOff or Error state

If you have nodes that are running SELinux with an older version of Docker you might experience a scenario where the coredns pods are not starting. To solve that you can try one of the following options:

a)Upgrade to a newer version of Docker.

b)Disable SELinux.

c)Modify the coredns deployment to set allowPrivilegeEscalation to true:

d)Another cause for CoreDNS to have CrashLoopBackOff is when a CoreDNS Pod deployed in Kubernetes detects a loop.

There are many ways to work around this issue, some are listed here:

  • Add the following to your kubelet config yaml: resolvConf: <path-to-your-real-resolv-conf-file> This flag tells kubelet to pass an alternate resolv.conf to Pods. For systems using systemd-resolved, /run/systemd/resolve/resolv.conf is typically the location of the "real" resolv.conf, although this can be different depending on your distribution.

  • Disable the local DNS cache on host nodes, and restore /etc/resolv.conf to the original.

  • A quick fix is to edit your Corefile, replacing forward . /etc/resolv.conf with the IP address of your upstream DNS, for example forward . 8.8.8.8. But this only fixes the issue for CoreDNS, kubelet will continue to forward the invalid resolv.conf to all default dnsPolicy Pods, leaving them unable to resolve DNS.

  • If CoreDNS pods and the kube-dns service is working fine, check the kube-dns service has valid endpoints.

           kubectl -n kube-system get ep kube-dns
    

If there are no endpoints for the service, inspect the service and make sure it uses the correct selectors and ports.

Kube-Proxy

Troubleshooting issues related to kube-proxy 1. Check kube-proxy pod in the kube-system namespace is running.

  1. Check kube-proxy logs.

  2. Check configmap is correctly defined and the config file for running kube-proxy binary is correct.

  3. kube-config is defined in the config map.

  4. check kube-proxy is running inside the container

Serviceのデバッグ | Kubernetes

Other Topics

JSON PATH

(Skip)

Advanced Kubectl Commands

(Skip)

個人メモ

staticPodPathの確認方法

・ps -aux | grep kubelet  ・「--config=/var/lib/kubelet/config.yaml」を見つける ・cat /var/lib/kubelet/config.yaml する ・staticPodPath: /etc/kubernetes/manifests

scpコマンド

リモートホストにscpでファイルを転送 ・scp test.txt node01:/etc/kubernetes