目录
1.什么是CI/CD?
从CI/CD过程开始,包含所有阶段并负责创建自动化和无缝的软件交付的一系列步骤称为CI/CD管道工作流。使用CI/CD管道,软件发布工件可以从代码提交阶段到测试、构建、部署和生产阶段在管道中移动和前进。这个概念非常强大,因为一旦指定了一个管道,它的一部分或全部就可以实现自动化,从而加快流程并减少错误。换句话说,CI/CD管道使企业更容易一天自动多次交付软件。
DevOps工程师经常会因为CI/CD中各个阶段的自动化而与CI/CD管道混淆。虽然不同的工具可以使CI/CD中的各个复杂阶段实现自动化,但由于人工干预,CI/CD的整个软件供应链仍然可能被打破。那么,就首先了解CI/CD过程中的各个阶段,以及CI/CD管道为什么对于组织快速、大规模地交付代码至关重要。
如下列举了常用的实现DevOps的工具,在实际的生产过程中通常只会使用其中的一部分产品,加粗的部分是我们在实际开发、部署中使用较多的产品。
代码管理(SCM):GitHub、GitLab、BitBucket、SubVersion
自动部署:Capistrano、CodeDeploy
持续集成(CI):Bamboo、Hudson、Jenkins
配置管理:Ansible、Chef、Puppet、SaltStack、ScriptRock GuardRail
容器:Docker、LXC、第三方厂商如AWS
编排:Kubernetes、Core、Apache Mesos、DC/OS
服务注册与发现:Zookeeper、etcd、Consul
脚本语言:python、ruby、shell
日志管理:ELK、Logentries
系统监控:Datadog、Graphite、Icinga、Nagios
性能监控:AppDynamics、New Relic、Splunk
压力测试:JMeter、Blaze Meter
预警:PagerDuty、pingdom、厂商自带如AWS SNS
HTTP加速器:Varnish
消息总线:ActiveMQ、SQS
应用服务器:Tomcat、JBoss
Web服务器:Apache、Nginx、IIS
数据库:MySQL、Oracle、PostgreSQL等关系型数据库;cassandra、mongoDB、redis等NoSQL数据库
构建工具:Ant、Gradle、maven
我们这里以java开源的ruoyi框架为例,实际操作ruoyi-vue这个前后端分离项目的CI/CD部署流程
2.组件安装
tips:如果只是简单的想要实现单节点代码自动发布部署,可以使用gitlab+jenkins即可,不需要用到harbor,如果涉及多节点或k8s+docker集群部署等,建议加上harbor仓库存储已打包的docker镜像,方便生产环境代码回退,系统恢复等等。
各组件安装方法已单独文章说明,这里不再重复。
安装gitlab:linux centos7安装自己的gitlab私有库
安装jenkins:linux下安装Jenkins(centos7,另附使用docker安装)
安装harbor:linux下安装docker仓库-Harbor
另外,如果是内网环境服务器无法访问外网的,建议另外安装maven私库:Linux搭建自己的Maven私有仓库(nexus)
3.jenkins配置
我这里gitlab和jenkins都是使用docker安装的,使用docker安装的jenkins因为容器权限和宿主机目录挂载的问题,会比直接安装的需要配置更多的配置项,也更容易导致其他问题,建议新手小伙伴不要安装jenkins时不要使用docker安装的方式。
gitlab、jenkins、harbor都安装好后,我们就可以开始进行jenkins流水线部署调试了。
我这里首先下载了ruoyi-vue框架源码,在新安装的gitlab私库上创建一个新项目,将本地代码上传到gitlab私库上。
3.1 安装jenkins插件
进入jenkins控制台,选择系统管理-插件管理,下载gitlab插件、maven插件、ssh插件、nodejs插件(前端项目),有的插件jenkins安装的时候可能已经默认安装好了,查看一下已安装的和可选的插件,确保上述插件都已安装即可。
插件安装好后重启jenkins,回到控制台,配置一下需要用到的各种凭证
3.2 配置jenkins凭据
点击管理凭据
我们需要的有gitlab 的api凭据(拉取代码),需部署的主机的ssh 的用户名密码(远程操控)
添加gitlab api:
类型选择Gitlab API Token
切换到gitlab,进入gitlab的控制台,进入项目,点击左下角设置-访问令牌
创建好以后上方会出现访问令牌,点击复制,回到jenkins,复制到API Token,ID随便填个名字,保存。
添加ssh凭据:
还是添加一个新凭据,类型选择 username with password,用户名和密码填写对应主机的ssh的用户名和密码,起个id名字,保存
jenkins需要的凭据我们就增加好了
3.3配置jenkins的环节变量
进入控制台,配置全局工具配置
打开后maven配置这里我们选默认,jdk由于我是docker环境安装的jenkins默认自带了jdk,不需要配置了,直接安装的话这里需要选择新增jdk
名字随便起一个,配置上jenkins所在机器的JAVA_HOME,也可以让jenkins自动安装一个jdk版本
同理配置好maven和nodejs环境,我这里maven和nodejs的文件分别位于/usr/local/maven,/usr/local/nodejs
保存后回到控制台,选择系统管理-系统配置
设置一下全局属性,增加环境变量 PATH
获取jenkins容器中的系统环境变量PATH
echo $PATH
查看一下如果没有nodejs的配置的话增加上nodejs的环境变量,我这里是/usr/local/nodejs/bin
否则后续jenkins打前端包的时候会出现npm command not found的情况。
配置ssh,涉及到集群部署的话需要调用多台机器的ssh,确保jenkins机器与每台机器的ssh都可用,hostname是要ssh机器的ip,credentials这里选之前我们ssh配置的凭据
这里出现Successfull connection,证明连接没问题
接着我们配置gitlab,名字随便起一个,URL用gitlab的地址(不是代码项目地址),凭据用我们上面配置的gitlab的api,点击Test Connection 测试一下,出现 Success代表没问题
到这里, jenkins的准备工作都完成了,我们可以开始编写部署流水线了。
3.4 jenkins流水线构建docker应用
回到控制台,新建任务
我这里新建一个名字为ruoyi-vue的项目,选自由风格
如果构建过程需要添加自定义参数,可以在这里勾选参数化构建过程,我这里是下载了jenkins的date parameter插件,用于生成时间戳,给后面镜像命名的 ,后面写脚本的时候占位符就需要根据这里起的参数名字用${nowdate} 代替
进入源码管理,配置拉取代码的信息,URL用项目代码的地址,Credentials由于我们已经配置了gitlab的API Token ,这里不需要额外凭据了
指定分支默认是master,根据自己实际情况修改
需要根据代码提交自动重新部署的话这里构建触发器选择webhook,复制提示的jenkins webhook url
下方点击高级,找到Secret token栏,下方有个generate,生成一个token,切到gitlab控制台
gitlab进入项目,点击设置,webhook,输入jenkins那边的webhook url和token,选择下方的需要出发的条件,保存。
回到jenkins,进入构建环节
选择添加构建,调用顶层Maven目标
配置如下 ,maven版本用我们之前配置的maven环节,配置了下拉这里会自动出现
需要maven私库的话这里可以打钩
然后增加shell脚本
shell命令如下,ip:port换成你的harbor的url
#!/bin/bash
# 服务名称(jenkins中取的)
SERVER_NAME=ruoyi-vue
# 源jar名称,mvn打包之后,target目录下的jar包名称,可以在在 xshell 使用 cd /data/jenkins_home/workspace/你的项目名(jenkins中取的),这个文件夹可以看见gitlab拉取的代码,之后maven打jar包后会在本地的target目录下
JAR_NAME= "ruoyi-admin"
# jenkins下的目录
JENKINS_HOME= "/var/jenkins_home/workspace/ruoyi-vue"
echo "-----------------------------准备打包-------------------------------------------"
# JENKINS_HOME下的jar包所在目录
cd /var/jenkins_home/workspace/ruoyi-vue/ruoyi-admin/target
# 把文件中的Dockerfile放在跟jar包一个位置,方便我们打成镜像
cp /var/jenkins_home/workspace/ruoyi-vue/ruoyi-admin/Dockerfile /var/jenkins_home/workspace/ruoyi-vue/ruoyi-admin/target
# 修改文件权限 JAR_NAME
chmod 755 ruoyi-admin.jar
echo "-------------------docker版本-----------------"
docker -v
echo "-----------------------停止容器-------------------------"
# 停止容器
docker stop ruoyi-vue
echo "--------------------------------删除容器------------------------"
# 删除容器
docker rm ruoyi-vue
echo "-----------------------删除镜像-----------------------------------"
# 删除镜像
docker rmi ruoyi-vue
echo "-------------------------------打包镜像------------------------------"
# 打包镜像
docker build -t ruoyi-vue -f Dockerfile .
echo "--------------------------运行镜像---------------------------------------"
# 运行镜像
docker run -d -p 8080:8080 --name ruoyi-vue ruoyi-vue
docker build -t ip:port/library/ruoyi-vue:v1${nowdate} . ## 自己调整
docker login -uadmin -p123456 ip:port
docker push ip:port/library/ruoyi-vue:v1${nowdate}
同时项目里根目录添加Dockerfile文件:
FROM openjdk:8
MAINTAINER qlove95
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
继续添加构建步骤,上述脚本jenkins已经把最新代码拉取并打包推送到了harbor仓库,现在需要ssh到各应用主机拉取镜像并运行了
添加构建步骤,选择ssh,
ssh site这里我们之前全局配置那里配置了对应主机内容的话这里会有显示,选择要连接的主机
shell内容
docker stop ruoyi-vue
docker rm -f ruoyi-vue
docker login -uadmin -p123456 ip:port ## 自己调整
docker pull ip:port/library/ruoyi-vue:v1${nowdate}
docker run -d -p 8080:8080 --name ruoyi-vue -v /usr/local/java/jdk1.8.0_144:/usr/local/jdk ip:port/library/ruoyi-vue:v1${nowdate}
至此配置步骤完成,可以保存测试构建效果,
可以点击控制台输出查看构建部署日志情况
如果提交了代码或者之前配置了gitlab webhook条件的话,也会自动触发构建和部署。至此CI/CD 持续交付部署构建完成。
3.5 可选(前端构建)
构建前端的话,一般都是打nginx镜像包,代码里前端项目根目录需要添加3个文件
Dockerfile:
FROM nginx
COPY ./dist/index.html /app/
COPY ./dist/static/js /app/static/js
COPY ./dist/static/css /app/static/css
COPY ./dist/static/fonts /app/static/fonts
COPY ./dist/static/img /app/static/img
COPY ./nginx.conf /etc/nginx/conf/nginx.conf
COPY ./default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
实际可能不止上述文件,根据实际打包生成的目录结构按需配置,我这里是ruoyi-ui生成包的结构
nginx.conf和default.conf用于覆盖初始nginx镜像的配置文件
nginx.conf:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 65535;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
default.conf:
server {
listen 80;
server_name localhost; #如果有需要监听的域名,这里也需要修改
location / {
root /app;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location /api {
if ($request_method = 'OPTIONS') {
return 204;
}
rewrite ^/api/(.*)$ /$1 break;
#后端接口域名,这里需要根据你自己的具体后端来填写
proxy_pass http://xxxxx:8080/;
}
}
继续添加shell步骤
shell命令:
#!/bin/bash
pwd
echo "------------------------开始打包前端项目-----------------------------------"
cd /var/jenkins_home/workspace/ruoyi-vue/ruoyi-ui
npm install
npm run build:prod #编译项目
echo "---------------------------------npm finish----------------------------------- "
docker build -t ruoyi-vue-ui:v1${nowdate} -f Dockerfile .
docker tag ruoyi-vue-ui:v1${nowdate} ip:port/library/ruoyi-vue-ui:v1${nowdate}
docker push ip:port/library/ruoyi-vue-ui:v1${nowdate}
添加ssh步骤
拉取部署脚本同后端类似
docker stop ruoyi-vue-ui
docker rm -f ruoyi-vue-ui
docker pull ip:port/library/ruoyi-vue-ui:v1${nowdate}
docker run -d -p 8090:80 --name ruoyi-vue-ui ip:port/library/ruoyi-vue-ui:v1${nowdate}