Kubernetes (minikube)

Deployment

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

The apiVersion field is the first required field, and it specifies the API endpoint on the API server which we want to connect to; it must match an existing version for the object type defined. The second required field is kind , specifying the object type - in our case it is Deployment , but it can be Pod, ReplicaSet, Namespace, Service, etc. The third required field metadata , holds the object’s basic information, such as name, annotations, labels, namespaces, etc. Our example shows two spec fields (spec and spec.template.spec ). The fourth required field spec marks the beginning of the block defining the desired state of the Deployment object. In our example, we are requesting that 3 replicas, that is 3 instances of the Pod, are running at any given time. The Pods are created using the Pod Template defined in spec.template . A nested object, such as the Pod being part of a Deployment, retains its metadata and spec and loses its own apiVersion and kind - both being replaced by template . In spec.template.spec , we define the desired state of the Pod. Our Pod creates a single container running the nginx:1.14.2 image from Docker Hub.

$ kubectl apply -f nginx-deployment.yaml

ReplicaSet

frontend.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # modify replicas according to your case
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
$ kubectl apply -f frontend.yaml

DeploymentとReplicaSetの関係

DeploymentによりReplicaSetが作成される。


kubectl create deployment

イメージ更新による新規レプリカセット作成とロールバック
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-deployment-em-

Create a deployment with the specified name.

$ kubectl create deployment NAME --image=image -- [COMMAND] [args...]

ex)

deployment mynginx の作成

$ kubectl create deployment mynginx --image=nginx

上記コマンドで作成された Deployment, ReplicaSet, Podのリスト

$ kubectl get deploy,rs,po -l app=mynginx
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mynginx   1/1     1            1           2m27s

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/mynginx-654f8684f8   1         1         1       2m27s

NAME                           READY   STATUS    RESTARTS   AGE
pod/mynginx-654f8684f8-whcsv   1/1     Running   0          2m27s

レプリカセットの作成(Podのレプリカを3つ作成)

$ kubectl scale deploy mynginx --replicas=3

作成されたレプリカ replicaset.apps/mynginx-654f8684f8 (3つのPod)の確認

$ kubectl get deploy,rs,po -l app=mynginx
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mynginx   3/3     3            3           9m23s

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/mynginx-654f8684f8   3         3         3       9m23s

NAME                           READY   STATUS    RESTARTS   AGE
pod/mynginx-654f8684f8-6frj5   1/1     Running   0          30s
pod/mynginx-654f8684f8-7j7vg   1/1     Running   0          30s
pod/mynginx-654f8684f8-whcsv   1/1     Running   0          9m23s

kubectl rollout

$ kubectl rollout history deployment/mynginx
deployment.apps/mynginx 
REVISION  CHANGE-CAUSE
1         <none>

$ kubectl rollout history deployment/mynginx --revision=1
deployment.apps/mynginx with revision #1
Pod Template:
  Labels:	app=mynginx
	pod-template-hash=654f8684f8
  Containers:
   nginx:
    Image:	nginx
    Port:	<none>
    Host Port:	<none>
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

nginx イメージのバージョン変更・アップデート(リビジョン2)

$ kubectl set image deployment mynginx nginx=nginx:1.21-alpine
deployment.apps/mynginx image updated

ロールアウト履歴

$ kubectl rollout history deployment/mynginx
deployment.apps/mynginx 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

$ kubectl rollout history deployment/mynginx --revision=2
deployment.apps/mynginx with revision #2
Pod Template:
  Labels:	app=mynginx
	pod-template-hash=574494d858
  Containers:
   nginx:
    Image:	nginx:1.21-alpine
    Port:	<none>
    Host Port:	<none>
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

レプリカセットが更新したイメージを反映しているか確認(変更したイメージに基づき新規レプリカセット replicaset.apps/mynginx-654f8684f8 が作成される)

$ kubectl get deploy,rs,po -l app=mynginx
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mynginx   3/3     3            3           34m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/mynginx-574494d858   3         3         3       4m10s
replicaset.apps/mynginx-654f8684f8   0         0         0       34m

NAME                           READY   STATUS    RESTARTS   AGE
pod/mynginx-574494d858-5kflv   1/1     Running   0          4m10s
pod/mynginx-574494d858-7cw4x   1/1     Running   0          3m28s
pod/mynginx-574494d858-b7ksw   1/1     Running   0          3m44s

リビジョン1へのロールバック

$ kubectl rollout undo deployment mynginx --to-revision=1
deployment.apps/mynginx rolled back

ロールバックするとリビジョン1が消去されてリビジョン3に移行します。

$ kubectl rollout history deployment/mynginx
deployment.apps/mynginx 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

元のレプリカセット replicaset.apps/mynginx-654f8684f8 に戻ったことを確認

$ kubectl get deploy,rs,po -l app=mynginx
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mynginx   3/3     3            3           48m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/mynginx-574494d858   0         0         0       17m
replicaset.apps/mynginx-654f8684f8   3         3         3       48m

NAME                           READY   STATUS    RESTARTS   AGE
pod/mynginx-654f8684f8-99vj5   1/1     Running   0          2m1s
pod/mynginx-654f8684f8-ch8rk   1/1     Running   0          93s
pod/mynginx-654f8684f8-xjwpq   1/1     Running   0          108s

kubectl for Docker Users

Pod内のコンテナへのアクセス

Podの確認

$ kubectl get pods
NAME     READY   STATUS    RESTARTS   AGE
pod001   1/1     Running   0          8m3s

コンテナシェルへ移動—> ls コマンド実行

$ kubectl exec -ti pod001 -- sh
# ls 
bin   dev		   docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc			 lib   media  opt  root  sbin  sys  usr

ポッドに複数のコンテナが稼働している場合

ポッドの詳細から稼働イメージ(コンテナ)の名称を確認

$ kubectl describe pods POD_NAME

コンテナ名を指定してコンテナシェル( bash または sh )に移動

$ kubectl exec -ti pods POD_NAME -c CONTAINER_NAME -- bash

ログ確認

Examples:
  # Return snapshot logs from pod nginx with only one container
  kubectl logs nginx
  
  # Return snapshot logs from pod nginx with multi containers
  kubectl logs nginx --all-containers=true
  
  # Return snapshot logs from all containers in pods defined by label app=nginx
  kubectl logs -l app=nginx --all-containers=true
  
  # Return snapshot of previous terminated ruby container logs from pod web-1
  kubectl logs -p -c ruby web-1
  
  # Begin streaming the logs of the ruby container in pod web-1
  kubectl logs -f -c ruby web-1
  
  # Begin streaming the logs from all containers in pods defined by label app=nginx
  kubectl logs -f -l app=nginx --all-containers=true
  
  # Display only the most recent 20 lines of output in pod nginx
  kubectl logs --tail=20 nginx
  
  # Show all logs from pod nginx written in the last hour
  kubectl logs --since=1h nginx
  
  # Show logs from a kubelet with an expired serving certificate
  kubectl logs --insecure-skip-tls-verify-backend nginx
  
  # Return snapshot logs from first container of a job named hello
  kubectl logs job/hello
  
  # Return snapshot logs from container nginx-1 of a deployment named nginx
  kubectl logs deployment/nginx -c nginx-1

Images

Image names

Container images are usually given a name such as pause, example/mycontainer, or kube-apiserver. Images can also include a registry hostname; for example: fictional.registry.example/imagename, and possibly a port number as well; for example: fictional.registry.example:10443/imagename.

Image pull policy

The imagePullPolicy for a container and the tag of the image affect when the kubelet attempts to pull (download) the specified image.

Here’s a list of the values you can set for imagePullPolicy and the effects these values have:

IfNotPresent
the image is pulled only if it is not already present locally.

