【Kubernetes】リソース整理メモ

(アホなので)各用途でリソースが何だったかわからなくなる…のでまとめた。
v1.31時点

# ワークロードリソース
## Deployment
ReplicaSetを管理してローリングアップデートやロールバックを実現する。
```yaml:deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  selector:
    matchLabels:               #templateセクションの設定が自動設定
      app: my-nginx
  strategy:
    type: RollingUpdate        #1podずつ更新する
  replicas: 3                  #pod数
  template:                    #podの仕様
    metadata:
      labels:                  #ここに設定したラベルがselectorにも適用されることでグループ化
        app: my-nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx
        imagePullPolicy: IfNotPresent       #ローカルでイメージが見つからない場合にのみイメージをpullする。
        ports:
        - containerPort: 80
```
たとえば"httpd-frontend"という名前のdeploymentをデプロイすると、
"httpd-frontend-5f494775df"という名前のreplicasetが作られ、
"httpd-frontend-5f494775df-random1"
"httpd-frontend-5f494775df-random2" というように-で枝分かれしたpodが作られる
一般的なユーザーリソースの他、
k8sのデフォルトのリソースとしては`CoreDNS`などで使用されている。


### RollingUpdate
deploymentのreplicasの数をeditで変えるとreplicasetの数も同時に変更される。※逆は不可
マニフェストの内容としてはkind以外はreplicasetと同じ
strategyは`RollingUpdate`で1podずつ更新。`Recreate`は全pod一気に削除→再作成

### imagePullPolicy
`IfNotPresent`: ローカルでイメージが見つからない場合にのみイメージをpullする。imagePullPolicy のタグが省略されていて、利用してるイメージのタグはあるが:latestでない場合にも適用される。

`Always`: kubeletがコンテナを起動する度に、コンテナイメージレジストリに問い合わせて、イメージのダイジェストの名前解決を行う。もし同じダイジェストのコンテナイメージをローカルにキャッシュしていたら、そのキャッシュされたイメージを利用する。そうでなければ、解決されたダイジェストのイメージをダウンロードし、そのイメージを利用してコンテナを起動する。imagePullPolicy のタグが省略されていて、利用しているイメージのタグが:latestの場合や省略されている場合にも適用される。

`Never`: 常にローカルでイメージを探そうとする。ない場合にもイメージはpullしない

## Daemonset

```yaml:daemonset
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: elasticsearch
  name: elasticsearch
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: elasticsearch    #templateのラベルと一致させる
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - image: registry.k8s.io/fluentd-elasticsearch:1.20
        name: fluentd-elasticsearch
```
数関係なくWorkerNodeに1ずつたてるpod
ワーカーノードを管理するデーモンをpodで動作させたい場合に使用
システムリソースのモニタリングツールやログ収集(fluentd)など。ノードが消えるとpodもそのまま消える。

代表的なものには、以下のようなコンポーネントがある
```
1. Node Exporter（Prometheus用）
Prometheusによって各ノードのメトリクスを収集するために使用されるエージェント。システムのリソース使用状況（CPU、メモリ、ディスクなど）をモニタリングする

2. Fluentd（またはその他のログ収集エージェント）
ログデータを集約し、中央のログ集約システム（例：Elasticsearch、Splunk）に送信するためのエージェント。ノード上のすべてのコンテナのログを収集できる

3. Node Problem Detector
ノードの健康状態を監視するためのコンポーネント。ノードのハードウェアやオペレーティングシステムレベルの問題を検出できる

4. Kube-proxy
Kubernetesのネットワークプロキシで、サービスのエンドポイント間の通信を管理する。主要な役割は、ネットワークトラフィックを適切なサービスエンドポイントにルーティングすること

5. CNIプラグイン（例えば、Cilium、Weave Net、Calico）
CNI（Container Network Interface）プラグインは、コンテナ間のネットワークを管理するために使用されるネットワークプラグイン。pod間の通信を制御・管理

6. ログ収集ユーティリティ（例：fluent-bit, logdna-agent）
これらのエージェントは、各ノードからログデータを収集し、集中管理するために使用される。

7. システムメトリクスコレクター（例：metrics-server）
metrics-serverは、クラスタ内の各ノードからシステムメトリクスを収集し、Kubernetes APIサーバに提供するエージェント
```

## Staticpod
通常の方法でDeploymentやReplicaSetなどkube-apiserverを介して各コントローラーで処理されるのではなく、コントロールプレーンの影響を受けずに特定のノードのkubeletプロセスによってのみ直接管理・処理されるpod
そのため、
・そもそもコントロールプレーンのコンポーネントをデプロイするのに使用されている
・両者ともkube-schedulerからは無視される
```
#コマンドでのデプロイ
kubectl run --restart=Never --image=busybox:1.28.4 static-busybox --dry-run=client -o yaml --command -- sleep 1000 > /etc/kubernetes/manifests/static-busybox.yaml
```
Static Podの名前には末尾に"-node名"が付く。
kubeletが監視している特定のディレクトリ（デフォルトでは `/etc/kubernetes/manifests`）に配置される
※定義ファイルの場所は各ノードのkubelet設定ファイル `/var/lib/kubelet/config.yml` の `staticPodPath:` で確認できる

