CKAD&CKA対策の個人的メモ

# はじめに
CKAD&CKA対策用の個人的なメモです。
試験中に公式ドキュメントやkubectlのhelpオプションによる確認ができるため、本メモの内容を全て暗記する必要はないです。しかしながら、時間がシビアなので、ある程度覚えておかないときついです。（毎回調べていたら多分時間が足りない）また、実務のことを考えると、やはりある程度は頭に入っていた方がよいと思います。
一部、too muchな内容もありますが、理解を深めるために記載しています。
よろしければご活用ください。メモなので表記揺れとかはご容赦ください。

# ▼Container
## Docker
### dockerコマンド
- カレントディレクトリにDockerfileからDockerイメージをbuildする
  - `docker image build -t <image>:<tag> -f <Dockerfile> .`
- イメージタグの変更
  - `docker image tag <before> <after>`
  - つけられるタグは一つだけ
- イメージpush
  - `docker image push <image>:<tag>`
- Dockerイメージをダウンロードする
  - `docker image pull <image>`
- Dockerイメージをtarにする
  - `docker save <image> -o <tar>`
- tarを解凍してDockerイメージにする
  - `docker load -i <tar>`
- イメージを軽くする（一例）
  - Alpineイメージを使う。python:3.6-alipneなど。
- イメージからコンテナ起動する。公開ポート8282のコンテナポート8080。
  - `docker container run -p 8282:8080 <image>`
- イメージからコンテナを起動してコマンド実行する
  - `docker container run <image> cat /etc`
- 起動中コンテナに擬似的なSSHする
  - `docker container exec -it <container> /bin/sh`
- コンテナのリソース使用状況を確認する
  - `docker container stats <container>`
- コンテナのログを確認する
  - `docker container logs <container>`

### Dockerfile
- Dockerfileから独自のDockerイメージを定義して、`docker run` で起動する。
- `ADD <url> <container path>` でリモートファイルをコンテナ上にコピーする。
- `COPY <local path> <container path>` でローカルファイルをコンテナ上にコピーする。
- RUNはビルド時に実行するコマンド
- ENTRYPOINTはコンテナ起動時に実行するコマンド
- CMDはENTRYPOINTと併用する際にはENTRYPOINTのコマンドの引数になる。
- kubernetesのYAMLのspec.containers[].commandでENTRYPOINTを上書きする。spec.containers[].argsでCMDを上書きする。commandでCMDを上書きではない。

## Podman
- Dockerと同様のコンテナエンジン。Dockerfileも使える。
- イメージビルド
	- `podman build -t <image>:<tag> -f <Dockerfile> .`
- イメージ一覧
	- `podman image ls`
- イメージpush
	- `podman push <image>:<tag>`
- バックグラウントで実行
    - `podman run -d --name <conatiner name> <image>:<tag>`
- コンテナ一覧
	- `podman ps`
- コンテナログ出力
	- `podman logs <container>`

## cri-o
- Kubernetesに最適化された軽量なOCI準拠なコンテナランタイム。crictlでCLI操作する。
- Dockerほど柔軟なCLIは用意されていないためローカル開発ではDockerが選択されるケースは依然として多いだろうが、今後のサーバ環境ではDockerからcri-oに置き換わるかもしれない。
- コンテナの一覧を表示する
	- `crictl ps -a`
- podの一覧を表示する
	- `crictl pods`
- コンテナのイメージ一覧を表示する 
	- `crictl images`
- 実行中コンテナでコマンド実行
	- `crictl exec -it <container id> <command>`
- ログを確認する
	- `crictl logs <container id>`

# ▼Workloads
## Pod
### kubectl
- podを起動して環境変数を設定する
	- `kubectl run <pod name> --image <image> --env=key1=val1`
- podを起動してClusterIPで公開する
	- `kubectl run <pod name> --image <image> --expose=true --port=<port> --target-port=<target port>`
- podを起動してコマンドを実行する。
	- `kubectl run <pod name> --image <image> --command -- <command> <args>`
	- containers[].commandとcontainers[].argsが設定される。
- podを起動してシェル経由でコマンドを実行する。
	- `kubectl run <pod name> --image <image> -- /bin/sh -c '<command and args>'`
	- containers[].commandは無しで、containers[].args配下に全て設定される。
- 起動中のpod（メインコンテナ）に擬似的なSSH接続する
	- `kubectl exec -it <pod name> -- /bin/sh`
- pod内の特定コンテナに擬似的なSSH接続する
	- `kubectl exec -it <pod name> -c <container name> -- /bin/sh`
- 前のリビジョンのpodのログを取る
	- `kubectl logs <pod> --previous`
- Pod中の特定コンテナのログを取る
	- `kubectl logs <pod> -c <container>` 
- 各podの少し詳しい情報を取得する
	- `kubectl get pods -o wide`
- 各podの詳細情報を取得する
	- `kubectl describe pods`
- 適当なpodを起動してpodに疎通確認
	- `kubectl run tmp --image <image> --rm -it -- curl -m 5 <pod ip>`
	- Serviceと違ってPod名では名前解決されないので要注意

### YAML
- spec.nodeNameで起動するNodeを指定する。
- spec.terminationGracePeriodSecondsに削除するまで何秒かを設定する。
	- Podの削除命令がされた場合に、「Serviceからの除外処理」と「preStop処理＋SIGTERM処理」が同時に実行される。terminationGracePeriodSecondsにこれらにかかるであろう時間を設定する。
- spec.containers[].ports.containerPortでコンテナのポートを設定する。
- spec.containers[].lifecycle.postStartにコンテナ起動直後に実行する処理（execかhttpGet）を指定する。
- spec.containers[].lifecycle.preStopにコンテナ停止直前に実行する処理（execかhttpGet）を指定する。
- podのyamlにcommandと引数を記述する場合は、リストで記述する。あるいはargsを活用する。
	- command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
	- command: ["printenv"]
	- args: ["HOSTNAME", "KUBERNETES_PORT"]

### マルチコンテナ
- マルチコンテナのpodを作成する
	- まず1コンテナのpodのyamlを作って、そのyamlに他podの情報を追記していく。kubectlだけではマルチコンテナpodは作れない。
- initコンテナの設定はspec.initContainersで設定する
- initコンテナが複数ある場合は順列に実行される。initコンテナ1 -> initコンテナ2 ...
- initコンテナの情報を取得する
	- `kubectl describe pod <pod>`

### Pod(Container)のリソース制限
- spec.containers[].resources.requestsでcpuとmemoryの下限を指定。
- spec.containers[].resources.limitsでcpuとmemoryの上限を指定。
- containerの合計がPodのリソース制限になる
- OOMKilledはPodに割り当てたメモリが不足している可能性。ノードに余裕あればlimitsのmemoryを増やすと起動するようになるかも。

