介绍
jenkins是非常出名的持续集成工具,在很多公司都有使用。
- 基于SCM(source code managment)比如git的webhook,有代码提交,jenkins就把代码checkout出来。
- 进行单元测试。
- 根据单测的覆盖率来进行质量控制。
- 部署到测试环境。
- 集成测试。
- 打包成release。
- 部署到预发环境。
- 验收测试。
- 部署到生产环境。
k8s完整CI/CD流程
- 开发写好代码提交PR。
- 代码构建,单元测试,E2E(端到端)测试,代码review。
- 代码merge合并到主分支或者release分支。
- release分支就绪后,发布官方编译的版本Official Build。
- 根据release进行E2E,集成测试,把所有能力进行一次回归。
- k8s本身是可能升级的,有些场景可能需要测试升级动作。
- 测试环境–预发环境–生产环境进行持续部署。
持续集成容器化
- 最主要解决的问题是保证CI构建环境和开发构建环境的统一。
- 使用容器作为标准的构建环境,将代码库作为 Volume 挂载进构建容器。
- 由于构建结果是由jenkins slave pod输出的Docker镜像,所以要在构建容器中执行 "docker build” 命令,这就需要注意DIND的问题。
docker in docker
-
dind镜像
https://hub.docker.com/search?q=docker%3Adind
docker run –privileged -d docker:dind可能引入的问题:
- 容器内外存储不能相同。
- 内部容器使用了安全配置后可能导致外部容器故障。
-
mount host docker.socket
docker run -v /var/run/docker.sock:/var/run/docker.sock….什么是/var/run/docker.sock?
- /var/run/docker.sock是默认的Unix套接字。套接字用于在同一主机上的进程之间进行通信。Docker守护程序默认情况下侦听docker.sock。在运行Docker daemon的主机上,则可以使用/var/run/docker.sock管理容器。
- 从容器中执行docker命令来构建镜像并将其推送到镜像仓库。在这里,实际的docker操作发生在运行docker容器的VM主机上,而不是在容器内部进行。意思是,即使您正在容器中执行docker命令,也只是Docker客户端通过docker.sock方式连接到VM主机docker-engine。
可能引入的问题:
- 安全性的问题,挂载同样的docker.sock,相当于主机上所有的容器都在运行CI job,如果有恶意的用户,就可以破坏掉其他容器的镜像。
- 可以通过权限控制来避免。让用户看不到slave pod。
-
一个栗子
ci容器通过挂载dind容器作为sidecar,再通过emptyDir让ci容器可以通过unix socket访问到dind容器apiVersion: v1 kind: Pod metadata: name: ci spec: containers: - name: dind image: 'docker:stable-dind' command: - dockerd - --host=unix:///var/run/docker.sock - --host=tcp://0.0.0.0:8000 securityContext: privileged: true volumeMounts: - mountPath: /var/run name: dind - name: ci ... volumeMounts: - mountPath: /var/run name: dind volumes: - name: dind emptyDir: {}
kaniko
https://github.com/GoogleContainerTools/kaniko
kaniko 是一个在容器或 Kubernetes 集群内从 Dockerfile 构建容器镜像的工具。kaniko 不依赖于 Docker 守护进程,并且完全在用户空间中执行 Dockerfile 中的每个命令。
docker run \
-v "$HOME"/.config/gcloud:/root/.config/gcloud \
-v /path/to/context:/workspace \
gcr.io/kaniko-project/executor:latest \
--dockerfile /workspace/Dockerfile \
--destination "gcr.io/$PROJECT_ID/$IMAGE_NAME:$TAG" \
--context dir:///workspace/
基于k8s的持续集成
- jenkins根据webhook检测到pr的提交,启动job来进行构建。
- jenkins master是不干活的,只提供一个前端和后端服务,前端给用户使用。job运行完成后,master向k8s要一个pod。jenkins读取pod模版,发送给k8s,然后k8s启动jenkins slave pod。
- slave pod连接到jenkins master,下载jnlp配置文件来运行job。
Jenkins部署
安装jenkins chart
helm search repo jenkins
helm pull stable/jenkins
tar xvf jenkins-2.5.2.tgz
# 设置存储卷
vim value.yaml
storageClass: nfs-client
helm install jenkins ./ -n jenkins
查看部署情况
k get pvc,pv -n jenkins | grep jenkins
k get all -n jenkins
生成ingress证书
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/C=CN/ST=ZheJiang/L=zhejiang/O=wghdr/OU=Personal/CN=jenkins.wghdr.top" -days 5000 -out ca.crt
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/C=CN/ST=ZheJiang/L=zhejiang/O=wghdr/OU=Personal/CN=jenkins.wghdr.top" -out server.csr
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
# 创建secret
kubectl create secret tls jenkins.wghdr.top --key server.key --cert server.crt -n jenkins
k get secret -n jenkins
创建ingress
cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
spec:
ingressClassName: nginx
rules:
- host: jenkins.wghdr.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
tls:
- hosts:
- jenkins.wghdr.top
secretName: jenkins.wghdr.top
k apply -f ingress.yaml
k get ingress -n jenkins
获取admin密码
Get your 'admin' user password by running:
printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
获取jenkins链接
如果没有用ingress可以使用下面的方法,也可以修改jenkins的svc为nodePort,通过ip:nodePort来访问。
Get the Jenkins URL to visit by running these commands in the same shell:
export POD_NAME=$(kubectl get pods --namespace jenkins -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=jenkins" -o jsonpath="{.items[0].metadata.name}")
echo http://127.0.0.1:8080
kubectl --namespace jenkins port-forward $POD_NAME 8080:8080
设置中文
- 插件管理->安装Locale plugin->Localization Support Plugin->Localization: Chinese (Simplified)。
- 系统管理->系统配置->Locale->输入zh_cn,勾选下面的选项。
修改密码
- Configure Global Security->Jenkins’ own user database。
- 用户列表->admin->设置->修改密码。
连接到k8s
-
先安装kubernets插件。
-
Manage Nodes and clouds,Configure Clouds。
Kubernetes URL: https://kubernetes.default
Kubernetes Namespace: jenkins(jenkins安装的ns)
Credentials: Add->Jenkins->Kind: Kubernetes Service Account
-
Jenkins 地址
http://jenkins:8080
Jenkins 通道
jenkins-agent:50000
-
slave pod 模版
label:jenkins/jenkins-jenkins-slave
-
容器模版
Name: jnlp
Image: jenkins/inbound-agent:4.3-4
Command: $fcomputer jnlpmac} $fcomputer.namej
-
保存
创建测试job
- Dashboard->新建item->Freestyle project
- 限制项目的运行节点->标签表达式->jenkins-jenkins-slave
- 构建->执行命令-> echo this is a test-item.->保存
- build now
相当于给jenkins一个指令,去启动jenkins slave pod来运行test-item的job。
- 查看pod
- 构建成功
- 查看构建日志(控制台输出)
- 查看slave pod已自动删除