Lazy loaded image
k8s 部署 buildkit 容器镜像构建服务
Words 2344Read Time 6 min
2025-10-14
2026-1-5
date
related_level
slug
type
relate_date
summary
status
tags
category
last_updated
Jan 5, 2026 01:47 PM
是否已更新
orginal_page
是否推荐
buildkit 简介
  • MediumMediumIntroducing BuildKit
  • buildkit 用于将源代码转换为以高效、富有表现力和可重复的方式构建工件
    • 前端/后端分离,支持多种前端,可输出为镜像、OCI tarball、Docker tar、本地文件系统等
    • 支持无 root 构建(rootless)、隔离构建上下文
  • buildctl 是 BuildKit 官方提供的命令行客户端,用于与 buildkitd 守护进程通信
buildkitd 有多种部署模式,这里选择 Deployment + Service 的 rootless 模式
kustomize 配置 buildkit-rootless deployment
  • mkdir -p ~/.config/k3s/workloads/deployment/buildkit-rootless/{ns,base,cred,network,tls,overlay}
  • cd ~/.config/k3s/workloads/deployment/buildkit-rootless
  • rootless 样例
    • curl -o buildkit-rootless.yaml https://raw.githubusercontent.com/moby/buildkit/refs/heads/master/examples/kubernetes/deployment%2Bservice.rootless.yaml
namespace
vim ns/kustomization.yaml
vim ns/ns.yaml
base
vim base/kustomization.yaml
vim base/buildkit-deploy.yaml
cred
  • mkdir cred/{config,secrets}
  • 如果需要自定义配置 buildkit 可以配置 buildkitd.toml
vim cred/kustomization.yaml
vim cred/secrets/.dockerconfigjson
  • 用于访问私有 harbor 的凭据
  • 生成 auth 字符串
    • echo -n "username:password" | base64
network
vim network/kustomization.yaml
vim network/buildkit-svc.yaml
vim network/buildkit-ingressroutetcp.yaml
  • 外部端口使用 443
  • 有自身的 TLS 所以不终止
    • HostSNI 需要与签发的证书保持一致
tls
vim tls/kustomization.yaml
vim tls/buildkit-cert.yaml
overlay
  • mkdir -p overlay/{init,prod}
vim overlay/init/kustomization.yaml
vim overlay/prod/kustomization.yaml
vim overlay/prod/patch-docker-cred.yaml
  • rootless 显示指定 DOCKER_CONFIG
vim overlay/prod/patch-nodeslector.yaml
vim overlay/prod/patch-probes.yaml
vim overlay/prod/patch-resources.yaml
kustomize 安装 buildkit-rootless deployment
vim ~/.config/k3s/buildkit-rootless.yaml
  • 修改默认端口 1234 为 11234
  • 未使用持久化缓存,通过 buildctl 指定 --export-cache, --import-cache 来共享缓存
  • 修改 TLS 部分,通过外部 step-ca 服务和 step-issuer 自动提供并续签 tls 证书
    • step-issuer 原理及运作详见相关文章
制品库等使用自签 CA 时需要加载 CA 证书到内部证书库
  • kubectl apply -k ~/.config/k3s/workloads/deployment/buildkit-rootless/overlay/init
    • 初始化配置相关资源
  • kubectl apply -k ~/.config/k3s/workloads/deployment/buildkit-rootless/overlay/prod
查看运行情况
  • kubectl get deployment -n registry buildkitd -o wide
  • kubectl get Certificate -n registry buildkitd-registry-svc-cluster-local-cert -o yaml
  • kubectl get pod -n registry -l app.kubernetes.io/name=buildkitd
  • kubectl describe pod -n registry -l app.kubernetes.io/name=buildkitd
  • kubectl logs -n registry deploy/buildkitd
  • kubectl describe -n kube-system deploy/traefik | grep namespace
    • 查看 traefik 是否为 registry 命名空间提供路由
外部 openssl 测试
添加 DNS 记录到 /etc/hosts
  • 获取 traefik 的 external-ip
    • kubectl get svc -n kube-system traefik -o wide
  • openssl s_client -connect buildkitd.registry.svc.cluster.local:443 -servername buildkitd.registry.svc.cluster.local | grep "subject="
由于采用了 mtls,buildctl 也需要签发客户端证书才能正常构筑
创建客户端证书 CSR
  • step certificate create --csr buildctl.client ~/.step/certs/buildctl.client.csr ~/.step/certs/buildctl.client.key --no-password --insecure
    • 不支持加密密钥所以需要添加 --no-password --insecure
    • subject name 无所谓,关键是由同 CA 签发的客户端证书
  • CSR_B64=$(cat ~/.step/certs/buildctl.client.csr | step base64)
  • 不支持二进制格式密钥还需要转换 key 为 pem 格式
    • step crypto key format ~/.step/certs/buildctl.client.key --out ~/.step/certs/buildctl.clientkey.pem --pem
配置 CertificateRequest 资源文件
  • 使用 StepClusterIssuer 跨命名空间签发
创建 CertificateRequest 资源
  • kubectl apply -f ~/.step/csr.buildctl.client.yaml
查看 CSR 签发情况
kubectl get certificaterequests -n registry buildctl-client-csr -o yaml
  • 查看签发情况
  • step-issuer 会等待 CertificateReques 满足已批准条件后再进行签名
  • 但 step-issuer 会生成 rolebinding 使其符合要求
    • kubectl get clusterrole step-issuer-approver-role
    • kubectl describe clusterrole step-issuer-approver-role
    • kubectl get clusterrolebinding step-issuer-approver-rolebinding
    • kubectl describe clusterrolebinding step-issuer-approver-rolebinding
获取 CSR 中的证书
  • kubectl get certificaterequests -n registry buildctl-client-csr -o jsonpath='{.status.certificate}'| base64 -d > ~/.step/certs/buildctl.client.crt
    • 有效期过了需要重新获取
    • 重新申请脚本
  • step certificate inspect ~/.step/certs/buildctl.client.crt
外部 openssl 测试 mtls 连接
  • openssl s_client -connect buildkitd.registry.svc.cluster.local:443 \ -servername buildkitd.registry.svc.cluster.local \ -cert ~/.step/certs/buildctl.client.crt \ -key ~/.step/certs/buildctl.client.key \ -CAfile ~/.step/certs/root_ca.crt
    • 假设已经设置了 DNS 记录
    • 需要输入之前填写的密码用于解密私钥
  • buildctl 客户端使用下发的证书
    • buildctl \ --addr tcp://buildkitd.registry.svc.cluster.local:443 \ --tlscacert ~/.step/certs/root_ca.crt \ --tlscert ~/.step/certs/buildctl.client.crt \ --tlskey ~/.step/certs/buildctl.clientkey.pem \ build ...
      • 需要输入之前填写的密码用于解密私钥
      • 这部分可以写成 alias 简化 buildctl 调用
buildctl 构筑测试项目 hellobuild
  • mkdir -p ~/project/hellobuild && cd ~/project/hellobuild
vim Dockerfile
vim hello.sh
  • 缓存共享使用了 truesnas 的 garage s3 存储,配置参考 truenas 存储配置
创建 s3 凭据 secret
  • echo -n "AWS Access Key: " && read -s AWS_ACCESS_KEY_ID; echo
  • echo -n "AWS Secret Key: " && read -s AWS_SECRET_ACCESS_KEY; echo
  • kubectl create secret generic s3-credentials \ --namespace=registry \ --from-literal=access_key="$AWS_ACCESS_KEY_ID" \ --from-literal=secret_key="$AWS_SECRET_ACCESS_KEY"
  • kubectl get secret -n registry s3-credentials -o yaml
  • unset AWS_ACCESS_KEY_ID && unset AWS_SECRET_ACCESS_KEY
  • export AWS_ACCESS_KEY_ID=$(kubectl get secret s3-credentials -n registry -o jsonpath='{.data.access_key}' | base64 --decode)
  • export AWS_SECRET_ACCESS_KEY=$(kubectl get secret s3-credentials -n registry -o jsonpath='{.data.secret_key}' | base64 --decode)
  • 使用 minio client 测试 s3 连接
    • mc alias set buildkit http://<truenas_ip>:30188 $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY
    • mc ls buildkit
构筑本地 oci 镜像
  • buildctl build --frontend dockerfile.v0 \ --local context=. \ --local dockerfile=. \ --opt platform=linux/amd64 \ --export-cache type=s3,endpoint_url=http://<truenas_ip>:30188,bucket=buildkit,region=garage,access_key_id=$AWS_ACCESS_KEY_ID,secret_access_key=$AWS_SECRET_ACCESS_KEY,mode=max,,name=hellobuild \ --import-cache type=s3,endpoint_url=http://<truenas_ip>:30188,bucket=buildkit,region=garage,access_key_id=$AWS_ACCESS_KEY_ID,secret_access_key=$AWS_SECRET_ACCESS_KEY,name=hellobuild \ --output type=oci,name=hellobuild:v1.0.0,dest=./hellobuild_v1.0.0.oci.tar
  • 测试镜像
    • nerdctl --namespace k8s.io run --rm --net=none hellobuild:v1.0.0 hello
导入本地镜像并在 k8s 集群上进行部署
  • 假设 k8s 运行时为 containerd 而非 docker
  • nerdctl --namespace k8s.io load --all-platforms -i ./hellobuild_v1.0.0.oci.tar
    • OCI tar 直接使用 load -i 而非 image import
  • nerdctl --namespace k8s.io image ls | grep hellobuild
  • nerdctl --namespace k8s.io image inspect hellobuild:v1.0.0
nerdctl 测试镜像
  • nerdctl --namespace k8s.io run --rm --net=none -it hellobuild:v1.0.0 /usr/local/bin/hello
如果存在问题可以通过 nerdctl 导出容器文件系统,查看对应路径是否存在
  • nerdctl --namespace k8s.io create --net=none --name temphello hellobuild:v1.0.0
  • nerdctl --namespace k8s.io export temphello -o temp.tar
  • nerdctl --namespace k8s.io rm temphello
  • mkdir -p ./tmp-rootfs && tar -xf temp.tar -C ./tmp-rootfs
vim ./job.hellobuild.yaml
  • 因为未上传到镜像仓库,需要指定节点为当前节点
  • kubectl apply -f ./job.hellobuild.yaml
  • kubectl describe job hellobuild
  • kubectl logs job/hellobuild
    • 应该看到 Hello from BuildKit!
清理测试项目
  • kubectl delete -f ./job.hellobuild.yaml
  • nerdctl --namespace k8s.io image rm hellobuild:v1.0.0
  • buildkit 不会热重载证书,需要通过 rollout restart 来更新证书
    • 可以通过 stakater/reloader 来检测证书更新并自动重载
上一篇
k8s 部署高可用 gitea 集群
下一篇
tekton + Argo CD 构筑 k8s 原生 CI/CD 体系

Comments
Loading...