Jenkins在Pod中实现Docker in Docker并用kubectl进行部署
准备工作
说明
Jenkins的kubernetes-plugin在执行构建时会在kubernetes集群中自动创建一个Pod,并在Pod内部创建一个名为jnlp的容器,该容器会连接Jenkins并运行Agent程序,形成一个Jenkins的Master和Slave架构,然后Slave会执行构建脚本进行构建,但如果构建内容是要创建Docker Image就要实现Docker In Docker方案(在Docker里运行Docker),如果要在集群集群内部进行部署操作可以使用kubectl执行命令,要解决kubectl的安装和权限分配问题。
因为默认的jnlp容器可以执行的命令比较少,所以要实现Docker In Docker和执行kubectl命令,就要自定义构建Docker Image,因为一个Pod内部可以运行多个容器,所以可以用自定义的Docker容器实现上述目的。
实现Docker In Docker
构建自定义镜像:
FROM scratch
ADD centos-7-x86_64-docker.tar.xz /
LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20200504" \
org.opencontainers.image.title="CentOS Base Image" \
org.opencontainers.image.vendor="CentOS" \
org.opencontainers.image.licenses="GPL-2.0-only" \
org.opencontainers.image.created="2020-05-04 00:00:00+01:00"
USER root
COPY docker-ce.repo /etc/yum.repos.d/docker-ce.repo
COPY kubernetes.repo /etc/yum.repos.d/kubernetes.repo
RUN yum install -y docker-ce kubectl
RUN systemctl enable docker
CMD ["/bin/bash"]
# 构建命令
docker build -t bluersw/centos-7-docker-kubectl:2.0 .
# 试运行命令
docker run -v /var/run/docker.sock:/var/run/docker.sock -it bluersw/centos-7-docker-kubectl:2.0 /bin/bash
# Pull命令
docker pull bluersw/centos-7-docker-kubectl:2.0
运行容器时需要将宿主机的/var/run/docker.sock挂载到容器中去,因为容器内运行不了Docker Daemon,但这样有安全隐患因为可以通过docker.sock提权进而获得宿主机root权限,所以只能运行安全可靠的镜像。
配置Pod Templates
为了方便配置一个Pod Templates,在配置kubernetes连接内容的下面,这里的模板只是模板(与类一样使用时还要实例化过程),名称和标签列表不要以为是Pod的name和label,这里的名称和标签列表只是Jenkins查找选择模板时使用的,Jenkins自动创建Pod的name是项目名称+随机字母的组合,所以我们填写jenkins-slave-temp,命名空间填写jenkins-ops(创建命令:kubectl create namespace jenkins-ops),Pod内添加一个容器名称是jnlp-docker(默认的jnlp容器会自动创建),Docker镜像填写:repo.bluersw.com:8083/bluersw/centos-7-docker-kubectl:2.0,repo.bluersw.com:8083是家里的Docker私有仓库(搭建Docker私有仓库),下面增加两个Host Path Volume:/var/run/docker.sock、/etc/docker/daemon.json,保存回到系统管理页面。
测试运行
修改构建脚本
podTemplate (inheritFrom: "jenkins-slave-temp"){
node(POD_LABEL) {
container('jnlp'){
stage('Run shell') {
sh 'echo hello world'
}
}
container('jnlp-docker'){
stage("Run docker"){
sh 'docker info'
}
}
}
}
- podTemplate:用Pod模版示例化一个Pod配置并在kubernetes内自动创建
- inheritFrom:意思是创建的Pod配置继承自jenkins-slave-temp模版
- POD_LABEL:自动创建Pod的label
- container:选择哪个容器执行脚本
执行构建结果:
Running on jenkins-test-10-dp8sp-8zxtg-m4x35 in /home/jenkins/agent/workspace/Jenkins-Test
[Pipeline] {
[Pipeline] container
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run shell)
[Pipeline] sh
+ echo hello world
hello world
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // container
[Pipeline] container
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run docker)
[Pipeline] sh
+ docker info
Client:
Debug Mode: false
Server:
Containers: 32
Running: 19
Paused: 0
Stopped: 13
Images: 11
Server Version: 19.03.9
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
init version: fec3683
Security Options:
seccomp
Profile: default
Kernel Version: 4.4.224-1.el7.elrepo.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 3.858GiB
Name: centos7-k8s-node1
ID: 3R5I:DJGZ:YRZY:ESCH:VW7H:VGAD:5SCC:GYZV:QZZS:EX5M:MV3N:246K
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
repo.bluersw.com:8083
repo.bluersw.com:8082
127.0.0.0/8
Live Restore Enabled: false
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS
注意:我K8S集群使用root运行的所以权限很高,你如果使用其他账号运行的K8S集群,会遇到/var/run/docker.sock没有访问权限的问题,因为Docker必须是root权限运行,解决办法是:
# Docker 服务重启要重新执行
chmod 777 /var/run/docker.sock
Pod内使用Kubectl命令
在所有Node节点上执行:
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/kubelet.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 测试一下
kubectl get pod -A