### ContainerのHealthCheck
- spec.containers[].startupProbeはPodの初回起動が完了しているかをチェックする。失敗したら他のProbeは実行しない。
- spec.containers[].readinessProbeはPodがリクエストを受け付けることができるかをチェックする。失敗したらトラフィックを流さない。再起動はしない。
- spec.containers[].livenessProbeはPodが正常に動作しているかをチェックする。失敗したらPodを再起動する。
- httpGetでヘルスチェック用エンドポイントを叩く。
- exec.commandでヘルスチェック用のコマンドを実行する。
- tcpSocketで特定ポートとの疎通を確認する。
- initialDelaySeconds、periodSeconds、timeoutSeconds、successThreshold、failureThresholdを設定する。

## ReplicaSet
- spec.selector.matchLablesで指定したラベルのpod数を管理する。ラベルしか注目しないため、そのReplicaSet外のpodのラベルも見てしまう点に注意する。
- Podの増減履歴を確認する
	- `kubectl describe replicaset <rs>`
- editしてもpodは自動で更新されないので、手動でpodをdeleteする。

## Deployment
- Deploymentのimageを変更する
	- `kubectl set image deployment <deployment> <container>=<new image>`
	- Podは自動で再起動する
- replicasの数を変更する
	- `kubectl scale deployment <deployment> --replicas=<number>` 
- HPAを設定する
	- `kubectl autoscale deployment <deployment> --min=5 --max=10 --cpu-percent=80`
- HPAを削除する
	- `kubectl delete hpa <hpa>`
- DeploymentをRolling Updateする
	- `kubectl rollout restart deployment <name>`
- Deploymentによる変更履歴を確認する
	- `kubectl rollout history`
- Deploymentを1つ前に戻す
	- `kubectl rollout undo deployment <deployment>`
	- （さらにもう一回実行すると元に戻る）
- Deploymentを指定のバージョンに戻す
	- `kubectl rollout undo deployment <deployment> --to-revision=<revision number>`
- DeploymentのStrategyを確認する
	- `kubectl describe deployment <deployment>`
- spec.selectorは.spec.template.metadata.labelsと一致している必要がある
- spec.strategy.typeはRecreateとRollingUpdateの二種類がある。RollingUpdateではmaxUnavailable（アップデート中にdesiredから何個減っても許容するか）とmaxSurge（アップデート中にdesiredから何個増えても許容するか）を調整する。
- 複数のDeploymentが存在する環境において、特定のDeploymentへのトラフィックを少なくす。
	- 特定のDeploymentのpodの数を少なくすると、そのDeploymentへのトラフィックを少なくできる。各Deploymentが抱えるpodへのリクエスト加重は均等。
- カナリアリリースする
	- 既存のDeploymentをコピーしてcanary用Deploymentを用意して、それぞれのDeploymentのPod数が目標の加重比率になるように調整する。例えばPrimary:Canary=80:20にする場合でPrimaryのDeploymentのPod数が4であれば、CanaryのDeploymentのPod数は1にする。
- replaceやrollout restartしてもDeploymentのAGEは変わらない。PodのAGEを確認するとよい。

## Label&Annotation
- podにラベルをつける
	- `kubectl label pod <pod> <key>=<value>`
- podのラベルを削除する
	- `kubectl label pod <pod> <key>-`
- 特定のラベルが付いたPodにラベルをつける
	- `kubectl label pod <key>=<value> -l <key>=<value>`
- 全てのpodにラベルをつける
	- `kubectl label pods --all <key>=<value>`
- Deploymentのラベルを上書きする
	- `kubectl label deployment <deployment> --overwrite <key>=<value>`
- 特定のラベルをノードにつけてそのノード上にpodを起動する
	- `kubectl label node <node> <key>=<value>`
	- podのYAMLでnodeSelectorかnodeAffinityでラベルを指定する。
- Podをラベル付きで一覧表示する
	- `kubectl get pods --show-labels`
- 特定のラベルを持ったpodを一覧表示する（複数ラベルでAND検索）
	- `kubectl get pods -l <key1>=<value1>,<key2>=<value2>`
- 特定のラベルを持ったpodを一覧表示する（複数ラベルでOR検索）
	- `kubectl get pods -l <key1>=<value1> -l <key2>=<value2>`
- 特定のラベルが貼られたpodを一覧表示する
	- `kubectl get pods -L <key>`
- podにラベルをつけて起動する
	- `kubectl run <name> --image <image> -l <key>=<value>`
- 特定ラベルのpodを削除する
	- `kubectl delete pods -l <key>=<value>`
- podにdescriptionアノテーションをつける
	- `kubectl annotate pod <pod> <key>=<value>`
- podのdescriptionアノテーションを削除する
	- `kubectl annotate pod <pod> <key>-`
- 特定のラベルが付いたPodにアノテーションをつける
	- `kubectl annotate pod <key>=<value> -l <key>=<value>`
- 全てのpodにアノテーションを付与する
	- `kubectl annotate pods --all <key>=<value>`

## Job
- spec.completions
	- Jobを何回成功するまで実行するか
- spec.parallelism
	- Jobを何並列にするか
- spec.backoffLimit
	- Job失敗時に何回までリトライするか
- spec.suspend
	- trueでJobを一時停止する
- spec.template.spec.restartPolicy
	- Job失敗時にAlways（Podが停止すると常に再起動）かOnFailure（同じPodで再起動）かNever（新しくPodを作り直す）
- spec.template.spec.activeDeadlineSeconds
	- 起動して何秒後に削除するか
- CronjobからJobを手動実行
	- `kubectl create job <job name> --from=cronjob/<cronjob>`
	- 明示的に削除しないと削除されない

## Cronjob
- Cronに関するものを設定する。Cronでない設定はJobの方。
- spec.startingDeadLineSeconds
	- Cronが何秒遅れて実行されても許すか
- spec.concurrencyPolicy
	- Cronで前のJobが完了していない場合に、Allow（同時実行許可）かForbid（同時実行不可）かReplace（前のJobを止めて新しいJobを開始）のどれか。
- spec.successfulJobsHistoryLimit
	- Cronで成功したjobをいくつ保持するか
- spec.failedJobsHistoryLimit
	- Cronで失敗したjobをいくつ保持するか
- spec.suspend
	- trueでCronを一時停止する
- spec.jobTemplate.specにJobの設定をする。
	- spec.jobTemplate.spec.activeDeadlineSecondsなど。
- 毎分特定コマンドを実行するCronjobを作成する
	- `kubectl create cronjob <name> --image=<image> --schedule="*/1 * * * *" -- /bin/sh -c 'echo Hello World'`
- `no matches for kind "CronJob" in version "batch/v1"` エラーになったら `batch/v1beta1` にする。

# ▼Network
## Service
- CKADでは主にClusterIP（クラスタ内通信）かNodePort（クラスタ外通信）を使用する。
- NodePort -> ClusterIP -> Podの順でトラフィックが流れる。
- nodePortは全てのKubernetesノードで受けるポート、portはClusterIPのポート、targetPortはコンテナのポートを設定する。
- ClusterIPのServiceを作成する
	- `kubectl create service clusterip <name> --tcp=<port>:<targetPort>`
