找回密码
 立即注册
首页 业界区 安全 服务云部署

服务云部署

谷江雪 前天 10:20
一、Dockerfile 手动部署方式:

相关参考
 
二、Dockerfile+Docker Compose 容器编排手动部署方式:

相关参考
 
三、Dockerfile+GitLab CI/CD 自动化部署方式:

1、GitLab CI/CD简介:

GitLab CI/CD 是 GitLab 内置的一套持续集成(CI)、持续部署(CD) 工具链,核心是通过 .gitlab-ci.yml 定义流程,由 GitLab Runner 执行任务,实现从代码提交到部署上线的全流程自动化。
(1)、持续集成(CI,Continuous Integration):

  • 开发者频繁将代码提交到仓库后,系统自动执行构建、编译、单元测试等操作,快速发现代码中的错误(如语法问题、测试失败),确保团队协作时代码始终可集成。
(2)、持续部署(CD,Continuous Deployment):

  • 在 CI 环节通过后,自动将代码部署到测试环境、预生产环境甚至生产环境,实现 “代码提交后自动上线”。
2、Docker-GitLab Runner安装:
  1. # 拉取镜像:docker pull gitlab/gitlab-runner:latest# 创建持久化目录:mkdir -p /data/gitlab-runner/config# 启动容器:docker run -d \  --name gitlab-runner \  -v /data/gitlab-runner/config:/etc/gitlab-runner \  -v /var/run/docker.sock:/var/run/docker.sock \  gitlab/gitlab-runner:latest
复制代码
3、GitLab Runner注册配置:

方式一、GitLab Runner 15.6版本前:

  • (1)、获取registration-token:



  • (2)、注册Runner:
  1. sudo docker exec -it gitlab-runner gitlab-runner register \  --non-interactive \  --url "http://127.0.0.1:8929/" \  --registration-token "xxxxxx-xxxx" \  --tag-list "my-demo-runner" \  --run-untagged="true" \  --locked="false" \  --access-level="not_protected" \  --executor "docker" \  --docker-image "docker:latest" \  --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
复制代码
参数格式

核心作用

取值说明 / 可选值

--non-interactive
非交互式注册
无取值(开关参数),执行命令时无需手动输入任何内容,所有配置由命令行参数指定
--url "http://127.0.0.1:8929/"
指定 GitLab 实例的地址
取值:GitLab 服务器的访问 URL(HTTP/HTTPS 均可)
--registration-token "xxxxxx-xxxx"
用于 Runner 与 GitLab 服务器认证的令牌
取值:从 GitLab 项目 / 组 / 实例的 “设置→CI/CD→Runner” 中获取的注册令牌
注意:新版 GitLab 也可用--token替代该参数,效果一致
--tag-list "xxxx"
给 Runner 打标签,用于 CI Job 指定 Runner 执行
取值:多个标签用逗号分隔(如"my-demo-runner"),无标签可留空;
作用:只有 CI Job 指定对应标签时,该 Runner 才会承接任务
--run-untagged="true"
控制 Runner 是否承接 “未打标签” 的 CI Job
可选值:
• true(承接)
• false(仅承接带匹配标签的 Job)
默认:false
--locked="false"
控制 Runner 是否被锁定(仅归属指定项目)
可选值:
• true(锁定,仅绑定的项目可用)
• false(不锁定,可被其他项目使用)
默认:true
--access-level="not_protected"
定义 Runner 可执行的 Job 的保护级别
可选值:
• not_protected(可执行非保护分支 / 标签的 Job)
• ref_protected(仅执行保护分支 / 标签的 Job)
默认:not_protected
--executor "docker"
指定 Runner 的执行器类型
可选值:docker、shell、kubernetes、virtualbox等核心;
选docker表示用 Docker 容器运行 CI Job
--docker-image "docker:latest"
指定 Docker Executor 默认使用的基础镜像(内置完整的 Docker CLI)
取值:任意有效的 Docker 镜像名(如alpine:latest、ubuntu:22.04、docker:27.0-alpine);
作用:CI Job 未指定image时,默认使用该镜像
--docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
给Docker Executor的Job容器挂载卷
取值:宿主机路径,容器内路径(格式与docker run -v一致)多个卷用逗号分隔(如"/var/run/docker.sock:/var/run/docker.sock","/cache:/cache")
核心:挂载docker.sock让 Job 容器能执行 Docker 命令
方式二、GitLab Runner 15.6版本及之后:

  • (1)、创建Runner,获取身份令牌token:




  • (2)、令牌相关信息:
  1. # 查看你相关令牌信息cat /data/gitlab-runner/config/config.toml# 移除相关令牌信息,移除后需重启rm -f /data/gitlab-runner/config/config.toml
复制代码

  • (3)、注册Runner:
  1. sudo docker exec -it gitlab-runner gitlab-runner register \  --non-interactive \  --url "http://127.0.0.1:8929/" \  --token "glrt-xxx.xx.xx" \  --executor "docker" \  --docker-image "docker:latest" \  --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
复制代码

注:
Token 类型

核心定义

适用场景

归属范围

跨项目复用性

项目级 Token
仅绑定单个特定项目的注册凭证,用于注册「项目专属 Runner」
单个项目独立使用(如生产环境项目、专属测试项目)
仅当前注册的目标项目
不可复用
群组级 Token
绑定整个 GitLab 群组的注册凭证,用于注册「群组共享 Runner」
群组下所有项目共用(如开发 / 测试团队共享执行器)
该群组及子群组下所有项目
可复用
实例级 Token
绑定整个 GitLab 服务器(实例)的注册凭证,用于注册「全实例共享 Runner」
GitLab 实例内所有项目共用(如企业级通用执行器)
GitLab 实例内所有项目(所有群组)
可复用
4、Gitlab CI-CD自动化部署SpringBoot项目:



(1)、父子项目工程配置:


  • 1)、父POM配置:
  1.     4.0.0    com.iven    my_demo    0.0.1-SNAPSHOT    pom                new-project1        new-project2                                                            org.springframework.boot                spring-boot-dependencies                2.7.15                pom                import                                                            org.springframework.boot            spring-boot-starter-web                                                                                                    org.springframework.boot                    spring-boot-maven-plugin                    2.7.15                                                                                                                                        repackage                                                                                                                                            org.apache.maven.plugins                    maven-compiler-plugin                    3.8.1                                                                    8                                                8                                                UTF-8                                                            
复制代码

  • 2)、new-project1子模块1配置(new-project2子模块2 同理):
POM配置:
  1.             com.iven        my_demo        0.0.1-SNAPSHOT        ../pom.xml        4.0.0    new-project1    new-project1    new-project1                                        org.springframework.boot                spring-boot-maven-plugin                        
复制代码
YML配置:
  1. server:  port: 8080spring:  application:    name: new-project1
复制代码
(2)、Dockerfile镜像构建配置:
  1. # ======================== 基础镜像选择 ========================# 核心原则:选择轻量、安全、与项目运行环境匹配的基础镜像# openjdk:8-jdk-alpine 对比说明:# - alpine版本:基于Alpine Linux(轻量级发行版,镜像体积约100MB左右)# - jdk-alpine:包含JDK编译环境(如需在容器内编译可保留,纯运行可换jre-alpine)# - 避免使用openjdk:8(debian完整版,体积超600MB),生产环境优先slim/alpine版本FROM openjdk:8-jdk-alpine# ======================== 可选配置 ========================# 维护者标签:标准化镜像归属,便于团队协作维护# 格式建议:姓名/团队 # LABEL maintainer="dev-team@your-company.com"# ======================== 工作目录配置 ========================# 1. 统一容器内工作目录,避免文件散落在根目录,提升可维护性# 2. Docker会自动创建/app目录(无需手动mkdir)# 3. 后续所有相对路径命令(COPY/ENTRYPOINT等)均基于此目录执行WORKDIR /app# ======================== 复制应用包 ========================# 1. COPY语法:COPY  # 2. target/*.jar:匹配宿主机子模块打包后的所有jar包(CI/CD构建时已进入子模块目录)# 3. app.jar:统一重命名为固定名称,避免因版本号不同导致启动命令变更# 注意:确保target目录下只有1个可执行jar包(避免覆盖或复制多个)COPY target/*.jar app.jar# ======================== 端口声明 ========================# 1. EXPOSE仅为"文档化声明",告知使用者容器内应用监听的端口,不实际映射端口# 2. 实际端口映射由docker run -p 或 docker-compose.yml的ports配置决定# 3. 声明多个端口(如8080主端口、8081监控端口),提升镜像可读性EXPOSE 8080 8081# ======================== 容器启动命令 ========================# 1. ENTRYPOINT使用exec格式(["命令", "参数1", "参数2"]),避免shell层封装导致信号传递问题# 2. JVM参数优化:#    -Xms512m:JVM初始堆内存(设置为与-Xmx相同,避免运行时动态扩容,提升性能)#    -Xmx1024m:JVM最大堆内存(根据服务器资源和应用需求调整)# 3. -jar app.jar:执行容器内/app目录下的app.jar包# 扩展:可添加更多JVM参数,如:# -XX:+UseG1GC(使用G1垃圾收集器)、-Dspring.profiles.active=prod(指定生产环境配置)ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]
复制代码
(3)、.gitlab-ci.yml-CI/CD流水线配置:


  • 1)、流水线实现效果:
在test分支时,所有子模块会被打包、构建测试环境镜像,并在Docker容器中自动部署,适合进行自动化测试。
在main分支时,只有通过手动Tag触发时才会进行生产镜像的构建,并可以选择推送到私有仓库中供后续docker-compose手动部署。


  • 2)、.gitlab-ci.yml配置:
  1. # ==============================================================================# GitLab CI/CD 配置文件 (.gitlab-ci.yml)# 配置核心说明:# 1. 适配场景:多模块Spring Boot项目(JDK8)的自动化构建、镜像打包、环境部署# 2. 分支策略:#    - test分支:代码提交自动触发「打包→构建测试镜像→部署测试容器」全流程#    - main分支:仅Tag提交触发「生产打包→构建带版本的生产镜像」(避免误触发生产流程)# 3. 扩展能力:支持私有Docker仓库推送、手动清理Runner残留资源# ==============================================================================# ==================== 【核心配置区】只需修改这里即可适配你的项目 ====================# 基础配置CONFIG_RUNNER_TAG: "my-demo-runner"       # GitLab Runner标签CONFIG_TEST_BRANCH: "test"                # 测试分支名称CONFIG_PROD_BRANCH: "main"                # 生产分支名称# 镜像版本CONFIG_MAVEN_IMAGE: "maven:3.6-openjdk-8" # Maven构建镜像CONFIG_DOCKER_IMAGE: "docker:24.0.2"      # Docker构建镜像# 项目模块CONFIG_SERVICES: "new-project1,new-project2" # 子模块列表(逗号分隔)# 测试端口CONFIG_SERVER_PORT_new_project1: "8080"CONFIG_SERVER_PORT_new_project2: "8081"# 生产镜像CONFIG_PROD_IMAGE_PREFIX: "my-prod"         # 生产镜像前缀# CONFIG_PRIVATE_REGISTRY: "127.0.0.1:5000" # 私有仓库地址(启用需取消注释)# CONFIG_REGISTRY_USER: "registry-user"     # 私有仓库用户名# CONFIG_REGISTRY_PWD: "registry-password"  # 私有仓库密码# 产物有效期CONFIG_TEST_ARTIFACTS_EXPIRE: "1 hour"    # 测试产物过期时间CONFIG_PROD_ARTIFACTS_EXPIRE: "1 week"    # 生产产物过期时间# ==================== 全局变量配置(基于核心配置区自动映射,无需修改) ====================variables:  # 1. Maven构建镜像:  #    - 选择maven:3.6-openjdk-8,与项目JDK8版本严格匹配,保证编译兼容性  #    - 避免使用高版本Maven/JDK,防止编译产物不兼容  MAVEN_IMAGE: "${CONFIG_MAVEN_IMAGE}"  # 2. Docker构建镜像:  #    - 选用docker:24.0.2稳定版,避免最新版API变更导致构建失败  #    - 所有Docker相关作业统一使用该版本,保证环境一致性  DOCKER_IMAGE: "${CONFIG_DOCKER_IMAGE}"  # 3. 子模块列表:  #    - 与项目根目录下的子模块目录名完全一致(逗号分隔,无空格)  #    - 后续循环处理所有子模块,无需为每个模块单独写作业  SERVICES: "${CONFIG_SERVICES}"  # 4. 测试环境端口配置:  #    - 命名规则:SERVER_PORT_  #    - 端口值需与子模块application.yml中server.port一致,避免端口映射错误  SERVER_PORT_new_project1: "${CONFIG_SERVER_PORT_new_project1}"  SERVER_PORT_new_project2: "${CONFIG_SERVER_PORT_new_project2}"  # 5. 生产镜像命名前缀:  #    - 统一命名规范:前缀/子模块名:版本号,便于镜像仓库管理和版本追溯  #    - 示例:my-prod/new-project1:v1.0.0  PROD_IMAGE_PREFIX: "${CONFIG_PROD_IMAGE_PREFIX}"  # 6. 私有Docker仓库配置(按需启用):  #    - 替换为实际的仓库地址、用户名、密码  #    - 生产镜像构建完成后可自动推送到私有仓库  #PRIVATE_REGISTRY: "${CONFIG_PRIVATE_REGISTRY}"  #REGISTRY_USER: "${CONFIG_REGISTRY_USER}"  #REGISTRY_PWD: "${CONFIG_REGISTRY_PWD}"# ==================== 构建阶段定义(按顺序执行) ====================stages:  - test-build    # test分支专属:源码编译打包(生成Jar包)  - test-image    # test分支专属:基于Jar包构建测试镜像  - test-deploy   # test分支专属:启动测试容器(映射端口,对外提供服务)  - prod-build    # main分支专属:生产环境打包(仅Tag触发)  - prod-image    # main分支专属:构建带版本号的生产镜像(仅Tag触发)# ==================== test分支自动化流程(代码提交自动触发) ====================# 作业1:test分支 - 统一打包所有子模块test-build-all:  stage: test-build          # 绑定到test-build阶段  image: $MAVEN_IMAGE        # 使用全局变量定义的Maven镜像  script:    - echo "==== 开始执行test分支Maven打包 ===="    - java -version          # 校验JDK版本(必做,避免镜像版本不符)    - mvn -v                 # 校验Maven版本(必做,避免编译命令不兼容)    # Maven核心打包命令:    # - clean:清理之前构建的旧产物(target目录)    # - package:编译源码并打包为Jar包    # -DskipTests:跳过单元测试(加速构建,测试可单独做)    # -B:批处理模式(非交互,适配CI/CD环境)    - mvn clean package -DskipTests -B    - echo "==== Maven打包完成,验证产物 ===="    # 校验打包结果:查找所有target目录下的Jar包,确认打包成功    - find . -name "*.jar" -type f | grep "target"  artifacts:    paths:      - "*/target/*.jar"  # 保留所有子模块的Jar包(作为后续作业的依赖产物)    expire_in: ${CONFIG_TEST_ARTIFACTS_EXPIRE}     # 产物1小时后过期(节省GitLab存储资源,测试产物无需长期保留)  only:    - ${CONFIG_TEST_BRANCH}  # 触发规则:仅test分支代码提交时执行(新增/修改/合并代码)  tags:    - ${CONFIG_RUNNER_TAG}  # 绑定指定的GitLab Runner(确保使用正确的构建节点)# 作业2:test分支 - 为所有子模块构建测试镜像test-image-all:  stage: test-image          # 绑定到test-image阶段  image:    name: ${DOCKER_IMAGE}      # 使用指定版本的Docker镜像    entrypoint: [""]         # 禁用Docker镜像默认的entrypoint(避免与脚本冲突)  variables:    # 关键配置:让容器内的Docker命令调用宿主机的Docker守护进程    # 需提前配置Runner挂载/var/run/docker.sock    DOCKER_HOST: "unix:///var/run/docker.sock"  dependencies:    - test-build-all  # 依赖test-build-all作业的产物(Jar包),确保先打包再构建镜像  before_script:    - docker --version  # 校验Docker环境是否可用(提前发现环境问题)  script:    - |  # 多行脚本开始标记(兼容shell语法)      echo "==== 开始构建测试环境Docker镜像 ===="      # 循环处理所有子模块:将逗号分隔的SERVICES转为换行,逐个读取      echo "$SERVICES" | tr ',' '\n' | while read service; do        echo "==== 处理子模块:$service ===="        # 前置校验:子模块目录是否存在(避免构建不存在的模块)        if [ ! -d "$service" ]; then          echo "错误:子模块目录 $service 不存在,请检查SERVICES配置"          exit 1  # 退出并标记作业失败        fi        # 进入子模块目录(Dockerfile读取当前目录的target/*.jar)        cd "$service"        # 构建测试镜像:        # -t "$service:test":镜像标签(子模块名:test),便于识别测试镜像        # -f ../Dockerfile:指定项目根目录的Dockerfile(所有子模块共用)        # .:构建上下文为当前子模块目录(确保COPY能找到target/*.jar)        docker build -t "$service:test" -f ../Dockerfile .        # 退回项目根目录(准备处理下一个模块)        cd ..        echo "==== 子模块 $service 测试镜像构建完成 ===="      done  only:    - ${CONFIG_TEST_BRANCH}  # 仅test分支触发  tags:    - ${CONFIG_RUNNER_TAG}# 作业3:test分支 - 部署所有子模块的测试容器test-deploy-all:  stage: test-deploy         # 绑定到test-deploy阶段  image:    name: ${DOCKER_IMAGE}    entrypoint: [""]         # 禁用默认entrypoint  variables:    DOCKER_HOST: "unix:///var/run/docker.sock"  # 调用宿主机Docker  before_script:    - docker ps  # 校验Docker服务是否正常运行(提前发现服务异常)  script:    - |      echo "==== 开始部署测试环境容器 ===="      # 循环处理所有子模块      echo "$SERVICES" | tr ',' '\n' | while read service; do        echo "==== 部署子模块:$service ===="        # 动态获取端口:        # 1. 将子模块名中的连字符(-)替换为下划线(_),匹配全局变量名        #    示例:new-project1 → SERVER_PORT_new_project1        var_name="SERVER_PORT_$(echo "$service" | tr '-' '_')"        # 2. 读取变量值(兼容简单shell环境)        eval "port=\${$var_name}"        # 端口校验:确保子模块配置了对应的测试端口        if [ -z "$port" ]; then          echo "错误:子模块 $service 未配置测试端口(请检查SERVER_PORT_*变量)"          exit 1        fi        # 清理旧容器:避免端口占用、容器名冲突        if docker ps -a | grep -q "${service}-test"; then          docker stop "${service}-test" || true  # 停止容器(失败不终止)          docker rm "${service}-test" || true    # 删除容器(失败不终止)        fi        # 启动新容器:        # -d:后台运行(守护进程模式)        # -p "${port}:${port}":端口映射(宿主机端口:容器内端口)        # --name "${service}-test":容器名(子模块名-test),便于识别        # "$service:test":使用测试镜像启动        docker run -d -p "${port}:${port}" --name "${service}-test" "$service:test"        echo "==== 子模块 $service 部署完成,访问地址:http://Runner服务器IP:$port ===="      done  only:    - ${CONFIG_TEST_BRANCH}  # 仅test分支触发  tags:    - ${CONFIG_RUNNER_TAG}# ==================== main分支自动化流程(仅Tag提交触发) ====================# 作业1:main分支 - 生产环境打包(仅Tag触发)prod-build-all:  stage: prod-build          # 绑定到prod-build阶段  image: $MAVEN_IMAGE        # 使用全局Maven镜像  script:    - |      echo "==== 开始生产环境Maven打包 ===="      echo "触发Tag:$CI_COMMIT_TAG"  # 输出触发的Tag版本(便于日志追溯)      # 生产打包命令(与测试打包逻辑一致,保证产物一致性)      mvn clean package -DskipTests -B      echo "==== 生产环境打包完成 ===="      # 打印产物路径,确认文件存在(便于排查)      ls -l new-project1/target/      ls -l new-project2/target/  artifacts:    paths:      - "*/target/*.jar"                           # 保留生产Jar包(用于构建生产镜像)    expire_in: ${CONFIG_PROD_ARTIFACTS_EXPIRE}     # 生产产物保留1周(便于问题排查)  rules:    # 触发规则:仅当提交为Tag时执行(避免main分支普通提交触发生产流程)    - if: '$CI_COMMIT_TAG'      when: always  tags:    - ${CONFIG_RUNNER_TAG}# 作业2:main分支 - 构建生产镜像(仅Tag触发)prod-image-all:  stage: prod-image          # 绑定到prod-image阶段  image:    name: ${DOCKER_IMAGE}    entrypoint: [""]         # 禁用默认entrypoint  variables:    DOCKER_HOST: "unix:///var/run/docker.sock"  # 调用宿主机Docker  dependencies:    - prod-build-all  # 依赖生产打包阶段的Jar包产物  script:    - |      echo "==== 开始构建生产环境Docker镜像 ===="      # 前置校验:确保触发源是Tag(防止规则配置错误)      if [ -z "$CI_COMMIT_TAG" ]; then        echo "错误:生产镜像仅支持Tag触发"        exit 1      fi      # 循环处理所有子模块      echo "$SERVICES" | tr ',' '\n' | while read service; do        echo "==== 处理子模块:$service ===="        # 校验子模块目录是否存在        if [ ! -d "$service" ]; then          echo "错误:子模块目录 $service 不存在"          exit 1        fi        # 进入子模块目录        cd "$service"        # 生产镜像命名规则:前缀/子模块名:Tag版本(符合生产镜像规范)        image_name="${PROD_IMAGE_PREFIX}/${service}:${CI_COMMIT_TAG}"        # 构建生产镜像(使用根目录Dockerfile)        docker build -t "$image_name" -f ../Dockerfile .        # 退回根目录        cd ..        echo "==== 子模块 $service 生产镜像构建完成(标签:$image_name) ===="        # 可选:推送镜像到私有仓库(需配置仓库信息)        # if [ -n "$PRIVATE_REGISTRY" ] && [ -n "$REGISTRY_USER" ] && [ -n "$REGISTRY_PWD" ]; then        #   docker login -u "$REGISTRY_USER" -p "$REGISTRY_PWD" "$PRIVATE_REGISTRY"  # 登录仓库        #   docker tag "$image_name" "$PRIVATE_REGISTRY/$image_name"                 # 打仓库标签        #   docker push "$PRIVATE_REGISTRY/$image_name"                              # 推送镜像        #   docker logout "$PRIVATE_REGISTRY"                                        # 退出登录(安全)        #   echo "==== 子模块 $service 镜像推送完成 ===="        # else        #   echo "==== 跳过私有仓库推送(未配置完整信息) ===="        # fi      done  rules:    - if: '$CI_COMMIT_TAG'  # 仅Tag提交触发      when: always  tags:    - ${CONFIG_RUNNER_TAG}# ==================== 辅助作业:手动清理Docker残留资源 ====================cleanup:  stage: .pre  # GitLab内置前置阶段(所有自定义阶段前执行,不影响主流程)  image:    name: ${DOCKER_IMAGE}    entrypoint: [""]  variables:    DOCKER_HOST: "unix:///var/run/docker.sock"  script:    - |      echo "==== 开始清理Runner服务器Docker资源 ===="      # 清理所有已停止的容器(-f:强制确认,无需交互)      docker container prune -f      # 清理所有无用镜像(-a:所有未使用,-f:强制)      docker image prune -af      # 针对性清理测试容器(避免残留容器占用端口)      echo "$SERVICES" | tr ',' '\n' | while read service; do        container_name="${service}-test"        if docker ps -a | grep -q "$container_name"; then          echo "清理残留测试容器:$container_name"          docker stop "$container_name" || true          docker rm "$container_name" || true        fi      done      echo "==== 资源清理完成 ===="      # 输出Docker资源使用情况(确认清理效果)      docker system df  when: manual  # 触发规则:仅手动点击触发(避免自动清理导致数据丢失)  tags:    - ${CONFIG_RUNNER_TAG}