```
#デフォルトでデプロイされているstaticpod群（例）↓：

/etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/kube-controller-manager.yaml
/etc/kubernetes/manifests/kube-scheduler.yaml
/etc/kubernetes/manifests/etcd.yaml
```

これらのStatic Podマニフェストファイルを編集することで、直接これらのコンポーネントの設定を変更することができる。Kubeletはこのディレクトリを監視しており、ファイルの変更を検知すると対応するPodを再作成し、ファイルが削除されるとpodを終了させる。


## sidecarコンテナ
同じPod内でメインのアプリケーションコンテナと一緒に動作する補助的なコンテナ。
起動したコンテナはCompletedで終了せずメインコンテナと並んで稼働し続ける。
```yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: alpine:latest
          command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
          volumeMounts:
            - name: data
              mountPath: /opt
      initContainers:
        - name: logshipper
          image: alpine:latest
          restartPolicy: Always
          command: ['sh', '-c', 'tail -F /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      volumes:
        - name: data
          emptyDir: {}
```

# Networkリソース

## ClusterIP
デフォルトのサービスタイプで、クラスタ内の内部トラフィックのみが対象
・クラスタ内部トラフィック用の仮想IPを提供
・外部からのアクセスはできない
・クラスター内部の通信に使用される

Serviceリソースに振られるNWは
`/etc/kubernetes/manifests/kube-apiserver.yaml`
の`   - --service-cluster-ip-range=10.96.0.0/12`
で確認できる。


```yaml:
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: ClusterIP
  ports:
    - port: 8080          #serviceが受け付けるport
      targetPort: 80      #podがリッスンしているport
  selector:               #ServiceがトラフィックをどのPodにルーティングするかを決定
    app: webapp
```

podのmetadata.labels: に`app: webapp`
と設定されているものだけが対象になる。
対象になったpodのアドレスがEndpointとして表示される

コマンドで設定したい場合は以下
```
# podを指定してデプロイ(svcが受け付けるportを6379で指定)
kubectl expose pod redis --port=6379 --name redis-service

# podデプロイ+ClusterIP(podと同じ名前のsvcが一緒にデプロイされる)
kubectl run httpd --image=httpd:alpine --port=80 --expose
```

クラスタ内部からアクセスできる
```
http://<ClusterIP>:8080

# 同namespaceからのリソースであれば、coreDNSに登録されているためサービス名でもアクセスできる
http://<SERVICENAME>:8080
```

## NodePort
開放した各クラスタノードの特定のポートを通じて外部トラフィックをサービスにルーティング
・クラスタ外部からアクセスできる
・ノードのIPアドレス上の指定ポートにアクセス
デプロイすると自動的にClusterIPも払い出される
```yaml:
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: NodePort
  ports:
    - port: 8080        #Serviceのport
      targetPort: 80    #Podが受け付けるport
      nodePort: 30080   #外部アクセス用のport.指定なしだと30000〜ランダムで割り振られる
  selector:
    app: webapp
```
アクセス(クラスタ外部から)
```
http://<NodeIP>:30080
```
get出力例
```
NAME             TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
webapp-service   NodePort   10.43.80.67   <none>        8080:30080/TCP   10m
```
`CLUSTER-IP`: 10.43.80.67 は自動的に割り当てられたClusterIP
`PORT(S)`: 8080:30080/TCP は、ClusterIPのポート(8080)と、各ノードのNodePort(30080)を示す

## ExternalIP
特定の外部IPから直接アクセスを受ける必要がある場合、特定のノードIPを外部トラフィックのエントリーポイントとして使用する
・外部のIPアドレスをノードに直接マッピングして、外部トラフィックを特定のサービスにルーティング
・ClusterIPと連携して外部からアクセスを提供

タイプがあるわけではなく、ClusterIPのマニフェストに`spec.externalIPs`を追加する。

```yaml:
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: ClusterIP
  externalIPs:
  - 192.168.1.100      #ノードのIPアドレスをマッピング
  ports:
    - port: 8080
      targetPort: 80
  selector:
    app: webapp
```
アクセス方法（外部から指定されたExternalIP）
```
http://192.168.1.100:8080
```
Clientからexternal IPに対して疎通ができなければならないため、あまり使われていない。
↓LoadBalancerのMetalLBでは external IPの仕組みをうまく使って通信を実現している。

## LoadBalancer
外部ロードバランサーを利用し、外部トラフィックをクラスタ内のサービスにルーティングする。
・クラウドプロバイダー(AWSなど)が外部ロードバランサーをプロビジョニングし、設定を管理
・自動的に負荷分散IPが割り当てられる
・ロードバランサーが転送する先のNodePortとClusterIP Serviceが自動的に作成される
```yaml:
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: LoadBalancer
  ports:
    - port: 8080
      targetPort: 80
  selector:
    app: webapp
```
アクセス方法(クラウドプロバイダーによる外部IP)
```
# クラウドプロバイダーが割り当てた外部IPアドレスでアクセス
http://<LoadBalancerIP>:8080
```
serviceとしてはEXTERNAL-IPにクラウドプロバイダから割り当てられたアドレスが入る
```
$ kubectl get svc
NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)          AGE
service-loadbalancer      LoadBalancer   192.168.66.72   129.X.X.X         8080:30334/TCP   115m
```

