Jenkins 集成 Gitlab 持续集成

Jenkins 是一个开源的、提供友好操作界面的持续集成 (CI) 工具,起源于 Hudson(Hudson 是商用的),主要用于持续、自动的构建 / 测试软件项目、监控外部任务的运行。Jenkins 用 Java 语言编写,可在 Tomcat 等流行的 servlet 容器中运行,也可独立运行。通常与版本管理工具 (SCM)、构建工具结合使用。常用的版本控制工具有 SVN、GIT,构建工具有 Maven、Ant、Gradle。

Jenkins 官方网站

实验前必须安装的环境:JDK11+、docker、docker-compose、tomcat9+、maven、Git、vim、wget。

实验过程:在本地 IDE 开发,提交代码到 Gitlab 仓库,Jenkins 自动监测仓库代码的变化,使用使用 docker-compose 自动化部署。

Gitlab 安装

官网安装文档

配置要求:

内存:最低 4G 以上,建议 6G

内核版本:3.10 以上 (查看内核版本命令:uname -r)

介绍

GitLab 是一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,并在此基础上搭建起来的 Web 服务。简单来说就是类似 GitHub 的一个 Git 开源代码管理平台,只是 Gitlab 可以自己搭建随意使用,可以用于小团队并且完全不用担心代码泄露。

方式一:docker 安装 (推荐)

新建文件夹用于存放 Gitlab 数据

bash
1
mkdir /opt/gitlab/{config,logs,data}

使用 docker-compose 安装

bash
1
cd /opt/gitlab && vim docker-compose.yml

docker-compose.yml 写入以下内容

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3'
services:
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: gitlab
restart: always
environment:
TZ: 'Asia/Shanghai' #设置时区
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['time_zone'] = 'Asia/Shanghai'
external_url 'http://192.168.2.12:980' #要修改成自己的centos7的IP
gitlab_rails['gitlab_shell_ssh_port'] = 2224 #使用ssh远程Gitlab端口
ports:
- '980:980'
- '2224:22'
volumes:
#将相关配置映射到当前目录下的config目录
- '/opt/gitlab/config:/etc/gitlab'
#将日志映射到当前目录下的logs目录
- '/opt/gitlab/logs:/var/log/gitlab'
#将数据映射到当前目录下的data目录
- '/opt/gitlab/data:/var/opt/gitlab'

构建容器

bash
1
docker-compose up -d
  • up: 表示运行容器并在前台运行
  • -d:表示运行容器在后台运行

浏览器打开 Gitlab

  1. 开放 980、2224 端口端口 (关闭防火墙:systemctl stop firewalld.service)
  2. 运行完 docker-compose up -d 指令后
  3. 在浏览器打开 http://IP:980 即可

初次访问 Gitlab 可能会出现 502 页面,Gitlab 比较消耗资源,需要一点时间加载,等 2 分钟左右再刷新访问就没问题了,如果还时 502,你应该看看是不是虚拟机的内存不够大

方式二:直接安装

官方安装文档:https://gitlab.cn/install/?version=ce

安装依赖

bash
1
2
3
4
5
6
# 安装依赖
sudo yum install -y curl policycoreutils-python openssh-server perl
# 启用 sshd
sudo systemctl enable sshd
# 启动 sshd程序
sudo systemctl start sshd

配置镜像

plaintext
1
curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash

开始安装

plaintext
1
2
sudo EXTERNAL_URL="http://192.168.44.103" 
yum install -y gitlab-jh

除非您在安装过程中指定了自定义密码,否则将随机生成一个密码并存储在 /etc/gitlab/initial_root_password 文件中 (出于安全原因,24 小时后,此文件会被第一次 gitlab-ctl reconfigure 自动删除,因此若使用随机密码登录,建议安装成功初始登录成功之后,立即修改初始密码)。使用此密码和用户名 root 登录。

gitlab 常用命令

bash
1
2
3
4
5
6
7
gitlab-ctl start                  # 启动所有 gitlab 组件;
gitlab-ctl stop # 停止所有 gitlab 组件;
gitlab-ctl restart # 重启所有 gitlab 组件;
gitlab-ctl status # 查看服务状态;
gitlab-ctl reconfigure # 启动服务;
vim /etc/gitlab/gitlab.rb # 修改默认的配置文件;
gitlab-ctl tail # 查看日志;

安装 Jenkins

如果你是使用官网最新的 Jenkins,建议先看一下官方文档