- NodePortのServiceを作成する
	- `kubectl create service nodeport <name> --tcp=<port>:<targetPort> --node-port=<nodePort>`
- spec.selectorで指定したlabelが付いたPodへ転送する。
	- PodにはServiceの転送用目印となるlabelを付与しておく必要あり。
	- 意外だがYAMLでDeployment名を指定して紐づけるといったようなことはしないし、Deploymentのlabelではダメ。
- Deploymentを公開する（Serviceを作成する）
	- `kubectl expose deployment <deployment> --name <service name> --type <type> --port <port> --target-port <target port>`
	- nodePortオプションはkubectlでは設定不可
	- exposeはselectorの設定が自動なので楽。
- endpoint（転送先PodのIPとポート）を確認する
	- `kubectl get endpoints <service>`
- sessionAffinity: ClientIPにより、送信元IPアドレスを使ってセッションアフィニティ（同じPod宛てにトラフィックを転送し続けること）ができる。
- NodePortのexternalTrafficPolicyはLocal（Nodeでトラフィックを受けたあとに別Nodeへのホップを無効にする。トラフィックの処理が偏る可能性がある。）とCluster（Nodeでトラフィックを受けたあとに別Nodeへのホップを有効にする。別のNodeへホップを許可することでトラフィック処理を分散できる。）がある。デフォルトはCluster。
- ServiceのIPレンジの確認
	- `cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep service-cluster-ip-range`
- 適当なPodを起動してClusterIP経由でPodへの疎通確認
	- `k run tmp --image nginx:alpine -n <namespace> --rm -it -- curl -m 5 <service name>:<port>`
- NodePort経由でPodへの疎通確認
	- `curl -m 5 <node ip>:<nodePort>`

## Ingress
- L7ロードバランサとしてクラスタ外からServiceへのアクセスを管理するリソース。
- パスベースルーティング機能
	- spec.rules[].http.paths[]にpathとbackend（Serviceのnameとport）を設定する。このportはServiceのport（ClusterIPのportかNodePortのport）と一致させる。
	- pathTypeはPrefixかExact。
	- spec.rules[].hostを設定しない場合は*扱い。
- SSL終端機能
	- spec.tls[]にhosts(TLS証明書を適用するドメイン名)とsecretName(TLS証明証を格納しているSecretの名前)を設定する。
- spec.defaultBackendにrulesにマッチングしなかったリクエスト用の404の設定をする。
- Ingressが動作するにはIngressコントローラ（NginxやIstioなど）が導入されている必要がある。
- パスベースルーティングが設定されたingressを作る。pathTypeはPrefix。
	- `kubectl create ingress <name> --rule="<host>/<path>*=<service name>:<service port>"`

## CNI(Container Network Interface)
- 複数Node上のPod間の疎通性を確保するための機能。
- プラグイン形式。様々なベンダーから提供される。WeaveやFlannelなど。controlplaneのNICが追加される。
- CNIバイナリはデフォルトで `/opt/cni/bin` に配置される。
- CNIの設定ファイルディレクトリはデフォルトで `/etc/cni/net.d`

## kube-proxy
- Service（ClusterIPやNodePort）宛のトラフィックをPodへ転送する機能。
- Node上でDaemonsetで起動している。
- userspaceモード
	- カーネル空間でなくユーザ空間でトラフィックを転送する。遅い。
- iptablesモード
	- カーネル空間でトラフィックを転送する。userspaceよりも速く、枯れているが、そもそもロードバランシング用途で開発されたものではない。
- ipvsモード
	- 速く、ロードバランシングのアルゴリズムに複数の選択肢が用意されている。ただし、枯れていない。

## CoreDNS
- CoreDNSのService/Deployment/Pod/Configmapはkube-systemネームスペース上に作成される。
- 設定はCorefileで行う。
	- DeploymentのArgsでCorefileのパスを指定する。
	- CorefileはConfigMapで管理することも可能。
	- クラスターのドメイン名を設定する。
		- 例えば `kubernetes svc.cluster.local`
- Serviceの名前解決は `<service name>.<namespace>.<domain>` で行う。
	- ドメイン名は省略可能。
	- 同じnamespaceであればnamespaceも省略可能。つまり、Service名のみで解決可能。
- Service名は名前解決されるがPod名は名前解決されない。
- Pod生成時に `/etc/resolv.conf` に自動で設定される。
	- `search default.svc.cluster.local svc.cluster.local cluster.local`
	- `nameserver 10.96.0.10`
		- CoreDNSのServiceのIP

# ▼ストレージ
## ConfigMap
- ConfigMapを作る（literal）
	- `kubectl create configmap --from-literal=<key1>=<value1> --from-literal=<key2>=<value2>`
- ConfigMapを作る（file）
	- `kubectl create configmap --from-file=<key1>=<file1> --from-file=<key2>=<file2>`
- ConfigMapを作る（env-file）
	- `kubectl create configmap --from-env-file=<file>`
- 環境変数としてPod(Container)に渡す
	- spec.containers[].env.valueFrom.configMapKeyRefでConfigMapとkeyを指定する。
	- spec.containers[].envFrom.configMapRef.nameでConfigMapを指定する。
- VolumeとしてPod(Container)に渡す
	- spec.volumes.configMapで指定して、spec.containers[].volumeMountsでマウントする。
	- 動的更新される

## Secret
- Secret（Opaque）を作成する。（literal）
	- `kubectl create secret generic --from-literal=<key1>=<value1> --from-literal=<key2>=<value2>`
- Secret（Opaque）を作成する。（file）
	- `kubectl create secret generic --from-file=<key1>=<file1> --from-file=<key2>=<file2>`
- Secret（Opaque）を作成する。（env-file）
	- `kubectl create secret generic --from-env-file <file>`
- 環境変数としてPod(Container)に渡す
	- spec.containers[].env.valueFrom.secretKeyRefでSecretとkeyを指定する。
	- spec.containers[].envFrom.secretRef.nameでSecretを指定する。

- VolumeとしてPod(Container)に渡す
	- spec.volumes.secretで指定して、spec.containers[].volumeMountsでマウントする。
	- 動的更新される
- secretに登録されている値をbase64デコードして取得する
	- `kubectl get secret <secret> -o yaml` して `echo <encoded value> | base64 -d`
	- `kubectl get secret <secret> -o jsonpath="{.data.<target>}" | base64 -d`
	- describeでも確認できる場合がある

## Volume
- あらかじめ用意された利用可能なボリューム（Node、nfs、iscsiなど）を使用するだけ。Kubernetesが管理するものではない。
- Podのspec.volumesで指定して、spec.containers[].volumeMountsでマウントする。
- emptyDirはホスト（Node）上の一時的な領域をPodに確保する。
  - 同一Pod内のコンテナ間では共有可能だが、Pod間での共有は不可。
  - Podが削除されると消える。
  - emptyDirに関する設定を何もしない場合はemptyDir :{}
  - emptyDir.medium: Memoryとすると高速なtmpfsのメモリ領域を利用できる。
