Docker/Kubernetes 実践コンテナ開発入門@33日目

Docker/Kubernetes 実践コンテナ開発入門:書籍案内|技術評論社

前回は、オンプレミス環境での k8s クラスタ構築について読み進めました。

今回は k8s の応用についてやっていきます。

7.Kubernetes の発展的な利用

7.1 Kubernetes の様々なリソース

  • 常駐型のサーバアプリケーション構築する上で基本となるリソース
    • Pod、ReplicaSet、Deployment、Service、Ingress
  • 上記以外にもジョブサーバなど多様な使い道がある

7.1.1 Job

  • 一つ以上の Pod を作成し、指定された数の Pod が正常に完了するまでを管理するリソース

  • Job による全ての Pod が正常に終了しても Pod は削除されずに保持される => Docker のコンテナと似ている

  • バッチ処理に向いている

  • simple-job.yaml

apiVersion: batch/v1
kind: Job # Jobリソース
metadata:
  name: pingpong # リソース名
  labels:
    app: pingpong # リソースのラベル
spec:
  parallelism: 3 # 同時に実行されるPod数
  template:
    metadata:
      labels:
        app: pingpong
    spec:
      containers:
      - name: pingpong
        image: gihyodocker/alpine:bash # Alpine Linuxにbashをインストールしたイメージ
        command: ["/bin/sh"]
        args:
          - "-c"
          - |
            echo [`date`] ping!
            sleep 10
            echo [`date`] pong!
      restartPolicy: Never # Pod終了時の再実行の設定。失敗時にPodを再作成して実行する
  • Job をデプロイするとエラー
$ kubectl apply -f simple-job.yaml
Unable to connect to the server: dial tcp 35.221.107.8:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
  • 先日クラスタ削除したためのエラーだと思われる。

  • クラスタを作り直す(PowerShell で実行)