安装最新版的 Jenkins 是有要求的,博主安装的版本是 2.346.3LTS 版本,需要 JDK 版本至少 JDK11 以上,如果你下载的 Jenkins 比我安装的还高,可能还有其他的环境要求。

使用 war 包方式安装 Jenkins

下载 Jenkins.war 包

bash
1
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/2.346.3/jenkins.war

将 war 包复制到 tomcat 下

暂停 tomcat

在复制 Jenkins.war 包之前,需要将 tomcat 暂停一下,避免出问题。

bash
1
{tomcat安装目录}/tomcat9/bin/shutdown.sh

复制文件到 tomcat 下

bash
1
cp jenkins.war {tomcat路径}/webapps/

打开 Jenkins

启动 tomcat

bash
1
{tomcat安装目录}/tomcat9/bin/startup.sh

打开 Jenkins

http://IP:8080/jenkins

配置 Jenkins 环境

所需环境:

  1. Gitlab (如果你还没安装 Gitlab,你应该先去安装 Gitlab)
  2. Git(yum -y install git)
  3. Jenkins 需要安装这四个插件:GitLab Plugin、Generic Webhook Trigger、Gitlab Authentication、GitLab Logo (我已打包好放在以下链接)

Jenkins 构建 Gitlab 必装四个插件:https://rookie1679.lanzoui.com/ikJqH0ducmfi

如果你还没安装 JDK、Maven、Git 你可以参考这篇文章去安装一下

参考这篇文章:https://blog.hikki.site/111f4f09.html

Jenkins 配置 maven

Manage Jenkins--->Global Tool Configeration

01Manage

02GlobalToolCfongi

maven 下的 settings.xml 文件

03settings

Jenkins 配置 JDK

04jdk

Jenkins 配置 Git

05git

Jenkins 配置 maven

06maven

安装 Jenkins 插件

Jenkins 集成 Gitlab 需要几个插件,我已经在官方下载并打包好并放在以下,有需要自己取,或者自己去官网下载也是可以的

  1. GitLab Plugin
  2. Generic Webhook Trigger
  3. Gitlab Authentication
  4. GitLab Logo

官网插件下载地址:https://plugins.jenkins.io/

插件下载地址:https://rookie1679.lanzoui.com/ikJqH0ducmfi

Manage Jenkins—>Manage Plugins—> 高级 —>Deploy Plugin—> 上传文件 —>Deploy—> 勾选安装完重启Jenkins

07安装插件

前言

我一开始在给容器命名的时候,是使用了下划线,在构建完的时候,我在浏览器打不开我的项目,访问总是返回 400,查了一下,是 nginx 不支持下划线的,会自动将下划线改为 -,就一直访问失败,所以我后面将_改为 -,如果你看到_,你应该将它改为 -

创建 Git 仓库

如果你有需要选择其他模板可以选择模板创建,比如 spring boot。

01创建Git仓库

初始化 idea 开发环境

新建项目

02创建本地项目

测试项目

测试项目是否正常运行,浏览器打开 http://localhost:8080/hi 项目正常运行

03本地开发已完成

推送代码至 Git 仓库

  1. 勾选需要推送的代码
  2. 提交备注是必填项
  3. 然后点击提交并推送 (推送到 Gitlab)

04推送代码

打开 Git 仓库刷新查看是否推送成功

如下图可以看到代码已经推送成功了

05提交代码到git仓库成功

Jenkins 添加 Gitlab 用户凭证

在 Jenkins 添加 Gitlab 的用户凭证,为了后面在 Jenkins 绑定 Gitlab 仓库进行其他操作做准备。

添加的用户名和密码为 Gitlab 的用户和密码。

05新建用户凭证

初始化 Jenkins 任务

新建Item--->输入任务名称--->构建一个maven项目--->确定--->Git--->填写Repository URL(Git仓库地址)--->Credentials(选择用户,没有就新建一个)--->构建触发器--->Build when a change is pushed to GitLab. GitLab webhook--->高级--->Secret token--->Generate--->复制token到Gitlab Secret 令牌--->去除SSL验证--->Add webhook--->Build--->填写Goals and options--->Run only if build succeeds--->保存

bash
1
clean package -Dmaven.test.skip=true

重点:在 Gitlab 添加 Webhooks 记得去掉 SSL 验证,除非你有 SSL 证书,否则不要勾选

06新建Jenkins任务

源码管理中,选择 Git,添加如下信息,如果在 Credentials 没有用户可以选择,你应该去 Jenkins 凭据管理添加一个 Gitlab 用户和密码,再过来选择用户。

构建 Jenkins 任务

