Jenkins + Docker 构建自己的自动化部署
当你写完代码后,点下push按钮,不到一会你的线上应用就完成了更新并且运行了起来,这就是完美的工作流。
准备流程
这样的工作流也称自动化部署,具体的流程:
- 开发人员推送代码到git仓库
- git仓库触发webhook请求build服务器
- build服务器执行构建任务
- build服务器打包docker并push到docker仓库
- build服务器登录生产服务器,停止旧服务,pull新镜像并运行
要构建这么一套自动化部署,我们需要有:
- git仓库
- 构建服务器
- docker镜像仓库
- 生产服务器
git仓库
github,码云,或者私有的gitea、gitlab都是可行的。
构建服务器
构建过程通常会占用较多的服务器资源,如果服务器配置不佳,在生产服务器上进行构建甚至会导致线上运行的其他应用被迫停止。
docker镜像仓库
如果是非开源项目,一般使用私有仓库,可以在一台服务器上使用docker-registry
自建私有仓库
推荐使用docker-registry-ui作为可视化ui,轻量级且支持basic auth
。
没有仓库服务器也可以直接使用阿里云的镜像仓库服务,非企业版是完全免费的。
生产服务器
生产服务器仅需要安装docker
,应用的runtime环境一般会打包在image
里。
搭建环境
构建服务器
Docker
安装docker
,按照官方文档操作(保证版本在17.05以上,因为这个版本开始才支持多阶段构建)。
安装完毕后需要启用远程连接(jenkins会用到)
vim /usr/lib/systemd/system/docker.service
- 找到
ExecStart
,然后在后面添加上-H tcp://0.0.0.0:2376 -H unix://var/run/docker.sock
最后再搭一块网桥,具体作用查看Docker 无法访问主机 localhost
docker network create -d bridge --subnet 192.168.0.0/24 --gateway 192.168.0.1 hostNet
Jenkins
自动化部署的核心,构建应用、推送镜像、登录生产服务器更新镜像都靠它解决。
拉取官方镜像,注意是jenkins/jenkins
不是jenkins
docker pull jenkins/jenkins
jenkins.sh
#!/bin/bash
name="jenkins"
mkdir -pv /var/data/$name
docker stop $name
docker rm $name
docker run --name $name -d \
--detach \
-p 50000:50000 \
-p 8080:8080 \
-v /var/data/$name:/var/jenkins_home \
jenkins/jenkins
写了个shell脚本方便快速重启,/var/jenkins_home
存储了jenkins的所有数据,一定要挂载到宿主机里避免重启后丢失。
启动后进入jenkins
,按照流程初始化,安装推荐插件即可。
随后需要再安装一些插件,假定我们所有的项目都是利用Docker
进行构建,那么理论上不需要任何环境插件(jdk、go、node等等)。
安装Docker plugin
插件,用于docker
构建。
安装完毕后需要配置docker cloud
,在系统配置页面拉到底,能看到cloud模块。
点击连接进入,然后新建一个cloud
这时在宿主机上创建的网桥就起作用了,它能让docker
内的容器通过网桥直接访问宿主机,2376端口则是docker
的远程连接端口。
安装Publish Over SSH
插件,用于登录生产服务器更新应用。
安装完毕后,在系统配置里找到Publish over SSH的模块,添加一台SSH Server,也就是你的生产服务器。
生产服务器
安装Docker
,同构建服务器。
如果生产服务器还装有Mysql
或Redis
一类的服务或镜像,也可以搭建一个网桥方便容器内应用访问。
搭建项目
现在自动化部署环境已经搭建完毕,尝试搭建一个项目吧,这里以我的一个golang项目为例子。
Dockerfile
FROM golang AS build-env
ENV CGO_ENABLED 0
ENV GO111MODULE on
ENV GOPROXY https://goproxy.io
ADD . /go/src/app
WORKDIR /go/src/app
RUN go mod download && go get github.com/gadelkareem/bee@fix-mod
RUN bee pack -be GOOS=linux
RUN mkdir -v build && tar -zxvf app.tar.gz -C ./build
FROM alpine
COPY --from=build-env /go/src/app/build /var/www/server
WORKDIR /var/www/server
EXPOSE 8080
CMD [ "./app" ]
这是一个多阶段构建
第一个阶段是使用Golang
镜像进行构建
第二阶段使用COPY
将上一阶段的构建产物复制到此阶段,然后用alpine
作为基础镜像运行
好处很明显,jenkins
不需要安装任何构建环境,因为构建也是在容器内进行,完全隔离。最终的产物仅包含第二阶段镜像的产物,镜像的大小非常可观。
git webhook
一般的代码库都会提供webhook
,以github为例
打开项目 - Settings - Webhooks - Add Webhook
Payload URL填写http://jenkins面板根目录/github-webhook/
,例如http://192.168.1.1:8080/github-webhook/
Content type选择application/json
勾选Active
添加完成即可
jenkins
在jenkins
上新建一个自由风格任务。
源码管理
源码管理选择git
,填写仓库路径,选择分支。
然后选择仓库对应的凭证,没有则添加一个。凭证也就是保存好的身份验证信息。
如果是https
的仓库的话,使用Username and password类型的凭证,即git账户密码。
如果是git
的仓库的话,使用SSH Username with private key类型的凭证,再填写你的私钥。
触发构建器
勾选GitHub hook trigger for GITScm polling
构建
不需要构建环境,因为我们的构建环境都在docker
里,直接进入构建环节。
增加一个Build / Publis Docker Image
cloud选择前面创建好的local cloud
,即宿主机的Docker
。
Image填写镜像名字
我填写为registry.cn-hangzhou.aliyuncs.com/sakuradon/sakuradon-cq:${BUILD_NUMBER}
直接指明了私有仓库,${BUILD_NUMBER}
则是jenkins
的环境变量,即这次构建的号码,我用它来作为tag
。
Registry Credentials则是镜像仓库的身份凭证,根据私有仓库填写。
这一步进行项目的构建打包并推送到镜像仓库。
增加一个Send files or execute commands over SSH
Name选择前面创建好的远程主机SSH连接。
然后在Exec command里写登陆后执行的shell
脚本
registry="registry.cn-hangzhou.aliyuncs.com"
image="${registry}/sakuradon/sakuradon-cq"
name="sakuradon-cq"
docker login --username=sakuraidon --password=xxxxxx ${registry}
docker pull ${image}:${BUILD_NUMBER}
docker stop ${name}
docker rm ${name}
docker rmi ${image}:running
docker tag ${image}:${BUILD_NUMBER} ${image}:running
docker run --name ${name} -d \
-p 8000:8080 \
${image}:running
在生产服务器上拉取最新镜像,删除原有容器,再把tag
标记为running
,最后创建并启动容器。
Or you can contact me by Email