复制代码

  • 3)、.gitlab-ci.yml常用关键字说明:
关键字

作用说明

示例用法

variables
定义全局变量,所有阶段可复用,集中管理配置(如镜像名、端口、仓库地址)
MAVEN_IMAGE: "maven:3.6-openjdk-8"
stages
定义构建阶段,按顺序执行,相同阶段的任务并行执行
stages: - test-build - test-image - test-deploy
stage
绑定任务到指定阶段(必须在stages中定义)
stage: test-build
image
指定执行该任务的 Docker 镜像(如 Maven、Docker 镜像)
image: $DOCKER_IMAGE
script
任务的核心执行命令(如打包、构建镜像、部署命令)
mvn clean package -DskipTests
only
限定任务触发条件(如分支、Tag)
only: - test 或 only: refs: - tags
except
排除任务触发条件(与only相反)
except: - branches
tags
匹配 GitLab Runner 的标签(仅带有该标签的 Runner 会执行任务)
tags: - docker
dependencies
定义任务依赖(依赖的任务执行完成后,当前任务才会执行)
dependencies: - test-build-all
cache
缓存依赖(如 Maven 依赖),加速后续构建(当前简化未用,可选添加)
cache: paths: - /root/.m2/repository/
(4)、相关核心执行流程:


  • 1)、测试环境:自动化部署