$ gcloud container clusters create gihyo --cluster-version=1.16.13-gke.401 --machine-type=n1-standard-1 --num-nodes=3
WARNING: Warning: basic authentication is deprecated, and will be removed in GKE control plane versions 1.19 and newer. For a list of recommended authentication methods, see: https://cloud.google.com/kubernetes-engine/docs/how-to/api-server-authentication
WARNING: Currently VPC-native is not the default mode during cluster creation. In the future, this will become the default mode and can be disabled using `--no-enable-ip-alias` flag. Use `--[no-]enable-ip-alias` flag to suppress this warning.
WARNING: Newly created clusters and node-pools will have node auto-upgrade enabled by default. This can be disabled using the `--no-enable-autoupgrade` flag.
WARNING: Starting with version 1.18, clusters will have shielded GKE nodes by default.
WARNING: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s).
Creating cluster gihyo in asia-northeast1-a... Cluster is being health-checked (master is healthy)...done.
Created [https://container.googleapis.com/v1/projects/marine-proposal-295213/zones/asia-northeast1-a/clusters/gihyo].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-northeast1-a/gihyo?project=marine-proposal-295213
kubeconfig entry generated for gihyo.
NAME   LOCATION           MASTER_VERSION   MASTER_IP        MACHINE_TYPE   NODE_VERSION     NUM_NODES  STATUS
gihyo  asia-northeast1-a  1.16.13-gke.401  104.xxx.xxx.xxx  n1-standard-1  1.16.13-gke.401  3          RUNNING


Updates are available for some Cloud SDK components.  To install them,
please run:
  $ gcloud components update
  • コンポーネントアップデート
$ gcloud components update
  • 再度デプロイ
$ kubectl apply -f simple-job.yaml
job.batch/pingpong created
  • ログを確認
  • ping!を表示し 10 秒 sleep した後に「ping!」を表示し終了する
$ kubectl logs -l app=pingpong
[Tue Nov 17 13:58:37 UTC 2020] ping!
[Tue Nov 17 13:58:47 UTC 2020] pong!
[Tue Nov 17 13:58:35 UTC 2020] ping!
[Tue Nov 17 13:58:45 UTC 2020] pong!
[Tue Nov 17 13:58:35 UTC 2020] ping!
[Tue Nov 17 13:58:45 UTC 2020] pong!
  • 終了した Pod は Completed として表示される
$ kubectl get pod -l app=pingpong
NAME             READY   STATUS      RESTARTS   AGE
pingpong-hcd7j   0/1     Completed   0          8m1s
pingpong-tzc8v   0/1     Completed   0          8m1s
pingpong-vd9j9   0/1     Completed   0          8m1s

7.1.2 CronJob

  • Job は一度きりの Pod の実行

  • 対して CronJob はスケジューリングして定期的に Pod を実行

  • simple-cronjob.yaml

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: pingpong
spec:
  schedule: "*/1 * * * *" # Cron記法でPodの起動スケジュールを定義できる
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: pingpong
        spec:
          containers:
          - name: pingpong
            image: gihyodocker/alpine:bash
            command: ["/bin/sh"]
            args:
              - "-c"
              - |
                echo [`date`] ping!
                sleep 10
                echo [`date`] pong!
          restartPolicy: OnFailure
  • CronJob をデプロイ
$ kubectl apply -f simple-cronjob.yaml
cronjob.batch/pingpong created
  • job の確認
$ kubectl get job -l app=pingpong
NAME                  COMPLETIONS   DURATION   AGE
pingpong              3/1 of 3      18s        14m
pingpong-1605622260   1/1           11s        87s
pingpong-1605622320   1/1           12s        27s
  • ログの確認
$ kubectl logs -l app=pingpong
[Tue Nov 17 14:11:04 UTC 2020] ping!
[Tue Nov 17 14:11:14 UTC 2020] pong!
[Tue Nov 17 14:12:04 UTC 2020] ping!
[Tue Nov 17 14:12:14 UTC 2020] pong!
[Tue Nov 17 14:13:04 UTC 2020] ping!
[Tue Nov 17 14:13:14 UTC 2020] pong!
[Tue Nov 17 13:58:37 UTC 2020] ping!
[Tue Nov 17 13:58:47 UTC 2020] pong!
[Tue Nov 17 13:58:35 UTC 2020] ping!
[Tue Nov 17 13:58:45 UTC 2020] pong!
[Tue Nov 17 13:58:35 UTC 2020] ping!
[Tue Nov 17 13:58:45 UTC 2020] pong!
  • 従来の非コンテナ環境では Linux の crontab にスケジュールと実行するスクリプトを定義する手法が中心だった。
  • k8s の CronJob を利用すれば全てをコンテナベースで解決できる

7.1.3 Secret

  • Secret リソースを定義すると、機密情報の文字列を Base64 文字列に変換
  • 例として、Nginx の Basic 認証の認証情報を記述したファイルを Secret で管理
  • openssl を利用してユーザー名とパスワードを暗号化し、その結果を Base64 文字列に変換
$ echo "your_username:$(openssl passwd -quiet -crypt your_password)" | base64
eW91cl91c2VybmFtZTpPOWhncjF3UXZIY1ZFCg==
  • nginx-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: nginx-secret
type: Opaque
data:
  .htpasswd: eW91cl91c2VybmFtZTpyejc5SXpTalplaWZvCg== # .htpasswdというファイルを生成し、内容にはBase64化された文字列を指定
  • Secret をデプロイ
$ kubectl apply -f nginx-secret.yaml
secret/nginx-secret created
  • ダッシュボードで Secret 確認

ダッシュボードでSecret確認

  • basic-auth.yaml
apiVersion: v1
kind: Service
metadata:
  name: basic-auth
spec:
  type: NodePort
  selector:
    app: basic-auth
  ports:
  - protocol: TCP
    port: 80
    targetPort: http
    nodePort: 30060

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: basic-auth
  labels:
    app: basic-auth
spec:
  replicas: 1
  selector:
    matchLabels:
      app: basic-auth
  template:
    metadata:
      labels:
        app: basic-auth
    spec:
      containers:
      - name: nginx
        image: "gihyodocker/nginx:latest"
        imagePullPolicy: Always
        ports:
          - name: http
            containerPort: 80
        env:
          - name: BACKEND_HOST
            value: "localhost:8080"
          - name: BASIC_AUTH_FILE
            value: "/etc/nginx/secret/.htpasswd" # nginx-secretで.htpasswdとして設定したBase64文字列は復号される
        volumeMounts:
          - mountPath: /etc/nginx/secret
            name: nginx-secret
            readOnly: true
      - name: echo
        image: "gihyodocker/echo:latest"
        imagePullPolicy: Always
        ports:
          - containerPort: 8080
        env:
          - name: HTTP_PORT
            value: "8080"
      volumes: # すでに作成しているSecretであるnginx-secretをボリュームとしてマウント
      - name: nginx-secret
        secret:
          secretName: nginx-secret
  • Deployment をデプロイ
$ kubectl apply -f basic-auth.yaml
service/basic-auth unchanged
deployment.apps/basic-auth created
  • 認証されるか HTTP リクエスト送信するとエラー
$ curl http://127.0.0.1:30060
curl: (7) Failed to connect to 127.0.0.1 port 30060: Connection refused
  • コンテナ作成中になっている。。時間がかかるのだろうか。
$ kubectl get pod
NAME                          READY   STATUS              RESTARTS   AGE
basic-auth-67667776f9-zj47j   0/2     ContainerCreating   0          5m22s

kubernetes で ContainerCreating (FailedMount) で Pod が起動しない時 | ytyng.com

  • 以下のような警告が出ている。
  • マウントできずにタイムアウトしてしまったようだ。
  • basic-auth.yaml のボリュームの t がコピペミスでなくなっていた。。修正したところちゃんと起動した。
$ kubectl describe pods
47j to gke-gihyo-default-pool-477390af-djj8
  Warning  FailedMount  2m38s (x2 over 4m56s)  kubelet, gke-gihyo-default-pool-477390af-djj8  Unable to attach or mount volumes: unmounted volumes=[nginx-secret], unattached volumes=[default-token-wxrm6 nginx-secret]: timed out waiting for the condition
  Warning  FailedMount  62s (x12 over 9m16s)   kubelet, gke-gihyo-default-pool-477390af-djj8  MountVolume.SetUp failed for volume "nginx-secret" : secret "nginx-secre" not found
  Warning  FailedMount  24s (x2 over 7m13s)    kubelet, gke-gihyo-default-pool-477390af-djj8  Unable to attach or mount volumes: unmounted volumes=[nginx-secret], unattached volumes=[nginx-secret default-token-wxrm6]: timed out waiting for the condition
  • 再度 curl すると認証されるはずだが、やっぱりエラーのまま…なぜ・・・!?

コラム 認証情報をセキュアに環境変数へ設定する

  • valueFrom.secretKeyRef を利用して Secret の data を渡すことができる。

今日の学び

  • ハンズオン時にはログを残しておくとあとで役にたつ。
  • 単発のバッチ処理には Job、スケジューリングしたバッチ処理には CronJob が便利。
  • セキュリティ対策として Secret を使える。
Hugo で構築されています。
テーマ StackJimmy によって設計されています。