构建并运行本地应用程序镜像

DockerBeginner
立即练习

介绍

之前的部署实验中使用的镜像均已存在于镜像仓库或集群缓存中。应用程序开发人员还需要了解本地镜像的工作流程:从应用程序文件构建镜像,使该镜像可供 Kubernetes 节点使用,并指示 Deployment 使用它。

在本实验中,你将使用 Minikube 在本地构建一个小型 Web 应用程序镜像,通过 imagePullPolicy: Never 进行部署,然后将应用程序重新构建为第二个镜像标签以进行滚动更新。这模拟了 CKAD 风格的常见任务:将应用程序制品与运行它的 Kubernetes 工作负载连接起来。

准备本地镜像工作区

在此步骤中,你将准备一个干净的命名空间,并确认镜像构建路径可用。

从 /home/labex/project 开始。你将在该目录中创建应用程序文件、镜像构建文件和 Kubernetes 清单。

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

检查 Kubernetes API 服务器是否可达。如果虚拟机刚启动且节点尚未就绪,请等待几秒钟后再运行该命令。

kubectl get nodes --request-timeout=5s

预期输出包括:

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

等待集群网络 Pod 就绪。由于应用程序将通过 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 来提供一个静态文件。文件内容即为可见的应用程序版本,以便稍后验证 Kubernetes 中运行的是哪个镜像标签。

创建应用程序目录和第一个网页:

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

重建并滚动更新新的本地镜像

在此步骤中,你将把应用程序重新构建为第二个镜像标签,并将 Deployment 滚动更新到该标签。

更改磁盘上的文件不会改变正在运行的镜像。你必须构建一个新的镜像标签并更新 Deployment,以便 Kubernetes 从该标签启动新的 Pod。这使得版本变更清晰可见,并避免依赖可变的本地镜像内容。

将网页内容替换为版本二:

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

构建第二个镜像标签:

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 运行镜像之前,确保该镜像已在节点上可用。