开发完成后,将代码推送到test分支,GitLab 自动触发 CI/CD 流水线。




  • 2)、生产环境:手动部署
测试通过后,合并test分支代码到main分支,手动创建 Tag 标签并推送到远程仓库,触发生产镜像构建





  • 2.1)、相关服务器操作:
docker-compose.yml容器编排配置:
  1. # Docker Compose版本:3.8(兼容Docker 24.0.2,功能足够满足需求)version: '3.8'# 定义生产环境所有服务services:  # 微服务1:new-project1(与子模块名、镜像名一致)  new-project1:    # 镜像名:与CI/CD构建的生产镜像名完全一致(修改Tag即可升级/回滚)    # 示例:my-prod/new-project1:v1.0.0(Tag为手动推送的Git Tag)    image: my-prod/new-project1:v1.0.0    container_name: new-project1-prod  # 容器名:子模块名-prod(区分测试环境容器)    ports:      - "8080:8080"  # 端口映射(主机端口:容器端口,与application.yml一致)    restart: always  # 容器异常退出时自动重启(提高生产环境可用性)    volumes:      # 挂载日志目录:将容器内的/app/logs目录映射到服务器本地的logs/new-project1目录      # 进入docker-compose.yml 所在的目录下,创建持久化日志目录: mkdir -p logs/new-project1 logs/new-project2      # 作用:日志持久化,避免容器重启后日志丢失,方便排查问题      - ./logs/new-project1:/app/logs      # 可选:挂载外部配置文件(如需动态修改生产环境配置,无需重新构建镜像)      # - ./config/new-project1:/app/config    # environment:      # 可选:指定生产环境配置文件(如application-prod.yml)      # - SPRING_PROFILES_ACTIVE=prod  # 微服务2:new-project2  new-project2:    image: my-prod/new-project2:v1.0.0    container_name: new-project2-prod    ports:      - "8081:8081"    restart: always    volumes:      - ./logs/new-project2:/app/logs      # - ./config/new-project2:/app/config    # environment:      # - SPRING_PROFILES_ACTIVE=prod
复制代码

  • 2.2)、手动创建持久化日志目录:
  1. # 进入docker-compose.yml所在目录# 当前目录下,创建日志目录mkdir -p logs/new-project1 logs/new-project2
复制代码

  • 2.3)、部署与回滚操作:
  1. # 部署与回滚均修改docker-compose.yml中的镜像Tag对应版本(如v1.0.0)docker-compose up -d
复制代码
 
四、Dockerfile+Jenkins自动化部署方式:

1、Jenkins简介:

Jenkins是一款开源的自动化 CI/CD 服务器,核心作用是实现代码从提交到部署的全流程自动化,涵盖自动拉取代码、编译构建、测试验证、打包制品乃至部署上线等环节,它拥有丰富的插件生态,能无缝集成 Git、Maven、Docker 等主流开发运维工具,支持多语言项目和跨平台部署,架构上采用 Master-Agent 分布式模式,可灵活扩展任务执行能力,是 DevOps 体系中实现持续集成与持续交付的核心工具。
2、DevOps环境下JDK+Maven安装:


  • (1)、相关目录创建:
  1. sudo mkdir -p /opt/installsudo mkdir -p /opt/download/jdksudo mkdir -p /opt/download/maven