Always
every time the kubelet launches a container, the kubelet queries the container image registry to resolve the name to an image digest. If the kubelet has a container image with that exact digest cached locally, the kubelet uses its cached image; otherwise, the kubelet pulls the image with the resolved digest, and uses that image to launch the container.

Never
the kubelet does not try fetching the image. If the image is somehow already present locally, the kubelet attempts to start the container; otherwise, startup fails. See pre-pulled images for more details.

DaemonSet

他のワークロード オブジェクトと同様に、DaemonSet は複製された Pod のグループを管理します。ただし、DaemonSet は、クラスタ全体またはノードのサブセットに渡って、ノードあたり 1 つの Pod のモデルを維持しようとします。ノードプールにノードが追加されると、DaemonSet は必要に応じて自動的に新しいノードに Pod を追加します。

DaemonSet は、Pod テンプレートを使用します。これには、その Pod の仕様が含まれています。Pod 仕様によって、各 Pod の外観(コンテナ内で実行するアプリケーション、マウントするボリューム、ラベルとセレクタなど)が決定されます。

DaemonSet Pod には、他の Pod と同じ優先順位のルールが適用されます。DaemonSet Pod は taint と許容値を考慮しますが、DaemonSet Pod には暗黙的な許容値があります

使用パターン

DaemonSet は、すべてのノードまたは特定のノードで実行する必要があり、ユーザーの介入を必要としない、進行中のバックグラウンド タスクのデプロイに便利です。このようなタスクの例としては、ceph などのストレージ デーモン、fluent-bit などのログ収集デーモン、collectd などのノード モニタリング デーモンがあります。

たとえば、すべてのノードでデーモンのタイプごとに DaemonSet を実行できます。または、1 つのタイプのデーモンに対して複数の DaemonSet を実行することもできますが、ハードウェア タイプやリソースニーズによって異なる構成を使用することもできます。


Service

Service とは、一連の Pod エンドポイントを 1 つのリソースにグループ化したものです。このグループにアクセスするさまざまな方法を構成できます。デフォルトでは固定クラスタ IP アドレスを取得し、クラスタ内のクライアントはそれを使って Service 内の Pod と通信できます。クライアントがこの IP アドレスにリクエストを送信すると、リクエストが Service 内のポッドの 1 つにルーティングされます。

Service は、セレクタを使用してメンバーの Pod を識別します。Pod が Service のメンバーとして識別されるには、セレクタで指定されたすべてのラベルが Pod に設定されている必要があります。ラベルは、オブジェクトに関連する任意の Key-Value ペアです。

次の Service マニフェストのセレクタには 2 つのラベルが指定されています。selector フィールドでは、app: metrics ラベルと department:engineering ラベルの両方を持つ Pod がこの Service のメンバーであることを示しています。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Kubernetes Service を使用する理由

Kubernetes クラスタの各 Pod は内部 IP アドレスを持ちます。しかし、Deployment 内の Pod が稼働して停止すると、IP アドレスが変わります。このため、Pod IP アドレスを直接使用しても意味はありません。Service を使用すると、メンバー Pod の IP アドレスが変更されても、Service の存続期間中に固定の IP アドレスを取得できます。

Service は負荷分散としても機能します。クライアントは単一の固定 IP アドレスを呼び出しますが、リクエストは Service のメンバーである Pod 全体で負荷分散されます。

Kubernetes Service のタイプ

Service には、次の 5 つのタイプがあります。

  • ClusterIP(デフォルト): 内部クライアントが内部の固定 IP アドレスにリクエストを送信します。
  • NodePort: クライアントは、Service が指定した 1 つ以上の nodePort 値を使用して、ノードの IP アドレスにリクエストを送信します。
  • LoadBalancer: クライアントがネットワーク ロードバランサの IP アドレスにリクエストを送信します。
  • ExternalName: 内部クライアントが、外部 DNS 名のエイリアスとして Service の DNS 名を使用します。
  • Headless: headless Service は、Pod のグループ化を行うものの、固定 IP アドレスは必要ない場合に使用します。

NodePort タイプは ClusterIP の拡張タイプです。したがって、NodePort タイプの Service はクラスタ IP アドレスを使用します。

LoadBalancer タイプは NodePort の拡張タイプです。したがって、LoadBalancer タイプの Service は、クラスタ IP アドレスと 1 つ以上の nodePort 値を使用します。

Kubernetes APIへのアクセスコントロール ( Authentication, Authorization, and Admission Control)

Kubernetes APIにはkubectl やクライアントライブラリ、あるいはRESTリクエストを用いてアクセスします。 APIアクセスには、人間のユーザーとKubernetesサービスアカウントの両方が認証可能です。 リクエストがAPIに到達すると、次の図のようにいくつかの段階を経ます。

トランスポート層のセキュリティ

一般的なKubernetesクラスターでは、APIはTLSで保護された443番ポートで提供されます。 APIサーバーは証明書を提示します。 この証明書は、プライベート認証局(CA)を用いて署名することも、一般に認知されているCAと連携した公開鍵基盤に基づき署名することも可能です。

クラスターがプライベート認証局を使用している場合、接続を信頼し、傍受されていないと確信できるように、クライアント上の~/.kube/configに設定されたそのCA証明書のコピーが必要です。

クライアントは、この段階でTLSクライアント証明書を提示することができます。

認証 (Authentication)

TLSが確立されると、HTTPリクエストは認証のステップに移行します。 これは図中のステップ1に該当します。 クラスター作成スクリプトまたはクラスター管理者は、1つまたは複数のAuthenticatorモジュールを実行するようにAPIサーバーを設定します。 Authenticatorについては、認証で詳しく説明されています。

認証ステップへの入力はHTTPリクエスト全体ですが、通常はヘッダとクライアント証明書の両方、またはどちらかを調べます。

認証モジュールには、クライアント証明書、パスワード、プレーントークン、ブートストラップトークン、JSON Web Tokens(サービスアカウントに使用)などがあります。

複数の認証モジュールを指定することができ、その場合、1つの認証モジュールが成功するまで、それぞれを順番に試行します。

認証できない場合、HTTPステータスコード401で拒否されます。 そうでなければ、ユーザーは特定のusernameとして認証され、そのユーザー名は後続のステップでの判断に使用できるようになります。 また、ユーザーのグループメンバーシップを提供する認証機関と、提供しない認証機関があります。

Kubernetesはアクセスコントロールの決定やリクエストログにユーザー名を使用しますが、Userオブジェクトを持たず、ユーザー名やその他のユーザーに関する情報をAPIはに保存しません。

認可 (Authorization)

リクエストが特定のユーザーからのものであると認証された後、そのリクエストは認可される必要があります。 これは図のステップ2に該当します。

リクエストには、リクエスト者のユーザー名、リクエストされたアクション、そのアクションによって影響を受けるオブジェクトを含める必要があります。 既存のポリシーで、ユーザーが要求されたアクションを完了するための権限を持っていると宣言されている場合、リクエストは承認されます。

例えば、Bobが以下のようなポリシーを持っている場合、彼は名前空間projectCaribou内のPodのみを読むことができます。

{
    "apiVersion": "abac.authorization.kubernetes.io/v1beta1",
    "kind": "Policy",
    "spec": {
        "user": "bob",
        "namespace": "projectCaribou",
        "resource": "pods",
        "readonly": true
    }
}

Bobが次のようなリクエストをした場合、Bobは名前空間projectCaribouのオブジェクトを読むことが許可されているので、このリクエストは認可されます。

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "projectCaribou",
      "verb": "get",
      "group": "unicorn.example.org",
      "resource": "pods"
    }
  }
}