なお、オンプレミスで使いたい場合、外部プロバイダーの代わりにMetalLBをデプロイすることでEXTERNAL-IPを払い出すことができる。

### MetalLB
Kubernetes環境の通信の負荷分散をする場合、クラウドでしか利用できないLoadBalancerタイプのServiceリソースをオンプレ環境でも利用できるようにする機能。

あらかじめユーザーで指定した範囲のIPアドレスプールからLoadBalancer ServiceにIPアドレスを割り振って、そのIPアドレスを周辺の機器に周知する。 クラウドのロードバランサーのようにグローバルIPが割り当てられることは基本的にはない

周知に使うプロトコルはMetalLBのモードによって異なる。

`L2モード`
・MetalLBがARP(IPv4)とNDP(IPv6)で、クライアントに対して仮想IPアドレスを解決する
・ロードバランシングはしないため、ノードダウンしない限り常に一定のリーダーノードにトラフィックが来る

`BGPモード`
・MetalLBがBGPをしゃべって、外部のBGPルータとBGP peeringして仮想IPアドレスへのルーティング情報を伝える。 
・ルータ側の設定によってノード間でロードバランシングが可能
・Kubernetesクラスタ外にBGPルータが必要

https://metallb.io/

```yaml:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: internalapi
  namespace: metallb-system
spec:
  addresses:
    - 192.168.0.20 - 192.168.0.100   #ロードバランサーへ割り当てるアドレス。レンジで指定するほか、/24のCIDR指定でも可
  autoAssign: true
  avoidBuggyIPs: false
```

```yaml:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: internalapi
  namespace: metallb-system
spec:
  ipAddressPools:
  - internalapi                      #AddressPoolを指定
  interfaces:
  - ens1f0                           #使用するIFを指定。
```
この設定で、
192.168.0.20から192.168.0.100までのIPアドレスがens1f0IF経由で同じL2NW上の他のデバイスやホストに対して広告される。
この状態でLoadBalancerTypeのサービスをデプロイすると、指定したレンジからEXTERNAL-IPが割り当てられる

## Ingress
複数のHTTPおよびHTTPSルータを定義し、クラスタ内の異なるサービスにトラフィックをルーティング
・ドメイン名やパスを基にしたルーティング
・SSL/TLS終端を管理できる

```yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /         #リクエストパスを指定したターゲットにリライトする。例えば、リクエストが/wear/somethingの場合、このリクエストは/somethingにリライトされてwear-serviceに送られる。
    nginx.ingress.kubernetes.io/ssl-redirect: "false"     #HTTPリクエストをHTTPSにリダイレクトするが、falseに設定されていると無効になる
  name: ingress-wear-watch
  namespace: app-space
spec:
  rules:
  - http:
      paths:
      - backend:
          service:
            name: wear-service                            #アプリケーションのserviceを指定
            port:
              number: 8080                                #serviceが受け付けるport
        path: /wear                                       #URLにつけるpath
        pathType: Prefix                                  #例えば、path: /wearと指定した場合、/wear, /wear/, /wear/somethingのようなパスにマッチする。
      - backend:
          service:
            name: video-service
            port:
              number: 8080
        path: /watch
        pathType: Prefix
```

アプリ例
```yaml:
apiVersion: v1
kind: Service
metadata:
  name: wear-service
  namespace: app-space
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: webapp-wear
  type: ClusterIP
```

```yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-wear
  namespace: app-space
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp-wear
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: webapp-wear
    spec:
      containers:
      - image: kodekloud/ecommerce:apparels
        name: simple-webapp
        ports:
        - containerPort: 8080
          protocol: TCP
```



アクセス(DNSが設定された場合)
```
http://webapp.example.com/wear
http://webapp.example.com/watch
```

### Ingress Controller
Ingressリソースは単なるルールの定義なので、実際のトラフィックルーティングを行うにはそれらのルールを実行するためのコンポーネント(Ingressコントローラ)が必要
#有名なIngressコントローラには以下のようなものがあり、URLから引っ張ってきてデプロイする
```
・NGINX Ingress コントローラ
・Traefik
・HAProxy
・Envoy
・Istio（サイドカープロキシとIngressゲートウェイとして）
```

Deployment/service例
```yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.1.2
    helm.sh/chart: ingress-nginx-4.0.18
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
        - --election-id=ingress-controller-leader
        - --watch-ingress-without-class=true
        - --default-backend-service=app-space/default-backend-service
        - --controller-class=k8s.io/ingress-nginx
        - --ingress-class=nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/cert
        - --validating-webhook-key=/usr/local/certificates/key
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image: registry.k8s.io/ingress-nginx/controller:v1.1.2@sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          name: https
          protocol: TCP
        - containerPort: 8443
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 101
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        kubernetes.io/os: linux
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: ingress-nginx
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
      - name: webhook-cert
        secret:
          defaultMode: 420
          secretName: ingress-nginx-admission
```

Service確認
```
k get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    172.20.43.138    <none>        80:30080/TCP,443:32103/TCP   9m48s
ingress-nginx-controller-admission   ClusterIP   172.20.165.224   <none>        443/TCP                      9m48s
```
```yaml:
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.1.2
    helm.sh/chart: ingress-nginx-4.0.18
spec:
  externalTrafficPolicy: Local
  internalTrafficPolicy: Cluster
  ports:
  - appProtocol: http
    name: http
    nodePort: 30080
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    nodePort: 32103
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: NodePort
```