复制代码

  • (2)、JDK安装:
  1. # 下载JDK到指定目录sudo wget --no-check-certificate -P /opt/download/jdk https://manongbiji.oss-cn-beijing.aliyuncs.com/ittailkshow/devops/download/jdk-8u341-linux-x64.tar.gz# 解压到/opt/install(解压后目录为jdk1.8.0_341)sudo tar -zxvf /opt/download/jdk/jdk-8u341-linux-x64.tar.gz -C /opt/install# 重命名解压后的目录sudo mv /opt/install/jdk1.8.0_341 /opt/install/jdk# 配置 JDK 环境变量# 1、编辑当前用户专属的环境配置文件vim ~/.bashrc# 2、在profile中添加以下内容(复制到文件末尾)export JAVA_HOME=/opt/install/jdkexport JRE_HOME=${JAVA_HOME}/jreexport CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/libexport PATH=${JAVA_HOME}/bin:$PATH# 3、配置生效source ~/.bashrc# 4、验证java -version
复制代码
(3)、Maven安装:
  1. # 下载Maven到指定目录sudo wget --no-check-certificate -P /opt/download/maven https://manongbiji.oss-cn-beijing.aliyuncs.com/ittailkshow/devops/download/apache-maven-3.8.6-bin.tar.gz# 解压到/opt/install(解压后目录为apache-maven-3.8.6)sudo tar -zxvf /opt/download/maven/apache-maven-3.8.6-bin.tar.gz -C /opt/install# 重命名解压后的目录sudo mv /opt/install/apache-maven-3.8.6 /opt/install/maven# 切换阿里云的settings.xml配置:sudo rm -f /opt/install/maven/conf/settings.xml && sudo wget --no-check-certificate -O /opt/install/maven/conf/settings.xml https://manongbiji.oss-cn-beijing.aliyuncs.com/ittailkshow/devops/download/settings.xml# 配置 Maven环境变量# 1、编辑当前用户专属的环境配置文件vim ~/.bashrc# 2、在profile中添加以下内容(复制到文件末尾)export MAVEN_HOME=/opt/install/mavenexport PATH=${MAVEN_HOME}/bin:$PATH# 3、配置生效source ~/.bashrc# 4、验证mvn -v
复制代码

3、Docker-Jenkins安装:
  1. # 拉取稳定版Jenkins镜像sudo docker pull jenkins/jenkins:lts# 创建宿主机Jenkins数据目录sudo mkdir -p /data/jenkins-data# 配置权限sudo chmod 777 /data/jenkins-data# 创建宿主机部署根目录sudo mkdir -p /data/module-data# 配置权限sudo chmod 777 /data/module-data# 启动容器sudo docker run -d \  --name jenkins \  -p 8930:8080 \  -p 50000:50000 \  -v /data/jenkins-data:/var/jenkins_home \  -v /data/module-data:/data/module-data \  -v /opt/install/jdk:/opt/install/jdk \  -v /opt/install/maven:/opt/install/maven \  -u root \  jenkins/jenkins:lts
复制代码
参数

作用说明

必要性

-p 8930:8080
宿主机 8930 端口映射到容器内 8080 端口
(Jenkins Web 访问端口)
必选
-p 50000:50000
宿主机 50000 端口映射到容器内 50000 端口
(Jenkins 代理 / 节点通信端口)
可选
-v /data/jenkins-data:/var/jenkins_home
将宿主机/data/jenkins-data目录挂载到容器内/var/jenkins_home
(Jenkins 核心数据目录)
必选
-v /data/module-data:/data/module-data
将宿主机部署目录挂载到容器内同路径,供 Jenkins 进行部署
可选
-v /opt/install/jdk:/opt/install/jdk
将宿主机 JDK 目录挂载到容器内同路径,供 Jenkins 调用 JDK 环境
可选
-v /opt/install/maven:/opt/install/maven
将宿主机 Maven 目录挂载到容器内同路径,供 Jenkins 调用 Maven 环境
可选
-u root
以 root 用户身份运行 Jenkins 容器
必选
jenkins/jenkins:lts
指定启动容器使用的镜像(Jenkins 长期支持版,稳定)
必选
4、Jenkins配置初始化:
  1. # 访问 Jenkins地址,输入初始密码http://127.0.0.1:8930# 获取初始密码# 通过日志方式:sudo docker logs jenkinssudo cat /data/jenkins-data/secrets/initialAdminPassword
复制代码

  • (1)、输入管理员密码:


  • (2)、选择安装推荐的插件方式:



  • (3)、安装完成后,创建管理员账号:


  • (4)、进行实例配置,配置Jenkins URL:


  • (5)、自定义插件安装:
系统管理 → 插件管理
用途

插件

角色权限管控插件
Role-based Authorization Strategy
拉取源代码
Git Parameter
通过SSH协议发布到远程服务器
Publish Over SSH
用于创建和管理流水线的核心插件
Pipeline




  • (6)、全局配置-初始化JDK和Maven:
系统管理 → 全局工具配置




  • (7)、系统配置- 配置Publish Over SSH远程服务器:
系统管理 → 系统配置
  1. # 进入Jenkins容器docker exec -it jenkins bash# 清空旧密钥和指纹-彻底重置rm -rf ~/.ssh/id_rsa* && > ~/.ssh/known_hosts# 生成新SSH密钥-无密码短语ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ""# 信任宿主机IP指纹-(替换)ssh-keyscan -H 127.0.0.1 >> ~/.ssh/known_hosts# 拷贝公钥到宿主机xxx用户-输入密码(替换)ssh-copy-id xxx@127.0.0.1# 复制Jenkins私钥cat ~/.ssh/id_rsa# 验证ssh xxx@127.0.0.1 "echo ' SSH免密登录成功!'"# 退出容器exit