Bobが名前空間projectCaribouのオブジェクトに書き込み(createまたはupdate)のリクエストをした場合、承認は拒否されます。 また、もしBobがprojectFishのような別の名前空間にあるオブジェクトを読み込む(get)リクエストをした場合も、承認は拒否されます。

Kubernetesの認可では、組織全体またはクラウドプロバイダー全体の既存のアクセスコントロールシステムと対話するために、共通のREST属性を使用する必要があります。 これらのコントロールシステムは、Kubernetes API以外のAPIとやり取りする可能性があるため、REST形式を使用することが重要です。

Kubernetesは、ABACモード、RBACモード、Webhookモードなど、複数の認可モジュールをサポートしています。 管理者はクラスターを作成する際に、APIサーバーで使用する認証モジュールを設定します。 複数の認可モジュールが設定されている場合、Kubernetesは各モジュールをチェックし、いずれかのモジュールがリクエストを認可した場合、リクエストを続行することができます。 すべてのモジュールがリクエストを拒否した場合、リクエストは拒否されます(HTTPステータスコード403)。

サポートされている認可モジュールを使用したポリシー作成の詳細を含む、Kubernetesの認可については、認可を参照してください。

アドミッションコントロール (Admission Control)

アドミッションコントロールモジュールは、リクエストを変更したり拒否したりすることができるソフトウェアモジュールです。 認可モジュールが利用できる属性に加えて、アドミッションコントロールモジュールは、作成または修正されるオブジェクトのコンテンツにアクセスすることができます。

アドミッションコントローラーは、オブジェクトの作成、変更、削除、または接続(プロキシ)を行うリクエストに対して動作します。 アドミッションコントローラーは、単にオブジェクトを読み取るだけのリクエストには動作しません。 複数のアドミッションコントローラーが設定されている場合は、順番に呼び出されます。

これは図中のステップ3に該当します。

認証・認可モジュールとは異なり、いずれかのアドミッションコントローラーモジュールが拒否した場合、リクエストは即座に拒否されます。

オブジェクトを拒否するだけでなく、アドミッションコントローラーは、フィールドに複雑なデフォルトを設定することもできます。

利用可能なアドミッションコントロールモジュールは、アドミッションコントローラーに記載されています。

リクエストがすべてのアドミッションコントローラーを通過すると、対応するAPIオブジェクトの検証ルーチンを使って検証され、オブジェクトストアに書き込まれます(図のステップ4に該当します)。


証明書の作成

認証方式によりAPIサーバへアクセスする場合に必要なセルフ証明書の作成

X.509


API Overview

API Reference

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#-strong-api-groups-strong-

RBAC認証によるAPIサーバへのアクセス(具体例)

認証局CAのキーファイルとこのキーファイルから作成されたCA証明書は minikube 起動時に作成されています ( .minikube/ ) 。

Role-based access control (RBAC)

RBACのAPIでは、次の4種のオブジェクト (kind) を定義しています。

Role , ClusterRole , RoleBinding, ClusterRoleBinding

新規 namespace の作成

$ kubectl create namespace auth-test
namespace/auth-test created

RBAC認証に必要な認証用ファイルを格納するディレクトリを作成し移動

$ mkdir rbac
$ cd rbac

新規作成した namespace にアクセスできるユーザ k9s-auth を登録

$ sudo useradd -s /bin/bash k9s-auth
$ sudo passwd k9s-auth
新しい パスワード: 
新しい パスワードを再入力してください: 
passwd: パスワードは正しく更新されました

クライアント(ユーザ : k9s-auth )側のRSAキーペア k9s-auth.key を作成

$ openssl genpkey -algorithm RSA -out k9s-auth.key -pkeyopt rsa_keygen_bits:2048
..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.......+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..............+......+.+...
.....
.....
..+..+.......+...............+.....+..........+.....+......+..........+......+....................+.+.....+...+.......+.....+......................+.....+.+............+..+...+..........+.........+.....+....+..+...+.+.....+......+...+.+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ユーザ公開キーの証明書署名要求 k9s-auth.csr を作成します

$ openssl req -new -key k9s-auth.key -out k9s-auth.csr -subj "/CN=k9s-auth/O=learner"

ここで kubectl で証明書署名要求する際に必要となる設定ファイル signing-request.yaml を作成します。

request: <assign encoded value from next cat command>

の箇所は後ほど指定します。

$ nano signing-request.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: k9s-auth-csr
spec:
  groups:
  - system:authenticated
  request: <assign encoded value from next cat command>
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - digital signature
  - key encipherment
  - client auth

証明書署名要求をBase64でエンコードし、その出力結果を上記request: <assign encoded value from next cat command> にコピーします。

$ cat k9s-auth.csr | base64 | tr -d '\n','%'
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0..........................
..............
..............

出力結果をコピー

$ nano signing-request.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: k9s-auth-csr
spec:
  groups:
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0..........................
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - digital signature
  - key encipherment
  - client auth

上記設定ファイルを指定して kubectl で証明書署名要求オブジェクトを作成します

$ kubectl create -f signing-request.yaml
certificatesigningrequest.certificates.k8s.io/k9s-auth-csr created

上記オブジェクトの状態を確認

$ kubectl get csr
NAME           AGE   SIGNERNAME                            REQUESTOR       REQUESTEDDURATION   CONDITION
k9s-auth-csr   27s   kubernetes.io/kube-apiserver-client   minikube-user   <none>              Pending

上記オブジェクトを承認します。

$ kubectl certificate approve k9s-auth-csr
certificatesigningrequest.certificates.k8s.io/k9s-auth-csr approved

再度オブジェクトの状態確認

$ kubectl get csr
NAME           AGE    SIGNERNAME                            REQUESTOR       REQUESTEDDURATION   CONDITION
k9s-auth-csr   111s   kubernetes.io/kube-apiserver-client   minikube-user   <none>              Approved,Issued

証明書署名要求が承認されたので、ユーザの公開キーを含むその証明書をBase64でデコードし k9s-auth.crt として出力します

$ kubectl get csr k9s-auth-csr -o jsonpath='{.status.certificate}' | base64 -d > k9s-auth.crt

証明書の中身を確認します

$ cat k9s-auth.crt
-----BEGIN CERTIFICATE-----
MIIDGjCCAgKgAwIBAgIQP3NjqIyzzDNEMISgSMrtcjANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDEwptaW5pa3ViZUNBMB4XDTIyMDkwMTAyMjM1M1oXDTIzMDkwMTAy
.....
.....
.....
1UnAKWlA8ywjohwUOmo3s6v/n4B3o6phzFLBuBlI31jWVTH8AoR6BPaWpP823Cdn
QKeOO6on+JpI1RoW1nMHZEmNC+BWBiD0brS2GlpE
-----END CERTIFICATE-----

kubectl のクライアント設定ファイルにプライベートキーとCAによる公開キーの証明書を保有するユーザ k9s-auth を追加します

$ kubectl config set-credentials k9s-auth --client-certificate=k9s-auth.crt --client-key=k9s-auth.key
User "k9s-auth" set.

同じく上記クライアント設定ファイルにユーザ k9s-auth 向けの新しい context : k9s-auth-contextを作成します

$ kubectl config set-context k9s-auth-context --cluster=minikube --namespace=auth-test --user=k9s-auth
k9s-auth
Context "k9s-auth-context" created.

Note) 上記 k9s-authk9s-auth-context を除外する場合

$ kubectl config unset users.k9s-auth
$ kubectl config unset contexts.k9s-auth-context