```yaml:
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller-admission
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.1.2
    helm.sh/chart: ingress-nginx-4.0.18
spec:
  internalTrafficPolicy: Cluster
  ports:
  - appProtocol: https
    name: https-webhook
    port: 443
    protocol: TCP
    targetPort: webhook
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  sessionAffinity: None
  type: ClusterIP
```

## multus
Multusは2つ以上のCNIのNetwork InterfaceをPodへアタッチする仕組み。
接続するネットワークを`NetworkAttachmentDefinition`(もしくは`net-attach-def`)というCustom Resourceとして表現する。基本的に連携するCNIに依存している

```yaml:
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-net
  namespace: namespace01
spec:
  config: |
    {
      "cniVersion": "0.3.1",
      "name": "macvlan-net",             #CNIプラグイン内で参照されるものであり、Podのアノテーションで設定する対象ではない
      "type": "macvlan",                 #CNIプラグインのタイプを指定
      "master": "eth0",                  #どの物理ネットワークインターフェースを基に仮想ネットワークを生成するかを定義
      "ipam": {
        "type": "whereabouts",           #IPAMプラグインを指定.他にはstatic,dhcp,host-local,azure-vnet-ipamなど
        "range": "172.16.0.0/24",
        "range_start": "172.16.0.30",
        "range_end": "172.16.0.70"
      }
    }
```
### CNIプラグインのtype
`bridge`: 一般的なネットワークブリッジを作成して、複数のコンテナを同じネットワークセグメントに接続。ホストにもvethペアの片側が残る。
`ipvlan`: IPアドレスを共有する複数のNWIFを作成する。物理IFと同じMACアドレスを共有する
`loopback`: コンテナ内のループバックデバイスを設定する。主にネットワークのテストやローカルアクセスに使用
`macvlan`: 物理IFを基に仮想NWIFを作成し、各仮想IFに独立したMACアドレスを割り当てる
`ptp`: Point-to-Point接続を使用してコンテナを物理ネットワークに接続(veth pair)
`host-device`: ホストのネットワークデバイスをコンテナに直接割り当てる。特殊なネットワーク設定が必要な場合に使用

### pod例
```yaml:
apiVersion: v1
kind: Pod
metadata:
  name: multus-pod01
  namespace: namespace01
  annotations:
    k8s.v1.cni.cncf.io/networks: '[
    {
      "name": "macvlan-net",
      "ips": [ "172.16.0.31/24" ]
    }
    ]'
spec:
  containers:
  - name: centos-tools
    image: docker.io/centos/tools:latest
    command:
    - /sbin/init
    securityContext:
      privileged: true

```
２つ目のIFがついていることを確認
```
kubectl exec -it multus-pod01 -- ip a
```

## coredns
`kube-dns`というserviceと`coredns`というdeploymentで構成されており、クラスタ内のリソースを名前解決してくれる。同namespaceであればPod名 or Service名で通信できる。
別のnamespaceへは`Service名.NameSpace名(.svc or .svc.デフォルトドメイン)`で通信できる。
名前解決確認例
```
・名前解決用のpodデプロイ 1hスリープさせてバックグラウンドで実行させることでコマンド実行
# kubectl run test-pod --image=busybox --restart=Never -- sleep 3600
# kubectl exec test-pod -- nslookup my-service.default.svc.cluster.local
サービス名だけでもOK

podの場合は
# kubectl exec test-pod -- nslookup 10-50-192-4.default.pod.cluster.local
```


適用されているconfigmapでdns設定を確認できる。


# Storageリソース
## PV作成(static)
```yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-log
 #labels:
   #type: log-storage                     #PVCで直接このPVを指定したい場合、ラベル付与
spec:
  persistentVolumeReclaimPolicy: Retain   #PVCが削除された後、PVがどのように扱われるかを制御するポリシー(Retain=そのまま残る,Delete=ボリュームもボリューム内のデータも削除)
  accessModes:
    - ReadWriteMany                       #ボリュームは複数ノードで読み書き可。ReadWriteOnce=単一ノードによって読み書き可、ReadOnlyMany=複数ノードで読み取り専用
  capacity:
    storage: 100Mi
  hostPath:                               #node上の領域を使用する
    path: /pv/log                         #node上の/pv/logを使う
```
```
# kubectl get pv -o wide
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE   VOLUMEMODE
pv-log   100Mi      RWX            Retain           Bound    default/claim-log-1                  <unset>                          16m   Filesystem
```

## PV作成(自動)
StorageClassを作成する。
PVCに伴って自動でPVが作成される。動的プロビジョニング
```yaml:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: volume-sc
provisioner: kubernetes.io/portworx-volume         #プロビジョナー(kubernetes.io/no-provisioner = local手動管理で動的プロビジョニングをサポートしていない)。外部ストレージなら/aws-ebsや/azure-diskなど
allowVolumeExpansion: true                         #ボリュームの拡張を許可
volumeBindingMode: WaitForFirstConsumer            #PVとPVCのバインディングの振る舞いを制御.PVC作成→PV作成ではなく、PVCを使用するPodが作成されるのを待機。(Immediate = PVC作成→すぐPV作成)
```