- hostPathはホスト（Node）上の任意の領域をマウントする。
    - pathでホストのパスを指定する
  - 同一Node内の他Podとの共有は可能。
  - Podが削除されても消えないがNodeが停止すると消える。
  - typeはDirectoryOrCreate/Directory/FileOrCreate/Fileなどがある。

## PersistentVolume(PV)
- 外部の永続ボリュームサービス（AWSのEBSなど）と連携したり、Nodeのリソースを使って、Kubernetes管理のボリュームを提供するリソース。
- 手動かStorageClassのDynamic Provisioningにより作成される。
- PodからPVを直接利用できず、必ずPVC経由で利用する。
- spec.capacity.storageで容量を設定する。
- spec.volumeModeはFilesystem（デフォルト）/Blockのいずれか。
- spec.accessModesはReadWriteOnce(単一NodeでReadWrite可能)/ReadOnlyMany(複数NodeでReadOnly可能)/ReadWriteMany(複数NodeでReadWrite可能)のいずれか。
- spec.persistentVolumeReclaimPolicyでPVCが削除される際にPVをDeleteするかRetainするかを指定する。ただし、Retainしても再度マウントすることはできず、Releasedというステータスになる。
- spec.storageClassNameを設定する。
- hostPathの場合は、spec.hostPath.pathを設定する。

## PersistentVolumeClaim(PVC)
- PVをPodにアサインするリソース。
- PodやDeploymentのspec.volumes[].persistentVolumeClaim.claimNameを設定して、spec.containers[].volumeMountsでマウントする。
- spec.storageClassNameを設定する。
- spec.accessModesを設定する。
- spec.volumeModeを設定する。
	- Blockの場合は、Podにはspec.containers[].volumeDevicesでマウントする。
- spec.resources.requests.storageを設定する。Dynamic Provisioningで生成されたPVでない場合は、実際にはこれよりも大きな容量のPVが割り当てられる可能性がある。
- PVとPVCの設定が一致し、PVCのspec.resources.requests.storageを満たしたPVがbindされる。
- selector.matchLabelsやselector.matchExpressionsにより、PVに付与されたlabelを使ってbindするPVを指定することも可能。
- Podから使われ続ける限りPVCは削除できない。
- PVはnamespaceスコープでないが、PVCはnamespaceスコープ。

## StorageClass
- ストレージの種類。例えば、低スループット・標準：高スループットなどの分類。Dynamic Provisioningも行う。
- 手動でPVを作る場合、「PVとPVCのstorageClassName」と「StorageClassのname」が一致することで紐づく。
- provisionerでAWSのEBSやOpenStackのCinderなどを指定する。
- reclaimPolicyを設定する。PVとPVCとStorageClassのreclaimPolicyは一致する必要がある。
- volumeBindingModeでDynamic ProvisioningによるPVの作成タイミングを設定する
    - Immediate（デフォルト）はPVCを作成すると即座にPVを作成する。
    - WaitForFirstConsumerはPodにアタッチされる直前のタイミングでPVを作成する。節約できる。
- provisioner: kubernetes.io/no-provisionerによりDynamic ProvisioningをOFFにする。
- allowVolumeExpansion: trueにすることで使用中のPVのサイズを拡張可能にする。サイズをあげる場合はPVCのYAMLでrequestsの値を増やす。

# ▼セキュリティ
## Admission Control
- KubernetesのAPI ServerへのAPIリクエストに対して、認証と認可を行った後のフェーズで、別途そのリクエストを受け入れるか制御する機能。
- kube-apiserverコマンドはkube-systemネームスペースのkube-apiserver-controlplaneポッドで実行する
	- `kubectl exec -it kube-apiserver-controlplane -n kube-system -- kube-apiserver -h`
- admission controlのenableになっているプラグインを取得する
	- `kube-apiserver -h | grep 'enable-admission-plugins'`
- kube-apiserverコマンドの `--enable-admission-plugins` と `--disable-admission-plugins` でカンマ区切りに有効無効にする認証方法を指定する。
- admission controlのYAML上でのプラグインの設定状況を調べる（デフォルト設定までは確認できない）
	- `cat /etc/kubernetes/manifests/kube-apiserver.yaml |grep admission`
- /etc/kubernetes/manifests配下にkube-apiserverとkube-controller-managerとkube-schedulerのPodのYAMLがある。これらのYAMLはviなどで編集すると自動で再起動する。
- プラグインはMutating（リクエストの内容を検証）かValidating（リクエストの内容を検証）のどちらかあるいは両方に分類される。
- 代表的なプラグイン
	- AlwaysAdmitは全てのリクエストを許可する。
	- AlwaysPullImagesはPodのimagePullPolicyをAlwaysに強制的に変更する。ノードにpull済みのprivateイメージが他のPodに使用されないようにするため。
	- AlwaysDenyは全てのリクエストを禁止する。テスト用。
	- ServiceAccountはServiceAccountが明示的に指定されていないPodに対して、デフォルトのもの紐付ける。また、トークンをPodに自動的にマウントする。
	- SecurityContextDenyはSecurityContextの設定のうち、SELinuxOptions、RunAsUserなどの設定をしているものを禁止する。
	- ResourceQuotaはリクエストがnamespace内のリソース制限を超えていないかを検証する。
	- LimitRangerはNamespaceに設定されるLimitRangeに対して、リクエストが適切かどうかを検証する。もしResourceが未設定の場合はデフォルト値を設定するときにも使われる。
	- NamespaceAutoProvisionは、存在しないnamespaceを指定してリソースを作ってもエラーにならず、自動でnamespaceを作成する。現在はdeprecated。
	- NamespaceLifecycleは、存在しないnamespaceや削除中のnamespaceへの指定を禁止する。
	- MutatingAdmissionWebhookは独自リソースに関するリクエストを必要に応じて改変する。ValidatingAdmissionWebhookは独自リソースに関するリクエストを検証する。Mutatingの後にValidatingが実行される。

## 証明書
- /etc/kubernetes/manifests/kube-apiserver.yaml のkube-apiserverコマンドでapi-server関連の証明書を指定している。
- /etc/kubernetes/manifests/etcd.yaml のectdコマンドでetcd関連の証明書を指定している。
- 証明書に記載されたCommon Name、Issuer、Alternative Nameなどを確認する
	- `openssl x509 -in <cert file> -text`