上記内容を反映したクライアント設定ファイルを確認します

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /home/user001/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Mon, 29 Aug 2022 15:14:57 JST
        provider: minikube.sigs.k8s.io
        version: v1.26.1
      name: cluster_info
    server: https://192.168.49.2:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    namespace: auth-test
    user: k9s-auth
  name: k9s-auth-context
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Mon, 29 Aug 2022 15:14:57 JST
        provider: minikube.sigs.k8s.io
        version: v1.26.1
      name: context_info
    namespace: default
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: k9s-auth
  user:
    client-certificate: /home/use001/rbac/k9s-auth.crt
    client-key: /home/user001/rbac/k9s-auth.key
- name: minikube
  user:
    client-certificate: /home/user001/.minikube/profiles/minikube/client.crt
    client-key: /home/user001/.minikube/profiles/minikube/client.key

namespace : auth-testnginx をデプロイします

$ kubectl -n auth-test create deployment nginx --image=nginx:alpine
deployment.apps/nginx created

ここで contextk9s-auth-context に指定してpodの確認をすると、指定した context でのユーザ k9s-auth にアクセス権限が設定されていないため以下のエラーが発生します。

$ kubectl --context=k9s-auth-context get pods
Error from server (Forbidden): pods is forbidden: User "k9s-auth" cannot list resource "pods" in API group "" in the namespace "auth-test"

pod-reader というロールオブジェクトを作成するための設定ファイルを作成します。namespace : test-authpod リソースに対して get, watch, list の権限を付与します。

$ nano role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: auth-test
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

ロールオブジェクトを作成します

$ kubectl create -f role.yaml
role.rbac.authorization.k8s.io/pod-reader created

ロールオブジェクトの確認

$ kubectl -n auth-test get roles
NAME         CREATED AT
pod-reader   2022-09-01T02:47:42Z

ロールオブジェクト pod-reader にユーザ k9s-auth を割当てるためのロールバインディングオブジェクトを作成するための設定ファイルを作成します。

$ nano rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-read-access
  namespace: auth-test
subjects:
- kind: User
  name: k9s-auth
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

上記設定ファイルを指定してオブジェクトを作成

$ kubectl create -f rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/pod-read-access created

contextを指定して get コマンドにより pod リソースがリストアップされるかどうか確認します

$ kubectl --context=k9s-auth-context get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-d7b6f6c9c-l8gfb   1/1     Running   0          6m52s

アドミッションコントローラ

以下アドミッションコントローラにイメージプルポリシーを追加することにより、ポリシー追加前と追加後で作成されるPodにそのポリシーがどのように反映されるか確認するデモです。

初めにAPIサーバでデフォルトで有効となっているアドミッションコントローラを確認します

$ kubectl -n kube-system describe pods/kube-apiserver-minikube | grep -i admission
      --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota

アドミッションコントローラ AlwaysPullImages を使用しないように(イメージプルポリシーを IfNotPresent で指定)して Nginx をデプロイ

$ kubectl run admitted --image=nginx --image-pull-policy=IfNotPresent
pod/admitted created

上記 Pod のステータス

$ kubectl get po
NAME       READY   STATUS    RESTARTS   AGE
admitted   1/1     Running   0          5m58s

PodImagePullPolicy の確認(yamlフォーマットで出力)

$ kubectl get pod admitted -o yaml | grep -i imagepull
    imagePullPolicy: IfNotPresent

ここでアドミッションコントローラにイメージプルポリシーを指定するため minikube sshminikube のノードにアクセスします。

$ minikube ssh

以下のコマンドで kube-apiserver で定義されているアドミッションコントローラを確認します。

$ sudo grep admission /etc/kubernetes/manifests/kube-apiserver.yaml
    - --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota

結果は $ kubectl -n kube-system describe pods/kube-apiserver-minikube | grep -i admission で出力した結果と同じになります。

:bangbang: kube-apiserver の設定を変更するため、変更前の設定ファイルをバックアップしておきます。

$ sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /kube-apiserver-yaml-backup

vienable-admission-pluginsAlwaysPullImages を追加します。

$ sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
.....
.....
- --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,AlwaysPullImages
.....
.....

kube-apiserverへのssh接続を切断します。

$ exit

アドミッションコントローラに AlwaysPullImages が追加されていることを確認

$ kubectl -n kube-system describe pods/kube-apiserver-minikube | grep -i admission
      --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,AlwaysPullImages

再び アドミッションコントローラ AlwaysPullImages を使用しないように Nginx をデプロイ

$ kubectl run mutated --image=nginx --image-pull-policy=IfNotPresent
pod/mutated created

起動Podの確認

$ kubectl get po 
NAME       READY   STATUS    RESTARTS   AGE
admitted   1/1     Running   0          76m
mutated    1/1     Running   0          82s

IfNotPresent を指定してもアドミッションコントローラで AlwaysPullImages を指定しているので Always が優先されます。

$ kubectl get pod mutated -o yaml | grep -i imagepull
    imagePullPolicy: Always

変更前に起動したpodについてはポリシーの変更はありません。

$ kubectl get pod admitted -o yaml | grep -i imagepull
    imagePullPolicy: IfNotPresent

Understanding Kubernetes Objects

Describing a Kubernetes object

When you create an object in Kubernetes, you must provide the object spec that describes its desired state, as well as some basic information about the object (such as a name). When you use the Kubernetes API to create the object (either directly or via kubectl), that API request must include that information as JSON in the request body. Most often, you provide the information to kubectl in a .yaml file. kubectl converts the information to JSON when making the API request.

Here’s an example .yaml file that shows the required fields and object spec for a Kubernetes Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

One way to create a Deployment using a .yaml file like the one above is to use the kubectl apply command in the kubectl command-line interface, passing the .yaml file as an argument. Here’s an example:

$ kubectl apply -f https://k8s.io/examples/application/deployment.yaml
deployment.apps/nginx-deployment created

Required Fields

In the .yaml file for the Kubernetes object you want to create, you’ll need to set values for the following fields:

  • apiVersion - Which version of the Kubernetes API you’re using to create this object
  • kind - What kind of object you want to create
  • metadata - Data that helps uniquely identify the object, including a name string, UID, and optional namespace
  • spec - What state you desire for the object

The precise format of the object spec is different for every Kubernetes object, and contains nested fields specific to that object.

The Kubernetes API Reference

can help you find the spec format for all of the objects you can create using Kubernetes.

Service

Kubernetes Service とは

Service とは、一連の Pod エンドポイントを 1 つのリソースにグループ化したものです。このグループにアクセスするさまざまな方法を構成できます。デフォルトでは固定クラスタ IP アドレスを取得し、クラスタ内のクライアントはそれを使って Service 内の Pod と通信できます。クライアントがこの IP アドレスにリクエストを送信すると、リクエストが Service 内のポッドの 1 つにルーティングされます。

Service は、セレクタを使用してメンバーの Pod を識別します。Pod が Service のメンバーとして識別されるには、セレクタで指定されたすべてのラベルが Pod に設定されている必要があります。ラベルは、オブジェクトに関連する任意の Key-Value ペアです。

次の Service マニフェストのセレクタには 2 つのラベルが指定されています。selector フィールドでは、app: metrics ラベルと department:engineering ラベルの両方を持つ Pod がこの Service のメンバーであることを示しています。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Kubernetes Service を使用する理由

Kubernetes クラスタの各 Pod は内部 IP アドレスを持ちます。しかし、Deployment 内の Pod が稼働して停止すると、IP アドレスが変わります。このため、Pod IP アドレスを直接使用しても意味はありません。Service を使用すると、メンバー Pod の IP アドレスが変更されても、Service の存続期間中に固定の IP アドレスを取得できます。

Service は負荷分散としても機能します。クライアントは単一の固定 IP アドレスを呼び出しますが、リクエストは Service のメンバーである Pod 全体で負荷分散されます。

Kubernetes Service のタイプ