复制代码




「系统管理」→「系统配置」→「Publish over SSH」
参数

说明

Name
自定义名称
Hostname
宿主机 IP
Username
宿主机登录用户
Remote Directory
留空
高级
勾选「Use password authentication or use a different key」
Key
私钥
5、Jenkins Pipeline + Dockerfile实现通用化 CI/CD流水线:

(1)、整体流程总览:

Jenkins 构建触发 → 拉取 Git 代码 → Maven 编译生成 Jar → 传输 Jar/Dockerfile 到宿主机 → 宿主机创建部署/日志目录 → Docker 构建镜像 → 停止旧容器 → 启动新容器(挂载日志+映射端口)→ 外部通过配置端口访问应用
(2)、Spring boot父子工程项目构建:




  • 1)、Dockerfile配置:
  1. # 基础镜像:固定JDK8版本,避免依赖漂移FROM openjdk:8-jdk-alpine# 构建参数:模块名、端口(由Docker build传入)ARG MODULE_NAMEARG PORT# 工作目录WORKDIR /app# 创建容器内日志目录RUN mkdir -p /app/log# 复制Jar包到容器COPY ${MODULE_NAME}-0.0.1-SNAPSHOT.jar app.jar# 暴露应用端口EXPOSE ${PORT}# 启动命令:指定日志输出路径,启用UTF-8编码ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-Dlogging.file.name=/app/log/app.log", "-jar", "app.jar"]