## UserAccount
- UserAccountは人間用アカウント。AWSのIAMなどにも連携できる。
- UserAccountの追加
	- 新規UserAccountのClusterアクセス用サーバ証明書の申請
		- 秘密鍵の作成
			- `openssl genrsa -out <key file> 2048`
		- 秘密鍵からCSRファイル（公開鍵にCNなどを付与したもの）の作成
			- `openssl req -new -key <key file> -out <csr file>`
		- CertificateSigningRequest(CSR)の作成
			- CSRは証明書発行要求。CSRファイルをCAに渡し、署名済みのサーバ証明書を発行して貰う。
			- spec.groupsには"system:authenticated"を設定する。
			- spec.requestにはCSRファイルをbase64エンコードした値を設定する。
			- spec.signerNameには"kubernetes.io/kube-apiserver-client"を設定する。
			- spec.usagesにはTLSクライアントの場合は"digitalsignature", "key encipherment", "client auth"を設定する。
		- CSRリソースの確認
			- `kubectl get csr`
	- 承認の場合
		- CAに承認される
			- `kubectl certificate approve <csr>`
		- 承認されるとCSRリソースのstatus.certificateにCRT（サーバ証明書）が出力されるため、それをファイルに出力する。
			- `kubectl get csr <csr> -o jsonpath='{.status.certificate}' | base64 -d > <crt file>`
		- CRTファイルを指定してUserAccountの認証情報を追加
			- `kubectl config set-credentials <user name> --client-certificate=<crt file>`
		- cluster, context, role, rolebindingを設定してリソース操作が可能になる。
	- 否認の場合
		- CAに否認される
			- `kubectl certificate deny <csr>`
		- CSRリソースの削除
			- `kubectl delete csr <csr>`	

## kubeconfig
- UserAccount（認証情報）とclusterとcontext（userとclusterの組み合わせ）を管理する。
- UserAccount（認証情報）の定義を追加
	- `kubectl config set-credentials <user name> --client-certificate=<crt file>`
- clusterの定義を追加
	- `kubectl config set-cluster <cluster name> --server=<url>`
- contextの定義を追加
	- `kubectl config set-context <context name> --cluster=<cluster name> --user=<user name> --namespace=<namespace>`
- 現在のcontextを表示
	- `kubectl config current-context`
- contextの変更
	- `kubectl config use-context <context name>`
- 使用するkubeconfigを変える
	- `--kubeconfig` オプションで別のconfigを指定する
	- 環境変数KUBECONFIGで別のconfigを指定する
	- `~/.kube/config` の中身を編集する
- userを指定してリソース操作をする
    - `kubectl get pods --as <user>`

## ServiceAccount
- ServiceAccountはPod用アカウント。
- ServiceAccountの作成
    - `kubectl create serviceaccount <name>`
    - v1.24以降はトークンは自動生成されなくなった
- ServiceAccount用のトークンを作成する
    - `kubectl create token <serviceaccount>`
- PodとServiceAccountを紐づける
    - Podのspec.serviceAccountNameを設定する。
- ServiceAccountをPodに紐づけることで、Podは `/var/run/secrets/kubernetes.io/serviceaccount` にマウントされたServiceAccountのトークンを使ってKubernetesリソースの操作ができるようになる。

## RBAC(Role Based Access Control)
- Role（Podの操作権限）を作成する
    - `kubectl create role <name> --verb=list,create,delete --resource=pods`
- RoleBindingを作成してroleとuserを紐づける
    - `kubectl create rolebinding <name> --role=<role> --user=<user>`
- ClusterRoleを作成する
    - `kubectl create clusterrole <name> --verb=<verb> --resource=<resource>`
- ClusterRoleBindingを作成してClusterRoleとServiceAccountを紐づける
    - `kubectl create clusterrolebinding <name> --clusterrole=<cluster role> --serviceaccount=<serviceaccount>`
- Role一覧を取得する
    - `kubectl get roles`
- RoleBinding一覧を取得する
    - `kubectl get rolebindings`
- RoleBindingが紐づくSubjects (User、Group、ServiceAccount)を確認する
    - `kubectl describe rolebinding <RoleBinding>`
- 1つのRoleに複数のSubjectを設定可能
- YAMLでrole/clusterroleを作成する場合はapiGroupsを自分で設定する必要がある。resourceごとに設定すべき値は、`kubectl api-resources` のAPIVERSIONで確認できる。例えば、storage.k8s.io/v1であればstorage.k8s.ioをapiGroupsに指定すればよい。
- クラスタの認証モードを確認する
    - `kubectl describe pod kube-apiserver-controlplane -n kube-system` を実行して、authorization-modeにRBACが含まれていればRBACが使える状態。

## Private Registry Image
- private registryのイメージを指定する
	- Podのspec.containers[].imageで `<repository>/<image>` と指定する
- docker-registryのSecretを作成する
	- `kubectl create secret docker-registry <secret name> --docker-username=<user> --docker-password=<password> --docker-email=<email> --docker-server=<server>`
- Secretを使う
	- Podのspec.imagePullSecretsでnameを指定する

## SecurityContext
### Podとコンテナ共通
- runAsUser/runAsGroup/runAsNonRoot/seLinuxOptionsはPodとコンテナの両方のSecurityContextで設定可能。重複する場合はコンテナのSecurityContextの設定が優先される。
- runAsUser でrootユーザを指定する場合はIDを0にする。
- podの実行ユーザを調べる
	- `kubectl exec <pod> -- whoami`
- 既存のpodの設定は変更できないため、変更する場合は一度podをdeleteする。

### Podに関するSecurityContext
- spec.securityContextに設定する。
- spec.securityContext.fsGroupでマウントするvolumeのグループを変更する。
	- Podにマウントしたvolumeはowner:group=root:rootのため、runAsUserで実行ユーザを変更すると権限エラーになってしまう。

### コンテナに関するSecurityContext
- spec.containers[].securityContextに設定する。
- capabilitiesでコンテナの特定の権限（SYS_ADMINなど）のadd/dropをする。
- privileged: trueにより、特権コンテナとして起動させる。コンテナにホストのrootと同等の権限を与える。
- allowPrivilegeEscalation: trueにより、権限昇格（コンテナにホストのroot以上の権限を与えること）させる。
- readOnlyRootFilesystem: trueにより、/etc配下などのKernel関連ファイルをreadOnlyにする。

## Network Policy
- クラスタ内のPod同士のトラフィックルール。
	- デフォルト（NetworkPolicyがPodに適用されていない）では、Podは分離されていない状態となるため、すべてのトラフィックを許可する。
	- NetworkPolicyがPodに適用されると、そのPodは分離されるようになる。ホワイトリスト形式で許可するものだけを設定する。
	- 複数のNetworkPolicyがPodに適用される場合は、OR条件で制限される。
- podSelector
	- spec.podSelectorでどのPodにこのNetwork Policyを有効にするかを指定する。ネットワーク系だけど意外とServiceと紐づけることはない。
		- `podSelector: {}` で全てのPodを対象にする。
	- spec.ingress.from.podSelector.matchLabelsで特定のラベルがついたPodからの通信を許可する
	- spec.egress.to.podSelector.matchLabelsで特定のラベルがついたPodへの通信を許可する。
- nameSpaceSelector
	- spec.ingress.from.nameSpaceSelector.matchLabelsで特定のラベルが付いたnamespace上のpodからの通信を許可する
	- spec.egress.to.nameSpaceSelector.matchLabelsで特定のラベルが付いたnamespace上のpodへの通信を許可する。
- ipBlock
	- spec.ingress.from.ipBlockでクラスタ外ネットワークの特定ipからの通信を許可する
	- spec.egress.to.ipBlockでクラスタ外ネットワークの特定ipへの通信を許可する。