## PVC作成
作成されると、クラスタ上で要件(accsessmodeや容量)に一致するPVを探し、自動的にバインドする。(複数PVが一致する場合は、容量の大きいものから使われる)
StorageClassを指定した場合はBindingModeに応じてPVが作成される
```yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim-log-1
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Mi
 #selector:
   #matchLabels:
     #type: log-storage                   #ラベル付きのPVを直接指定する場合
 #volumeName: pv-log                      #直接PV名を指定でも可
  storageClassName: volume-sc             #StorageClassを指定する場合.SCのbindingmodeにより即時またはPVC呼び出し時にPV作成
```

```
# kubectl get pvc -o wide
NAME          STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
claim-log-1   Bound    pv-log   100Mi      RWX                           <unset>                 11m   Filesystem
```
PVがない場合、STATUSはPendingになる

Podで利用
```yaml:
apiVersion: v1
kind: Pod
metadata:
  name: webapp
spec:
  containers:
  - name: event-simulator
    image: kodekloud/event-simulator
    env:
    - name: LOG_HANDLERS
      value: file
    volumeMounts:
    - mountPath: /log
      name: log-volume

  volumes:
  - name: log-volume
    persistentVolumeClaim:
      claimName: claim-log-1
   #hostpath:                        #nodeの領域を使う.シングルノードや一時利用専用
   #  path: /data                    #node上の/dataを使う
   #  type: directory                #/dataはディレクトリで存在する必要がある
```

### PVCを削除した場合
ReclaimPolicyが`Retain`の場合、PVCを削除すると...
```
# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Bound    default/claim-log-1                  <unset>                          17m
# 
# kubectl get pvc
NAME          STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Bound    pv-log   100Mi      RWX                           <unset>                 3m9s
# 
# kubectl delete pvc claim-log-1
persistentvolumeclaim "claim-log-1" deleted
#
# kubectl get pvc
NAME          STATUS        VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
claim-log-1   Terminating   pv-log   100Mi      RWX                           <unset>                 6m59s
#
# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Bound    default/claim-log-1                  <unset>                          21m


podがpvcを呼び出しているため、terminatingになる.PVは残るが、使用できない
podを削除↓
# kubectl delete pod webapp
pod "webapp" deleted
#
# kubectl get pvc
No resources found in default namespace.
#
# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-log   100Mi      RWX            Retain           Released   default/claim-log-1                  <unset>                          25m
```
pvcを呼び出しているpodが消えるとpvcも削除される。pvは残っており、STATUSは`Released`になっている


# スケジューリングを制御するリソース
## drain/cordon
ノード再起動や一時的なメンテナンス用

drain = 指定したノードからpodを退避する
cordon = 指定したノードへのスケジューリングを無効にする
```
kubectl drain host03 --ignore-daemonsets --delete-local-data --force
```
`--ignore-daemonsets`: DaemonSet で管理されている Pod は退避の対象外
`--delete-local-data`: ノード上のローカルストレージを使用している Pod を強制的に削除
`--force`: 静的 Pod を強制的に削除

drainすると自動でcordonも設定される
```
#設定
kubectl cordon host03

#解除
kubectl uncordon host03
```
ノードに`SchedulingDisabled`というステータスがつく
ノード上の既存のPodはそのまま継続して実行されるが、それ以上新しいPodがスケジュールされることはない
taint/tolerationが一致していたとしても`SchedulingDisabled`の方が優先される。

## taint/toleration
ノードの役割管理、特定の用途に対するノードの使用制限用途
特定のノードには特定のポッドしかスケジュールしないようにしたい場合(高性能ノードを特定のワークロード専用にする等)

`taint` = ノードにカスタムラベルを付与し、設定した条件を満たさない場合にスケジュールさせない
`toleration` = Podへ設定することで選択的にtaintされたノードにスケジュールする

ノードにtaint付与
```
#設定
kubectl taint nodes host03 key=value:NoSchedule

#解除
kubectl taint nodes host03 key-
```
`NoSchedule`: このtaintを持つノードにPodをスケジュールできない
`PreferNoSchedule`: なるべくこのノードにPodをスケジュールしないようにする
`NoExecute`: すでにノード上で動作しているPodも追い出し、再配置

```yaml:podにtoleration設定
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mycontainer
    image: nginx
  tolerations:
  - key: "key"
    value: "value"
    operator: "Equal"     #keyとvalueの両方が一致する場合に許容."Exists"=keyが存在する場合に許容。つまりvalueはなくても通る
    effect: "NoSchedule"
```

後述のAffinity設定との差異としては、ノードに対して直接設定されるため、全てのpodに対して適用される

## Affinity
こちらはノードにラベルを付与して指定する方法
同じ種類のpodを異なるノードに分散して配置する等で、単一のノード障害時の影響を最小化する場合

Podに適用され、どのノードにスケジュールされるかを制御
affinity設定に基づき、スケジューラーはpodを特定のlabelを持つノードに優先的に配置する


ノードにラベル付与
```
#ラベル付与
kubectl label node node01 color=blue

#確認
kubectl get node --show-labels
```

