DevOps实战-基于Docker的CI/CD
Posted 逼格运维说
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DevOps实战-基于Docker的CI/CD相关的知识,希望对你有一定的参考价值。
DevOps实战-基于Docker的CI/CD
一、DevOps实战-基于Docker的CI/CD
在本篇博客,我们将使用如下技术一步步实现全部的持续部署流程。[Spring Boot, GitLab, Jenkins,Docker and Slack. ] 首先,我们会创建一个带有单元测试和集成测试的spring boot样品应用,然后将它push到GitLab.在push代码到gitlab上之后,Jenkins pipeline 将通过web hook自动获取到代码,然后运行测试用例。如果这些测试全部通过,没有任何错误信息,Jenkins将去编译代码,并且通过docker将代码部署到服务器上。最后,它将发送docker image到本地的docker私有仓库。如果整个测试流水线有任何一步失败,它将通过Slack去通知用户。
在开始持续部署操作之前,让我们先看下整个架构图:
图1:基于docker的CI/CD流水线
二、准备工作
注意:在该方案中,我们需要Spring Boot应用。你可以去github上面克隆样本应用:(https://github.com/onedaywillcome1/ContinuousIntegrationAndContinuousDeliveryApp.git)这是一个Hello World Spring Boot-Maven 应用,并且附带了一个单元测试和集成测试。
首先,我们需要在gitlab的集成菜单上设置一下去触发Jenkins.
图2:基于gitlab以及jenkins相关设置
当所有的设置都在Jenkins上设置完之后,GitLab将准备好去随时触发Jenkins。
接下来,我们需要安装Jenkins,Docker以及一些其他相关的依赖。
下图是在AWS EC2上运行的一个实例,实例的外网ip为:52.11.94.229
图3:AWS实例
现在我们就可以ssh到实例上去安装下列依赖:
# ssh to instance
ssh -i ~/.ssh/jenkinskeypair.pem ec2-user@52.11.194.229
# Update packages
sudo yum update -y
# Install Git
sudo yum install git -y
# Download Jekins repo
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo # Import jenkins key
sudo rpm — import https://jenkins-ci.org/redhat/jenkins-ci.org.key
# Install Jenkins
sudo yum install jenkins -y
# Start Jenkins
sudo service jenkins start
# Enter to home directory
cd ~
# Download Java 8
wget — no-cookies — no-check-certificate — header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept securebackup-cookie" "http://download.oracle.com/otn pub/java/jdk/8u60-b27/jdk-8u60-linux-x64.rpm" # Install Java 8
sudo yum localinstall jdk-8u60-linux-x64.rpm
# Check the java version
java -version
# Copy JAVA_HOME to bash_profile echo "export JAVA_HOME=/usr/java/jdk1.8.0_60/jre" >> ~/.bash_profile
# Run the bash_profile
source ~/.bash_profile
# Check JAVA_HOME is successfully installed as environment variable env
# Download Maven wget http://mirror.olnevhost.net/pub/apache/maven/maven-3/3.0.5/binaries/apache-maven-3.0.5-bin.tar.gz
# Untar maven gz file
tar xvf apache-maven-3.0.5-bin.tar.gz
#Move apache file to /usr/local dir
sudo mv apache-maven-3.0.5 /usr/local/apache-maven # Copy below Maven commands to bash_profile
echo "export M2_HOME=/usr/local/apache-maven" >> ~/.bash_profile echo "export M2=$M2_HOME/bin" >> ~/.bash_profile echo "export PATH=$M2:$PATH" >> ~/.bash_profile
# Run the bash_profile
source ~/.bash_profile
# Check Maven commands successfully installed as env. variable
env
# Install Docker
sudo yum install -y docker
# Start docker
sudo service docker start
# Add docker user to ec2-user and jenkins
sudo usermod -a -G docker ec2-usersudo usermod -a -G docker jenkins
# Check docker info
sudo docker info
# Exit from instance
exit
# Ssh again
ssh -i ~/.ssh/jenkinskeypair.pem ec2-user@52.11.194.229
# Now we are able to check info without
sudo docker info
# Finally restart jenkins & docker
sudo service docker restart
sudo service jenkins restart
Jenkins现在启动并且正常运行起来了,你可以访问http://52.11.194.229:8080,不过需要拷贝jenkins admin的密码(jenkins启动日志中会有)去解锁jenkins并且安装一些推荐的plugins。
图4:jenkins安装
在jenkins中安装gitlab和slack插件:
跳转到(http://52.11.194.229:8080/pluginManager/available),选择gitlab和slack plugin使用不重启安装。
在安装了slack和gitlab插件之后,我们可以接下来以下的操作(可选)。Slack插件需要有webhook配置,如果我们不去配置这个webhook,jenkins将会出现异常。因此,为了解决这个问题,我们将做如下操作(使用groovy脚本去管控):
sudo mkdir /var/lib/jenkins/init.groovy.d sudo vi /var/lib/jenkins/init.groovy.d/disable-slack-webhooks.groovy
groovy脚本disable-slack-webhooks.groovy内容如下:
import jenkins.model.Jenkins import hudson.model.RootAction def j = Jenkins.instance; def removal = { lst -> lst.each { x -> if(x.getClass().name.contains("slack.webhook")) { lst.remove(x) } } } removal(j.getExtensionList(RootAction.class)) removal(j.actions)
给init.groovy.d目录添加权限,并重启jenkins:
sudo chown jenkins:jenkins -R /var/lib/jenkins/init.groovy.d sudo service jenkins restart
现在,让我们开始去配置jenkins:
访问 (http://52.11.194.229:8080/configure) 去配置java_home和m2_home作为环境变量并且填写slack的通知设置。
图5:jenkins配置
图6:slack配置
访问 http://52.11.194.229:8080/configureTools 去配置M2的路径:
图7:m2配置
三、Demo演示
现在我们已经全部配置完毕,并且运行在 jenkins上,现在我们需要创建一个pipeline job并且创建pipeline script。选择"Build when a change is pushed to GitLab"按钮,因为我们将要push代码到gitlab上,然后gitlab将会触发jenkins。
图8:job设置
图9:jenkins触发构建
拷贝以下pipeline script到pipeline job,在"准备(preparation)"阶段,Jenkins将从Gitlab上克隆样品spring boot应用,并在"Test"阶段进行测试,如果测试通过,它将切换到"编译(Build)"阶段,生成编译的结果并进入到最终的"部署(deployment)"阶段.
node { def mvnHome stage(‘Preparation’) { // for display purposes git ‘git@gitlab.com:<myRepo>/ContinuousIntegrationAndContinuousDeliveryApp.git' mvnHome = tool 'M2' }
stage('Test') { try { sh "'${mvnHome}/bin/mvn' test" } catch (e) { notifyStarted("Tests Failed in Jenkins!") throw e } } stage('Build') { try { sh "'${mvnHome}/bin/mvn' clean package -DskipTests" }catch (e) { notifyStarted("Build Failed in Jenkins!") throw e } } stage('Results') { try{ archive 'target/*.jar' }catch (e) {
notifyStarted("Packaging Failed in Jenkins!") throw e } } } stage('Deployment') { try{ sh '/var/lib/jenkins/workspace/Pipeline/runDeployment.sh' }catch (e) { notifyStarted("Deployment Failed in Jenkins!") throw e } } notifyStarted("All is well! Your code is tested,built,and deployed.") } def notifyStarted(String message) { slackSend (color: '#FFFF00', message: "${message}: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})") }
现在,切换到/var/lib/jenkins/workspace/Pipeline目录,创建一个runDeployment.sh脚本,部署目录并且在部署目录放置一个Dockerfile.
cd /var/lib/jenkins/workspace/Pipeline mkdir deployment #Copy below Dockerfile sudo vi deployment/Dockerfile FROM centos RUN yum install -y wget RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u60-b27/jdk-8u60-linux-x64.rpm" RUN yum localinstall jdk-8u60-linux-x64.rpm -y EXPOSE 8090 ADD app.jar myApp.jar ENTRYPOINT ["java","-jar","myApp.jar"]
# Create runDeployment.sh and copy below script with your docker username and password. sudo vi runDeployment.sh #!/bin/bash -ex echo "Deploying app.jar to docker folder" packageName=`ls target/continuousintegrationandcontinuousdeliveryapp*.jar` versionid=`echo $packageName | awk -F "-" '{ print $2}'` versionname=`echo $packageName | awk -F "-" '{ print $3}' | awk -F "." '{ print $1}'` version=`echo $versionid-$versionname`echo "version: $version" cp -r $packageName deployment/app.jar dockerImageName=onedaywillcome/myapp dockerpid=`docker ps -a | grep $dockerImageName | grep "Up" | awk -F " " '{ print $1 }'` if [[ $dockerpid != "" ]];then docker kill $dockerpid docker rm $dockerpid fi docker build -t $dockerImageName deployment/. docker run -d -p 8090:8090 $dockerImageName dockerImageId=`docker images | grep $dockerImageName | grep latest | awk -F " " '{print $3}'`
docker tag $dockerImageId $dockerImageName:$version docker login -u <DOCKER_USERNAME> -p <DOCKER_PASSWORD> docker push $dockerImageName:$version#Give jenkins ownershipt to deployment directory and runDeployment.sh sudo chown jenkins:jenkins runDeployment.sh sudo chmod 775 runDeployment.sh sudo chown jenkins:jenkins -R deployment
到此为止,所有的工作都已经完成。
当你现在去push你的代码到gitlab的时候,Gitlab将触发Jenkins,然后jenkins将首先进行测试,编译然后再服务器上部署,同时将编译生成的image镜像上传到Docker Registry,而在整个部署流水线中如果发生什么异常问题,它将通过Slack去通知你相关的异常点。
图10:部署流水线
我们的Spring boot应用现在就会运行起来了。
图11:spring-app
应用相关的docker image文件也已经上传到Docker hub registry:
图12:docker hub镜像仓库
这样,我们就完成了一个持续集成持续部署(CI-CD)的Demo.
四、总结:
当然了,本篇博客只是一个很小的Demo,在实际企业内部使用过程中,这些环节需要更多的功能点以及安全方面的考虑。但是,站在企业研发者的角度去考虑这个问题,整个持续集成到持续测试很大程度上减少了时间损耗,这样开发人员在每次提交代码到主干分支,进行编译测试后就能很快的反馈测试结果,更佳方便了研发的效率;同时还有更重要的一点是,应用最终的产出物品是一个docker image,倘若在集成测试阶段可以正常的运行业务应用,那么最终使用该image镜像文件部署在预发布环境或者生产环境部署也依然会一切正常,因为业务代码以及业务应用运行时环境都被统一封装到了docker image中去了,这样也在很大程度上减少了业务应用多环境异构的情况,从此妈妈再也不用担心研发大人们的代码在本地和测试环境可以运行,而在生产环境不能正常运行了。
以上是关于DevOps实战-基于Docker的CI/CD的主要内容,如果未能解决你的问题,请参考以下文章
CODING 敏捷实战系列课第四讲:从头搭建持续集成 DevOps 流水线