- fromやtoにnamespaceSelectorとpodSelectorとipBlockを設定する場合、 `-` が合わせて1つならばAND条件。それぞれに `-` があればOR条件。つまり、 `-` ごとにルールがまとまる。
- ports
	- spec.ingress.portsで許可する送信元ポートを設定する。
	- spec.eggres.portsで許可する宛先ポートを設定する。
	- portsの設定がない場合は全てのポートを許可。
	- `-` 付き（ `- ports:` ）であれば、fromやtoの設定にOR条件。
	- `-` なし（ `ports:`）であれば、fromやtoの設定にAND条件。
- 全てのトラフィックを許可する場合は、ingress/egressに `{}` を設定する。
- 全てのトラフィックを遮断する場合は、policyTypesだけ設定して、ingress/egressの設定を書かない。
- fromあるいはtoをyamlに複数設定する場合は `to:` や `from:` を複数書く。それぞれがOR条件になる。
- kubectlではingressは作成できるがegressは作成できない。どちらにせよYAMLで書いたほうがわかりやすい。
- Network Policy一覧を取得
	- `kubectl get networkpolicy`
- 短縮名はnetpol

# ▼リソース制限
- LimitRangeで特定namespaceのContainer/Pod/PersistentVolumeClaimに関するリソース(CPU、memory、容量)のmin/max/defaultなどの設定をする。
- LimitRangeの設定を確認する
	- `kubectl describe limitrange <limitrange>`
- ResourceQuotaで特定namespace全体での「リソース数」と「リソース使用量」の制限をする。
	- spec.hard.services
	- spec.hard.requests.memory
- ResourceQuotaの設定を確認する
	- `kubectl describe quota <quota>`

# ▼Helm
- repositoryのchartを使ってreleaseをデプロイすることで、簡単にKubernetes上にリソース一式（DeploymentやServiceなど）を用意するためのパッケージマネージャ。
- プログラミング的に言うと、chartはクラスでreleaseはインスタンス。
- Helm関連の環境変数表示
	- `helm env`
- リポジトリの登録
	- `helm repo add <repository name> <repository url>`
- リポジトリの一覧表示
	- `helm repo list`
- リポジトリの更新
	- `helm repo update`
- Artifact Hubからchartを探す
	- `helm search hub <chart>`
- リポジトリから検索（versionなどを出力する）
	- `helm search repo <repository>`
- chartで設定可能なvaluesを表示する
	- `helm show values <repo/chart>`
- chartをインストールしてreleaseを生成（バージョン指定、パラメータを個別指定）
	- `helm install <release> <chart> --version <version> --set <key=value>`
- chartをインストールしてreleaseを生成（バージョン指定、パラメータをvaluesファイルで読み込み）
	- `helm install <release> <chart> --version <version> --values <file>`
- chartをアンインストールしてreleaseを削除
	- `helm uninstall <release>`
- releaseの一覧
	- `helm list`
- statusがdeployedでないreleaseも含めた一覧
	- `helm list -a`
- releaseの詳細情報を表示
	- `helm get all <release>`
- releaseをアップグレードする
	- `helm upgrade <release> <repo/chart> --version <version> --set <key=value>`
- releaseの履歴を確認する
	- `helm history <releasee>`
- releaseをロールバックする
	- `helm rollback <release> <revision>`
- 独自chart用の雛形を作成する
	- `helm create <chart>`
- 独自chartのインストール
	- `helm install <release> <chart path>`
- 独自chartをパッケージ（tgz）化
	- `helm package <chart path>`
- リポジトリからchartをDLして解凍する（インストールはしない）
	- `helm pull <url or repo/chart> --untar`
- テンプレートとvaluesファイルからマニフェストを生成する。（releaseは作成しない。）
	- `helm template <manifest name> <template> --version <version> --values <file>`

# ▼CRD
- CustomResourceDefinitionのYAMLで独自のCustomResourceの仕様を定義する。CustomResourceのYAMLでCustomResourceを設定する。CRDのYAMLをapplyしてもCRを生成するわけではない。（クラスやインスタンスのような関係ではない）
- metadata.nameは `<plural name>.<group>` の形式にする。
- spec.groupとspec.versions.nameを結合したものがそのリソースのApiVersionとして扱われる。
- spec.versions[].servedでそのバージョンの有効無効を設定する。
- spec.versions[].storageでetcdに保存するバージョンを設定する。storage: trueにできるのは一つのバージョンだけ。代表的なバージョン？みたいな理解。
- spec.versions[].schema.openAPIV3SchemaでCustomResourceのプロパティを設定する。
- spec.scopeはNamespacedかCluster。
- spec.namesでplural/singular/kind/shortNamesを設定する。
- CRD一覧を取得する
	- `kubectl get crd`
- CRの一覧を取得する
	- `kubectl get <cr>`

# ▼API Version
- rbac.authorization.k8s.ioのv1alpha1をenableにする
	- 
`/etc/kubernetes/manifests/kube-apiserver.yaml` に `--runtime-config=rbac.authorization.k8s.io/v1alpha1` を設定する。

- deprecatedなAPI VersionのYAMLを更新してリソースを作成する
	- `kubectl convert -f <yaml> |kubectl create -f -`

# ▼Scheduling
## Affinity
- AffinityはNodeに付与されているビルトインノードラベルや自分で付与した独自ラベルを使って、ラベルベースに条件を最も満たすnodeにPodをSchedulingをする方式。
- Podのspec.affinityに設定する。
- spec.nodeSelectorは単純に、ラベルのkey/valueが一致するNodeにPodをSchedulingする。
- spec.affinity.nodeAffinityはrequiredDuringSchedulingIgnoredDuringExecutionを満たすかつ、preferredDuringSchedulingIgnoredDuringExecutionをなるべく満たすNodeにPodをSchedulingする。
- podAffinityはrequiredDuringSchedulingIgnoredDuringExecutionを満たすかつ、preferredDuringSchedulingIgnoredDuringExecutionをなるべく満たすPodが存在するドメイン（ノードかAZ）にPodをSchedulingする。topologyKeyでドメイン（ノードかAZ）を指定する。
- podAntiAffinityはrequiredDuringSchedulingIgnoredDuringExecutionを満たすかつ、preferredDuringSchedulingIgnoredDuringExecutionをなるべく満たすPodが存在しないドメイン（ノード、AZなど）にPodをSchedulingする。
- matchExpressionsのoperatorはIn/NotIn/Exists/DoesNotExist/Gt/Ltのいずれか。

## Taints&Toleration
- ノードにtaintsをつけておき、それをtolerationsできるPodのみをSchedulingする方式。
- taintsを付与する
    - `kubectl taint node <node> <key>=<value>:<effect>`
- taintsを削除する
    - `kubectl taint node <node> <key>=<value>:<effect>-`
- taintsを確認する
	- `kubectl describe node <node>`
