CI/CD概述
持续集成(Continuous Integration,CI):代码合并、构建、部署、测试都在一起,不断地执行这个过程,并对结果反馈。
持续部署(Continuous Deployment,CD):部署到测试环境、预生产环境、生产环境。
持续交付(Continuous Delivery,CD):将最终产品发布到生产环境,给用户使用。
CI工作流程设计
开发者提交代码到gitlab仓库,gitlab随后触发jenkins代码编译,构建镜像以及推送镜像到harbor仓库,紧接着Jenkins部署到docker主机(从harbor仓库拉取镜像到本地部署启动)。
gitlab主机
jenkins主机
harbor主机
192.168.0.11/24
192.168.0.13/24
192.168.0.12/24
项目环境表
1、部署Gitlab
1.1 部署Gitlab
mkdir gitlabcd gitlabdocker run -d \ --name gitlab \ -p 8443:443 \ -p 9999:80 \ -p 9998:22 \ -v $PWD /config:/etc/gitlab \ -v $PWD /logs:/var/log/gitlab \ -v $PWD /data:/var/opt/gitlab \ -v /etc/localtime:/etc/localtime \ --restart=always \ lizhenliang/gitlab-ce-zh:latest
访问地址:http://IP:9999
初次会先设置管理员密码 ,然后登陆,默认管理员用户名root,密码就是刚设置的。
1.2 创建项目,提交测试代码
进入后先创建项目,提交代码,以便后面测试。
unzip tomcat-java-demo-master.zip cd tomcat-java-demo-mastergit init git remote add origin http://192.168.0.11:9999/root/java-demo.git git add . git config --global user.email "you@example.com" git config --global user.name "Your Name" git commit -m 'all' git push origin master
2、部署Harbor镜像仓库
2.1 安装docker与docker-compose
2.2 解压离线包部署
hostname: reg.ctnrs.com https: harbor_admin_password: Harbor12345
2.3 在Jenkins主机配置Docker可信任,如果是HTTPS需要拷贝证书
由于habor未配置https,还需要在docker配置可信任。
{"registry-mirrors" : ["https://b9pmyelo.mirror.aliyuncs.com" ], "insecure-registries" : ["192.168.0.12" ] }
2.4 构建tomcat镜像并上传到harbor仓库上(供jenkinsfile脚本调用)
#准备的安装包(apache-tomcat-8.5.43.tar.gz)和Dockerfile
FROM centos:7 MAINTAINER www.ctnrs.com ENV VERSION=8.5.43 RUN yum install java-1.8.0-openjdk wget curl unzip iproute net-tools -y && \ yum clean all && \ rm -rf /var/cache/yum/* ADD apache-tomcat-${VERSION} .tar.gz /usr/local/ RUN mv /usr/local/apache-tomcat-${VERSION} /usr/local/tomcat && \ sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH :/usr/local/tomcat/bin WORKDIR /usr/local/tomcat EXPOSE 8080 CMD ["catalina.sh" , "run" ]
构建并上传到harbor
docker build -t 192.168.0.12/library/tomcat:v1 . docker login 192.168.0.12 docker /images docker push 192.168.0.12/library/tomcat:v1
3、部署Jenkins
3.1 准备JDK和Maven环境
将二进制包上传到服务器并解压到工作目录,用于让Jenkins容器挂载使用。
修改Maven源:
vi /usr/local/maven/conf/setting.xml <mirrors> <mirror> <id >central</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>
部署jenkins
docker run -d --name jenkins -p 80:8080 -p 50000:50000 -u root \ -v /opt/jenkins_home:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /usr/bin/docker:/usr/bin/docker \ -v /usr/local/maven:/usr/local/maven \ -v /usr/local/jdk:/usr/local/jdk \ -v /etc/localtime:/etc/localtime \ --restart=always \ --name jenkins jenkins/jenkins
访问地址:http://IP
3.2 安装插件
管理Jenkins->系统配置–>管理插件**–>搜索git/pipeline,选中点击安装。
默认从国外网络下载插件,会比较慢,建议修改国内源:
cd /opt/jenkins_home/updatessed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && \ sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json docker restart jenkins
3.3 Jenkins Pipeline介绍
Jenkins Pipeline是一套插件,支持在Jenkins中实现集成和持续交付管道;
Pipeline通过特定语法对简单到复杂的传输管道进行建模;
声明式:遵循与Groovy相同语法。pipeline { }
脚本式:支持Groovy大部分功能,也是非常表达和灵活的工具。node { }
Jenkins Pipeline的定 义被写入一个文本文件,称为Jenkinsfile。
注意: 发布之前可以在jenkins主机上测试一下是否能登录harbor仓库
如果不能登录报错为连接443拒绝,那么请使用以下方式解决:
修改Docker启动文件添加“–insecure-registry 192.168.0.12”
vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.0.12 systemctl restart docker
4、发布测试
4.1添加连接git仓库凭据和harbor仓库凭据
管理Jenkins->安全–>管理凭据->Jnekins->添加凭据->Username with password
Username:用户名
Password:密码
ID:留空
Description:描述
分别添加连接git和harbor凭据,并修改脚本为实际凭据ID。
4.2 创建项目并配置
New Item -> Pipeline -> This project is parameterized -> String Parameter
4.3 Pipeline脚本(在Jenkins本地机器上部署并启动容器)
一. 添加注释方便查看使用说明(添加注释到jenkins执行会报错,请使用第二个构建)
#!/usr/bin/env groovy def registry = "192.168.0.12" def project = "dev" def app_name = "java-demo" def image_name = "${registry} /${project} /${app_name} :${Branch} -${BUILD_NUMBER} " def git_address = "http://192.168.0.11:9999/root/java-demo.git" def docker_registry_auth = "30fae7e1-22c4-4083-848f-a5e90eff9e1f" def git_auth = "05750892-5303-49ab-a6d0-33a78ef6c839" pipeline { agent any stages { stage('拉取代码' ){ steps { checkout([$class : 'GitSCM' , branches: [[name: '${Branch}' ]], userRemoteConfigs: [[credentialsId: "${git_auth} " , url: "${git_address} " ]]]) } } stage('代码编译' ){ steps { sh "" " pwd ls JAVA_HOME=/usr/local/jdk PATH=$JAVA_HOME /bin:/usr/local/maven/bin:$PATH mvn clean package -Dmaven.test.skip=true " "" } } stage('构建镜像' ){ steps { withCredentials([usernamePassword(credentialsId: "${docker_registry_auth} " , passwordVariable: 'password' , usernameVariable: 'username' )]) { sh "" " echo ' FROM ${registry} /library/tomcat:v1 LABEL maitainer liuzhe RUN rm -rf /usr/local/tomcat/webapps/* ADD target/*.war /usr/local/tomcat/webapps/ROOT.war ' > Dockerfile docker build -t ${image_name} . docker login -u ${username} -p '${password} ' ${registry} docker push ${image_name} " "" } } } stage('部署到Docker' ){ steps { sh "" " docker rm -f tomcat-java-demo |true docker container run -d --name tomcat-java-demo -p 88:8080 ${image_name} " "" } } } }
二.请使用这个pipeline脚本构建
#!/usr/bin/env groovy def registry = "192.168.0.12" def project = "dev" def app_name = "java-demo" def image_name = "${registry} /${project} /${app_name} :${Branch} -${BUILD_NUMBER} " def git_address = "http://192.168.0.11:9999/root/java-demo.git" def docker_registry_auth = "30fae7e1-22c4-4083-848f-a5e90eff9e1f" def git_auth = "05750892-5303-49ab-a6d0-33a78ef6c839" pipeline { agent any stages { stage('拉取代码' ){ steps { checkout([$class : 'GitSCM' , branches: [[name: '${Branch}' ]], userRemoteConfigs: [[credentialsId: "${git_auth} " , url: "${git_address} " ]]]) } } stage('代码编译' ){ steps { sh "" " pwd ls JAVA_HOME=/usr/local/jdk PATH=$JAVA_HOME /bin:/usr/local/maven/bin:$PATH mvn clean package -Dmaven.test.skip=true " "" } } stage('构建镜像' ){ steps { withCredentials([usernamePassword(credentialsId: "${docker_registry_auth} " , passwordVariable: 'password' , usernameVariable: 'username' )]) { sh "" " echo ' FROM ${registry} /library/tomcat:v1 LABEL maitainer liuzhe RUN rm -rf /usr/local/tomcat/webapps/* ADD target/*.war /usr/local/tomcat/webapps/ROOT.war ' > Dockerfile docker build -t ${image_name} . docker login -u ${username} -p '${password} ' ${registry} docker push ${image_name} " "" } } } stage('部署到Docker' ){ steps { sh "" " docker rm -f tomcat-java-demo |true docker container run -d --name tomcat-java-demo -p 88:8080 ${image_name} " "" } } } }
上述脚本中,docker_registry_auth 和git_auth变量的值为Jenkins凭据ID,添加凭据后修改。
4.4 Pipeline脚本( 在其他的Docker主机上部署并启动容器)
安装jenkins插件
插件名称: SSH Pipeline Steps
使用说明: https://github.com/jenkinsci/ssh-steps-plugin#pipeline-steps
#!/usr/bin/env groovy def registry = "192.168.0.12" def project = "dev" def app_name = "java-demo" def image_name = "${registry} /${project} /${app_name} :${Branch} -${BUILD_NUMBER} " def git_address = "http://192.168.0.11:9999/root/java-demo.git" def docker_registry_auth = "30fae7e1-22c4-4083-848f-a5e90eff9e1f" def git_auth = "05750892-5303-49ab-a6d0-33a78ef6c839" def remote = [:] remote.name = "test" remote.host = "192.168.0.12" remote.user = 'root' remote.password = '123.com' remote.allowAnyHosts = true pipeline { agent any stages { stage('拉取代码' ){ steps { checkout([$class : 'GitSCM' , branches: [[name: '${Branch}' ]], userRemoteConfigs: [[credentialsId: "${git_auth} " , url: "${git_address} " ]]]) } } stage('代码编译' ){ steps { sh "" " pwd ls JAVA_HOME=/usr/local/jdk PATH=$JAVA_HOME /bin:/usr/local/maven/bin:$PATH mvn clean package -Dmaven.test.skip=true " "" } } stage('构建镜像' ){ steps { withCredentials([usernamePassword(credentialsId: "${docker_registry_auth} " , passwordVariable: 'password' , usernameVariable: 'username' )]) { sh "" " echo ' FROM ${registry} /library/tomcat:v1 LABEL maitainer liuzhe RUN rm -rf /usr/local/tomcat/webapps/* ADD target/*.war /usr/local/tomcat/webapps/ROOT.war ' > Dockerfile docker build -t ${image_name} . docker login -u ${username} -p '${password} ' ${registry} docker push ${image_name} " "" } } } stage('部署到Docker' ){ steps { sshCommand remote: remote, command : "" " ip a docker rm -f tomcat-java-demo |true docker pull ${image_name} docker container run -d --name tomcat-java-demo -p 88:8080 ${image_name} " "" } } } }
验证:
1.访问harbor仓库查看是否有上传的镜像 http://192.168.0.12/
2.docker主机上运行的项目镜像容器
3.访问部署java-demo示例 http://192.168.0.13:88/
CI/CD收益
高效的CI/CD环境可以获得:
1.及时发现问题
2.大幅度减少故障率
3.加快迭代速度
4.减少时间成本