Docker+Jenkins+GIT CICD持续化集成实战

一、需求

开发将源码上传到github仓库,通过jenkins持续集成引擎结合git工具,将源码拉取到jenkins服务器,通过工具maven在本地讲源码编译打包成war包,在ssh到Docker宿主机,通过执行脚本生成制作自定义的Dockerfile,最终执行生成images,并启动container,即启动了包含war包的tomcat,即可实现对外提供web服务。

产品发布流程:

产品设计成型 -> 开发人员开发代码 -> 测试人员测试功能 -> 运维人员发布上线

持续集成 (Continuous integration,简称CI)
持续交付(Continuous delivery)
持续部署(continuous deployment)

二、Jenkins服务器配置

1、Jenkins简介

Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。

集成Jenkins可以用于一些测试和部署技术,Jenkins是一种软件允许持续集成。

Jenkins作用:

  1. 持续、自动地构建/测试软件项目。
  2. 监控软件开放流程,快速问题定位及处理,提示开放效率。

 特性:

  • 开源的java语言开发持续集成工具,支持CI,CD。
  • 易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理。
  • 消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告。
  • 分布式构建:支持Jenkins能够让多台计算机一起构建/测试。
  • 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。
  • 丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker等。

2、Jenkins安装配置

1. yum安装

最低配置: 不少于256M内存,不低于1G磁盘,jdk版本>=8

安装jdk1.8

yum install -y java-1.8.0-openjdk && \
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo && \
rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key &&\
yum clean all && yum makecache && \
yum install -y jenkins && \
systemctl start jenkins

查询admin密码:less /var/log/jenkins/jenkins.log
访问http://ip:8080/ 进行安装。

jenkins相关目录:

rpm -ql jenkins #查看jenkins安装相关目录
  • 安装目录/var/lib/jenkins
  • 配置文件 /etc/sysconfig/jenkins
  • 日志目录 /var/log/jenkins

2. 下载war包安装

yum install -y java-1.8.0-openjdk && mkdir -p /usr/local/jenkins/ && \
wget -c -O /usr/local/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.war &&\
nohup java -jar /usr/local/jenkins/jenkins.war &

密码查看:/root/.jenkins/secrets/initialAdminPassword。

访问 http://ip:8080/ 进行安装。

如何想通过其他端口启动可以指定httpPort选项即可:

nohup java -jar jenkins.war --httpPort=8899 &

3. docker形式安装

yum install docker -y  && systemctl start docker && \
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s && systemctl restart docker
docker search jenkins
docker pull docker.io/jenkins
docker run -d -p 8080:8080 docker.io/jenkins
docker exec -it 52873fa3dce4 /bin/bash
cat /var/jenkins_home/secrets #查看密码

访问 http://ip:8080/ 进行安装。

3、相关工具安装

工具安装可在jenkins的web界面系统管理—管理插件—可选插件勾选需要的,也可以手动安装。

1. git安装

yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc-c++ perl-ExtUtils-MakeMaker wget autoconf -y
wget https://www.kernel.org/pub/software/scm/git/git-2.7.3.tar.gz
tar xf git-2.7.3.tar.gz
cd git-2.7.3
make configure
./configure --prefix=/usr/local/git
make profix=/usr/local/git
make install
echo "export PATH=$PATH:/usr/local/git/bin" > /etc/profile.d/git.sh
source /etc/profile.d/git.sh

2. maven安装

cd /usr/local/ && wget -c wget  http://mirror.bit.edu.cn/apache/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz &&\
tar -zxf apache-maven-3.5.2-bin.tar.gz && \
echo "export PATH=$PATH:/usr/local/apache-maven-3.5.2/bin" > /etc/profile.d/maven.sh && \
source /etc/profile.d/maven.sh
mvn --version 查看版本

3. svn安装

yum install subversion -y
mkdir /svnrepo
svnadmin create /svnrepo/project1      #创建一个新的Subversion项目

启动项目1:

svnserve -d -r /svnrepo/project1/

启动整个项目:

svnserve -d -r /svnrepo/

4. jdk安装

某些情况下会遇到openjdk无法编译java程序,或在编译中存在异常,需要我们手动安装jdk,首先去Oracle官网下载对应版本的jdk。

