最近使用jenkins+docker完成了持续部署nodejs程序,战线拉的很长,知识点也很碎,也踩过一些坑,遂写篇文章总结一下,日后要有遗忘,也可以回来翻阅。
首先先说一下要达成的目标:用户提交代码并打tag后,在jenkins界面上选择对应的tag执行构建,构建的过程中会将代码通过docker打包成镜像,然后推送到镜像仓库中,接着ssh到应用服务器上,拉取对应的镜像,停止之前运行的旧版本容器,将新的镜像run起来。
首先安装docker环境,我的机器是ubuntu16.04
添加软件仓库(阿里云仓库)
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
安装docker
sudo apt-get update
sudo apt-get install docker-ce
重启docker
sudo service docker restart
测试docker是否安装成功,如果执行下面命令打印出docker对应的版本,代表docker已成功安装
docker --version
docker安装成功之后,就基于这个docker环境安装jenkins
由于国内网的问题,可先添加DaoCloud的加速器:在DaoCloud官网上找到加速器 选项,找到你对应的操作系统
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://dfe09f6e.m.daocloud.io
拉取jenkins
sudo docker pull jenkins:lts
创建jenkins配置文件目录
sudo mkdir /var/jenkins_home
sudo chmod 777 /var/jenkins_home ##注意这里必须配置本地卷的权限,否则启动失败
运行jenkins镜像
注意:我们是通过jenkins来构建镜像的,但是我们的jenkins容器里面是没有安装docker的,但是我们宿主机是安装了docker,所以我们需要将宿主机的docker挂到容器中, 参考链接:https://www.jianshu.com/p/8b7...
sudo docker run -d \
-p 9000:8080 \
-v /var/jenkins_home:/var/jenkins_home \
--restart=always \
#Docker重启后该容器也为随之重启
-u root \
-v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7 \
--name myjenkins jenkins:lts
-d:后台运行
-p:宿主机的9000端口,映射到jenkins的默认8080端口
-v:将宿主机的目录挂载到容器里,容器停止后jenkins配置的东西还存在
--name:给容器取个名称
这个时候访问9000端口就可以看到jenkins的界面了,注意:如果是阿里云上的服务器,需要在安全策略处配置允许9000端口
访问jenkins界面后,会提示输入一个密码,根据提示找到对应的文件查看密码,并复制
cat /var/jenkins_home/secrets/initialAdminPassword
插件安装完成后,创建用户,之后就初始化完成了。
接下来,安装我们这次部署nodejs程序需要的插件,我们的目标是,在jenkins上选git上的tag,做为源码,所以我们需要安装git parameters插件
点击系统管理-》插件管理 -》选择可选插件tab,找到Git Parameter Plug-In 安装,然后再搜索SSH 找到SSH plugin插件安装,等待安装完成
插件安装完成,我们的基础工作就基本上做好了,接下来,我们就要开始在jenkins上创建任务达成我们的目标了。点击新建任务,填一个任务名称,选择“构建一个自由风格的软件项目”, 进来后选择参数化构建过程,以便在构建时,选择tag进行构建
指定分支填入${Tag}
之后在构建脚本中可以通过$Tag取到构建时选择的tag
接着就是配置构建了,选择执行shell
# 进入项目目录
cd /var/jenkins_home/workspace/[填入你的git仓库名]
# tag名称
tagName=$Tag
# docker仓库,可以在阿里云镜像仓库,申请自己的镜像仓库
REPOSITORY=[镜像仓库的域名]/[镜像仓库的命名空间]/[镜像仓库的名称]:jenkins-$tagName
# 构建镜像,注意后面有个. 代表使用当前目下下的dockerfile,后面会说dockerfile怎么写
docker build -t $REPOSITORY .
# 如果是私有的镜像仓库,例如我的阿里云镜像仓库,需要登录后才能push,如果公有的不需要这步
docker login -u [用户名] -p [密码] [镜像仓库域名]
# 将构建好的镜像,推送到远程的镜像仓库
docker push $REPOSITORY
# 删除本地构建的镜像
docker rmi -f $REPOSITORY
上面我们说了构建镜像需要有dockerfile,这个dockerfile其实就是docker在构建时,根据这个文件的内容,打包镜像,看一下我那个项目的dockerfile可以对照参考,很简单
# 基于某个镜像,来构建新的镜像,我们是nodejs项目,选择一个带有nodejs环境的镜像
FROM node:13.5.0-buster-slim
# 打一个标签,
LABEL zhangchao [邮箱名]
# 设置环境变量,nodejs代码中可以取到这个环境变量,如果没有可不写
ENV NODE_ENV=production
# 创建一个代码目录
RUN mkdir -p /usr/src/webapp
# 将代码拷贝到这个目录中
COPY . /usr/src/webapp
# 设置工作目录
WORKDIR /usr/src/webapp
# 安装nodejs项目依赖
RUN /bin/sh -c 'cd /usr/src/webapp/ && \
npm install --unsafe-perm'
# 对外暴露3000端口
EXPOSE 3000
# 启动nodejs服务
CMD node server.js
打包好镜像后,接下来我们进行最后一步,就是通过我们刚才安装的jenkins的SSH插件,shell到应用服务器上,停掉之前版本的镜像,将我们新构建的镜像Run起来
我们先配置下我们应用服务器的地址信息。
在上一步创建的域下添加一个凭证,类型选择Username with password下面的Username和Password即为要连接的linux服务器的登录账户和密码
添加remote host
进入jenkins–>系统管理–>系统配置–>SSH remote hosts(在系统设置中找到SSH remote hosts),添加该linux服务器连接
选择配置的SSH Site,填入远程执行的脚本
# 设置tagName
tagName=$Tag
# 登录私有仓库,如果是公有仓库,这步不用写
docker login -u [用户名] -p [密码] [镜像仓库域名]
# 拉取远程镜像 pull后面跟的是仓库名称:tag名称
docker pull [镜像仓库的域名]/[镜像仓库的命名空间]/[镜像仓库的名称]:jenkins-$tagName
# 根据容器名称查找容器id
containerId=`docker ps -a | grep [上一版启动的容器名称] | awk '{print $1}' `
# 根据容器名称查找镜像名称
imageName=`docker ps -a | grep [上一版启动的容器名称] | awk '{print $2}' `
# 如果容器id存在就停止掉旧容器运行,并删除掉旧的容器和镜像
if [ -n "$containerId" ]; then
docker stop $containerId
docker rm $containerId
docker rmi -f $imageName
fi
# 运行新的镜像,最后面其实是仓库名称:tag名
docker run -d --name [容器名称] -p 3000:3000 [镜像仓库的域名]/[镜像仓库的命名空间]/[镜像仓库的名称]:jenkins-$tagName
点击保存,我们的构建过程就配置好了,可以点击build with params,选择git仓库的tag进行构建了,有任何疑问可以在评论中提出来,看到后我会回复,希望你们能一次成功。
参考链接:
ubuntu 16.04 安装配置docker:
https://www.jianshu.com/p/724...
如何从容器内部执行宿主机的docker命令:
https://www.jianshu.com/p/8b7...
使用jenkins插件SSH Plugin执行远程ssh
https://blog.csdn.net/df0128/...