Service には、次の 5 つのタイプがあります。

  • ClusterIP(デフォルト): 内部クライアントが内部の固定 IP アドレスにリクエストを送信します。
  • NodePort: クライアントは、Service が指定した 1 つ以上の nodePort 値を使用して、ノードの IP アドレスにリクエストを送信します。
  • LoadBalancer: クライアントがネットワーク ロードバランサの IP アドレスにリクエストを送信します。
  • ExternalName: 内部クライアントが、外部 DNS 名のエイリアスとして Service の DNS 名を使用します。
  • Headless: headless Service は、Pod のグループ化を行うものの、固定 IP アドレスは必要ない場合に使用します。

NodePort タイプは ClusterIP の拡張タイプです。したがって、NodePort タイプの Service はクラスタ IP アドレスを使用します。

LoadBalancer タイプは NodePort の拡張タイプです。したがって、LoadBalancer タイプの Service は、クラスタ IP アドレスと 1 つ以上の nodePort 値を使用します。


デフォルトサービスのClusterIPをNodePortに変更して外部からNodeにアクセス(デモ)

Pod:pod-hello の起動

$ kubectl run pod-hello --image=pbitty/hello-from:latest --port=80 --expose=true
service/pod-hello created
pod/pod-hello created

Pod, Service, Endpoint の確認

$ kubectl get po,svc,ep --show-labels
NAME            READY   STATUS    RESTARTS   AGE   LABELS
pod/pod-hello   1/1     Running   0          98s   run=pod-hello

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   LABELS
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   18d   component=apiserver,provider=kubernetes
service/pod-hello    ClusterIP   10.99.121.52   <none>        80/TCP    98s   <none>

NAME                   ENDPOINTS           AGE   LABELS
endpoints/kubernetes   192.168.49.2:8443   18d   endpointslice.kubernetes.io/skip-mirror=true
endpoints/pod-hello    172.17.0.8:80       98s   <none>

pod-hello サービスのセレクター確認

$ kubectl describe svc pod-hello | grep -i selector
Selector:          run=pod-hello

デフォルトでは外部(ホスト)からノードにアクセスできません。

$ minikube service --all
|-----------|------------|-------------|--------------|
| NAMESPACE |    NAME    | TARGET PORT |     URL      |
|-----------|------------|-------------|--------------|
| default   | kubernetes |             | No node port |
|-----------|------------|-------------|--------------|
😿  サービス default/kubernetes は NodePort がありません
|-----------|-----------|-------------|--------------|
| NAMESPACE |   NAME    | TARGET PORT |     URL      |
|-----------|-----------|-------------|--------------|
| default   | pod-hello |             | No node port |
|-----------|-----------|-------------|--------------|
😿  サービス default/pod-hello は NodePort がありません

minikube ssh によりクラスターのシェルに移動

$ minikube ssh
Last login: Sat Sep  3 04:09:13 2022 from 192.168.49.1

クラスター内ではサービスのクラスターIP 10.99.121.52 またはエンドポイント 172.17.0.8 を指定することでPodにアクセスできます。

$ curl 10.99.121.52
Hello from pod-hello (172.17.0.8)

$ curl 172.17.0.8
Hello from pod-hello (172.17.0.8)

クラスターのシェルから出て、ホストのシェルに戻ります。

$ exit

外部(ホスト)からアクセスできるようにサービスの内容を変更します。
type: ClusterIP から type: NodePort に変更します。

$ kubectl edit svc pod-hello
service/pod-hello edited

pod-hello のサービスタイプが ClusterIP から NodePort に変更になったことを確認

$ kubectl get po,svc,ep --show-labels
NAME            READY   STATUS    RESTARTS   AGE   LABELS
pod/pod-hello   1/1     Running   0          26m   run=pod-hello

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   LABELS
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        19d   component=apiserver,provider=kubernetes
service/pod-hello    NodePort    10.99.121.52   <none>        80:30613/TCP   26m   <none>

NAME                   ENDPOINTS           AGE   LABELS
endpoints/kubernetes   192.168.49.2:8443   19d   endpointslice.kubernetes.io/skip-mirror=true
endpoints/pod-hello    172.17.0.8:80       26m   <none>

以下割当てられたURLにアクセスするとブラウザで Hello from pod-hello (172.17.0.8) という表示が確認できます。

$ minikube service --all
|-----------|------------|-------------|--------------|
| NAMESPACE |    NAME    | TARGET PORT |     URL      |
|-----------|------------|-------------|--------------|
| default   | kubernetes |             | No node port |
|-----------|------------|-------------|--------------|
😿  サービス default/kubernetes は NodePort がありません
|-----------|-----------|-------------|---------------------------|
| NAMESPACE |   NAME    | TARGET PORT |            URL            |
|-----------|-----------|-------------|---------------------------|
| default   | pod-hello |          80 | http://192.168.49.2:30613 |
|-----------|-----------|-------------|---------------------------|
🎉  デフォルトブラウザーで default/pod-hello サービスを開いています...

次に同じイメージによるpodを3つデプロイし、 kubectl expose コマンドでタイプに NodePort を指定します。

$ kubectl create deployment deploy-hello --image=pbitty/hello-from:latest --port=80 --replicas=3
deployment.apps/deploy-hello created

$ kubectl expose deployment deploy-hello --type=NodePort
service/deploy-hello exposed

ラベル app=deploy-hello を指定してDeployment, Pod, Service, Endpoint の確認

$ kubectl get deploy,po,svc,ep -l app=deploy-hello --show-labels
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE    LABELS
deployment.apps/deploy-hello   3/3     3            3           2m5s   app=deploy-hello

NAME                               READY   STATUS    RESTARTS   AGE    LABELS
pod/deploy-hello-6c5fd5cc9-4kc7n   1/1     Running   0          2m4s   app=deploy-hello,pod-template-hash=6c5fd5cc9
pod/deploy-hello-6c5fd5cc9-mkvhr   1/1     Running   0          2m4s   app=deploy-hello,pod-template-hash=6c5fd5cc9
pod/deploy-hello-6c5fd5cc9-zscq2   1/1     Running   0          2m4s   app=deploy-hello,pod-template-hash=6c5fd5cc9

NAME                   TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE   LABELS
service/deploy-hello   NodePort   10.97.23.69   <none>        80:30322/TCP   64s   app=deploy-hello

NAME                     ENDPOINTS                                     AGE   LABELS
endpoints/deploy-hello   172.17.0.10:80,172.17.0.11:80,172.17.0.9:80   64s   app=deploy-hello

deploy-hello のURLの確認

$ minikube service --all
|-----------|--------------|-------------|---------------------------|
| NAMESPACE |     NAME     | TARGET PORT |            URL            |
|-----------|--------------|-------------|---------------------------|
| default   | deploy-hello |          80 | http://192.168.49.2:30322 |
|-----------|--------------|-------------|---------------------------|
|-----------|------------|-------------|--------------|
| NAMESPACE |    NAME    | TARGET PORT |     URL      |
|-----------|------------|-------------|--------------|
| default   | kubernetes |             | No node port |
|-----------|------------|-------------|--------------|
😿  サービス default/kubernetes は NodePort がありません
|-----------|-----------|-------------|---------------------------|
| NAMESPACE |   NAME    | TARGET PORT |            URL            |
|-----------|-----------|-------------|---------------------------|
| default   | pod-hello |          80 | http://192.168.49.2:30613 |
|-----------|-----------|-------------|---------------------------|
🎉  デフォルトブラウザーで default/deploy-hello サービスを開いています...
🎉  デフォルトブラウザーで default/pod-hello サービスを開いています...

ホストからアクセスすると3つのpodの何れかに割り振られていることが確認できます。

$ curl http://192.168.49.2:30322
Hello from deploy-hello-6c5fd5cc9-4kc7n (172.17.0.9)
$ curl http://192.168.49.2:30322
Hello from deploy-hello-6c5fd5cc9-zscq2 (172.17.0.11)
$ curl http://192.168.49.2:30322
Hello from deploy-hello-6c5fd5cc9-zscq2 (172.17.0.11)
$ curl http://192.168.49.2:30322
Hello from deploy-hello-6c5fd5cc9-mkvhr (172.17.0.10)

yamlフォーマットによる pod, service, endpoint の各マニフェスト

$ kubectl get pod/pod-hello -o yaml
$ kubectl get svc/pod-hello -o yaml
$ kubectl get ep/pod-hello -o yaml

マルチポート設定

pod-hello のポート設定変更・追加

$ kubectl edit svc pod-hello
.....
.....
ports:
  - name: http
    nodePort: 30613
    port: 8080
    protocol: TCP
    targetPort: 80
  - name: https
    nodePort: 31443
    port: 8443
    protocol: TCP
    targetPort: 80
.....
.....

変更・追加した pod, service, endpoint の確認

$ kubectl get po,svc,ep pod-hello 
NAME            READY   STATUS    RESTARTS   AGE
pod/pod-hello   1/1     Running   0          20h

NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                         AGE
service/pod-hello   NodePort   10.99.121.52   <none>        8080:30613/TCP,8443:31443/TCP   20h

NAME                  ENDPOINTS                     AGE
endpoints/pod-hello   172.17.0.8:80,172.17.0.8:80   20h

クラスター内部からはクラスターIPまたは pod のIPとポートを指定することによりアクセス可能

$ minikube ssh

$ curl http://10.99.121.52:8080
Hello from pod-hello (172.17.0.8)

$ curl http://10.99.121.52:8443
Hello from pod-hello (172.17.0.8)

$ curl http://172.17.0.8       
Hello from pod-hello (172.17.0.8)

クラスター外部からは kubernetes のシステムIPとnodePortを指定してアクセス

$ curl http://192.168.49.2:30613
Hello from pod-hello (172.17.0.8)

$ curl http://192.168.49.2:31443
Hello from pod-hello (172.17.0.8)

Configure Liveness, Readiness and Startup Probes

Liveness

ポッド(コンテナ)の状態を監視し不意に停止してしまったときに再起動をかけるためのポッドの設定条件

以下 livenessProbe/tmp/healthy を5秒 (periodSeconds) ごとに cat するデモ
initialDelaySecondskubelet が最初に cat コマンドを実行するまでの待ち時間
/tmp/healthy ファイルが作成後30秒後に削除されます)

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

上記ポッドの作成・起動
注) 既存のポッドが起動していて変更した設定を適用する場合は kubectl apply を指定するが、既存のポッドが存在しない場合には $ kubectl apply または $ kubectl create でも可

$ kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
pod/liveness-exec created

30秒後にポッドが再起動していることを確認

$ kubectl describe pod liveness-exec
.....
.....
.....
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  65s                default-scheduler  Successfully assigned default/liveness-exec to minikube
  Normal   Pulling    61s                kubelet            Pulling image "registry.k8s.io/busybox"
  Normal   Pulled     54s                kubelet            Successfully pulled image "registry.k8s.io/busybox" in 6.604873952s
  Normal   Created    51s                kubelet            Created container liveness
  Normal   Started    50s                kubelet            Started container liveness
  Warning  Unhealthy  10s (x3 over 20s)  kubelet            Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    10s                kubelet            Container liveness failed liveness probe, will be restarted

ポッドの再起動回数確認

$ kubectl get pod liveness-exec
NAME            READY   STATUS    RESTARTS      AGE
liveness-exec   1/1     Running   3 (34s ago)   4m40s

Volumes


Types of Persistent Volumes

PersistentVolume types are implemented as plugins. Kubernetes currently supports the following plugins:

  • cephfs - CephFS volume
  • csi - Container Storage Interface (CSI)
  • fc - Fibre Channel (FC) storage
  • hostPath - HostPath volume (for single node testing only; WILL NOT WORK in a multi-node cluster; consider using local volume instead)
  • iscsi - iSCSI (SCSI over IP) storage
  • local - local storage devices mounted on nodes.
  • nfs - Network File System (NFS) storage
  • rbd - Rados Block Device (RBD) volume

The following types of PersistentVolume are deprecated. This means that support is still available but will be removed in a future Kubernetes release.


2つのイメージ(コンテナ)で hostPath ボリュームを共有(マウント)するデモ

2つのイメージ(コンテナ)を1つのポッドにデプロイするマニフェスト(設定ファイル)を作成

各コンテナはマウントするボリューム名 host-volume を指定、マウントボリュームの hostPath が各コンテナの mountPath に該当

$ vi app-blue-shared-vol.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: blue-app
  name: blue-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blue-app
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: blue-app
        type: canary
    spec:
      volumes:
      - name: host-volume
        hostPath:
          path: /home/docker/blue-shared-volume
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: host-volume
      - image: debian
        name: debian
        volumeMounts:
        - mountPath: /host-vol
          name: host-volume
        command: ["/bin/sh", "-c", "echo Welcome to BLUE App! > /host-vol/index.html ; sleep infinity"]
status: {}

ポッドの起動

$ kubectl apply -f app-blue-shared-vol.yaml
deployment.apps/blue-app created

ノードのポートを開放するサービスの追加

$ kubectl expose deployment blue-app --type=NodePort
service/blue-app exposed

デプロイ、ポッド、サービスの確認

$ kubectl get deploy,po,svc
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/blue-app   1/1     1            1           5m11s

NAME                           READY   STATUS    RESTARTS   AGE
pod/blue-app-dbcdfc9fd-k2j4q   2/2     Running   0          5m11s

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/blue-app     NodePort    10.110.129.230   <none>        80:30488/TCP   62s
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        22d

URLの確認(ブラウザで Welcome to BLUE App! が表示されること確認して下さい)

$ minikube service list
|----------------------|------------------------------------|--------------|---------------------------|
|      NAMESPACE       |                NAME                | TARGET PORT  |            URL            |
|----------------------|------------------------------------|--------------|---------------------------|
| default              | blue-app                           |           80 | http://192.168.49.2:30488 |
| default              | kubernetes                         | No node port |

curlコマンドによる確認

$ curl http://192.168.49.2:30488
Welcome to BLUE App!

作成された index.html ファイルの確認

kubernetesのホストマシンのディレクトリが、ポッドの2つのコンテナのディレクトリと共有されているか確認します。

ホストマシン(kubernetes)へのアクセス

minikube ssh でホストのシェルへ移動 —> ls コマンドでファイルを確認 —> シェルから退場

$ minikube ssh
Last login: Fri Sep  9 06:13:09 2022 from 192.168.49.1
docker@minikube:~$ ls /home/docker/blue-shared-volume
index.html
docker@minikube:~$ exit

ポッド内コンテナのシェルへ移動

ポッドの詳細からコンテナ名をチェック

$ kubectl describe pod/blue-app-dbcdfc9fd-k2j4q
.....
.....
Containers:
  nginx:
  .....
  .....
  debian:
  .....
  .....

コンテナ名を指定して各コンテナ( nginx, debian )のシェルへ移動 —> ls コマンドでファイルを確認 —> シェルから退場

$ kubectl exec -ti blue-app-dbcdfc9fd-k2j4q -c nginx -- bash
# ls /usr/share/nginx/html
index.html
# exit

$ kubectl exec -ti blue-app-dbcdfc9fd-k2j4q -c debian -- bash
# ls /host-vol
index.html
# exit

YAML basics in Kubernetes

参考)yamlの構文ルール

https://developer.ibm.com/tutorials/yaml-basics-and-usage-in-kubernetes/

  1. Key Value Pair — The basic type of entry in a YAML file is of a key value pair. After the Key and colon there is a space and then the value.
  2. Arrays/Lists — Lists would have a number of items listed under the name of the list. The elements of the list would start with a -. There can be a n of lists, however the indentation of various elements of the array matters a lot.
  3. Dictionary/Map — A more complex type of YAML file would be a Dictionary and Map.

ConfigMaps

ポッド内のコンテナの環境変数や実行コマンドなどを定義

ConfigMap の作成

$ kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
configmap/my-config created

yaml フォーマットで詳細表示

$ kubectl get configmaps my-config -o yaml
apiVersion: v1
data:
  key1: value1
  key2: value2
kind: ConfigMap
metadata:
  creationTimestamp: "2022-09-12T01:40:31Z"
  name: my-config
  namespace: default
  resourceVersion: "719705"
  uid: a085e999-450b-4fdc-bd19-918df195a978

ConfigMap によるコンテナアプリが読み込むファイルの指定(デモ)

ConfigMapでは、アプリが読み込むファイル定義も可能です。

Nginx のコンテナで ConfigMap で定義した index.html ファイルを読み込みます。

index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to GREEN App!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
        background-color: GREEN;
    }
</style>
</head>
<body>
<h1 style=\"text-align: center;\">Welcome to GREEN App!</h1>
</body>
</html>

上記ファイルから ConfigMap を作成します。

$ kubectl create configmap green-web-cm --from-file=index.html
configmap/green-web-cm created

ConfigMap(cm) リスト

$ kubectl get cm
NAME               DATA   AGE
green-web-cm       1      40s
kube-root-ca.crt   1      25d

ConfigMap:green-web-cm 詳細確認。Dataセクションに index.html ファイルの内容が反映されています。

$ kubectl describe cm green-web-cm
Name:         green-web-cm
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
index.html:
----
<!DOCTYPE html>
<html>
<head>
<title>Welcome to GREEN App!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
        background-color: GREEN;
    }
</style>
</head>
<body>
<h1 style=\"text-align: center;\">Welcome to GREEN App!</h1>
</body>
</html>


BinaryData
====

Events:  <none>

ConfigMap を指定した Nginxコンテナをデプロイするマニフェストの作成

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: green-web
  name: green-web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: green-web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: green-web
    spec:
      volumes:
      - name: web-config
        configMap:
          name: green-web-cm
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: web-config
status: {}

上記マニフェストを指定してポッドを起動

$ kubectl apply -f web-green-with-cm.yaml
deployment.apps/green-web created

外部からアクセスするためノードのポートを開放します。

$ kubectl expose deployment green-web --type=NodePort
service/green-web exposed

Pod, Deploy, Service, Replicaset のリスト一覧

$ kubectl get all
NAME                             READY   STATUS    RESTARTS   AGE
pod/green-web-56f5c8655d-j5hb6   1/1     Running   0          4m36s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/green-web    NodePort    10.97.55.109   <none>        80:32101/TCP   22s
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        25d

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/green-web   1/1     1            1           4m36s

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/green-web-56f5c8655d   1         1         1       4m36s

URLの確認

$ minikube service list  -n default
|-----------|------------|--------------|---------------------------|
| NAMESPACE |    NAME    | TARGET PORT  |            URL            |
|-----------|------------|--------------|---------------------------|
| default   | green-web  |           80 | http://192.168.49.2:32101 |
| default   | kubernetes | No node port |
|-----------|------------|--------------|---------------------------|

curl コマンドまたはブラウザで上記 URL:http://192.168.49.2:32101 にアクセスして表示内容を確認して下さい。

Secrets

Managing Secrets using kubectl

ユーザとパスワードを別々のファイルで保存(-n オプションで改行なし)

$ echo -n 'admin' > ./username.txt
$ echo -n '1f2d1e2e67df' > ./password.txt

上記ファイルからSecretオブジェクト db-user-pass を作成

$ kubectl create secret generic db-user-pass \
  --from-file=./username.txt \
  --from-file=./password.txt
secret/db-user-pass created

keyを明示する場合 : --from-file=[key=]source

$ kubectl create secret generic db-user-pass \
  --from-file=username=./username.txt \
  --from-file=password=./password.txt

key:value を直接指定する場合: --from-literal=<key>=<value>

$ kubectl create secret generic db-user-pass \
  --from-literal=username=devuser \
  --from-literal=password='S!B\*d$zDsb='

Secretオブジェクトリスト

$ kubectl get secret
NAME            TYPE                                  DATA   AGE
db-user-pass    Opaque                                2      56s

詳細確認

$ kubectl describe secrets/db-user-pass
Name:         db-user-pass
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  12 bytes
username:  7 bytes

エンコードされた username:password を抽出

$ kubectl get secret db-user-pass -o jsonpath='{.data}'
{"password":"UyFCXCpkJHpEc2I9","username":"ZGV2dXNlcg=="}

上記エンコードされた値を入力しデコード

$ echo 'xxxxxxxxxxxxxxxxx' | base64 --decode

または、次の書式でエンコードされた値をデコード(passwordをデコード)

$ kubectl get secret db-user-pass -o jsonpath='{.data.password}' | base64 --decode
S!B\*d$zDsb=

削除

$ kubectl delete secret ds-user-pass

その他Secretオプション


Managing Secrets using Configuration File


Managing Secrets using Kustomize

kubectl edit デフォルトエディターの変更

Linuxでは kubectl edit コマンドのデフォルトエディターは vi ですが、コマンド実行前に環境変数 KUBE_EDITOR を指定することで任意のエディターに変更できます。

nano を指定

$ export KUBE_EDITOR=/usr/bin/nano

vs-code を指定

$ export KUBE_EDITOR='code --wait'

継続使用する場合は .bashrc に上記 export ~ を追加すること。

Ingress

Name-Based Virtual Hosting

Ingress によりホスト名でアクセスするサーバを振分ける

apiVersion: networking.k8s.io/v1 
kind: Ingress
metadata:
  name: virtual-host-ingress
  namespace: default
spec:
  rules:
  - host: blue.example.com
    http:
      paths:
      - backend:
          service:
            name: webserver-blue-svc
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: green.example.com
    http:
      paths:
      - backend:
          service:
            name: webserver-green-svc
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific

Fanout

Ingress によりホストのディレクトリでアクセスするサーバを振分ける

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fan-out-ingress
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /blue
        backend:
          service:
            name: webserver-blue-svc
            port:
              number: 80
        pathType: ImplementationSpecific
      - path: /green
        backend:
          service:
            name: webserver-green-svc
            port:
              number: 80
        pathType: ImplementationSpecific


Kubernetes Ingress Nginx Controller

ingress-nginx is an Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer.

標準では無効になっているため、minikube のアドオンから有効化する必要があります。

