使用argo workflow 实现springboot 项目的CI、CD

文章目录

在实现 Spring Boot 项目的 CI/CD 流程时,可以使用 Argo Workflows 来自动化构建、测试和部署过程。Argo Workflows 是一个 Kubernetes 原生的工作流引擎,能够在 Kubernetes 集群中定义、运行、监控和管理复杂的工作流。

基础镜像制作

基础镜像

shell 复制代码
FROM openjdk:8-jdk-slim

这行指定了构建的基础镜像是 openjdk:8-jdk-slim。这是一个包含了 Java 8 开发工具包(JDK)的精简版镜像,适用于 Java 开发和运行环境。

设置镜像源并安装工具git

shell 复制代码
RUN echo "deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib" > /etc/apt/sources.list \
    && apt-get update \
    && apt-get install -y git wget tar \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*
  • 更改 apt 源:使用阿里云的 Debian 镜像源(bullseye),提高安装软件包时的速度和稳定性,尤其是在中国地区。

  • 更新软件包索引:apt-get update 更新包索引。

  • 安装软件包:通过 apt-get install -y 安装 git(用于版本控制)、wget(用于下载文件)、和 tar(用于解压文件)。

  • 清理缓存:使用 apt-get clean 清理下载缓存,减少镜像体积。然后,rm -rf /var/lib/apt/lists/* 删除 apt 包索引文件,进一步减小镜像体积。

下载和安装 Maven

shell 复制代码
RUN wget https://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.tar.gz -P /tmp || (echo "Maven download failed!" && exit 1)
  • 下载 Maven:使用 wget 从阿里云镜像站点下载 Maven 3.8.6 的二进制压缩包。如果下载失败,将输出错误消息并终止构建。
shell 复制代码
RUN tar -xvzf /tmp/apache-maven-3.8.6-bin.tar.gz -C /usr/share/ \
    && rm -f /tmp/apache-maven-3.8.6-bin.tar.gz \
    && ln -s /usr/share/apache-maven-3.8.6/bin/mvn /usr/bin/mvn
  • 解压 Maven:解压下载的 Maven 压缩包到 /usr/share/目录。

  • 清理临时文件:删除下载的压缩包。

  • 创建符号链接:通过 ln -s 创建一个符号链接,将 Maven 的可执行文件 mvn 链接到 /usr/bin/mvn,使得 Maven 命令可以在任何地方使用。

设置环境变量

shell 复制代码
ENV MAVEN_HOME=/usr/share/apache-maven-3.8.6
ENV PATH=$MAVEN_HOME/bin:$PATH
  • MAVEN_HOME:设置 Maven 的环境变量,指向解压后的 Maven 目录。
  • 更新 PATH:将 Maven 的 bin 目录添加到 PATH 环境变量中,这样就可以直接在命令行使用 mvn 命令。

设置工作目录

shell 复制代码
WORKDIR /app

设置容器的工作目录为 /app。所有后续的命令(如构建、运行程序)将会在该目录下执行。这个目录是你在容器中执行应用程序的默认位置。

默认命令

shell 复制代码
CMD ["bash"]
  • 这个命令指定了容器启动时的默认命令是 bash。也就是说,如果你运行这个容器但没有指定其他命令,它将启动一个交互式的 bash shell。

最终dockerfile

shell 复制代码
FROM openjdk:8-jdk-slim

# 使用 Debian 11 (bullseye) 的镜像源
RUN echo "deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib" > /etc/apt/sources.list \
    && apt-get update \
    && apt-get install -y git wget tar \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 下载 Maven
RUN wget https://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.tar.gz -P /tmp || (echo "Maven download failed!" && exit 1)

# 解压 Maven 并创建符号链接
RUN tar -xvzf /tmp/apache-maven-3.8.6-bin.tar.gz -C /usr/share/ \
    && rm -f /tmp/apache-maven-3.8.6-bin.tar.gz \
    && ln -s /usr/share/apache-maven-3.8.6/bin/mvn /usr/bin/mvn

# 设置环境变量
ENV MAVEN_HOME=/usr/share/apache-maven-3.8.6
ENV PATH=$MAVEN_HOME/bin:$PATH

# 设置工作目录
WORKDIR /app

# 默认命令
CMD ["bash"]

执行构建:

复制代码
docker build -t git-maven-base:v1 . -f Dockerfile

制作ci argo workflow 模版

volumeClaimTemplates

yaml 复制代码
volumeClaimTemplates:
  - metadata:
      name: shared-workdir
    spec:
      accessModes: ["ReadWriteMany"]
      resources:
        requests:
          storage: 1Gi
  - metadata:
      name: maven-repo-cache
    spec:
      accessModes: [ "ReadWriteMany" ]
      resources:
        requests:
          storage: 2Gi
  • shared-workdir: 这个 PVC 用于在工作流中的不同任务之间共享数据。它的存储请求为 1 GiB,并且支持 ReadWriteMany,意味着多个 pod 可以同时读写该存储。

  • maven-repo-cache : 用于缓存 Maven 本地仓库的数据。它的存储请求为 2 GiB,同样支持 ReadWriteMany可以在不同的 pod 之间共享缓存数据,避免每次构建时都重新下载依赖

templates

在 templates 部分定义了多个步骤的模板,每个步骤会在不同的容器中执行。

main 模板

yaml 复制代码
- name: main
  dag:
    tasks:
      - name: git-clone
        template: git-clone
      - name: docker-build
        template: docker-build
        dependencies: [git-clone]
  • dag:这里使用的是 DAG(有向无环图) 结构,git-clone 任务是 docker-build 的前置依赖(即 docker-build 需要在 git-clone 完成后才开始执行)。

git-clone 模板

yaml 复制代码
- name: git-clone
  container:
    image: git-maven-base:v1
    command: [sh, -c]
    args:
      - |
        git clone https://gitee.com/qfxcoffee/shield.git /src
        cd /src/arthas-study && mvn clean package -DskipTests
        cd /src/arthas-study/target
        mv arthas-study.jar /src/arthas-study.jar
        mv /src/arthas-study/docker/Dockerfile /src/
        cp -r /src/. /mnt/  # 将文件复制到挂载的 PVC 中
    volumeMounts:
      - name: shared-workdir
        mountPath: /mnt  # 挂载到容器的 /mnt 目录
      - name: maven-repo-cache
        mountPath: /root/.m2/repository  # 挂载到 Maven 本地仓库路径

git-clone 任务使用一个 git-maven-base:v1 的镜像来执行 Git 克隆操作,并且使用 Maven 构建项目。

构建过程中,Maven 会将依赖缓存到 /root/.m2/repository,并且将源码和构建产物(如 arthas-study.jarDockerfile)复制到 /mnt,这个路径会映射到共享的 PVC (shared-workdir),保证不同任务之间的数据共享。

docker-build 模板

yaml 复制代码
- name: docker-build
  container:
    image: docker:19.03.12-dind
    command: [ "/bin/sh", "-c" ]
    args: [
      "docker info && cd /mnt && docker build -t my-image:v1 ."
    ]
    volumeMounts:
      - name: shared-workdir
        mountPath: /mnt  # 挂载到容器的 /mnt 目录
      - name: docker-socket
        mountPath: /var/run/docker.sock
      - name: maven-repo-cache
        mountPath: /root/.m2/repository  # 挂载到 Maven 本地仓库路径
  • docker-build 任务使用 docker:19.03.12-dind 镜像(Docker-in-Docker),这意味着可以在容器内执行 Docker 命令。它会进入挂载的 /mnt 目录,执行 docker build 来构建 Docker 镜像。

  • 挂载了 docker-socket,这样容器可以与宿主机上的 Docker 服务进行通信,执行构建命令。

volumes

yaml 复制代码
volumes:
  - name: docker-socket
    hostPath:
      path: /var/run/docker.sock
      type: Socket
  - name: maven-repo-cache
    hostPath:
      path: /root/.m2/repository
      type: Directory
  • docker-socket: 宿主机上的 Docker 套接字 (/var/run/docker.sock) 被挂载到容器中,使得容器能够访问宿主机的 Docker 引擎,从而执行 Docker 命令。

  • maven-repo-cache: 这里挂载了宿主机上的 /root/.m2/repository 目录到容器中,用于缓存 Maven 本地仓库。这意味着 Maven 任务在执行时会使用这个缓存,而不必每次都从远程仓库下载依赖,减少了构建时间。

hostPathvolumeClaimTemplates 中的 PVC 用法:

hostPath 通过指定宿主机上的目录或套接字,让容器能够访问宿主机的资源。
volumeClaimTemplates 则是在 Kubernetes 中动态创建 PVC,并在 Pod 内部挂载这些 PVC,使得多个任务之间可以共享文件和数据。

这两种挂载方式在某些场景下配合使用,可以提供灵活的数据共享和存储策略。

完整workflow文件

复制代码
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: pvs-demo-
spec:
  entrypoint: main
  volumeClaimTemplates:
    - metadata:
        name: shared-workdir  # 共享的 PVC 名称
      spec:
        accessModes: ["ReadWriteMany"]  # 多个 Pod 可以同时读取和写入
        resources:
          requests:
            storage: 1Gi
    - metadata:
        name: maven-repo-cache  # 用于缓存 Maven 本地仓库
      spec:
        accessModes: [ "ReadWriteMany" ]
        resources:
          requests:
            storage: 2Gi
  templates:
    - name: main
      dag:
        tasks:
          - name: git-clone
            template: git-clone
          - name: docker-build
            template: docker-build
            dependencies: [git-clone]

    - name: git-clone
      container:
        image: git-maven-base:v1
        command: [sh, -c]
        args:
          - |
            git clone https://gitee.com/qfxcoffee/shield.git /src
            cd /src/arthas-study && mvn clean package -DskipTests
            cd /src/arthas-study/target
            mv arthas-study.jar /src/arthas-study.jar
            mv /src/arthas-study/docker/Dockerfile /src/
            cp -r /src/. /mnt/  # 将文件复制到挂载的 PVC 中
        volumeMounts:
          - name: shared-workdir  # 挂载 PVC
            mountPath: /mnt  # 挂载到容器的 /mnt 目录
          - name: maven-repo-cache
            mountPath: /root/.m2/repository  # 将 PVC 挂载到 Maven 本地仓库路径

    - name: docker-build
      container:
        image: docker:19.03.12-dind
        command: [ "/bin/sh", "-c" ]
        args: [
          "docker info && cd /mnt && docker build -t my-image:v1 ."
        ]
        volumeMounts:
          - name: shared-workdir  # 挂载共享 PVC,确保构建上下文可用
            mountPath: /mnt  # 挂载到容器的 /mnt 目录
          - name: docker-socket
            mountPath: /var/run/docker.sock
          - name: maven-repo-cache
            mountPath: /root/.m2/repository  # 将 PVC 挂载到 Maven 本地仓库路径

  volumes:
    - name: docker-socket
      hostPath:
        path: /var/run/docker.sock
        type: Socket
    - name: maven-repo-cache
      hostPath:
        path: /root/.m2/repository  # 宿主机上的目录路径
        type: Directory  # 可以是 Directory 或 File,取决于你的需求

可以看到maven构建及docker构建镜像成功

制作cd argo workflow 模版

Workflow 结构

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: springboot-service-workflow-
spec:
  entrypoint: springboot-workflow
  • apiVersion: argoproj.io/v1alpha1kind: Workflow:这定义了这是一个 Argo Workflow 类型的资源,表示这个文件用于定义一个工作流。

  • metadata.generateName: springboot-service-workflow-:这个字段为工作流生成一个唯一的名称。generateName 表示 Argo 会在每次创建工作流时,为该工作流添加一个随机的后缀,以确保工作流名称的唯一性。

  • spec.entrypoint: springboot-workflow:指定工作流的入口点,即从哪个模板开始执行。在这个例子中,工作流会从 springboot-workflow 模板开始执行。

Templates 定义

接下来的部分定义了工作流中的多个步骤 (steps),这些步骤会按顺序执行。

创建 Kubernetes 服务 (create-service)

yaml 复制代码
- name: create-service
  resource:
    action: apply
    manifest: |
      apiVersion: v1
      kind: Service
      metadata:
        name: springboot-service
      spec:
        selector:
          app: springboot-app
        ports:
          - protocol: TCP
            port: 8080
            targetPort: 8080
        type: NodePort  # 可以根据需要修改为 LoadBalancer 或 NodePort
  • name: create-service:这个步骤的名称。
  • resource:
    • action: apply:表示使用 kubectl apply 命令应用 Kubernetes 资源,创建一个服务。
    • manifest: 这是一个 Kubernetes Service 的 YAML 定义,描述了服务的配置。
    • apiVersion: v1 和 kind: Service:表示这个资源是一个 Kubernetes 服务。
    • metadata.name: springboot-service:服务的名称是 springboot-service。
      • spec:
        • selector: 用于选择应用的 Pod。这里的选择器选择标签为 app: springboot-app 的 Pod。
        • ports: 定义服务的端口,服务监听 8080 端口,并将请求转发到目标端口 8080。
        • type: NodePort:指定服务类型为 NodePort,这意味着服务将暴露在 Kubernetes 节点的一个端口上,便于从外部访问应用。你可以根据需要将其改为 LoadBalancer 或 ClusterIP,具体取决于你的网络需求。

启动 Spring Boot 容器 (springboot-container)

yaml 复制代码
- name: springboot-container
  container:
    name: springboot-app
    image: my-image:v1  # 替换成你的 Docker 镜像
    command: [ "java" ]  # 显式指定命令为 `java`
    args: [ "-jar", "arthas-study.jar" ]  # 显式指定 `arthas-study.jar` 文件作为参数
    ports:
      - containerPort: 8080
    env:
      - name: SPRING_PROFILES_ACTIVE
        value: "prod"
  metadata:
    labels:
      app: springboot-app

完整workflow内容

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: springboot-service-workflow-
spec:
  entrypoint: springboot-workflow
  templates:
    - name: springboot-workflow
      steps:
        - - name: create-service
            template: create-service
        - - name: start-springboot-container
            template: springboot-container

    - name: create-service
      resource:
        action: apply
        manifest: |
          apiVersion: v1
          kind: Service
          metadata:
            name: springboot-service
          spec:
            selector:
              app: springboot-app
            ports:
              - protocol: TCP
                port: 8080
                targetPort: 8080
            type: NodePort  # 可以根据需要修改为 LoadBalancer 或 NodePort

    - name: springboot-container
      container:
        name: springboot-app
        image: my-image:v1  # 替换成你的 Docker 镜像
        command: [ "java" ]  # 显式指定命令为 `java`
        args: [ "-jar", "arthas-study.jar" ]  # 显式指定 `arthas-study.jar` 文件作为参数
        ports:
          - containerPort: 8080
        env:
          - name: SPRING_PROFILES_ACTIVE
            value: "prod"
      metadata:
        labels:
          app: springboot-app

可以看到springboot项目已经运行成功。

复制代码
kubectl get svc -n argo
复制代码
http://192.168.56.115:32356/user/1
相关推荐
raoxiaoya38 分钟前
同时安装多个版本的golang
开发语言·后端·golang
考虑考虑2 小时前
go使用gorilla/websocket实现websocket
后端·程序员·go
李少兄2 小时前
解决Spring Boot多模块自动配置失效问题
java·spring boot·后端
Piper蛋窝3 小时前
Go 1.19 相比 Go 1.18 有哪些值得注意的改动?
后端
码农BookSea3 小时前
不用Mockito写单元测试?你可能在浪费一半时间
后端·单元测试
他҈姓҈林҈4 小时前
Spring Boot 支持政策
spring boot
codingandsleeping4 小时前
Express入门
javascript·后端·node.js
ss2735 小时前
基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
spring boot·后端·高考
两点王爷5 小时前
springboot项目文件上传到服务器本机,返回访问地址
java·服务器·spring boot·文件上传
专注API从业者5 小时前
《Go 语言高并发爬虫开发:淘宝商品 API 实时采集与 ETL 数据处理管道》
开发语言·后端·爬虫·golang