ローカルアプリケーションイメージのビルドと実行

DockerBeginner
オンラインで実践に進む

はじめに

これまでのデプロイメントに関する実験では、レジストリやクラスターキャッシュに既に存在するイメージを使用してきました。アプリケーション開発者は、ローカルでのイメージワークフローを理解しておく必要があります。つまり、アプリケーションファイルからイメージをビルドし、そのイメージを Kubernetes ノードで利用可能にし、Deployment に対してそのイメージを使用するように指示するプロセスです。

この実験では、Minikube を使用して小規模な Web アプリケーションイメージをローカルでビルドし、imagePullPolicy: Never を指定してデプロイします。その後、ローリングアップデートのためにアプリケーションを別のイメージタグとして再ビルドします。これは、アプリケーションの成果物をそれを実行する Kubernetes ワークロードに接続するという、CKAD 試験でよく見られるタスクを再現したものです。

ローカルイメージ用ワークスペースの準備

このステップでは、クリーンな名前空間を準備し、イメージのビルドパスが利用可能であることを確認します。

/home/labex/project から開始します。このディレクトリ内にアプリケーションファイル、イメージビルドファイル、および Kubernetes マニフェストを作成します。

mkdir -p /home/labex/project
cd /home/labex/project

Kubernetes API サーバーに到達可能であることを確認します。VM が起動した直後でノードの準備ができていない場合は、数秒待ってから再度コマンドを実行してください。

kubectl get nodes --request-timeout=5s

期待される出力例:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

クラスターネットワーキングの Pod が「Ready」になるまで待ちます。アプリケーションは Service 経由でテストされるため、ネットワークが正常である必要があります。

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

期待される出力:

pod/calico-node-... condition met

ckad-prep-local-image という名前の名前空間を作成し、現在の名前空間として設定します。

kubectl create namespace ckad-prep-local-image
kubectl config set-context --current --namespace=ckad-prep-local-image

名前空間を確認し、Minikube のイメージコマンドを確認します。minikube image build コマンドは、Minikube プロファイルに対して直接イメージをビルドするため、レジストリにプッシュすることなく Pod から使用できます。

kubectl config view --minify --output 'jsonpath={..namespace}'; echo
minikube image build --help | sed -n '1,4p'

期待される出力例:

ckad-prep-local-image
Build a container image...

最初のローカルイメージのビルド

このステップでは、小規模な Web アプリケーションを作成し、local-message-app:v1 としてビルドします。

このイメージは、BusyBox の httpd を使用して 1 つの静的ファイルを提供します。ファイルの内容は目に見えるアプリケーションのバージョンであり、後で Kubernetes でどのイメージタグが実行されているかを証明するために使用します。

アプリケーションディレクトリと最初の Web ページを作成します。

mkdir -p local-message-app/www
cat > local-message-app/www/index.html <<'EOF'
local-image-v1
EOF

Dockerfile を作成します。COPY 命令はローカルの www/index.html ファイルをイメージ内に配置し、CMD はイメージからコンテナが実行されたときにポート 8080 で BusyBox Web サーバーを起動します。

cat > local-message-app/Dockerfile <<'EOF'
FROM busybox:1.36
COPY www/index.html /www/index.html
EXPOSE 8080
CMD ["httpd", "-f", "-p", "8080", "-h", "/www"]
EOF

アクティブな Minikube プロファイル用にイメージをビルドします。-t オプションはイメージにローカルタグを付与し、最後のパスはビルドコンテキストディレクトリを指定します。

minikube image build --profile labex-v135 -t local-message-app:v1 ./local-message-app

期待される出力例:

naming to docker.io/library/local-message-app:v1 done

Minikube が認識しているイメージを一覧表示し、新しいタグを探します。

minikube image ls --profile labex-v135 | grep local-message-app

期待される出力:

docker.io/library/local-message-app:v1

ローカルイメージのデプロイ

このステップでは、Kubernetes でローカルイメージを実行します。

local-message-app:v1 はリモートレジストリにプッシュされていないため、Deployment では imagePullPolicy: Never を使用します。これにより、kubelet はネットワークからイメージをプルしようとせず、ノード上に既に存在するイメージを使用するようになります。

local-image-app.yaml を作成します。

cat > local-image-app.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: local-message-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: local-message-app
  template:
    metadata:
      labels:
        app: local-message-app
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: web
        image: local-message-app:v1
        imagePullPolicy: Never
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 1
          periodSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
  name: local-message-app
spec:
  selector:
    app: local-message-app
  ports:
  - port: 80
    targetPort: 8080
EOF

マニフェストを適用し、Deployment の完了を待ちます。

kubectl apply -f local-image-app.yaml
kubectl rollout status deployment/local-message-app --timeout=120s

期待される出力例:

deployment.apps/local-message-app created
service/local-message-app created
deployment "local-message-app" successfully rolled out

クライアント Pod を作成し、Service をテストします。

kubectl run image-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/image-client --timeout=120s
kubectl exec image-client -- wget -qO- http://local-message-app

期待される出力:

local-image-v1

新しいローカルイメージの再ビルドとロールアウト

このステップでは、アプリケーションを 2 番目のイメージタグとして再ビルドし、Deployment をそのタグにロールアウトします。

ディスク上のファイルを変更しても、実行中のイメージは変更されません。新しいイメージタグをビルドし、Kubernetes がそのタグから新しい Pod を開始するように Deployment を更新する必要があります。これにより、バージョン変更が可視化され、変更可能なローカルイメージの内容に依存することを回避できます。

Web ページの内容をバージョン 2 に置き換えます。

cat > local-message-app/www/index.html <<'EOF'
local-image-v2
EOF

2 番目のイメージタグをビルドします。

minikube image build --profile labex-v135 -t local-message-app:v2 ./local-message-app

期待される出力例:

naming to docker.io/library/local-message-app:v2 done

Deployment のイメージを更新し、ロールアウトを待ちます。

kubectl set image deployment/local-message-app web=local-message-app:v2
kubectl rollout status deployment/local-message-app --timeout=120s

期待される出力例:

deployment.apps/local-message-app image updated
deployment "local-message-app" successfully rolled out

イメージタグとアプリケーションの応答の両方を確認します。

kubectl get deployment local-message-app -o jsonpath='{.spec.template.spec.containers[0].image}'; echo
kubectl exec image-client -- wget -qO- http://local-message-app

期待される出力:

local-message-app:v2
local-image-v2

まとめ

Minikube プロファイル用に小規模なアプリケーションイメージをビルドし、imagePullPolicy: Never を指定してデプロイし、Kubernetes Service 経由でテストしました。その後、アプリケーションを新しいイメージタグとして再ビルドし、Deployment を更新しました。重要なワークフローは、Pod が実行される前に、ノードでイメージを利用可能にすることです。