nodeSelectorまたはnodeAffinityでlabelのついたnodeにのみデプロイされるようにする
```yaml:podに設定(ノードセレクタ)
    spec:
      containers:
      - image: nginx
        name: nginx
      nodeSelector:
        color: blue
```

```yaml:podに設定(ノードアフィニティ)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue
  labels:
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
      affinity:
       nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
           - matchExpressions:
              - key: color
                operator: In
                values:
                 - blue
```
operatorは
`"Exists"`: keyに対する値が存在する場合に一致する（value値はなくてもよい）
`"In"`: keyに対する値が指定したvaluesの一部と一致する場合に一致する。（valueが必須）


# Securityリソース

## NetworkPolicy
リソース単体でACLをかけたい場合
```yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: internal-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      name: internal
  policyTypes:
  - Egress
  - Ingress
  ingress:
    - {}
  egress:
  - to:
    - podSelector:
        matchLabels:
          name: mysql
    ports:
    - protocol: TCP
      port: 3306

  - to:
    - podSelector:
        matchLabels:
          name: payroll
    ports:
    - protocol: TCP
      port: 8080

  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
```

## Role
特定の名前空間内でアクセス制御を定義
リソースへのアクセス権限（例えば、読み取り、書き込み、削除など）を指定

```
# kubectl create role my-role --namespace=mynamespace --verb=get,list,watch,create,update,delete --resource=pods,services
```

```yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: mynamespace
  name: pod-reader
rules:
- apiGroups: [""]             #コアAPIグループ(v1)の範囲。kubectl api-resources で確認
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
```

## RoleBinding
特定のnamespace内で、Role または ClusterRole をユーザー、グループ、またはサービスアカウントに関連付ける。
```
# kubectl create rolebinding my-rolebinding --namespace=mynamespace --role=my-role --user=my-user
```
```yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: mynamespace
subjects:
- kind: User                  #Group や ServiceAccount も指定できる
  name: jane                  #kubectl get pod --as=jane でなりすまして実行確認できる
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader            #roleリソース名を指定して紐づけ
  apiGroup: rbac.authorization.k8s.io
```

権限確認は以下コマンドで行える
my-userによるhoge-ns上でservice作成ができるか
```
kubectl auth can-i create services --as=my-user -n=hoge-ns
```
yesかnoが返ってくる。

## ClusterRole
クラスタ全体でアクセス制御を定義。namespaceに限定されないため、クラスター全体のリソースに対するアクセス権限を付与できる。

```yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-admin
rules:
- apiGroups: ["*"]             #すべてのAPIグループ
  resources: ["*"]             #すべてのリソース
  verbs: ["*"]                 #すべての動作。つまりこれはフルアクセスになる
```

## ClusterRoleBinding
クラスタ全体で、ClusterRole をユーザー、グループ、またはサービスアカウントに関連付ける。

```yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-binding
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
```

## ServiceAccount
podからの通信に使用するアカウント。podをdescribeすると使用されているアカウントを確認できる。

アカウント作成
```
# kubectl create sa testsa
```

role、rolebindingで権限付与し、deploymentで指定
```yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: default
spec:
  selector:
    matchLabels:
      name: web-app
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: web-app
    spec:
      serviceAccountName: testsa
      containers:
      ...
```

# 情報を別出しするリソース
マニフェストファイルが似ており、どちらも用途としては同じ。

## Configmap
```yaml: 
apiVersion: v1
data:
  APP_COLOR: darkblue              # 格納する KEY: VALUE
  APP_OTHER: disregard
kind: ConfigMap
metadata:
  name: webapp-config-map          # ConfigMap名。適用時に使用する
  namespace: default
```

podに適用(環境変数)
```yaml:
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: webapp-color
  name: webapp-color
  namespace: default
spec:
  containers:
  - env:
    - name: APP_COLOR
      valueFrom:
        configMapKeyRef:
         name: webapp-config-map     # この値を取得するConfigMap名
         key: APP_COLOR              # 取得するKEY
    image: webapp
    imagePullPolicy: Always
    name: webapp-color
```

podに適用(ボリュームマウント)
```yaml:
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: webapp-color
  name: webapp-color
  namespace: default
spec:
  containers:
  - name: webapp-color
    image: webapp
    imagePullPolicy: Always
    volumeMounts:
    - mountPath: /etc/config         # マウントするパスを指定
      name: config-volume
  volumes:
  - name: config-volume
    configMap:
      name: webapp-config-map        # このConfigMapからデータを取得
```

Podが起動すると、ConfigMapの各キーは指定されたディレクトリ内にファイルとして表示される。
```
/etc/config/
├── APP_COLOR     #ファイルの内容は darkblue
└── APP_OTHER     #ファイルの内容は disregard
```



## Secret
機密情報(パスワード、OAuthトークン、SSHキーなど)を保存するためのリソース
Pod内のコンテナにマウントされ、アプリケーションが機密情報に安全にアクセスできるようにする。
マニフェストの場合、値ベタ書きだとダメ。base64エンコードが必要

```
# echo -n "XXX" |base64
```

