介绍
供应链安全在工作负载运行于集群之前就已经开始了。如果镜像包含不必要的工具、来源不明或使用了未经批准的标签,那么你之前学到的运行时控制措施将面临更大的风险。一个最小化的合规镜像应具备:较小的构建上下文、清晰的基础镜像、明确的应用程序入口点、有用的元数据标签,以及能够在目标集群中运行的证明。
在本实验中,你将创建一个小型本地镜像构建上下文,在 labex-v134 minikube 配置中构建镜像,检查生成的镜像元数据,使用 imagePullPolicy: Never 进行部署,并从 Kubernetes 验证其运行时内容。本实验侧重于实践:你暂时不会进行镜像扫描,也不会强制执行镜像仓库策略。你将学习供应链的第一项习惯:构建一个小型、命名规范、可检查的镜像,并证明其内部包含的内容。
创建小型镜像构建上下文
在此步骤中,你将创建构成镜像的文件。构建上下文是发送给镜像构建器的目录。保持构建上下文精简非常重要,因为每一个多余的文件都有可能被意外复制到镜像中。
在实验工作区开始:
cd /home/labex/project/minimal-approved-image
阅读实验说明:
sed -n '1,160p' IMAGE_BUILD_NOTES.md
确认 CKS 上下文和命名空间:
kubectl config current-context | tee context-check.txt
kubectl get namespace cks-prep-image | tee namespace-check.txt
创建应用程序脚本。该脚本会打印就绪消息,打印运行时 UID,然后进入睡眠状态,以便 Kubernetes 能够保持容器运行以供检查。
cat > app.sh <<'EOF'
#!/bin/sh
set -eu
echo "minimal approved image ready"
echo "runtime uid: $(id -u)"
sleep 300
EOF
chmod 0755 app.sh
创建 Dockerfile。busybox:1.36 是本实验使用的小型基础镜像。OCI 风格的标签记录了该镜像在本实验中被批准的原因,USER 65534:65534 使镜像默认以非 root 的数字用户身份运行。
cat > Dockerfile <<'EOF'
FROM busybox:1.36
LABEL org.opencontainers.image.title="minimal-approved-app"
LABEL org.opencontainers.image.source="local-cks-prep"
LABEL security.labex.io.approved="true"
WORKDIR /app
COPY app.sh /app/app.sh
RUN chmod 0555 /app/app.sh
USER 65534:65534
ENTRYPOINT ["/app/app.sh"]
EOF
保存构建上下文清单和应用程序脚本的校验和:
find . -maxdepth 1 -type f -printf '%f\n' | sort | tee build-context-files.txt
sha256sum app.sh | tee app-sha256.txt
sed -n '1,120p' Dockerfile | tee dockerfile-review.txt
现在你的目录中将包含 Dockerfile、app.sh、说明文件以及你保存的证据文件。镜像边界的关键在于 Dockerfile 中的 COPY 行:只有 app.sh 被复制到了镜像内的 /app/app.sh。
在 Minikube 配置中构建镜像
在此步骤中,你将在 labex-v134 minikube 配置中构建镜像。在此处构建非常重要,因为 Kubernetes 将从 minikube 节点运行时运行容器。如果你仅在外部 VM 的 Docker 守护进程上构建镜像,minikube 节点可能无法识别它。
使用明确的本地标签构建镜像:
minikube -p labex-v134 image build -t labex/minimal-approved:1.0 .
检查 minikube 配置中的镜像。第一条命令确认镜像存在于节点运行时中。第二条命令保存关键元数据,包括配置的用户、入口点和标签。
minikube -p labex-v134 ssh -- 'docker image ls labex/minimal-approved:1.0' | tee built-image-list.txt
minikube -p labex-v134 ssh -- 'docker image inspect labex/minimal-approved:1.0' | tee built-image-inspect.json
使用 jq 提取合规证明所需的相关字段:
jq '.[0].Config | {User, Entrypoint, Labels}' built-image-inspect.json | tee built-image-approval.json
你应该能在 built-image-list.txt 中看到镜像标签,User 设置为 65534:65534,Entrypoint 设置为 /app/app.sh,且合规标签设置为 true。
在 Kubernetes 中运行合规镜像
在此步骤中,你将在 Kubernetes 中运行本地镜像。Pod 使用 imagePullPolicy: Never,因为镜像是在 minikube 配置内部构建的,而不是推送到镜像仓库的。该设置告诉 Kubernetes 使用本地节点镜像,如果镜像不存在则报错。
创建 Pod 清单:
cat > approved-image-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: approved-image-app
namespace: cks-prep-image
labels:
app: approved-image-app
supply-chain.labex.io/approved: "true"
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
containers:
- name: app
image: labex/minimal-approved:1.0
imagePullPolicy: Never
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
EOF
应用 Pod 并等待其就绪:
kubectl apply -f approved-image-pod.yaml
kubectl wait --for=condition=Ready pod/approved-image-app -n cks-prep-image --timeout=120s
保存 Pod 日志和当前的 Pod YAML:
kubectl logs approved-image-app -n cks-prep-image | tee approved-image-logs.txt
kubectl get pod approved-image-app -n cks-prep-image -o yaml | tee approved-image-pod.current.yaml
日志应显示 minimal approved image ready 和 runtime uid: 65534。这证明了 Kubernetes 正在以预期的非 root 用户身份运行镜像入口点。
验证运行时内容
在此步骤中,你将从 Kubernetes 检查正在运行的容器。镜像合规性不应仅停留在标签名称上。你需要证据证明运行时包含预期的应用程序路径,且不包含本不应存在于镜像中的多余文件。
检查应用程序目录:
kubectl exec -n cks-prep-image approved-image-app -- sh -c 'ls -la /app; test -f /app/app.sh; echo APP_PATH_OK' | tee runtime-app-path.txt
检查运行时用户,并对不必要的调试文件进行简单的负面检查:
kubectl exec -n cks-prep-image approved-image-app -- sh -c 'id -u; test ! -e /app/debug-tool && echo NO_DEBUG_TOOL' | tee runtime-content-check.txt
保存一份结合了 Kubernetes 状态和镜像元数据的最终合规记录:
kubectl get pod approved-image-app -n cks-prep-image -o json | jq '{image: .spec.containers[0].image, imagePullPolicy: .spec.containers[0].imagePullPolicy, podSecurityContext: .spec.securityContext, containerSecurityContext: .spec.containers[0].securityContext}' | tee final-pod-approval.json
jq '.[0].Config | {User, Entrypoint, Labels}' built-image-inspect.json | tee final-image-approval.json
最终证据应显示本地合规镜像标签、imagePullPolicy: Never、非 root 运行时设置、/app/app.sh 入口点以及合规标签。
总结
在本 CKS 准备课程中,你练习了供应链的第一个工作流:构建并证明一个最小化的合规镜像。你创建了一个小型构建上下文,在 labex-v134 minikube 配置中构建了 labex/minimal-approved:1.0,检查了镜像元数据和标签,使用 imagePullPolicy: Never 部署了本地镜像,并从 Kubernetes 验证了运行时用户和应用程序内容。后续的供应链实验将在此基础上,进一步学习清单扫描、Helm 输出审查、SBOM 和校验和证明、受信任的镜像仓库控制以及构建密钥清理等内容。



