DevOps实战-基于Docker的CI/CD

Posted 逼格运维说

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DevOps实战-基于Docker的CI/CD相关的知识,希望对你有一定的参考价值。

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去通知用户。


在开始持续部署操作之前,让我们先看下整个架构图:

DevOps实战-基于Docker的CI/CD

图1:基于docker的CI/CD流水线


二、准备工作


注意:在该方案中,我们需要Spring Boot应用。你可以去github上面克隆样本应用:(https://github.com/onedaywillcome1/ContinuousIntegrationAndContinuousDeliveryApp.git)这是一个Hello World Spring Boot-Maven 应用,并且附带了一个单元测试和集成测试。


首先,我们需要在gitlab的集成菜单上设置一下去触发Jenkins.


DevOps实战-基于Docker的CI/CD

DevOps实战-基于Docker的CI/CD

DevOps实战-基于Docker的CI/CD

图2:基于gitlab以及jenkins相关设置


当所有的设置都在Jenkins上设置完之后,GitLab将准备好去随时触发Jenkins。


接下来,我们需要安装Jenkins,Docker以及一些其他相关的依赖。


下图是在AWS EC2上运行的一个实例,实例的外网ip为:52.11.94.229

DevOps实战-基于Docker的CI/CD

图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。

DevOps实战-基于Docker的CI/CD

图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的通知设置。

DevOps实战-基于Docker的CI/CD


图5:jenkins配置

DevOps实战-基于Docker的CI/CD

图6:slack配置


访问  http://52.11.194.229:8080/configureTools 去配置M2的路径:

DevOps实战-基于Docker的CI/CD

图7:m2配置


三、Demo演示

现在我们已经全部配置完毕,并且运行在 jenkins上,现在我们需要创建一个pipeline job并且创建pipeline script。选择"Build when a change is pushed to GitLab"按钮,因为我们将要push代码到gitlab上,然后gitlab将会触发jenkins。

DevOps实战-基于Docker的CI/CD

DevOps实战-基于Docker的CI/CD图8:job设置

DevOps实战-基于Docker的CI/CD

图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去通知你相关的异常点。

DevOps实战-基于Docker的CI/CD

DevOps实战-基于Docker的CI/CD图10:部署流水线


我们的Spring boot应用现在就会运行起来了。

DevOps实战-基于Docker的CI/CD

DevOps实战-基于Docker的CI/CD图11:spring-app


应用相关的docker image文件也已经上传到Docker hub registry:

DevOps实战-基于Docker的CI/CD

图12:docker hub镜像仓库

这样,我们就完成了一个持续集成持续部署(CI-CD)的Demo.


四、总结:

当然了,本篇博客只是一个很小的Demo,在实际企业内部使用过程中,这些环节需要更多的功能点以及安全方面的考虑。但是,站在企业研发者的角度去考虑这个问题,整个持续集成到持续测试很大程度上减少了时间损耗,这样开发人员在每次提交代码到主干分支,进行编译测试后就能很快的反馈测试结果,更佳方便了研发的效率;同时还有更重要的一点是,应用最终的产出物品是一个docker image,倘若在集成测试阶段可以正常的运行业务应用,那么最终使用该image镜像文件部署在预发布环境或者生产环境部署也依然会一切正常,因为业务代码以及业务应用运行时环境都被统一封装到了docker image中去了,这样也在很大程度上减少了业务应用多环境异构的情况,从此妈妈再也不用担心研发大人们的代码在本地和测试环境可以运行,而在生产环境不能正常运行了。




以上是关于DevOps实战-基于Docker的CI/CD的主要内容,如果未能解决你的问题,请参考以下文章

Docker最全教程——从理论到实战

Docker和CI/CD实战

CODING 敏捷实战系列课第四讲:从头搭建持续集成 DevOps 流水线

CODING 敏捷实战系列课第四讲:从头搭建持续集成 DevOps 流水线

Docker最全教程——从理论到实战

云原生Java架构实战 K8s+Docker+KubeSphere+DevOps(下)