服务云部署

一、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安装:

# 拉取镜像:
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:

1

2

  • (2)、注册Runner:
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:

3

4

5

  • (2)、令牌相关信息:
# 查看你相关令牌信息
cat /data/gitlab-runner/config/config.toml

# 移除相关令牌信息,移除后需重启
rm -f /data/gitlab-runner/config/config.toml
  • (3)、注册Runner:
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"

6

注:

Token 类型

核心定义

适用场景

归属范围

跨项目复用性

项目级 Token

仅绑定单个特定项目的注册凭证,用于注册「项目专属 Runner」

单个项目独立使用(如生产环境项目、专属测试项目)

仅当前注册的目标项目

不可复用

群组级 Token

绑定整个 GitLab 群组的注册凭证,用于注册「群组共享 Runner」

群组下所有项目共用(如开发 / 测试团队共享执行器)

该群组及子群组下所有项目

可复用

实例级 Token

绑定整个 GitLab 服务器(实例)的注册凭证,用于注册「全实例共享 Runner」

GitLab 实例内所有项目共用(如企业级通用执行器)

GitLab 实例内所有项目(所有群组)

可复用

4、Gitlab CI-CD自动化部署SpringBoot项目:

8

7

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

  • 1)、父POM配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.iven</groupId>
    <artifactId>my_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!--聚合机制-->
    <modules>
        <module>new-project1</module>
        <module>new-project2</module>
    </modules>

    <!-- 统一管理依赖版本(子模块无需写version,直接继承) -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot核心依赖(JDK8兼容版本:2.7.x) -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.7.15</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 所有子模块共用的依赖(无需在子模块重复引入) -->
    <dependencies>
        <!-- Spring Boot Web依赖(提供HTTP服务) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!-- 统一配置打包插件(确保子模块打出可执行Jar) -->
    <build>
        <!-- pluginManagement:子模块可继承,不强制引入 -->
        <pluginManagement>
            <plugins>
                <!-- Spring Boot打包插件(打可执行Jar,包含依赖) -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>2.7.15</version>
                    <executions>
                        <execution>
                            <goals>
                                <!-- 关键:将普通Jar转为可执行Jar -->
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- Maven编译插件(指定JDK8) -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <!-- 源码JDK版本 -->
                        <source>8</source>
                        <!-- 编译后JDK版本 -->
                        <target>8</target>
                        <!-- 编码统一 -->
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>
  • 2)、new-project1子模块1配置(new-project2子模块2 同理):

POM配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.iven</groupId>
        <artifactId>my_demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>new-project1</artifactId>
    <name>new-project1</name>
    <description>new-project1</description>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

YML配置:

server:
  port: 8080

spring:
  application:
    name: new-project1

(2)、Dockerfile镜像构建配置:

# ======================== 基础镜像选择 ========================
# 核心原则:选择轻量、安全、与项目运行环境匹配的基础镜像
# 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配置:
# ==============================================================================
# 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 流水线。

9.1

9.2

10

  • 2)、生产环境:手动部署

测试通过后,合并test分支代码到main分支,手动创建 Tag 标签并推送到远程仓库,触发生产镜像构建

11

12

13

14

  • 2.1)、相关服务器操作:

docker-compose.yml容器编排配置:

# 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)、手动创建持久化日志目录:
# 进入docker-compose.yml所在目录
# 当前目录下,创建日志目录
mkdir -p logs/new-project1 logs/new-project2
  • 2.3)、部署与回滚操作:
# 部署与回滚均修改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)、相关目录创建:
sudo mkdir -p /opt/install
sudo mkdir -p /opt/download/jdk
sudo mkdir -p /opt/download/maven
  • (2)、JDK安装:
# 下载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/jdk
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

# 3、配置生效
source ~/.bashrc

# 4、验证
java -version

(3)、Maven安装:

# 下载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/maven
export PATH=${MAVEN_HOME}/bin:$PATH

# 3、配置生效
source ~/.bashrc

# 4、验证
mvn -v

1(1)

3、Docker-Jenkins安装:

# 拉取稳定版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配置初始化:

# 访问 Jenkins地址,输入初始密码
http://127.0.0.1:8930

# 获取初始密码
# 通过日志方式:sudo docker logs jenkins
sudo cat /data/jenkins-data/secrets/initialAdminPassword
  • (1)、输入管理员密码:

1(2)

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

2

3

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

4

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

5

  • (5)、自定义插件安装:

系统管理 → 插件管理

用途

插件

角色权限管控插件

Role-based Authorization Strategy

拉取源代码

Git Parameter

通过SSH协议发布到远程服务器

Publish Over SSH

用于创建和管理流水线的核心插件

Pipeline

6

7

8

  • (6)、全局配置-初始化JDK和Maven:

系统管理 → 全局工具配置

9

10

11(1)

  • (7)、系统配置- 配置Publish Over SSH远程服务器:

系统管理 → 系统配置

# 进入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指纹-(替换<宿主机IP>)
ssh-keyscan -H 127.0.0.1 >> ~/.ssh/known_hosts

# 拷贝公钥到宿主机xxx用户-输入密码(替换<宿主机用户与IP>)
ssh-copy-id xxx@127.0.0.1

# 复制Jenkins私钥
cat ~/.ssh/id_rsa

# 验证
ssh xxx@127.0.0.1 "echo ' SSH免密登录成功!'"

# 退出容器
exit

11(1.1)

11(2)

11(3)

11(4)

「系统管理」→「系统配置」→「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父子工程项目构建:

11(5)

12(1)

  • 1)、Dockerfile配置:
# 基础镜像:固定JDK8版本,避免依赖漂移
FROM openjdk:8-jdk-alpine

# 构建参数:模块名、端口(由Docker build传入)
ARG MODULE_NAME
ARG 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)配置:
/*
 * 通用化 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部署脚本:
#!/bin/bash
# 通用化 Spring Boot 部署脚本
# 接收参数:
# $1: MODULES(模块配置,格式:模块名:端口,多模块用逗号分隔)
# $2: HOST_IP(宿主机IP)
# $3: HOST_USER(宿主机登录用户)
# $4: HOST_BASE_DEPLOY_DIR(宿主机部署根目录)
# $5: PARENT_PROJECT_NAME(父工程名)

# 定义变量(接收参数)
MODULES=$1
HOST_IP=$2
HOST_USER=$3
HOST_BASE_DEPLOY_DIR=$4
PARENT_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.tmp

echo "所有模块部署完成,最终部署目录:${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 路径)

其余配置保持默认 → 点击「保存」

12(2)

13

14

15

(3)、执行Jenkins构建:

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

16

  • 2)、构建成功后:

17

18

访问应用

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):

 相关参考

 

posted on 2025-12-26 09:46  爱文(Iven)  阅读(6)  评论(0)    收藏  举报

导航