gitlab-runner根据maven打包结果构建docker镜像

长孙鸿波
2023-12-01

转载于 http://blog.c7d8.com/blog/18.html ,原文可能有更新,以原文为准

背景

现有的应用编译、maven打包、docker镜像构建都是在一个job或者同一个gitlab-runner中完成的,且使用了 maven 的 插件 “docker-maven-plugin” ,虽然一个命令 mvn package 就可以在CI环境构建为镜像,但毕竟maven本身的打包过程被强行与docker镜像的打包过程耦合在了一起,也会导致不了解的同学在自己的开发机器上执行mvn package的时候出现缺少docker的错误,本篇文章就是为了避免以上问题

要实现上一个job的构建物(即我们的mvn package执行产生的jar/war包)传递到下一个,我们需要了解 artifacts ,artifacts.path你可以填写你需要传递的路径,可以正则匹配,符合的文件/文件夹会被上传到gitlab。我们看看构建日志

//这里我们提前创建好了放构建物的路径 并将所有构建物 依赖包 dockerfile都整理到一起
$ mkdir -p sartifacts/test-order-service && mkdir -p sartifacts/test-product-service && mkdir -p sartifacts/test-user-service $$ mkdir -p sartifacts/test-webapp-app
$ cp -r test-order-service/target/test-order-service-*.jar test-order-service/target/lib test-order-service/Dockerfile sartifacts/test-order-service
$ cp -r test-product-service/target/test-product-service-*.jar test-product-service/target/lib test-product-service/Dockerfile sartifacts/test-product-service
$ cp -r test-user-service/target/test-user-service-*.jar test-user-service/target/lib test-user-service/Dockerfile sartifacts/test-user-service
$ cp  test-webapp-app/target/app.war test-webapp-app/Dockerfile sartifacts/test-webapp-app
Uploading artifacts...
sartifacts/*: found 326 matching files             
Uploading artifacts to coordinator... ok            id=1862 responseStatus=201 Created token=ydasdaeyvZ

下一个job执行的时候会自动下载回来。所以我们的.gitlab-ci.yml前半部分是这样

makejava:
    image: maven:3-jdk-8
    stage: package
    tags:
      - docker
    script:
  #    - mvn clean
      - mvn clean package -Dmaven.test.skip=true
      # 在根目录创建一个文件夹来放所有的构建物
      - mkdir -p sartifacts/test-order-service && mkdir -p sartifacts/test-product-service && mkdir -p sartifacts/test-user-service $$ mkdir -p sartifacts/test-webapp-app
      - cp -r test-order-service/target/test-order-service-*.jar test-order-service/target/lib test-order-service/Dockerfile sartifacts/test-order-service
      - cp -r test-product-service/target/test-product-service-*.jar test-product-service/target/lib test-product-service/Dockerfile sartifacts/test-product-service
      - cp -r test-user-service/target/test-user-service-*.jar test-user-service/target/lib test-user-service/Dockerfile sartifacts/test-user-service
      - cp  test-webapp-app/target/app.war test-webapp-app/Dockerfile sartifacts/test-webapp-app
      - du -h --max-depth=1 sartifacts
    artifacts:
      name:  "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}"
      paths:
        - sartifacts/*
      expire_in: 1 day

为了不给gitlab的存储增加压力,我们将构建物的有效期设置为1天

在下一个job我们可以看到上一个job缓存的构建物已经下载好了 我们就可以直接执行docker build命令了

发现构建物已经上传gitlab成功后,我们就可以忙活在docker中构建一个镜像了,这会涉及到“docker in docker”,因为我们需要在docker容器中执行docker build构建命令,所以我们另外搭建了一个runner专门干构建镜像的事情。这里我们参考了 这篇文章,其提供了三种方式来实现在容器中执行docker命令,我们选择了其中第三种

Use Docker socket binding

第三种方法是将/var/run/docker.sock绑定装载到容器中,以便 docker 在该镜像的上下文中可用。

为了做到这点,遵循以下步骤:

gitlab-runner register -n   --url http://gitlab.example.com/   --registration-token REGISTRATION_TOKEN   --executor docker   --description "My Docker Runner"   --docker-image "docker:latest"   --docker-volumes /var/run/docker.sock:/var/run/docker.sock

上面的命令将注册一个新的 Runner 来使用 Docker 提供的特殊docker:latest镜像。请注意,它正在使用 Runner 本身的 Docker 守护进程,docker 命令产生的任何容器都将是 Runner 的兄弟,而不是所运行程序的子进程。这可能会有不适合您的工作流程的复杂性和局限性。

  • 您现在可以在构建脚本中使用docker(请注意,在 Docker 执行器中使用 Docker 时,不需要包含docker:dind服务):

现在我们需要完善.gitlab-ci.yml

image: docker:latest
stages:
    - package
    - build
variables:
    test_order_service: 172.16.1.111:5000/cdyb/test-order-service:latest
    test_product_service: 172.16.1.111:5000/cdyb/test-product-service:latest
    test_user_service: 172.16.1.111:5000/cdyb/test-user-service:latest
    test_webapp_app: 172.16.1.111:5000/cdyb/test-webapp-app:latest
    test_webapp_center: 172.16.1.111:5000/cdyb/test-webapp-center:latest
    test_ttsaqc_service: 172.16.1.111:5000/cdyb/test-ttsaqc-service:latest

makejava:
    image: maven:3-jdk-8
    stage: package
    tags:
      - docker
    script:
  #    - mvn clean
      - mvn clean package -Dmaven.test.skip=true
      # 在根目录创建一个文件夹来放所有的构建物
      - mkdir -p sartifacts/test-order-service && mkdir -p sartifacts/test-product-service && mkdir -p sartifacts/test-user-service $$ mkdir -p sartifacts/test-webapp-app
      - cp -r test-order-service/target/test-order-service-*.jar test-order-service/target/lib test-order-service/Dockerfile sartifacts/test-order-service
      - cp -r test-product-service/target/test-product-service-*.jar test-product-service/target/lib test-product-service/Dockerfile sartifacts/test-product-service
      - cp -r test-user-service/target/test-user-service-*.jar test-user-service/target/lib test-user-service/Dockerfile sartifacts/test-user-service
      - cp  test-webapp-app/target/app.war test-webapp-app/Dockerfile sartifacts/test-webapp-app
      - du -h --max-depth=1 sartifacts
    artifacts:
      name:  "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}"
      paths:
        - sartifacts/*
      expire_in: 1 day
docker-build:
    stage: build
    tags:
      - imagebuild
    script:
      - docker build -t $test_order_service ./sartifacts/test-order-service/
      - docker build -t $test_product_service ./sartifacts/test-product-service/
      - docker build -t $test_user_service ./sartifacts/test-user-service/
      - docker build -t $test_webapp_app ./sartifacts/test-webapp-app/

需要注意的是

  • 我们在头部加上了image: docker:latest
  • runner所在的环境预装了最新版本的docker
  • 请注意上下文关系,即docker build指定的路径会上传的docker damen环境,然后再该环境下,dockerfile的路径都是基于此处指定的路径,可以参考 这篇文章

总结

使用maven插件的方式却是比较方便,特别是对于需要构建一个多模块的maven项目的时候,但我们的这种做法比较清晰明朗。

 类似资料: