基于 Kubernetes 的 Jenkins 服务也可以去 Docker 了

基于 Kubernetes 的 Jenkins 服务也可以去 Docker 了

作者:陈少文 2021-02-26 08:37:47

云计算 在 1.20 版本之后, Kubernetes 社区放弃了对 Docker 的支持, 而后又有其他社区接手, 隐约给 Docker 蒙上了一层阴影。在这样的背景下, 我们开始考虑非 Docker 环境下, 如何进行 CICD 实践。

[[383773]]

本文转载自微信公众号「问其」,作者陈少文 。转载本文请联系问其公众号。  

1. 去 Docker 给 CICD 带来新的挑战

在 CICD 场景下, 我们经常需要在流水线中构建和推送镜像。

在之前的文档 《在 Kubernetes 上动态创建 Jenkins Slave》[1] 中, 我描述了通过挂载 /var/run/docker.sock 文件, 允许在 Docker 驱动的 Kubernetes 集群中构建和推送镜像。在文档 《如何在 Docker 中使用 Docker》[2]中, 我又进行了更加详细地阐述, 其原理是共享主机 Docker Daemon。

在 1.20 版本之后, Kubernetes 社区放弃了对 Docker 的支持, 而后又有其他社区接手, 隐约给 Docker 蒙上了一层阴影。在这样的背景下, 我们开始考虑非 Docker 环境下, 如何进行 CICD 实践。

非 Docker 环境意味着之前挂载 /var/run/docker.sock 的方式失效了, 我们需要寻找新的解决方案。

2. 测试集群环境

2.1 Kubernetes – 1.17.9

执行如下命令, 查看 Kubernetes 版本:

  1. kubectl version 
  2.  
  3. Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.9", GitCommit:"4fb7ed12476d57b8437ada90b4f93b17ffaeed99", GitTreeState:"clean", BuildDate:"2020-07-15T16:18:16Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"
  4. Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.9", GitCommit:"4fb7ed12476d57b8437ada90b4f93b17ffaeed99", GitTreeState:"clean", BuildDate:"2020-07-15T16:10:45Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"

2.2 Containerd – 1.4.3

执行如下命令, 查看 containerd 版本:

  1. containerd --version 
  2.  
  3. containerd github.com/containerd/containerd v1.4.3 269548fa27e0089a8b8278fc4fc781d7f65a939b 

3. 镜像管理工具 Podman

由于 Containerd 不支持 Docker API, 常见的 docker build、docker push 等命令在 Containerd 环境下无法使用。因此, 需要一种不依赖于 Docker, 针对 OCI 标准的镜像构建和推送工具。

3.1 Podman 简介

Podman 是一个实现 OCI 标准的容器和镜像管理工具, 同时也是 Daemonless, 不需要守护进程, 也支持非特权用户使用。Podman 提供了类似 Docker CLI 的功能, 大部分情况下可以执行 alias docker=podman 使用 Podman 替换 Docker , 而不会有任何问题。

3.2 Podman 安装

  • 安装 Podman 命令行工具

安装方法可以参考 Podman 的安装指引[3]。这里以 CentOS 7 为例:

  1. curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_7/devel:kubic:libcontainers:stable.repo 
  2. yum -y install podman 
  • 查看 Podman 版本
  1. podman --version 
  2.  
  3. podman version 3.0.1 
  • 查看命令参数

这里为了方便查阅, 贴出完整的帮助文档。

 

  1. podman --help 
  2. manage pods and images 
  3.  
  4. Usage: 
  5.   podman [flags] 
  6.   podman [command] 
  7.  
  8. Available Commands: 
  9.   attach      Attach to a running container 
  10.   build       Build an image using instructions from Containerfiles 
  11.   commit      Create new image based on the changed container 
  12.   container   Manage Containers 
  13.   cp          Copy files/folders between a container and the local filesystem 
  14.   create      Create but do not start a container 
  15.   diff        Inspect changes on container's file systems 
  16.   events      Show podman events 
  17.   exec        Run a process in a running container 
  18.   export      Export container's filesystem contents as a tar archive 
  19.   generate    Generated structured data 
  20.   healthcheck Manage Healthcheck 
  21.   help        Help about any command 
  22.   history     Show history of a specified image 
  23.   image       Manage images 
  24.   images      List images in local storage 
  25.   import      Import a tarball to create a filesystem image 
  26.   info        Display podman system information 
  27.   init        Initialize one or more containers 
  28.   inspect     Display the configuration of a container or image 
  29.   kill        Kill one or more running containers with a specific signal 
  30.   load        Load an image from container archive 
  31.   login       Login to a container registry 
  32.   logout      Logout of a container registry 
  33.   logs        Fetch the logs of a container 
  34.   mount       Mount a working container's root filesystem 
  35.   network     Manage Networks 
  36.   pause       Pause all the processes in one or more containers 
  37.   play        Play a pod 
  38.   pod         Manage pods 
  39.   port        List port mappings or a specific mapping for the container 
  40.   ps          List containers 
  41.   pull        Pull an image from a registry 
  42.   push        Push an image to a specified destination 
  43.   restart     Restart one or more containers 
  44.   rm          Remove one or more containers 
  45.   rmi         Removes one or more images from local storage 
  46.   run         Run a command in a new container 
  47.   save        Save image to an archive 
  48.   search      Search registry for image 
  49.   start       Start one or more containers 
  50.   stats       Display a live stream of container resource usage statistics 
  51.   stop        Stop one or more containers 
  52.   system      Manage podman 
  53.   tag         Add an additional name to a local image 
  54.   top         Display the running processes of a container 
  55.   umount      Unmounts working container's root filesystem 
  56.   unpause     Unpause the processes in one or more containers 
  57.   unshare     Run a command in a modified user namespace 
  58.   varlink     Run varlink interface 
  59.   version     Display the Podman Version Information 
  60.   volume      Manage volumes 
  61.   wait        Block on one or more containers 
  62.  
  63. Flags: 
  64.       --cgroup-manager string     Cgroup manager to use (cgroupfs or systemd) (default "systemd") 
  65.       --cni-config-dir string     Path of the configuration directory for CNI networks 
  66.       --config string             Path of a libpod config file detailing container server configuration options 
  67.       --conmon string             Path of the conmon binary 
  68.       --cpu-profile string        Path for the cpu profiling results 
  69.       --events-backend string     Events backend to use 
  70.       --help                      Help for podman 
  71.       --hooks-dir strings         Set the OCI hooks directory path (may be set multiple times) 
  72.       --log-level string          Log messages above specified level: debug, info, warn, error, fatal or panic (default "error") 
  73.       --namespace string          Set the libpod namespace, used to create separate views of the containers and pods on the system 
  74.       --network-cmd-path string   Path to the command for configuring the network 
  75.       --root string               Path to the root directory in which data, including images, is stored 
  76.       --runroot string            Path to the 'run directory' where all state information is stored 
  77.       --runtime string            Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc 
  78.       --storage-driver string     Select which storage driver is used to manage storage of images and containers (default is overlay) 
  79.       --storage-opt stringArray   Used to pass an option to the storage driver 
  80.       --syslog                    Output logging information to syslog as well as the console 
  81.       --tmpdir string             Path to the tmp directory 
  82.       --trace                     Enable opentracing output 
  83.   -v, --version                   Version of podman 
  84.  
  85. Use "podman [command] --help" for more information about a command. 

Podman 在覆盖 Docker 命令的同时,增加了对 Pod 操作的支持。

3.3 主机上测试编译并推送镜像

在使用上可以直接将 docker 命令替换为 podman 即可。

  • 编译镜像
  1. echo -e 'FROM busybox\nRUN echo "hello world"' | podman build -t docker.io/shaowenchen/myimage:latest - 
  2.  
  3. STEP 1: FROM busybox 
  4. Getting image source signatures 
  5. Copying blob 5c4213be9af9 done 
  6. Copying config 491198851f done 
  7. Writing manifest to image destination 
  8. Storing signatures 
  9. STEP 2: RUN echo "hello world" 
  10. hello world 
  11. STEP 3: COMMIT 
  12. 4c8794086d9de80f71d182457b6d2cb18b9d61975b98bcd4cb167bdcabae5b2c 
  13. 4c8794086d9de80f71d182457b6d2cb18b9d61975b98bcd4cb167bdcabae5b2c 
  • 查看编译的镜像
  1. podman images |grep shaowenchen 
  2. docker.io/shaowenchen/myimage   latest   4c8794086d9d   4 minutes ago   1.46 MB 
  • 登录 DockerHub
  1. podman login docker.io -u shaowenchen 
  2.  
  3. Password
  4. Login Succeeded! 
  • 推送镜像
  1. podman push docker.io/shaowenchen/myimage:latest 
  2.  
  3. Getting image source signatures 
  4.  
  5. Copying blob 2893437c336c done 
  6. Copying blob 84009204da3f done 
  7. Copying config 4c8794086d done 
  8. Writing manifest to image destination 
  9. Storing signatures 

4. Jenkns 中使用 Podman 构建镜像

4.1 关键配置

  • 使用 hostPath 将 /var/lib/containers 挂载到主机上

也可以使用 PVC,但是 PVC 可能需要加参数,见下文。

否则会有如下报错:

  1. Error: 'overlay' is not supported over overlayfs, a mount_program is required: backing file system is unsupported for this graph driver 
  • privileged 特权模式

否则会有如下报错:

  1. Error: kernel does not support overlay fs: 'overlay' is not supported over extfs at "/var/lib/containers/storage/overlay": backing file system is unsupported for this graph driver 
  • Podman 参数 –cgroup-manager=cgroupfs

在使用 PVC 作为存储目录时, 需要考虑这项配置。内核通过 Cgroup Driver 隔离一组资源, 可选的参数有 cgroupfs 和 systemd, 需要与集群环境保持一致, 因为他们共用一个内核。我的测试环境使用的是 cgroupfs 。

否则会有如下报错:

  1. unable to write system event: "write unixgram @0011c->/run/systemd/journal/socket: sendmsg: no such file or directory 
  • Podman 参数 –events-backend=file

这项配置通常不会 Block 执行流程,如果你想保持日志更加干净,可以添加。

否则会有如下报错:

  1. unable to write system event: "write unixgram @0011c->/run/systemd/journal/socket: sendmsg: no such file or directory 

4.2 示例一: 在 Jenkinsfile 中显式使用 yaml 模板

这里将容器 /var/lib/containers 挂载到主机 /var/lib/containers 目录,也可以挂载到主机 /tmp 目录,并没有强制要求。主机目录只是提供一个存放数据的地方。

  1. pipeline { 
  2.   agent { 
  3.     kubernetes { 
  4.       yaml ""
  5. apiVersion: v1 
  6. kind: Pod 
  7. spec: 
  8.   containers: 
  9.   - name: centos 
  10.     image: centos:7 
  11.     command: 
  12.     - cat 
  13.     tty: true 
  14.     securityContext: 
  15.         privileged: true 
  16.     volumeMounts: 
  17.     - name: storage 
  18.       mountPath: /var/lib/containers 
  19.   volumes: 
  20.   - name: storage 
  21.     hostPath: 
  22.       path: /var/lib/containers 
  23. ""
  24.    }} 
  25.    stages { 
  26.       stage('Hello') { 
  27.          steps { 
  28.             container('centos') { 
  29.               sh ''
  30.               curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_7/devel:kubic:libcontainers:stable.repo 
  31.               yum -y install podman 
  32.               echo -e 'FROM busybox\nRUN echo "hello world"' | podman --events-backend=file build -t docker.io/shaowenchen1/myimage:latest - 
  33.               podman --events-backend=file images |grep shaowenchen1 
  34.               ''
  35.             } 
  36.          } 
  37.       } 
  38.    } 

Jenkins 的执行日志:

  1. ··· 
  2. Dependency Updated: 
  3.   systemd.x86_64 0:219-78.el7_9.3      systemd-libs.x86_64 0:219-78.el7_9.3      
  4.  
  5. Complete! 
  6. + podman --events-backend=file build -t docker.io/shaowenchen1/myimage:latest - 
  7. + echo -e 'FROM busybox 
  8. RUN echo "hello world"
  9. STEP 1: FROM busybox 
  10. STEP 2: RUN echo "hello world" 
  11. --> Using cache 4c8794086d9de80f71d182457b6d2cb18b9d61975b98bcd4cb167bdcabae5b2c 
  12. STEP 3: COMMIT docker.io/shaowenchen1/myimage:latest 
  13. --> 4c8794086d9 
  14. 4c8794086d9de80f71d182457b6d2cb18b9d61975b98bcd4cb167bdcabae5b2c 
  15. + podman --events-backend=file images 
  16. + grep shaowenchen1 
  17. docker.io/shaowenchen1/myimage  latest  4c8794086d9d  19 hours ago  1.46 MB 

4.3 示例二: 使用 PVC 挂载 /var/lib/containers 目录

在使用 PVC 存储 Podman 数据时,需要提前准备好集群的存储。

  • 查看集群是否有默认的 StorageClass
  1. kubectl get sc 
  2.  
  3. NAME                         PROVISIONER                                                RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE 
  4. openebs-device               openebs.io/local                                           Delete          WaitForFirstConsumer   false                  19d 
  5. openebs-hostpath (default)   openebs.io/local                                           Delete          WaitForFirstConsumer   false                  19d 
  6. openebs-jiva-default         openebs.io/provisioner-iscsi                               Delete          Immediate              false                  19d 
  7. openebs-snapshot-promoter    volumesnapshot.external-storage.k8s.io/snapshot-promoter   Delete          Immediate              false                  19d 
  • 为 Podman 创建一个 PVC

这里的 namespace 需要与 Jenkins 中动态 Agent 所在的 namespace 保持一致。

  1. cat <<EOF | kubectl apply -f - 
  2. apiVersion: v1 
  3. kind: PersistentVolumeClaim 
  4. metadata: 
  5.   name: storage 
  6.   namespace: default 
  7. spec: 
  8.   accessModes: 
  9.     - ReadWriteOnce 
  10.   resources: 
  11.     requests: 
  12.       storage: 30Gi 
  13. EOF 
  • 查看创建的 PVC
  1. kubectl -n default get pvc 
  2.  
  3. NAME         STATUS    VOLUME                                     CAPACITY   ACCESS MODES    
  4. storage      Pending                                                                        openebs-hostpath   11s 

由于使用的是 WaitForFirstConsumer 模式,需要等到有 Pod 使用 PVC 时,才会绑定 PV。

  • 创建 Jenkins 流水线执行
  1. pipeline { 
  2.   agent { 
  3.     kubernetes { 
  4.       yaml ""
  5. apiVersion: v1 
  6. kind: Pod 
  7. spec: 
  8.   containers: 
  9.   - name: centos 
  10.     image: centos:7 
  11.     command: 
  12.     - cat 
  13.     tty: true 
  14.     securityContext: 
  15.         privileged: true 
  16.     volumeMounts: 
  17.     - name: storage 
  18.       mountPath: /var/lib/containers 
  19.   volumes: 
  20.   - name: storage 
  21.     persistentVolumeClaim: 
  22.       claimName: storage 
  23. ""
  24.    }} 
  25.    stages { 
  26.       stage('Hello') { 
  27.          steps { 
  28.             container('centos') { 
  29.               sh ''
  30.               curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_7/devel:kubic:libcontainers:stable.repo 
  31.               yum -y install podman 
  32.               echo -e 'FROM busybox\nRUN echo "hello world"' | podman --events-backend=file build -t docker.io/shaowenchen2/myimage:latest - 
  33.               podman --events-backend=file images |grep shaowenchen2 
  34.               ''
  35.             } 
  36.          } 
  37.       } 
  38.    } 

Jenkins 的执行日志:

  1. ··· 
  2. Dependency Updated: 
  3.   systemd.x86_64 0:219-78.el7_9.3      systemd-libs.x86_64 0:219-78.el7_9.3      
  4.  
  5. Complete! 
  6. + echo -e 'FROM busybox 
  7. RUN echo "hello world"
  8. + podman --events-backend=file build -t docker.io/shaowenchen2/myimage:latest - 
  9. STEP 1: FROM busybox 
  10. STEP 2: RUN echo "hello world" 
  11. --> Using cache f4676f5b5e47a78970f2d97f4a5b77423f381e9742faae06d8c1a2d93bdb27c2 
  12. STEP 3: COMMIT docker.io/shaowenchen2/myimage:latest 
  13. --> f4676f5b5e4 
  14. f4676f5b5e47a78970f2d97f4a5b77423f381e9742faae06d8c1a2d93bdb27c2 
  15. + podman --events-backend=file images 
  16. + grep shaowenchen2 
  17. docker.io/shaowenchen2/myimage  latest  f4676f5b5e47  2 hours ago  1.46 MB 

5. 总结

本文主要提供了一种在非 Docker 驱动的 Kubernetes 集群中,进行 CICD 镜像构建的思路,使用 Podman 替换 Docker 。选择 Podman 的原因是, 其使用方式更贴近 Docker,而 Buildah 需要用户修改镜像编译指令,因为 Buildah 使用的是 buildah bud。

在生产实践过程中,我们需要将 Podman 命令打包到 CI Agent 的基础镜像中。通过 alias docker=podman , 对基于 Docker 命令的流水线进行替换。

下面简单总结一下,使用 Podman 的要点:

  • 支持缓存。通过挂载 /var/lib/containers 目录,可以缓存镜像,并且可以根据业务划分到不同目录。
  • 与 Docker 无缝替换。如果有 hook 的地方,可以用户无感知地切换。
  • 更加通用。针对 OCI 标准实现,不依赖具体组件。
  • 特权模式。容器中运行 Podman 需要特权模式。容器套娃很难摆脱的运行模式。

6. 参考

https://github.com/kubernetes-sigs/cri-tools

http://docs.podman.io/en/latest/

参考资料

[1]《在 Kubernetes 上动态创建 Jenkins Slave》: https://www.chenshaowen.com/blog/creating-jenkins-slave-dynamically-on-kubernetes.html

[2]《如何在 Docker 中使用 Docker》: https://www.chenshaowen.com/blog/how-to-use-docker-in-docker.html

[3]Podman 的安装指引: https://podman.io/getting-started/installation

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/238077.html<

(0)
运维的头像运维
上一篇2025-04-22 18:48
下一篇 2025-04-22 18:50

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注