tar -zxvf jdk-8u121-linux-x64.gz -C /usr/local && \
ln -sv /usr/local/jdk1.8.0_121 /usr/local/jdk1.8 && \
echo "export PATH=$PATH:/usr/local/jdk1.8/bin" >/etc/profile.d/java.sh
source /etc/profile.d/java.sh

4、WEB界面配置

1. 密码破解

 cd /var/lib/jenkins/users/admin          #此为admin用户的目录,也可以对应自己创建的用户
 vim config.xml                                  //定位到<passwordHash>那一行
 删除改行,改为
 <passwordHash>#jbcrypt:$2a$10$pDQks0ytOkCfmpdgpLygrOC3uY7i/XnZHBKRQDhrBPwKoN2f5Kz8C</passwordHash>

重启一下jenkins,新密码为admin。

2. maven配置

手动安装的maven,需要取消自动安装maven,name可以自定义,MAVEN_HOME指定下载安装的maven具体文件目录。

3. GIT配置

手动安装的git,web界面只需添加具体可执行路径即可。

4. jdk配置

对应手动安装的jdk,需要web配置java_home路径。

5. 邮件配置

jenkins有内置的邮件功能但由于其对于成功的发布不会发送邮件可定制化程度低,在此直接配置插件邮件(Editable Email Notification),2.32以上版本的jenkins,常用的插件都已经在最初部署的时候安装了(如果你当初选择的是suggest的plugins)。

可以使用qq邮件服务器或163等其他邮件服务器,在此配置使用163邮箱,首先需要开启163邮箱的smtp服务。

需要记录此处开启smtp时的密码。

在jenkins 系统管理—系统设置—Extended E-mail Notification. 

在默认的触发器 Default Triggers 标签下,可以勾选邮件通知触发的情况,如任何情况下均需要选择always,也可以在仅失败情况下发送,也可以对应的邮件接受人不通,进行邮件分类。

至此全局插件邮件已经配置完毕,需要在具体的项目中使用此邮件进行发送通知。

5、测试php程序自动发布

1. 插件安装

系统管理—管理插件—已安装。

检查是否有“Git plugin”和“Publish Over SSH”两个插件,如果没有,则需点击“可选插件”,找到它并安装。

安装好两个插件后,点击“系统管理”-- “系统设置”。

2. SSH配置

系统管理—系统设置—Publish over SSH

在key内填写jenkins服务器的私钥,如果没有需要先在jenkins服务器生成私钥与公钥。

ssh-keygen -t rsa 回车后会在登录用户的家目录下生成一个.ssh 的目录,此目录下存在id_rsa私钥与id_rsa.pub公钥。且讲公钥发布至代码发布的目标服务器上:

ssh-copy-id -i /root/.ssh/id_rsa.pub root@IP

SSH Server配置:

  • name:需要将php程序发布到目标服务器的名称,可自定义。
  • Hostname:填写目录服务器的IP地址
  • Username:使用那个用户进行发布,此处为进行密钥互信的用户
  • Remote Directory:此出为发布到目标服务器的相对根路径,建议填写/,防止后续填写路径异常。

注:如果为多台目标服务器,可以继续添加,如果目标服务器存在代理,也可设置proxy。 

3. 构建项目

新建Item—填入项目名称—选择构建一个自由风格的软件项目—确定。

源码管理选择git。

Repository URL 填写具体git上的仓库url,如果为私有,需要继续添加Credentials,如果为公有直接填写url即可,Credentials为none。

构建后够操作:

