Gitlab+Jenkins+Docker自动部署SpringBoot微服务

在公司用了半年的 SpringCloud + Docker + Jenkins 的技术框架,现在流行持续集成,还没有抽点时间自己实际走一下全流程开发环境的搭建,正好赶上端午节,可以宅在出租屋里好好研究一下,特此记录一下实践过程中遇到的问题及解决方案。

搭建测试项目

请求接口

接口地址:/api/user-management/users

@GetMapping("/users")
public Response<List<UserPo>> listUsers(@RequestParam int count) {
    Response<List<UserPo>> response = new Response<>();
    response.setCode(0);
    response.setMessage("请求成功");
    response.setData(userService.listUsers(count));
    return response;
}

返回数据格式:

{
  "code": 0,
  "message": "请求成功",
  "data": [
    {
      "no": "U00-0",
      "name": "U-name0",
      "level": "高级用户",
      "point": 245
    },
    {
      "no": "U00-1",
      "name": "U-name1",
      "level": "初级用户",
      "point": 238
    },
    {
      "no": "U00-2",
      "name": "U-name2",
      "level": "初级用户",
      "point": 240
    }
  ]
}

Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY springboot-demo.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
EXPOSE 8080

Jenkinsfile

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building..'
                sh 'mvn clean && mvn package'
                sh 'cp target/springboot-demo.jar src/main/docker/springboot-demo.jar'
                echo 'Build completed.'
            }
        }
        stage("Image") {
            steps {
                echo 'Imaging..'
                sh 'cd src/main/docker && docker build --rm -t springboot-demo:v1 .'
                echo 'Image completed.'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying....'
                sh 'docker run -d -p 8082:8001 --name springboot-demo springboot-demo:v1'
                echo 'Deploy completed.'
            }
        }
    }
}

Docker安装以及Dockerhub账户注册

注册Dockerhub账号,然后安装docker。

# 安装docker
curl -sSL https://get.daocloud.io/docker | sh

# 将用户加入docker组中
sudo gpasswd -a chenxii docker
# 更新docker组
sudo grpnew docker

# 登录docker,用docker id登录而不是邮箱
# 不要直接 -p 登录,不安全
cat passwd.txt | docker login -u chenxii81 --password-stdin

Gitlab安装

本来想用VPS的,但是从docker启动gitlab之后总是几分钟就会Exit,应该是配置太低了,才512M内存,1核处理器。只能放到虚拟机弄了。

为了配置方便,用 Docker 安装 Gitlab:

docker pull gitlab/gitlab-ce:latest

docker run -d  -p 443:443 -p 80:80 -p 222:22 --name gitlab gitlab/gitlab-ce:latest
# e176b0d7d3d8775a293701d85029421eebf0ae6d013e79edb791c47df0e8c857

docker ps -a
# 状态为 healthy之后就可以用宿主机ip进行访问了,Up 3 minutes (healthy)

# 修改gitlab地址
# 打开文件 /etc/gitlab/gitlab.rb 文件并找到 
# external_url 'GENERATED_EXTERNAL_URL' 这行,去掉注释,并按照下面的格式修改。
# 使用hosts里配置的域名,git提交会被redirect,最好用ip
external_url 'http://gitlab.chenxii.com' 或者 external_url 'http://192.168.8.188'
# 然后执行下面的命令使配置生效
sudo docker exec gitlab gitlab-ctl reconfigure

# 修改完之后仓库的地址:
[email protected]:gitlab-instance-8190bce8/Monitoring.git
http://gitlab.chenxii.com/gitlab-instance-8190bce8/Monitoring.git


# 将代码传到gitlab
git remote add origin http://192.168.8.188/root/springboot-demo.git
git add .
git commit -m "init repo"
git push -u origin --all
git push -u origin --tags

初次登录需要重设密码,之后可以用root + 新密码登录。

截图

Jenkins安装

使用Docker配置Jenkins

docker pull jenkins/jenkins:lts

# Jenkins Docker镜像中没有Maven,所以将宿主机的Maven挂载到Docker容器
docker run -d -p 8081:8080 --name jenkins \
-v /opt/jdk/jdk1.8.0_181:/usr/lib/jvm/java-1.8-openjdk \
-v /opt/maven/maven-3.5.4:/usr/local/maven3 jenkins/jenkins:lts

# 使用docker logs查看Jenkins初始化密码
docker logs container_id

安装推荐插件之后,创建用户进入Jenkins

截图

安装Jenkins插件

maven

下载地址: apache-maven-3.8.1-bin.tar.gz

配置:

# 因为maven-3.8.1报错,换成了3.5.4版本
sudo mv ~/Downloads/apache-maven-3.5.4-bin.tar.gz /opt/maven  
sudo tar -zxvf apache-maven-3.5.4-bin.tar.gz
cd apache-maven-3.5.4
sudo mv apache-maven-3.5.4/opt /maven-3.5.4

vim ~/.bashrc
export MAVEN_HOME=/opt/maven/maven-3.5.4
export PATH=$PATH:$MAVEN_HOME/bin

配置Gitlab Key

SSH Key

在 Gitlab 中 SSH Key 页面(http://192.168.8.188/-/profile/keys),将自己本地 ~/.ssh/id_rsa.pub 内容存进去,这样传代码不需要每次都输入密码。

Access Tokens

1、给Jenkins安装Publish Over SSH插件

2、Jenkins需要从Gitlab拉取代码,所以需要为Jenkins配置一个Access Tokens,类似:5nU3oGSxyZXsxHyuwekH,生成之后将其配置到 系统配置 > Publish over SSH > Key 保存。

Jenkins报错

mvn命令找不到

Jenkins报错 mvn 命令找不到,因为 Docker Jenkins里没有Maven。

+ mvn clean

/var/jenkins_home/workspace/springboot-demo_master@tmp/durable-c0a723ef/script.sh: 1: /var/jenkins_home/workspace/springboot-demo_master@tmp/durable-c0a723ef/script.sh: mvn: not found

script returned exit code 127

配置如下:

在这里卡了很长时间,最后找到一个解决方案:Jenkins打包Maven项目找不到mvn解决办法script.sh: line 1: mvn: not found

启动命令中将宿主机上的maven路径挂在到Docker容器的 /usr/local/maven3目录下,然后在 系统配置 > 全局属性 下,将MAVEN_HOME追加到环境变量中,然后扫描流水线就可以下载依赖了。

# docker run中挂载宿主机maven到docker容器中
-v /opt/maven/maven-3.5.4:/usr/local/maven3 jenkins/jenkins:lts

还有一种挂载方式不需要重新运行镜像,直接给容器挂载新的目录:

修改 /var/run/docker/containerid/容器id/hostconfig.json 和 /var/run/docker/containerid/容器id/config.v2.json

参见:docker给已经启动容器添加挂载目录

MAVEN_HOME /usr/local/maven3
PATH+EXTRA $MAVEN_HOME/bin

docker命令找不到

解决方案:

给启动的Docker容器挂载宿主机的 docker 环境

参见:docker给已经启动容器添加挂载目录

/var/run/docker.sock: connect: permission denied

运行到 docker 构建镜像的时候提示权限不足,/var/run/docker.sock 只有 root 权限才能调用,可以将 jenkins 用户加到 docker 组下:

sudo gpasswd -a jenkins docker
newgrp docker

但是这里docker是挂载了宿主机的docker目录,所以不存在docker组,直接将 /var/run/docker.sock 改成 777 权限:

docker exec -u 0 -it 容器id /bin/bash
chmod -R 777 /var/run/docker.sock
exit

再次构建:

截图

截图

截图

截图

20次的流水线扫描,上百次 Bing 搜索,终于成功看到了赏心悦目的绿色和接口返回值 🎉

总结

其实上个月已经做个一个 Jenkins Pipeline 的实践项目,但是上次 Jenkins 和 Gitlab 都是虚拟机安装,没有使用 Docker,所以这次两天的实践基本上是填 Docker 中遇到的坑,端午节假期今天结束了,很庆幸虽然这两天断断续续但还是赶在最后的时间点部署成功了。对 Docker 、 Jenkins 和 Gitlab 这一套技术有了更深的理解。