使用gitlab CI 对Springboot项目进行容器化持续发布

创建一个Springboot项目

可以使用如下多种方式创建项目:

  • 使用idea的Springboot插件
  • Maven
  • Springboot CLI

我们只需要创建一个空项目,不需要写太多的代码。为了验证,我们给项目提供actuator的功能。

management.endpoint.beans.enabled=true
management.endpoint.info.enabled=true
management.endpoint.health.enabled=true
management.endpoints.web.exposure.include=health,info

1
2
3
4
5

项目创建完成后,启动项目测试一下:

# curl http://localhost:8080/actuator/health

{"status":"UP"}%

1
2
3
4

给项目提供gitlab CI功能

项目容器编译脚本

FROM openjdk:8u111-jdk-alpine
VOLUME /tmp
ADD /target/springbootci-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
1
2
3
4

springbootci-0.0.1-SNAPSHOT.jar是项目pom文件声明的产物名称


    <groupId>com.freshal.example</groupId>
    <artifactId>springbootci</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springbootci</name>
    <description>Demo project for Spring Boot</description>

1
2
3
4
5
6
7

创建CI pipeline 脚本

image: docker:latest
services:
  - docker:dind

variables:
  DOCKER_DRIVER: overlay
  SPRING_PROFILES_ACTIVE: gitlab-ci

stages:
  - build
  - package

maven-build:
  image: maven:3-jdk-8A
  stage: build
  script: "mvn package -B"
  artifacts:
    paths:
      - target/*.jar

docker-build:
  stage: package
  script:
    - docker build -t freshal/springbootci .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

image 和service

GitLab Runner可以使用容器镜像来支持流水线。image元素定义了我们要使用哪个镜像。 有效的镜像仅限于本地容器引擎和Docker Hub存储的。 service元素定义了额外的要使用的链接到主容器的镜像。在我们的例子中,主要容器是一个普通容器镜像,而链接容器是一个容器中的容器(Docker in Docker)

  • 关于dind的说明:https://docs.gitlab.com/ee/ci/docker/using_docker_build.html

Variables

变量可以定义编译环境使用的参数。 具体参考:https://docs.gitlab.com/ee/ci/yaml/#variables

GITALB已经预定义了一些变量,见:http://git.manystar.com/help/ci/variables/predefined_variables.md

Stages

stages元素定义了流水线的生命周期。我们给每一个stage都关联一个job。一个stage中的所有job并行运行,并按照我们定义的顺序依次触发各个stage,即,只有在上一个stage完成后才启动下一个stage。

maven build job

这个job是执行maven构建,所以使用了maven:3-jdk-8作为执行构建的容器镜像。

script是一个gitlab runner要执行的shell 命令。The mvn package -B启动一个非交互式的maven构建过程。mvn package包括validate,compile,和test。

在不同的job之前持久化可执行的jar,我们声明job的产物。这些产物是每次成功构建后的输出文件,可以在gitlab流水线的界面上下载。 ci-artifacts.jpg

  • maven 详细例子:https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
  • gradle 详细例子:https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml

容器创建

关于容器创建的详细例子参考:https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Docker.gitlab-ci.yml

缓存maven库

如果每次都新建容器,下载依赖,非常影响效率,为了解决这个问题,可以使用cache。


image: docker:latest
services:
  - docker:dind

variables:
  DOCKER_DRIVER: overlay
  SPRING_PROFILES_ACTIVE: gitlab-ci
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

cache:
  paths:
    - .m2/repository

stages:
  - build
  - package

maven-build:
  image: maven:3-jdk-8A
  stage: build
  script: "mvn package -B"
  artifacts:
    paths:
      - target/*.jar

docker-build:
  stage: package
  script:
    - docker build -t freshal/springbootci .
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
29
30

关于cache的详细例子: https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Maven.gitlab-ci.yml

其他总结

gitlab runner配置模式

gitlab runner有三种配置方式

  • shell执行
  • Docker in Docker
  • Docker socket bind 这三种模式没有一种更好,更多的需要权衡。dind模式会比较慢一些,因为每一个job都在一个干净的环境中,但是这允许并发且不会冲突。另外dind和socket bind模式不能混用。

config.toml里的concurrent字段的意义

concurrent限制了整个GitLab Runner能并发处理job的数量。特别注意concurrent与worker数量无任何关系,所有worker的工作是受GitLab Runner控制的,如果concurrent值为1并且有一个worker已经在工作了,那么即使其他worker达到了可以工作的条件也只能“pending”。

config.toml配置说明: https://docs.gitlab.com/runner/configuration/advanced-configuration.html

cache存储在哪里

https://docs.gitlab.com/ee/ci/caching/#where-the-caches-are-stored

这里讲了如何使用cache,以及cache的最佳实践:

  • Tag your Runners and use the tag on jobs that share their cache.
  • Use sticky Runners that will be only available to a particular project.
  • Use a key that fits your workflow (for example, different caches on each branch). For that, you can take advantage of the CI/CD predefined variables.

怎样清除cache

注意cache是没有过期时间的,而且每一次新的push触发的pipeline,都会重新生成cache,重新生成的cache的名字为<cache-key>-<num>,其中num是随着push数量递增的。如果不去清除cache,cache会永久保留在Runner上,日积月累会填满存储空间的,因此最好隔一段时间进行一次清除,清除方法请参考https://docs.gitlab.com/ee/ci/caching/#clearing-the-cache,或者使用clear_volumes.sh 这个简单脚本来处理它, 清除cache的原理是将相关的volume移除,当然,docker也有自带的清除命令,推荐将docker system prune -f --volumes加入到定时任务中。

mac上的docker volume在哪

~/Library/Containers/com.docker.docker/Data/vms/0/

使用screen 命令可以连接tty进入

Gitlab CI详解

  • 基本概念:https://docs.gitlab.com/ee/ci/introduction/
  • CI配置详解:https://docs.gitlab.com/ee/ci/yaml/
  • Gitlab容器注册:https://docs.gitlab.com/ee/user/packages/container_registry/index.html#enable-the-container-registry-for-your-project
  • 与Docker容器集成:https://docs.gitlab.com/ee/ci/docker/using_docker_build.html
  • pipeline详解:https://docs.gitlab.com/ee/ci/pipelines/index.html
  • gitlab runner配置详细说明:https://docs.gitlab.com/runner/configuration/

maven的settings.xml

修改config.toml,加入volumes

volumes = ["/Users/marszhang/.m2/settings.xml:/mvn/.m2/settings.xml","/var/run/docker.sock:/var/run/docker.sock","/cache"]
1

修改.gitlab-ci.yml,加入before_script段

maven-build:
  image: maven:3-jdk-8
  stage: build
  before_script:
    - cp -f /mvn/.m2/settings.xml  $HOME/.m2/settings.xml
  script:
    - "mvn package -B"
  after_script:
    - rm -f $HOME/.m2/settings.xml
1
2
3
4
5
6
7
8
9