$ minikube addons enable ingress
$ minikube addons list
|-----------------------------|----------|--------------|--------------------------------|
|         ADDON NAME          | PROFILE  |    STATUS    |           MAINTAINER           |
|-----------------------------|----------|--------------|--------------------------------|
| ambassador                  | minikube | disabled     | 3rd party (Ambassador)         |
| auto-pause                  | minikube | disabled     | Google                         |
| csi-hostpath-driver         | minikube | disabled     | Kubernetes                     |
| dashboard                   | minikube | enabled ✅   | Kubernetes                     |
| default-storageclass        | minikube | enabled ✅   | Kubernetes                     |
| efk                         | minikube | disabled     | 3rd party (Elastic)            |
| freshpod                    | minikube | disabled     | Google                         |
| gcp-auth                    | minikube | disabled     | Google                         |
| gvisor                      | minikube | disabled     | Google                         |
| headlamp                    | minikube | disabled     | 3rd party (kinvolk.io)         |
| helm-tiller                 | minikube | disabled     | 3rd party (Helm)               |
| inaccel                     | minikube | disabled     | 3rd party (InAccel             |
|                             |          |              | [[email protected]])            |
| ingress                     | minikube | enabled ✅   | Kubernetes                     |
| ingress-dns                 | minikube | disabled     | Google                         |
| istio                       | minikube | disabled     | 3rd party (Istio)              |
| istio-provisioner           | minikube | disabled     | 3rd party (Istio)              |
| kong                        | minikube | disabled     | 3rd party (Kong HQ)            |
| kubevirt                    | minikube | disabled     | 3rd party (KubeVirt)           |
| logviewer                   | minikube | disabled     | 3rd party (unknown)            |
| metallb                     | minikube | disabled     | 3rd party (MetalLB)            |
| metrics-server              | minikube | enabled ✅   | Kubernetes                     |
| nvidia-driver-installer     | minikube | disabled     | Google                         |
| nvidia-gpu-device-plugin    | minikube | disabled     | 3rd party (Nvidia)             |
| olm                         | minikube | disabled     | 3rd party (Operator Framework) |
| pod-security-policy         | minikube | disabled     | 3rd party (unknown)            |
| portainer                   | minikube | disabled     | 3rd party (Portainer.io)       |
| registry                    | minikube | disabled     | Google                         |
| registry-aliases            | minikube | disabled     | 3rd party (unknown)            |
| registry-creds              | minikube | disabled     | 3rd party (UPMC Enterprises)   |
| storage-provisioner         | minikube | enabled ✅   | Google                         |
| storage-provisioner-gluster | minikube | disabled     | 3rd party (Gluster)            |
| volumesnapshots             | minikube | disabled     | Kubernetes                     |
|-----------------------------|----------|--------------|--------------------------------|

Annotations 注釈

Ex)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webserver
  annotations:
    description: Deployment based PoC dates 2nd Mar'2022
$ kubectl describe deployment webserver

Name:                webserver
Namespace:           default
CreationTimestamp:   Fri, 25 Mar 2022 05:10:38 +0530
Labels:              app=webserver
Annotations:         deployment.kubernetes.io/revision=1
                     description=Deployment based PoC dates 2nd Mar'2022
... 

Horizontal Pod Autoscaler (HPA)

HPA is an algorithm-based controller API resource which automatically adjusts the number of replicas in a ReplicaSet, Deployment or Replication Controller based on CPU utilization.

Vertical Pod Autoscaler (VPA)

VPA automatically sets Container resource requirements (CPU and memory) in a Pod and dynamically adjusts them in runtime, based on historical utilization data, current resource availability and real-time events.

Cluster Autoscaler

Cluster Autoscaler automatically re-sizes the Kubernetes cluster when there are insufficient resources available for new Pods expecting to be scheduled or when there are underutilized nodes in the cluster.


Resource Quotas リソースの割当て


Jobs

  • parallelism - to set the number of pods allowed to run in parallel;
  • completions - to set the number of expected completions;
  • activeDeadlineSeconds - to set the duration of the Job;
  • backoffLimit - to set the number of retries before Job is marked as failed;
  • ttlSecondsAfterFinished - to delay the clean up of the finished Jobs.

Cronjob

  • startingDeadlineSeconds - to set the deadline to start a Job if scheduled time was missed;
  • concurrencyPolicy - to allow or forbid concurrent Jobs or to replace old Jobs with new ones.

StatefulSets

Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of their Pods. These pods are created from the same spec, but are not interchangeable: each has a persistent identifier that it maintains across any rescheduling.

If you want to use storage volumes to provide persistence for your workload, you can use a StatefulSet as part of the solution. Although individual Pods in a StatefulSet are susceptible to failure, the persistent Pod identifiers make it easier to match existing volumes to the new Pods that replace any that have failed.

Ex)

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  minReadySeconds: 10 # by default is 0
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi

In the above example:

  • A Headless Service, named nginx, is used to control the network domain.
  • The StatefulSet, named web, has a Spec that indicates that 3 replicas of the nginx container will be launched in unique Pods.
  • The volumeClaimTemplates will provide stable storage using PersistentVolumes provisioned by a PersistentVolume Provisioner.

The name of a StatefulSet object must be a valid DNS subdomain name.


Custom Resource Definitions (CRDs)

This is the easiest way to add custom resources and it does not require any programming knowledge. However, building the custom controller would require some programming.

API Aggregation

For more fine-grained control, we can write API Aggregators. They are subordinate API services which sit behind the primary API Server. The primary API Server acts as a proxy for all incoming API requests - it handles the ones based on its capabilities and proxies over the other requests meant for the subordinate API services.

セキュリティとネットワークポリシー

Pod Security Admission

is a built in admission controller for Pod Security that is enabled by default in the API Server.

It can enforce the three Pod Security Standards

Pod Security Standards

at namespace level, by automating the security context restriction to pods when they are deployed.

Profile Description
Privileged Unrestricted policy, providing the widest possible level of permissions. This policy allows for known privilege escalations.
Baseline Minimally restrictive policy which prevents known privilege escalations. Allows the default (minimally specified) Pod configuration.
Restricted Heavily restricted policy, following current Pod hardening best practices.

Network Policies

are sets of rules which define how Pods are allowed to talk to other Pods and resources inside and outside the cluster. Pods not covered by any Network Policy will continue to receive unrestricted traffic from any endpoint.

ログ取得とモニタリング

Metrics Server

is a cluster-wide aggregator of resource usage data - a relatively new feature in Kubernetes.

Prometheus

Managing Resouces

サービス、デプロイなどのリソースのマニフェストを1つのファイルに纏めることも出来ます。
--- で仕切り)

nginx-app.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

上記マニフェストからサービスとデプロイのリソースを同時に作成

$ kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created

複数のマニフェストやそれらが格納されているディレクトリを指定して複数のリソースを作成することも出来ます。

$ kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
$ kubectl apply -f https://k8s.io/examples/application/nginx/

What Happens During a Kubernetes Control Plane Failure?

クラスター全体を管理する Control Plane (マスターノード)をインストールしているマシンに不具合が発生した場合、既に稼働しているワーカーノードには直ぐに影響は及びません。ただし、ワーカーノード内でのレプリカ作成やスケジューリングなどを Control Plane (マスターノード)が担っているため事前に以下の対策が必要となります。

Options for Highly Available Topology

Stacked control plane and etcd nodes

kubeadm-ha-topology-stacked-etcd

External etcd nodes

kubeadm-ha-topology-external-etcd

minikubeクラスターにローカルに保存している既存イメージを投入する方法

以下の8通りの方法が提示されています。

Method Supported Runtimes Performance Load Build
docker-env command only docker good yes yes
cache command all ok yes no
podman-env command only cri-o good yes yes
registry addon all ok yes no
minikube ssh all best yes* yes*
ctr/buildctl command only containerd good yes yes
image load command all ok yes no
image build command all ok no yes

シェルのDocker環境変数を指定してアクセス
docker コマンドはシェルを閉じるまでクラスター内で処理されます。

$ eval $(minikube -p minikube docker-env)

コンテナクラスターへ minikube ssh コマンドでアクセス
プロフィール "-p minikube" は省略可

$ minikube -p minikube ssh
Last login: Fri Sep 30 06:40:35 2022 from 192.168.49.1
docker@minikube:~$ 

コンテナクラスターへ "docker exec" コマンドでアクセス

$ docker exec -ti minikube bash
root@minikube:/#