- tolerationsはPodのYAMLに設定する。tolerationsはkubectlでは作成不可。
- effectはPreferNoSchedule（なるべくスケジュールしない）/NoSchedule（スケジュールしない）/NoExecute（スケジュールしないし、既にスケジュールされているPodは停止する。）のどれか。
    - NoScheduleとNoExecuteの場合は、「taintsのkey/value/effect」と「tolerationsのkey/value/effect」が一致する場合のみ、そのNodeにPodをSchedulingする。
    - PreferNoScheduleの場合は一致しなくても優先度は下がるが、Scheduling自体はする。

## PriorityClass
- SchedulingにおけるPodの優先度。kind: PriorityClassで作成する。
- valueが高いほど優先度は高い。
- 既にリソースの限界までSchedulingされている状態でpriorityの高いPodを作成しようとすると、priorityの低いPodは退避される。また、複数のPodがScheduling待ちの状態ではpritoriy順にソートされる。
- PodのYAMLのpriorityClassNameで紐づける。

## cordon/uncordon/drain
- ノードのSchedulingステータスを確認する
    - `kubectl get nodes`
- ノードにSchedulingされないようにする
    - `kubectl cordon <node>`
- ノードにSchedulingされるように戻す
    - `kubectl uncordon <node>`
- ノードにSchedulingされないようにするかつ、起動中のpodは別のノードに退避させる。
    - `kubectl drain <node> --force --ignore-daemonsets --delete-local-data`
    - 対象ノード上でReplicaSet経由でないPodが起動しているとエラーになるため `--force` をつける。 そのPodは削除される。
    - 対象ノード上でDaemonSet経由で作られたPodが起動しているとエラーになるため `--ignore-daemonsets` をつける。
- PodDisruptionBudgetでdrain時に全てのpodが停止しないようにminAvailable（podの最小起動数）を設定する。
    - 退避されずに残ったpodは、他のpodの退避が完了したら退避される。
    - selector.matchLabelsでラベルベースにPodDisruptionBudgetの対象のpodを指定する。
- cordonするとノードにtaintsが付く仕組み。ただし単なるtaintsではない。したがって、cordonしてもpodのtolerationsをうまく設定すればSchedulingされてしまうのではないかという心配はしなくてよい。

## リソースに関連するスケジューリング
- requests基準でCluster Autoscaleのスケジューリング判断を行う。
	- requestsが高すぎると実際の負荷がそうでもないのにCluster Autoscaleされてしまう可能性がある。
	- requestsがlimitsに対して低すぎると実際の負荷がかなり高いのにCluster Autoscaleしてくれない可能性がある。
	- requestsは高すぎず、limitsと大きく離れた値にしないこと。実際の設定値は負荷試験で見極めていく。
- Guranteed > Burstable > BestEffortの順で優先度が高い。
	- Guranteed
		- requests/limitsが同じでCPUとmemoryの両方が設定されている
	- Burstable
		- Guaranteedではないが1つ以上のrequests/limitsが設定されている
	- BestEffort
		- requests/limitsがどちらも未設定
- HPAはレプリカ数をCPU負荷などに応じて水平スケジューリングする機能。
	- 各podのCPU使用率の平均値がtargetAverageUtilization（閾値）より高ければスケールアウトし、低ければスケールインする。
	- スケジューリング判断のチェックは30秒に1回だが、スケーリング時のノイズを除去するために実際のスケールアウトは最大3分に1回、スケールインは最大5分に1回。
	- いくつにスケーリングするかは、各podのCPU使用率の合計値をtargetAverageUtilizationで割った結果になる。（小数点切り上げ）

## スケジューラその他
Podのspec.schedulerNameでschedulerを指定可能。

# ▼Monitoring&Observability
- 各Nodeのリソース使用状況を確認する
	- `kubectl top nodes`
- 各Podのリソース使用状況を確認する
	- `kubectl top pods`

# ▼kubeadmによるオンプレKubernetes環境の構築
## kubeadmのインストール
以下を全てのNode（control planeおよびdata plane）で実施する。

```
// k8s.confの設定
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
> br_netfilter
> EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
> net.bridge.bridge-nf-call-ip6tables = 1
> net.bridge.bridge-nf-call-iptables = 1
> EOF
sudo sysctl --system

// aptのupdate
sudo apt-get update
// 必要パッケージのインストール
sudo apt-get install -y apt-transport-https ca-certificates curl

// Google Cloudの公開鍵をダウンロード
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg

// Kubernetesのaptリポジトリを追加
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

// aptのupdate
sudo apt-get update
// kubelet, kubeadm, kubectlのインストール
sudo apt-get install -y kubelet=<version> kubeadm=<version> kubectl=<version>
// パッケージが更新されないようにする
sudo apt-mark hold kubelet kubeadm kubectl
```

## control planeのセットアップ
controle planeのNodeで以下を実行する。Flannelを使用する為、--pod-network-cidr=10.244.0.0/16を指定する。

`kubeadm init --apiserver-cert-extra-sans=controlplane --apiserver-advertise-address <ip eth0> --pod-network-cidr=10.244.0.0/16`

## data planeのセットアップ
### kubeadm join tokenの作成とjoinコマンドの出力
controle planceのNodeで以下を実行する。

`kubeadm token create --print-join-command`

### joinコマンドの実行（data planeのノードに入って実行）
data planeのNodeで以下を実行する。

`kubeadm join 10.33.92.10:6443 --token d3qmbz.wbotnx9alm0gbi4s --discovery-token-ca-cert-hash sha256:ffaddad5d14644d9ec0d421b729a17a17a80726d78b301521efb48fd9af719eb`

### flannel CNIのインストール
data planeのNodeで以下を実行する。

`kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.20.2/Documentation/kube-flannel.yml`

## 構築作業に失敗した場合
kubeadm initやkubeadm joinを実行する前の状態に戻す。
controle planceのNodeで以下を実行する。

`sudo kubeadm reset`

# ▼Clusterのバージョンアップ
## 現在のClusterのバージョンを確認する
`kubectl get nodes`

## アップグレート可否とアップグレード可能なバージョンを確認する
`kubeadm upgrade plan`

## 起動中のPodを別のNodeに退避させる
`kubectl drain <node> --force --ignore-daemonsets --delete-local-data`

##  アップグレードする
Nodeを1つずつアップグレードする。

### control planeのアップグレード
control planceのNodeで以下を実行する。

```
# kubeadmによるアップグレード
apt-get update
apt-get install kubeadm=<version>
kubeadm upgrade apply <version>

# kubeletのアップグレード
apt-get install kubelet=<version>
systemctl daemon-reload
systemctl restart kubelet
```

### data planeのアップグレード
data planeのNodeで以下を実行する。

```
# kubeadmによるアップグレード
apt-get update
apt-get install kubeadm=<version>
kubeadm upgrade node

# kubeletのアップグレード
apt-get install kubelet=<version>
systemctl daemon-reload
systemctl restart kubelet
```

# ▼etcd
## HA topology
### Stacked etcd topology
#### 概要
コントロールプレーンノードの内部にetcdを配置する構成。
セットアップやレプリケーションの管理がシンプルというメリットがある。
コントロールプレーンノードが故障するとetcdも故障するというデメリットがある。