当构建结束后,看到绿色的小勾,说明已经构建成功了。如果执行失败,打开控制台输出可以看到错误内容了。

07开始构建

构建 Docker 镜像

构建两个容器,一个 nginx 容器负责反向代理,web-server-auto 负责运行我们开发代码的 war 包,通过容器化,减少依赖对系统环境的影响,而且容器化更方便管理,可以提高效率。

  • /home/docker/nginx:nginx 映射目录

  • /home/auto:用于存放 Dockerfile、项目 jar 包、docker-compose.yml

初始化工作目录

bash
1
mkdir /home/auto && cd /home/auto

复制 auto-0.0.1-SNAPSHOT.war 包到工作目录

刚刚我们已经在 Jenkins 完成简单的构建了,在构建完成时,会在 /root/.jenkins/workspace/auto/target 下生成 auto-0.0.1-SNAPSHOT.war 包,我们需要将 war 包构建成 Docker 镜像。

bash
1
cp /root/.jenkins/workspace/auto/target/auto-0.0.1-SNAPSHOT.war /home/auto/

Dockerfile 与 docker-compose

Dockerfile 编写

bash
1
vim Dockerfile

将以下内容写入 Dockerfile

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 拉取镜像
FROM openjdk:11
# 作者信息
MAINTAINER wtl
#开放端口
EXPOSE 8080
#挂载目录
VOLUME /home/auto
#执行shell指令
RUN mkdir -p /home/auto
#执行工作目录
WORKDIR /home/auto
#复制宿主机文件到镜像中
COPY auto-0.0.1-SNAPSHOT.war /home/auto/auto-0.0.1-SNAPSHOT.war
#开始认证服务
ENTRYPOINT ["java","-jar","auto-0.0.1-SNAPSHOT.war"]

编写 docker-compose.yml

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
version: "3.1"
services:
nginx_auto: #服务名称,自定义
image: nginx:latest #镜像版本
restart: always
container_name: nginx-auto
privileged: true #解决nginx的文件调用的权限问题
environment:
- TZ=Asia/Shanghai
ports: #暴露端口
- "801:80"
- "4444:443"
volumes:
- /home/docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- /home/docker/nginx/log:/var/log/nginx
links:
- web-server-auto # 将容器nginx_auto连接到web-server-auto

web-server-auto:
restart: always
environment:
- TZ=Asia/Shanghai # 设置时区
build:
context: /home/auto # 构建文件的路径
dockerfile: Dockerfile #构建文件Dockerfile
container_name: web-server-auto #容器名字,可自定义
ports: # 暴露端口 宿主机端口:docker容器端口
- 7889:8080

09创建docker

添加执行权限

/home/auto/ 文件夹下的所有文件都给予执行权限,因为该文件夹下存储着 Dockerfile 和 docker-compose.yml、jar 包,这些文件需要执行权限。

bash
1
chmod +x -R /home/auto/
  • -R :对目前目录下的所有档案与子目录进行相同的权限变更 (即以递回的方式逐个变更)

添加脚本

添加执行脚本

Jenkins 实时监测 Gitlab 中 auto 仓库的代码变动,一旦有代码更新,Jenkins 就会实时构建,在构建时,我们可以添加一些脚本来达到我们想要的目的,比如我们添加如下脚本,表示再构建时删除旧的容器的镜像,重新生成新的容器和镜像。

auto--->配置--->Post Steps--->Run only if build succeeds--->Add post-build step--->Excute shell--->在输入框中输入以下shell脚本--->保存

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
WORKSPACE_DIR='/root/.jenkins/workspace/auto/'
DEVOPS_DIR='/home/auto'

echo "删除之前的容器"
docker ps -a | grep web-server-auto | awk '{print $1}' | xargs docker rm -f
docker ps -a | grep nginx-auto | awk '{print $1}' | xargs docker rm -f

echo "删除上一个版本的jar包"
sudo rm -rf ${DEVOPS_DIR}/auto-0.0.1-SNAPSHOT.war
echo "复制打包最新版的jar包"
cp ${WORKSPACE_DIR}/target/auto-0.0.1-SNAPSHOT.war ${DEVOPS_DIR}
echo "赋予jar包权限"
chmod 777 -R /home/auto
echo "启动容器"
cd /home/auto/
docker-compose up -d

08添加Jenkins执行脚本

测试结果

在添加完脚本后,我们来测试一下刚刚添加的脚本是否执行成功。

在 Gitlab 打开 Git 仓库,设置 —>Webhooks—> 测试 —>Push events

10提交测试

测试结果出错

出错了,打开控制台看看我的错误是什么。

auto--->构建记录--->控制台输出--->查看错误

11打开控制台查看错误

12运行出错

解决错误

大概意思说删除的容器指令出错,返回错误。

bash
1
2
docker ps -a | grep web-server-auto | awk '{print $1}' | xargs docker rm -f
docker ps -a | grep nginx-auto | awk '{print $1}' | xargs docker rm -f

我们在 Jenkins 任务中添加了 shell 指令,以上是部分的指令。

我们一开始是不存在 web-server-auto、nginx-auto 容器的,直接查找该容器并删除,但是容器不存在的,系统就说指令不正确了,那我们就把指令稍微改一改,在指令后面添加一下确定的容器名字应该就没问题了。

bash
1
2
docker ps -a | grep web-server-auto | awk '{print $1}' | xargs docker rm -f web-server-auto
docker ps -a | grep nginx-auto | awk '{print $1}' | xargs docker rm -f nginx-auto

等第一次启动完,再把指令改为原来的指令就不会出错了。

13解决错误

重新构建

10提交测试

构建成功

重新构建后应该是成功了。

成功后在浏览器打开 http://192.168.2.12:801/hi,其中的 IP 地址改为你的 IP 地址,这时,浏览器显示出来了,但是我们还没完全成功,这只是初步显示出来了,还不够完善

14运行成功

完善 Jenkins 任务

完善 shell 脚本

原来的脚本中,只是可以新建容器和镜像,可能会出现一些奇怪的问题,我们应该在每次构建时删除旧的容器和镜像,重新构建新的镜像和容器,减少环境对构建的影响。

将以下脚本内容复制到 Jenkins 任务中

auto--->Post Steps--->Excute shell

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh
WORKSPACE_DIR='/root/.jenkins/workspace/auto/'
DEVOPS_DIR='/home/auto/'

echo "删除之前的容器"
docker ps -a | grep web-server-auto | awk '{print $1}' | xargs docker rm -f
docker ps -a | grep nginx-auto | awk '{print $1}' | xargs docker rm -f

echo "删除上一个版本的jar包"
sudo rm -rf ${DEVOPS_DIR}/auto-0.0.1-SNAPSHOT.war
echo "复制打包最新版的jar包"
cp ${WORKSPACE_DIR}/target/auto-0.0.1-SNAPSHOT.war ${DEVOPS_DIR}
echo "赋予jar包权限"
chmod 777 -R /home/auto
echo "删除镜像"
docker rmi -f auto_web-server-auto
echo "启动容器"
cd /home/auto/
docker-compose up -d

15完善shell脚本

推送代码构建

在本地 idea 开发,推送代码到 Gitlab,Jenkins 检测到 Gitlab 仓库的更新,实时构建,构建完即可在浏览器打开预览内容。http://IP:801/hi

16实时更新内容

此次学会了自动构建 maven 项目的构建,其实还是很方便的,以后开发的还是直接 push,然后打开浏览器一看,减少自己操作的时间。

其他

重启、关闭、重载 jenkins

重启 jenkins

在 jenkins 服务后台的 URL 后面加上 restart,回车即可重启 jenkins 服务

http
1
http://localhost:8080/jenkins/restart

关闭 jenkins

在 jenkins 后面加上 exit

bash
1
http://localhost:8080/jenkins/exit

重载 jenkins

在 jenkins 服务后台的 URL 后面加上 reload

bash
1
http://localhost:8080/jenkins/reload

可能遇到的错误

maven 拒绝 http 请求

bash
1
2
3
ERROR: Failed to parse POMs
org.apache.maven.project.ProjectBuildingException: Some problems were encountered while processing the POMs:
[FATAL] Non-resolvable parent POM for com.example:devops:0.0.1-SNAPSHOT: org.springframework.boot:spring-boot-starter-parent:pom:2.7.4 failed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of maven-default-http-blocker has elapsed or updates are forced. Original error: Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:2.7.4 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [alimaven (http://maven.aliyun.com/nexus/content/groups/public/, default, releases)] and 'parent.relativePath' points at no local POM @ line 5, column 13

解决办法

不提示 http 请求不安全,换一个镜像站即可解决问题

02修改settings

返回 400-Rad Request

返回400

解决方法

nginx 是不支持下划线的_,但是我在容器中使用了下划线,同时 nginx 也使用到了这个容器,就报错了,将所有的下划线都改为 - 即可。

报错内容

02无法打开共享对象

解决办法

如图,这真的是个大坑,搞了好久,去除这个转发X11 就解决了

01不要打勾