复制代码

  • 2)、Jenkinsfile流水线(Jenkins-Pipeline)配置:
  1. /* * 通用化 Spring Boot CI/CD 流水线 * 功能:Maven编译 + Docker构建 + 宿主机部署(日志持久化) */pipeline {    // 执行节点(使用任意可用节点)    agent any    environment {        // ===================== 核心配置区(仅需修改以下参数)=====================        // 宿主机IP        HOST_IP = "127.0.0.1"        // 宿主机登录用户        HOST_USER = "xxx"        // 宿主机部署根目录        HOST_BASE_DEPLOY_DIR = "/data/module-data"        // 父工程名        PARENT_PROJECT_NAME = "jenkins-demo"        // 模块配置(模块名:端口,多模块用逗号分隔)        // MODULES = "new-project1:8080,new-project2:8081,xxxx:xxxx"        MODULES = "new-project1:8080"        // ======================================================================    }    // 构建工具(引用Jenkins全局配置的JDK和Maven)    tools {        jdk 'jdk'        maven 'maven'    }    stages {        /*         * 编译+部署阶段         * 调用外部deploy.sh脚本完成编译、构建、部署全流程         */        stage('编译与部署') {            steps {                // 给部署脚本添加执行权限                sh "chmod +x ./docker/deploy.sh"                // 执行部署脚本(传递核心配置参数)                sh "./docker/deploy.sh ${MODULES} ${HOST_IP} ${HOST_USER} ${HOST_BASE_DEPLOY_DIR} ${PARENT_PROJECT_NAME}"            }        }    }    /*     * 构建后置操作     */    post {        success {            echo "构建号:${currentBuild.number}"            echo "构建部署成功,应用访问地址与日志路径:"            sh """                echo "${MODULES}" | tr ',' '\\n' | while read MODULE; do                    if [ -z "\${MODULE}" ]; then continue; fi                    MODULE_NAME=\$(echo \${MODULE} | cut -d':' -f1)                    MODULE_PORT=\$(echo \${MODULE} | cut -d':' -f2)                    echo "  - \${MODULE_NAME}:http://${HOST_IP}:\${MODULE_PORT}"                    echo "  - 日志路径:${HOST_BASE_DEPLOY_DIR}/${PARENT_PROJECT_NAME}/\${MODULE_NAME}/log/app.log"                done            """            echo "宿主机执行 docker images | grep ${PARENT_PROJECT_NAME} 可查看构建的镜像"        }        failure {            echo "构建号:${currentBuild.number}"            echo "构建部署失败,排查步骤:"            echo "1. 登录宿主机:ssh ${HOST_USER}@${HOST_IP}"            echo "2. 查看容器日志:docker logs 模块名-app(如new-project1-app)"            echo "3. 检查端口占用:netstat -tulpn | grep 模块端口(如8080)"            echo "4. 检查部署目录:cd ${HOST_BASE_DEPLOY_DIR}/${PARENT_PROJECT_NAME}/模块名"        }    }}
复制代码

  • 3)、deploy.sh部署脚本:
  1. #!/bin/bash# 通用化 Spring Boot 部署脚本# 接收参数:# $1: MODULES(模块配置,格式:模块名:端口,多模块用逗号分隔)# $2: HOST_IP(宿主机IP)# $3: HOST_USER(宿主机登录用户)# $4: HOST_BASE_DEPLOY_DIR(宿主机部署根目录)# $5: PARENT_PROJECT_NAME(父工程名)# 定义变量(接收参数)MODULES=$1HOST_IP=$2HOST_USER=$3HOST_BASE_DEPLOY_DIR=$4PARENT_PROJECT_NAME=$5# 步骤1:Maven编译(固定跳过测试)echo "开始编译父工程:${PARENT_PROJECT_NAME}"MVN_CMD="mvn clean package -DskipTests"echo "执行Maven命令:${MVN_CMD}"${MVN_CMD} || { echo "Maven编译失败,终止部署"; exit 1; }# 步骤2:解析模块列表并部署每个模块echo "开始部署模块到宿主机:${HOST_IP}"echo "${MODULES}" | tr ',' '\n' > /tmp/modules.tmp# 遍历模块部署while read MODULE; do    # 跳过空行    [ -z "${MODULE}" ] && continue    # 拆分模块配置(模块名:端口)    MODULE_NAME=$(echo ${MODULE} | cut -d':' -f1)    MODULE_PORT=$(echo ${MODULE} | cut -d':' -f2)    # 定义部署相关路径    DEPLOY_DIR="${HOST_BASE_DEPLOY_DIR}/${PARENT_PROJECT_NAME}/${MODULE_NAME}"    LOG_DIR="${DEPLOY_DIR}/log"    IMAGE_NAME="${PARENT_PROJECT_NAME}-${MODULE_NAME}:latest"    # 建议:若需区分版本,可手动给镜像加标签,如 IMAGE_NAME="${PARENT_PROJECT_NAME}-${MODULE_NAME}:v1.0.0"    CONTAINER_NAME="${MODULE_NAME}-app"    JAR_FILE="${MODULE_NAME}/target/${MODULE_NAME}-0.0.1-SNAPSHOT.jar"    # 验证Jar包是否存在    if [ ! -f "${JAR_FILE}" ] || [ ! -s "${JAR_FILE}" ]; then        echo "模块${MODULE_NAME}编译失败:Jar包不存在或为空(路径:${JAR_FILE})"        rm -f /tmp/modules.tmp        exit 1    fi    echo "模块${MODULE_NAME}编译成功,Jar包路径:${JAR_FILE}"    # 步骤3:宿主机操作(创建目录、上传文件、构建镜像、启动容器)    echo "开始部署模块:${MODULE_NAME}"    # 3.1 创建宿主机部署目录和日志目录    ssh -o StrictHostKeyChecking=no ${HOST_USER}@${HOST_IP} "mkdir -p ${DEPLOY_DIR} ${LOG_DIR} && chmod 775 ${LOG_DIR} && chown -R iven:iven ${LOG_DIR}"    # 3.2 上传Dockerfile和Jar包到宿主机    scp -o StrictHostKeyChecking=no ./docker/Dockerfile ${HOST_USER}@${HOST_IP}:${DEPLOY_DIR}/    scp -o StrictHostKeyChecking=no ${JAR_FILE} ${HOST_USER}@${HOST_IP}:${DEPLOY_DIR}/    # 3.3 构建Docker镜像并启动容器(挂载日志目录)    ssh -o StrictHostKeyChecking=no ${HOST_USER}@${HOST_IP} "        set -e        cd ${DEPLOY_DIR}        # 构建Docker镜像        echo '构建Docker镜像:${IMAGE_NAME}'        docker build -t ${IMAGE_NAME} --build-arg MODULE_NAME=${MODULE_NAME} --build-arg PORT=${MODULE_PORT} .        # 停止并删除旧容器(避免端口占用)        echo '停止旧容器:${CONTAINER_NAME}'        docker stop ${CONTAINER_NAME} 2>/dev/null || true        docker rm ${CONTAINER_NAME} 2>/dev/null || true        # 启动新容器(设置重启策略+挂载日志目录)        echo '启动新容器:${CONTAINER_NAME}'        docker run -d \            --name ${CONTAINER_NAME} \            --restart=on-failure:3 \            -p ${MODULE_PORT}:${MODULE_PORT} \            -v ${LOG_DIR}:/app/log \            ${IMAGE_NAME}        # 等待应用启动并验证状态        sleep 3        if docker ps --filter 'name=${CONTAINER_NAME}' --filter 'status=running' | grep -q ${CONTAINER_NAME}; then            echo '模块${MODULE_NAME}部署成功'        else            echo '模块${MODULE_NAME}部署失败,容器日志:'            docker logs ${CONTAINER_NAME} 2>/dev/null            exit 1        fi        # ===================== 第三方镜像仓库推送(按需开启)=====================        # 说明:如需将镜像推送到Harbor/Docker Hub等仓库,取消以下注释并修改配置        # 前置操作:宿主机需先登录镜像仓库(docker login 仓库地址 -u 用户名 -p 密码)        # 示例(Harbor):        # REPOSITORY_URL="harbor.example.com/library"  # 镜像仓库地址        # IMAGE_TAGGED="\${REPOSITORY_URL}/\${IMAGE_NAME}"        # docker tag \${IMAGE_NAME} \${IMAGE_TAGGED}     # 给镜像打仓库标签        # docker push \${IMAGE_TAGGED}                   # 推送镜像到仓库        # echo '镜像${IMAGE_TAGGED}已推送到第三方仓库'        # ======================================================================    "    echo "模块${MODULE_NAME}部署完成"done < /tmp/modules.tmp# 清理临时文件rm -f /tmp/modules.tmpecho "所有模块部署完成,最终部署目录:${HOST_BASE_DEPLOY_DIR}/${PARENT_PROJECT_NAME}"echo "宿主机执行 docker images | grep ${PARENT_PROJECT_NAME} 可查看所有构建的镜像,手动记录版本便于回退"
复制代码
(2)、Jenkins创建流水线项目:

新建任务 → 流水线
「流水线」→「Pipeline script from SCM」→「SCM」→「Git」
参数

说明

Repository URL
Git项目地址
凭证
选择「用户名 + 密码」
指定分支
*/main(根据实际分支调整,如 */dev)
脚本路径
docker/Jenkinsfile(指定 Git 项目中的 Jenkinsfile 路径)
其余配置保持默认 → 点击「保存」




(3)、执行Jenkins构建:


  • 1)、进入流水线项目,点击「立即构建」:


  • 2)、构建成功后:


访问应用
http://宿主机IP:8080(new-project1)
查看日志
/data/module-data/jenkins-demo/new-project1/log/app.log
查看镜像
宿主机执行 docker images | grep jenkins-demo 即可看到构建的镜像
查看当前目录结构
find . -print | sed -e 's;[^/]*/;|____;g;s;____|;    |;g'
6、学习参考:

(1)、DevOps-文章目录:

相关参考
(2)、Docker+Jenkins+Git实现企业持续集成持续部署(CI/CD):

 相关参考
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册