#### 見分け方
`kubectl get pods -n kube-system` でetcdのミラーPodが存在すればStacked etcd topology。

#### バックアップ
作業はコントロールプレーンノード上で行う。
バックアップファイルは耐障害性の観点から別のストレージに移動した方がよい。

```
etcdを起動した際のオプションを確認する
kubectl describe pod <etcd> -n kube-system

スナップショットを取得する
ETCDCTL_API=3 etcdctl snapshot save <backup path> --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_API=3 etcdctl snapshot status <backup path> --write-out=table --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
```

#### リストア
作業はコントロールプレーンノード上で行う。
バックアップファイルがコントロールプレーンノード以外の場所にある場合は、事前にscpなどでコントロールプレーンノードに持ってくる。

```
ETCDCTL_API=3 etcdctl snapshot restore <backup path> --data-dir <data path>

/etc/kubernetes/manifests/etcd.yamlのvolumesのetcd-dataのpathを--data-dirで指定したデータベース保存先パスに置き換える。自動でrebootされる。
```

### External etcd topology
#### 概要
クラスターの外部にetcdを配置する構成。
コントロールプレーンノードそれぞれに対してetcdのホストが必要になるためインフラコストは増加する。

`ETCDCTL_API=3 etcdctl member list --endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/pki/ca.pem --cert=/etc/etcd/pki/etcd.pem --key=/etc/etcd/pki/etcd-key.pem` でetcdノードの数を確認する

#### 見分け方
kube-apiserverコマンドの--etcd-serversオプションで外部のサーバが指定されている場合はExternal etcd topology。
  
#### バックアップ
作業はetcdノード上で行う。
バックアップファイルは耐障害性の観点から別のストレージに移動した方がよい。

```
etcdを起動した際のオプションを確認する
ps -ef |grep etcd

スナップショットを取得する
ETCDCTL_API=3 etcdctl snapshot save <backup path>  --endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/pki/ca.pem --cert=/etc/etcd/pki/etcd.pem --key=/etc/etcd/pki/etcd-key.pem 

スナップショットを確認する
ETCDCTL_API=3 etcdctl snapshot status <backup path> --write-out=table --endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/pki/ca.pem --cert=/etc/etcd/pki/etcd.pem --key=/etc/etcd/pki/etcd-key.pem 
```
  
#### リストア
作業はetcdノード上で行う。
バックアップファイルがetcdノード以外の場所にある場合は、事前にscpなどでetcdノードに持ってくる。

```
ETCDCTL_API=3 etcdctl snapshot restore <backup path> --data-dir <data path>

/etc/systemd/system/etcd.serviceのvolumesのetcd-dataのpathを--data-dirで指定したデータベース保存先パスに置き換える。

systemctl daemon-reload
systemctl restart etcd
```

# ▼Static Pod
- Static Podはkube-apiserverを介さずにkubeletが直接管理するPodのこと。例えば、control planeで動いているkube-api-server/scheduler/controller-manager/corednsなど。
- kubeletは各Static Podに対応するmirror podを自動的にkube-apiserver上に作成するため、kubectl(kube-apiserver)で確認できる。
- `/etc/kubernetes/manifests` 配下にStatic PodのYAMLを配置する。このパスは、kubeletコマンドのconfigオプションで指定したconfigファイル内のstaticPodPathで変更可能。
	- このパスにPodのYAMLを配置すればStatic Podとして扱われる。つまり、自作のStatic Podを作成できる。当然ながらapplyは不要。
	- Static Podを削除する場合はこのYAMLファイルを削除する。単にpodを削除しても自動で復活してしまう。

# ▼その他
## テストハック系
- hostPathのPVのYAML例は公式ドキュメントで「PV hostpath」と検索するとでてくる。
- YAMLの設定項目を確認する
	- `kubectl explain <resource> --recursive | less`
	- 公式ドキュメントのYAMLの例が見当たらない場合や、YAMLを参考にしたのになぜかエラーになる場合はこれで確認する。
- 実際にはリソース作成せずにYAMLだけ作る
	- `kubectl run <pod name> --image <image> --dry-run=client -o yaml > <yaml>`
- editしても変更不可だった場合は/tmp配下にYAMLが自動生成される。そのファイルを--forceでapplyすれば変更できる。
  - editよりも `k get <resource> -o yaml > <yaml> `してそのyamlを編集してreplaceする方が速い。
- podのyamlを編集してapply（replace）したところ、変更不可だった場合は--forceする。
- ネットワーク繋がらない系問題の解き方
	- NetworkPolicyの問題
		- NetworkPolicyのspec.podSelectorで適切なPodのラベルが設定されているか
		- ルールが適切か
	- Ingressの問題
		- backendのnameとportは適切か
	- Serviceの問題
		- Serviceのspec.selectorで適切なPodのラベルを設定できているか（endpointsがserviceに設定されていない場合は特に怪しい）
	- Podの問題
		- Podの状態やログを確認する。imagePullBackOffやHealthCheckで落ちていないかなど。

## kubectl系
- 全てのnamespace
	- `kubectl get all -A`
- イベントを取得する
	- `kubectl get event -n <namespace>`
- リソース数を取得する
	- `kubectl get <resource> --no-headers | wc -l`
- 大雑把に全リソースを取得する
	- `kubectl get all`
- 全リソースを取得する
	- `kubectl api-resources`
	- 略称もこれで確認できる
- PersistentVolume関連はkubectlでは作成不可。

## kubectl結果からの抽出
- Node名の一覧を抽出
	- `kubectl get nodes -o jsonpath="{.items[*].metadata.name}"`
- PersistentVolumeを容量順にソート
	- `kubectl get pv --sort-by=.spec.capacity.storage`
- PersistentVolumeを容量順にソートして、カラムを絞った上でカラム名をつける。
	- `kubectl get pv --sort-by=.spec.capacity.storage -o=custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage`
- 特定kubeconfigの特定ユーザのコンテキスト名を取得する
	- `kubectl config view --kubeconfig my-kube-config -o jsonpath="{.contexts[?(@.context.user=='aws-user')].name}"`

## Linuxコマンド系
- OSを確認する
	- `cat /etc/os-release`
- grepで後10行も見たい
    - `| grep -A10`
- grepで前10行も見たい
    - `| grep -B10`

## ネットワーク系コマンド
- NIC確認
	- `ip a`
- ルーティング設定を確認
	- `ip route`
	- defaultがデフォルトゲートウェイ。
- 各プロセスのIPやポートなどを確認
	- `netstat -nplt`
	- nで名前解決しないでIPで表示。
	- pでプログラムやプロセス名を表示。
	- lでLISTENのものを抽出。
	- tでTCPのものを抽出。

## 頻出バグ原因
Image名が不適切、ポート番号が不適切、ラベルが不適切、ファイル名が不適切、コマンドが不適切、Podの権限不足（RoleやRoleBindingの不備、ServiceAccountNameが設定されていない）、通信が通らない