选择(Send files or execute commands over SSH)

  • SSH Server选择目标服务器如:php-server
  • Source files: **/** #将git拉去下来的原始文件
  • Remote directory:/var/www/html #发布到目标服务器的制定目录
  • Exec command:chown apache:apache -R /var/www/html/* #制定后续的操作

此时可以选择Editable Email Notification来构建邮件通知。

在此处,之前的邮件主题,内容均可以自定义,在高级里面,选择邮件接受人。 

点击保存,并立即构建,可以点击console output查看日志。

此时打开php程序发现程序文件已经成功发布到目标服务器上: 

此时可以查看邮件也已经发送成功。 

三、CICD环境部署

|主机名          |     IP地址   |  作用
| ------------  | ----------- |---------
|Docker-server  | 172.20.6.20 |Docker宿主机
|Jenkins-server | 172.20.6.22 |Jenkins服务器

1、Docker宿主机配置

需要在Docker宿主机pull下tomcat的基础环境以及jenkins服务器通过docker用户登录Docker宿主机,将war包发布到制定目录,执行特定脚本来生成Dockerfile,最终根据Dockerfile生成images,并启动基于包含war包的container,从而实现对外提供WEB服务。

创建ssh发布用户及目录:

useradd docker
echo "docker:docker" |chpasswd      #为docker用户设置密码
mkdir -pv /data/dockerfiles/scripts

上传脚本:

将脚本上传到 /data/dockerfiles/scripts,命名为devops,此名称可自定义,但是之后在配置jenkins执行ssh命令时候的脚本名称需要一致。由于脚本内部的分发路径是写的绝对路径,所以需要讲目录为固定,也可以根据实际修改。此脚本author:junsansi,可以参考其进行修改。

cat >/data/dockerfiles/scripts/devops.sh<<EOF
#!/bin/bash
# this script function is :                
# deploy new docker container             
#                                          
# USER        YYYY-MM-DD - ACTION          
# junsansi    2016-01-25 - CREATED        
parasnum=5
# function
help_msg()
{
cat << help
+ Error Cause:
+ you enter $# parameters
+ the total paramenter number must be $parasnum
+ 1st :DOCKER_NAME
+ 2nd :PROJECT_NAME
+ 3rd :PROJECT_VERSION
+ 4th :SOURCE_PORT
+ 5th :DESTINATION_PORT
help
}
# Check parameter number
if [ $# -ne ${parasnum} ]
then
        help_msg 
        exit
fi
# Initialize the parameter.
DOCKER_NAME=$1
PROJECT_NAME=$2
PROJ_VERSION=$3
SPORT=$4
DPORT=$5
PROJ_VERSION=${PROJ_VERSION/"origin/"/""}
DOCKER_FILE="/data/dockerfiles/${DOCKER_NAME}/Dockerfile"
DOCKER_FILE_DIR=/data/dockerfiles/${DOCKER_NAME}
if [ ! -d ${DOCKER_FILE_DIR} ]; then
        mkdir -p ${DOCKER_FILE_DIR}
fi
# check docker images
DOCKER_IMAGE=`/usr/bin/docker images | grep ${DOCKER_NAME} | awk -F ' ' '{print $3}'`
if [ -n "${DOCKER_IMAGE}" ]; then
        # check docker container
        for dc in `/usr/bin/docker ps -a | grep ${DOCKER_NAME} | awk -F " " '{print $1}'`
        do
                echo "Stop container: ${dc}"
                /usr/bin/docker stop ${dc}
                # delete while docker container was exists
                echo "##Delete exists Container_Id: "${dc}
                /usr/bin/docker rm ${dc}
        done

        # delete while docker image was exists
        echo "#Delete exists Image: "${DOCKER_IMAGE}
        /usr/bin/docker rmi ${DOCKER_IMAGE} 
fi
# Init dockerfile
echo "**Init dockerfile start: "${DOCKER_FILE}
echo "FROM tomcat" > ${DOCKER_FILE}
echo 'MAINTAINER junsansi "[email protected]"' >> ${DOCKER_FILE}
echo "ADD *.war /usr/local/tomcat/webapps/${PROJECT_NAME}.war" >> ${DOCKER_FILE}
echo "EXPOSE 8080" >> ${DOCKER_FILE}
echo "CMD /usr/local/tomcat/bin/startup.sh && tail -f /usr/local/tomcat/logs/catalina.out" >> ${DOCKER_FILE}
cat ${DOCKER_FILE}
echo "**Init dockerfile end."
# Build dockerfile
cd ${DOCKER_FILE_DIR}
rm *.war -rf
mv /data/dockerfiles/war/${DOCKER_NAME}/*.war ./
echo ""
echo "##Build dockerfile for "${DOCKER_NAME}
/usr/bin/docker build -t ${DOCKER_NAME}:${PROJ_VERSION} . 
# Run docker container
echo ""
echo "##Running docker container: "${DOCKER_NAME}
/usr/bin/docker run --name ${DOCKER_NAME}_d1 -d -p ${SPORT}:${DPORT} ${DOCKER_NAME}:${PROJ_VERSION}
EOF
chmod +x  /data/dockerfiles/scripts/devops.sh
chown docker.docker /data/dockerfiles -R

Docker宿主机获取tomcat镜像:

docker pull docker.io/tomcat

使用docker images查看tomcat镜像:

此时Docker宿主机就已经配置完毕。 

2、Jenkins配置

登录Jenkins的WEB界面。

1. 配置Docker宿主机的ssh信息

系统管理---系统设置---Publish over SSH---增加SSH Server。

添加SSH Server可以使用密钥形式添加,也可以直接使用用户名密码, 此处使用用户名密码,选择:Use password authentication, or use a different key,即docker用户的密码,进行登录发布,之前已经将/data/dockerfiles目录的属主属组更改为docker,确认Jenkins服务器使用docker用户可以正常在此目录下进行后续操作。

2. 构建一个maven项目 

一般设置: 

为保证Jenkins服务器的磁盘有充足的空间,在选中丢弃旧的构建->保持构建的最大个数为10个。 

在真实开发环境中,成员直接相互协助,GIT是多分支的,考虑到分支管理,需在此选中参数化构建->选择Git Parameter->定义名称为release_branch,因此选择参数类型为Branch:如果自己发现devops脚本可以看到里面是调用了此参数进行选择构建的分支。

同时创建考虑到创建Docker的名称,此时需要给后续创建的docker images以项目的名称命名。

源码管理:

源码管理选择git,填入仓库url:[email protected]:redhatxl/zrlog.git。

此时发现会出现报错信息,因为此仓库为我的私有仓库,需要配置Credentials,点开add, Add Credentials的 Kind选择SSH Username with private key,Username选择之前在github上传的公钥用户的用户名,此次为root,Private Key为jenkins服务器登录github的本地私钥,查看私钥cat /root/.ssh/id_rsa 复制粘贴到Key区域,完成添加。此时可以发现报错已经消失。 

在Branches to build模块需要填写之前我们参数话的变量,在此引用$release_branch。

环境构建:

在build的Goals and options添加maven构建命令。

clean install -D maven.test.skip=true

增加构建后操作:

增加构建后步骤---选择:Send build artifacts over SSH;

SSH-Server name选择Docker宿主机;

Transfers中填写Source files:target/*.war;

Remove prefix:target/;

Remote directory:/war/$project_name,即在远端/data/dockerfiles下的war目录(/data/dockerfiles/war/docker01-tomcat-zrlog)。

Exec command:/data/dockerfiles/scripts/devop.sh $project_name zrlog $release_branch 8888 8080

即jenkins服务器ssh到docker宿主机之后执行的脚本命令,执行/data/dockerfiles/scripts/devop.sh脚本,此脚本需要传入5个参数:

  • project_name:项目名称,即docker生成images的名称;
  • zrlog:即项目名称;
  • release_branch:在git上提交的分支,此处我们只有master分支;
  • 两个端口,前一个端口及宿主机的监听端口,后一个端口及映射到docker容器内部的端口,在此处使用的为tomcat,默认的为8080端口;

注意:再次可以添加多个server,即实现集群,可以讲web服务器为无状态,将日志文件挂载到本地物理磁盘以实现日志监控即数据持久化存储。

添加增加构建后操作,选择Editable Email Notification,利用插件邮件来发送通知。

可以根据需求自定义邮件主题与内容,此处添加信息接受人,由于全局配置了always,在高级设置内,填写接受人邮箱。

创建完毕后点击应用并保存。 

3. 执行构建

选择Build with Parameters,然后在右边release_branch内选择需要执行的github上的分支,此处为master,同理选择 project_name,为docker images的name可以选择自己添加自定义的名字,点击开始构建。

查看Console Output: 

查看邮件通知: 

登录docker宿主机查看images与container: 

网页测试: 

3、启动多个容器

在配置jenkins的ssh后的命令我们可以添加多个server从而实现分布式,同时我们也可以对在一台主机上通过区分端口号来生成多个images并启动多个不通端口的container。

在General的参数化构建过程中增加第三个参数proxy_port可以设置为docker宿主机的本地监听端口从而实现多端口多实例。

在ssh命令中调用: 

在构建开始时可以定义不同的images对应不通的端口: 

查看启动后的容器: 

注意:如果有特殊需求,例如发布php代码或其他可以自行对脚本进行修改,可以根据需求定义多个参数灵活使用。

猜你喜欢

转载自blog.csdn.net/qq_35029061/article/details/127292967