8.3.4 Jenkins容器使用宿主机Docker
构建镜像和发布镜像到harbor都需要使用到docker命令。而在Jenkins容器内部安装Docker成本比较高,官方推荐直接采用宿主机带的Docker。
首先要修改/var/run/docker.sock
的所属组和权限,让其他人也拥有读写的权限;然后通过数据卷的方式,把相应的文件同步到Jenkins容器内部。从而达到在Jenkins内部可以使用docker命令的目的。
- 设置宿主机docker.sock权限:
# 修改docker.sock所属组为root sudo chown root:root /var/run/docker.sock # 增加其他用户的读写权限 sudo chmod o+rw /var/run/docker.sock
修改前
修改后
- 添加数据卷
由于我安装Jenkins时使用的是docker run命令安装的,这里修改执行命令后再次执行
cd /usr/local/docker/jenkins_docker/ #修改命令并运行 docker run -di --name jenkins \ -p 8080:8080 -p 50000:50000 -u root \ -v ./data:/var/jenkins_home \ -v /usr/bin/docker:/usr/bin/docker \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /etc/docker/daemon.json:/etc/docker/daemon.json \ --restart always \ jenkins/jenkins:2.361.2 # 配置国内源安装插件 cd /usr/local/docker/jenkins_docker/data/updates wget https://mirrors.aliyun.com/jenkins/updates/update-center.json
- 如果使用
docker-compose.yml
文件跑起来的,这里可以修改docker-compose.yml
文件后重新docker-compose up -d
修改Jenkins容器的docker-compose.yml
文件内容,追加数据卷(最后三行)
cd /usr/local/docker/jenkins_docker/ vim docker-compose.yml version: "3.1" services: jenkins: image: jenkins/jenkins container_name: jenkins ports: - 8080:8080 - 50000:50000 volumes: - ./data/:/var/jenkins_home/ - /usr/bin/docker:/usr/bin/docker - /var/run/docker.sock:/var/run/docker.sock - /etc/docker/daemon.json:/etc/docker/daemon.json #重新启动 docker-compose up -d
- 进入Jenkins容器内部查看
docker exec -it jenkins bash 在容器内部执行docker命令测试
8.3.5 Jenkins构建自定义镜像推送到harbor仓库
目的:使用Jenkins制作自定义镜像并且推送到harbor仓库上,再让Jenkins通知目标服务去harbor仓库上拉取镜像。
制作自定义镜像只需要Dockerfile文件,不需要docker-compose.yml文件。
使用docker build 运行Dockerfile文件中的命令构建自定义镜像,然后推送到Harbor仓库,再让Jenkins通知目标服务去Harbor仓库上拉取镜像,运行。
- Jenkins需要通知目标服务器的信息:
- 告知目标服务器拉取哪个镜像
- 判断当前服务器是否正在运行容器,如果正在运行需要删除
- 如果目标服务器已经存在当前镜像,需要删除
- 让目标服务器拉取harbor上的镜像
- 将拉取下来的镜像运行成容器
如果在Jenkins来执行这一系列判断条件,成本较高。所以在目标服务器上建一个脚本文件,让Jenkins通知目标服务器来执行这个脚本文件就可以了。
- 修改gitla上的java内容,标记一下v3.0.0
2、gitlab上创建tag标签
3、修改mytest任务配置
① 删除构建后操作:
② 在构建操作中,检测完代码后再追加一个步骤“执行shell”
此处默认的路径是/usr/local/docker/jenkins_docker/data/workspace/mytest
。我的Dockerfile文件就在/usr/local/docker/jenkins_docker/data/workspace/mytest
下,所以第二行指定 . 就可以了,表示当前目录
③由于Jenkins使用的是宿主机的docker,所以构建成功后可以在宿主机上查看images,发现多了一个v3.0.0版本的mytest
④ 现在通过docker build和Dockerfile文件在Jenkins内已经构建好镜像了,我们将Jenkins构建好的自定义镜像推送到harbor仓库,就需要在shell命令中追加登录、打包更名、推送的命令
执行报错:
mv: cannot move 'target/maven-archiver' to './maven-archiver': File exists Build step 'Execute shell' marked build as failure Finished: FAILURE
原因:上次构建在/usr/local/docker/jenkins_docker/data/workspace/mytest目录下已经产生了maven-archiver 文件,所以再次构建,就无法执行移动的操作。我们在构建前需要将 /usr/local/docker/jenkins_docker/data/workspace/mytest/maven-archiver 删掉
解决:报错说无法把target/maven-archiver’移动到 ‘./maven-archiver’,因为./maven-archiver已经存在了,所以需要把./下的maven-archiver文件删掉。先用find命令找出target/maven-archiver文件在哪,然后把它删掉,再次构建就能成功了。
⑤ 查看harbor仓库是否有新推送的v3.0.0版本的镜像
shell脚本内容:
# 构建自定义镜像到Jenkins容器内部 mv target/* ./ # “./” 表示Dockerfile所在的路径;这步是把/usr/local/docker/jenkins_docker/data/workspace/mytest/target/下的内容都移动到/usr/local/docker/jenkins_docker/data/workspace/mytest/下,也就是Dockerfile所在路径 docker build -t mytest:$tag . #注意“.”,一定要加dockerfile路径 # 将Jenkins构建好的自定义镜像推送到harbor仓库 docker login -u admin -p Harbor12345 192.168.2.211:80 docker tag mytest:$tag 192.168.2.211:80/repo/mytest:$tag docker push 192.168.2.211:80/repo/mytest:$tag
8.3.6 目标服务器上编写部署脚本
- Jenkins需要通知目标服务器的信息,并在目标服务器执行相应命令:
- 告知目标服务器拉取哪个镜像
- 判断当前服务器是否正在运行容器,如果正在运行需要删除
- 如果目标服务器已经存在当前镜像,需要删除
- 让目标服务器拉取harbor上的镜像
- 将拉取下来的镜像运行成容器
如果在Jenkins来执行这一系列判断条件,成本较高。所以可以在目标服务器上建一个脚本文件,让Jenkins把镜像信息和端口号情况告诉目标服务器,目标服务器接收到后再来执行这个脚本文件就可以了。
- Jenkins通知目标服务器信息
① 镜像信息:harbor地址/harbor仓库/镜像名:镜像版本
② 端口号占用情况
逻辑如图:
Jenkins将镜像构建完成、推送到harbor仓库后,需要将镜像信息以及端口号占用情况告知目标服务器,目标服务器接受到之后,执行脚本文件。
部署项目需要通过Publish Over SSH插件,让目标服务器执行命令。为了方便一次性实现拉取镜像和启动的命令,推荐采用脚本文件的方式。
添加脚本文件到目标服务器,再通过Publish Over SSH插件让目标服务器执行脚本即可。
- 编写脚本文件,添加到目标服务器
harbor_addr=$1 # 表示执行命令中的第一个参数,harbor仓库地址 192.168.2.211:80 harbor_repo=$2 # 表示执行命令中的第二个参数,harbor仓库 repo project=$3 # 表示执行命令中的第三个参数,镜像仓库名 mytest version=$4 # 表示执行命令中的第四个参数,镜像版本/tag标签 v3.0.0 container_port=$5 # 表示执行命令中的第五个参数,容器内端口 端口号 8080 host_port=$6 # 表示执行命令中的第六个参数,宿主机端口 端口号 8082 imageName=$harbor_addr/$harbor_repo/$project:$version echo $imageName containerId=`docker ps -a | grep ${project} | awk '{print $1}'` # 检查目标服务器是否存在正在运行的、与拉取镜像同名的容器,拿到这个容器对应的容器ID,后面需要删除 echo $containerId if [ "$containerId" != "" ] ; then #删除上一步查到的正在运行的容器,如果容器ID不为空,说明有正在运行的容器,则先停止,再删除 docker stop $containerId docker rm $containerId echo "Delete Container Success" fi tag=`docker images | grep ${project} | awk '{print $2}'` # 检查目标服务器是否存在同名的镜像,拿到这个镜像对应的容器tag版本,后面需要删除 echo $tag if [[ "$tag" =~ "$version" ]] ; then #如果上一步查到的镜像版本与要拉取的版本一致,则删除这个镜像 docker rmi -f $imageName echo "Delete Image Success" fi docker login -u admin -p Harbor12345 $harbor_addr docker pull $imageName docker run -d -p $host_port:$containerport --name $project $imageName echo "Start Container Success" echo $project
- 设置脚本文件
deploy.sh
权限为可执行
chmod a+x deploy.sh #给所有用户给予deploy.sh文件可执行权限
3、将deploy.sh
文件移动到/usr/bin
目录下,这样就可以在任何位置执行
4、测试脚本文件
sh deploy.sh 192.168.2.211:80 repo mytest v3.0.0 8080 8082
8.3.7 配置构建后操作
到目前为止,目标服务器中的脚本文件已经编辑完成,下面就要让Jenkins通知目标服务器执行这个脚本文件。
我们要到Jenkins中配置构建后操作
增加container_port
和host_port
参数,这样就可以直接引用了($container_port $host_port)
构建镜像:
去目标服务器中检查容器是否运行起来了(docker ps),然后用IP+端口号登录网页查看是否能访问即可