```yaml:
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:                                # stringDataというフィールドにすればエンコード不要。作成後に自動でエンコードされた値が入る
  DB_Host: c3FsMDE=                  # base64エンコードされた値を入れる.sql01
  DB_User: cm9vdA==                  # root
  DB_Password: cGFzc3dvcmQxMjM=      # password123
```
以下でも作成できる。--from-literalでOpaque形式。エンコードは不要
```
# kubectl create secret generic --from-literal=DB_Host=sql01 --from-literal=DB_User=root --from-literal=DB_Password=password123
```

pod適用(環境変数利用)

```yaml:
apiVersion: v1
kind: Pod
metadata:
  name: db-pod
spec:
  containers:
    - name: app-container
      image: mysql
      env:
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_Host
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_User
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_Password
```

pod適用(ボリュームマウント)
```yaml:
apiVersion: v1
kind: Pod
metadata:
  name: db-pod
spec:
  containers:
  - name: app-container
    image: mysql
    command:
     - sleep
     - "4800"
    volumeMounts:
    - name: secret-volume             # ボリュームの名前
      mountPath: /etc/db-secret       # マウントするパス
      readOnly: true                  # 読み取り専用
  volumes:
  - name: secret-volume               # ボリュームの定義
    secret:
      secretName: db-secret           # 使用するSecretの名前
```

Podが起動すると、ConfigMapの各キーは指定されたディレクトリ内にファイルとして表示される。
内容はデコード済みの値(DB_Hostならsql01)
```
/etc/db-secret/
├── DB_Host
├── DB_User
└── DB_Password
```

# LivenessProbeとReadinessProbe
`livenessProbe`: コンテナの生存確認。このプローブが失敗すると、Kubernetesはコンテナを再起動する
`readinessProbe`: コンテナの準備確認。トラフィックの受け入れ可能かどうかを確認。このプローブが失敗すると、コンテナはServiceから取り除かれる。

## 設定方法
.spec.containersのセクションの下に設定する

・HTTP プローブ：特定のエンドポイントにHTTPリクエストを送信
```yaml:
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 5
    readinessProbe:
      httpGet:
        path: /ready
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
```
・TCP ソケットプローブ：特定のポートがオープンかどうかを確認
```yaml:
    livenessProbe:
      tcpSocket:
        port: 6379
      initialDelaySeconds: 15
      periodSeconds: 10
    readinessProbe:
      tcpSocket:
        port: 6379
      initialDelaySeconds: 10
      periodSeconds: 10
```
・コマンドプローブ：指定されたコマンドを実行し、終了コードを確認
```yaml:
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
    readinessProbe:
      exec:
        command:
        - cat
        - /tmp/ready
      initialDelaySeconds: 5
      periodSeconds: 5
```

# ETCDについて
Kubernetesクラスター内での設定情報や状態情報を保存するために広く使用されている、オープンソースの分散データストア

## etcd-podの引数

```:k describe pod etcd-controlplane -n kube-system
etcd
      --advertise-client-urls=https://192.168.63.164:2379
      --cert-file=/etc/kubernetes/pki/etcd/server.crt  ★
      --client-cert-auth=true
      --data-dir=/var/lib/etcd
      --experimental-initial-corrupt-check=true
      --experimental-watch-progress-notify-interval=5s
      --initial-advertise-peer-urls=https://192.168.63.164:2380
      --initial-cluster=controlplane=https://192.168.63.164:2380
      --key-file=/etc/kubernetes/pki/etcd/server.key  ★
      --listen-client-urls=https://127.0.0.1:2379,https://192.168.63.164:2379  ★
      --listen-metrics-urls=http://127.0.0.1:2381
      --listen-peer-urls=https://192.168.63.164:2380
      --name=controlplane
      --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
      --peer-client-cert-auth=true
      --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
      --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
      --snapshot-count=10000
      --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt  ★

★は後述のバックアップコマンドに使用する
```
`--advertise-client-urls=https://192.168.63.164:2379:`
クライアント（他のサービスやアプリケーション）が接続するための URL をアドバタイズする。ここでは、接続先として https://192.168.63.164:2379 を指定

`--cert-file=/etc/kubernetes/pki/etcd/server.crt:`  ★
etcd サーバーがクライアントに提供するサーバー証明書のファイルパスを指定。TLS/SSL 通信の際に使用される。
秘密鍵(--key-file)と共に使用される。

`--client-cert-auth=true:`
クライアント証明書認証を有効にするオプション。これを有効にすると、クライアントは有効な証明書を提供しなければならない。

`--data-dir=/var/lib/etcd:`
etcd のデータを保存するディレクトリを指定。ここでは /var/lib/etcd がデータディレクトリと設定されている。

`--experimental-initial-corrupt-check=true:`
etcd サーバーが起動時にデータの整合性チェックを行うオプション。

`--experimental-watch-progress-notify-interval=5s:`
ウォッチの進行状況更新の通知間隔を指定。ここでは 5 秒ごとに通知が行われる。

`--initial-advertise-peer-urls=https://192.168.63.164:2380:`
etcd クラスタ内の他のメンバーに対する広告 URL を指定。

`--initial-cluster=controlplane=https://192.168.63.164:2380:`
初期クラスタの構成を定義。この例では、クラスタには controlplane というメンバーが https://192.168.63.164:2380 でアドバタイズされていることを示す。

`--key-file=/etc/kubernetes/pki/etcd/server.key:`  ★
etcd サーバーの秘密鍵ファイルのパス。TLS/SSL 通信に使用される。
サーバー証明書(--cert-file)とともに使用される

`--listen-client-urls=https://127.0.0.1:2379,https://192.168.63.164:2379:`  ★
クライアント接続を受け付けるURLを指定。ここではローカルホストと特定のIPアドレスの両方で受け付ける。

`--listen-metrics-urls=http://127.0.0.1:2381:`
メトリクスのリスニングURLを指定。ここではローカルホストのポート 2381 でメトリクスのエンドポイントを提供

`--listen-peer-urls=https://192.168.63.164:2380:`

etcd クラスタ内の他のメンバーからの接続を受け入れるURLを指定。ここでは、特定のIPアドレスのポート 2380 でリスニングする。

`--name=controlplane:`
etcd インスタンスの名前を指定

`--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt:`
ピア間通信で使用される証明書ファイルのパスを指定。etcd メンバー間のTLS通信に使用される。

`--peer-client-cert-auth=true:`
ピア接続に対するクライアント証明書認証を有効。これが有効になっている場合、ピアは有効な証明書を提供する必要がある。

`--peer-key-file=/etc/kubernetes/pki/etcd/peer.key:`
ピア間通信で使用される秘密鍵ファイルのパス。

`--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt:`
ピア間通信で使用されるCA証明書のファイルパスを指定します。これにより、証明書の信頼性を検証する。

`--snapshot-count=10000:`
10,000回の操作ごとにスナップショットが作成される。

`--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt:`  ★
クライアント接続の際に使用されるCA証明書のファイルパス。これにより、クライアント証明書の信頼性を検証する。

## バックアップコマンド
```
# ETCDCTL_API=3 etcdctl --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 \
snapshot save /opt/snapshot-pre-boot.db
```

確認
```
# ETCDCTL_API=3 etcdctl --write-out=table snapshot status snapshot.db
```


リストア
```
# ETCDCTL_API=3 etcdctl --data-dir /var/lib/etcd-from-backup \
snapshot restore /opt/snapshot-pre-boot.db

2024-11-27 14:58:40.873462 I | mvcc: restore compact to 1712
2024-11-27 14:58:40.876912 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
```



`/etc/kubernetes/manifests/etcd.yaml`
を更新する必要がある

etcd スナップショットがコントロールプレーンの新しいパス (/var/lib/etcd-from-backup) に復元されたので、etcd-data ボリュームの hostPath を古いディレクトリ (/var/lib/etcd) から新しいディレクトリ (/var/lib/etcd-from-backup) に変更する。

```yaml:/etc/kubernetes/manifests/etcd.yaml
volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd-from-backup     #ここを/var/lib/etcdから変更
      type: DirectoryOrCreate
    name: etcd-data
```

この変更により、コンテナ上の /var/lib/etcd はコントロールプレーン上の /var/lib/etcd-from-backup を指すようになる。
staticpodのため、ファイルが更新されると自動的に再作成される。

※元の場所と同じ場所にリストアする場合、上記手順は必要ないがetcdを一度止めてディレクトリも移す必要がある
```
# systemctl stop etcd
# mv /var/lib/etcd /var/lib/etcd_backup
# ETCDCTL_API=3 etcdctl --data-dir /var/lib/etcd snapshot restore /opt/snapshot-pre-boot.db
# systemctl start etcd
```


# おまけ
忘れがちなやつリスト
```
・namespace固定
# kubectl config set-context --current -namespace=NAMESPACE


・APIリソース確認
# kubectl api-resources


・コンテナのシェルへログイン。(-c なしでpodへログイン)
# kubectl exec -it my-pod -c my-container -- /bin/bash


・json整形(出力を抜き出して表示)
# kubectl get pod -o=jsonpath='{.items[*].metadata.name}'
nginx redis

# kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}'
192.168.1.1 192.168.1.2
→
[?(@.type=="InternalIP")]でフィルタリングしている。@は現在のオブジェクトを指す


・出力を抜き出して任意のカラムを追加して表示.名前でソート
# kubectl get deployment -n admin -o custom-columns="DEPLOYMENT:metadata.name,CONTAINER_IMAGE:spec.template.spec.containers[].image,REPLICAS:status.replicas,NAMESPACE:metadata.namespace" --sort-by=.metadata.name
DEPLOYMENT   CONTAINER_IMAGE   REPLICAS   NAMESPACE
deploy1      nginx             1          admin
deploy2      nginx:alpine      1          admin
deploy3      nginx:1.16        1          admin
deploy4      nginx:1.17        1          admin
deploy5      nginx:latest      1          admin2


・Pod作成
# kubectl run 名 --restart=Never nginx --image=nginx:alpine
　　--restartで挙動を設定できる
　　　Always: デプロイコントローラで起動、要求を待ち続け終了せず、異常終了したら再起動する(デフォ)
　　　Never: podを直接起動、podが停止したときにリスタートしない
　　　OnFailure: jobの制御下で起動、起動失敗した時に所定の回数に達するまでポッドの起動を再試行

・Deployment作成
kubectl create deployment redis-deploy --image=redis --replicas=2 -n dev-ns
```

# 参考
[kodecloud](https://learn.kodekloud.com/)