前端部署-CICD

一、什么是CICD

CICD 是 Continuous Integration (持续集成)和 Continuous Delivery (持续交付)或 Continuous Deployment(持续部署)的缩写。它是一套现代软件开发方法,用于自动化软件开发过程中的构建、测试、发布等环节,从而提高开发效率、减少人为错误,并确保软件始终处于可交付状态。

1. 持续集成(CI)

持续集成的核心理念是开发人员频繁地(通常是每天多次)将代码集成到共享的代码库中。在每次代码提交后,CI 工具会自动执行以下步骤:

  • 自动化构建:对代码进行编译和构建。
  • 自动化测试:执行单元测试、集成测试等,以确保新提交的代码不会破坏现有功能。
  • 代码质量检查:比如静态代码分析、代码覆盖率检查等。

目的是及时发现和解决问题,避免积压大量的错误和技术债务。

2. 持续交付(CD)

持续交付指的是将持续集成的成果(通过自动化构建和测试的代码)自动部署到一个与生产环境相似的环境中。通过自动化的方式,确保代码随时可以部署到生产环境,只需要一次手动操作就能推送到生产。持续交付的目的是确保软件交付的速度更快、质量更高,同时能够在任意时刻发布软件。

3. 持续部署(CD)

持续部署是持续交付的进一步延伸,指的是自动化将通过测试的代码自动部署到生产环境中。每次代码提交通过所有的测试后,系统会立即将新版本的应用程序部署到生产环境,而无需人工干预。这样开发团队可以更频繁地发布新功能或修复bug。

4、CICD 的好处:

  • 提高开发效率:自动化构建和测试减少了手动操作,提高了开发人员的工作效率。
  • 快速发现问题:通过持续集成和自动化测试,能在早期发现代码中的问题,减少了bug的积压。
  • 稳定的发布流程:确保每次发布都是经过充分测试的,降低了生产环境出错的风险。
  • 更频繁的发布:团队可以更快速地推出新功能或修复bug,缩短产品的迭代周期。

提交代码 -> 检测变化 -> 生成镜像 -> 自动部署镜像

二、基础了解

1、yaml

一个按照特定语法实现的可以顺序执行的一种特殊的数据结构文件。通常用于编写CICD的整个自动化过程的一个执行文件。

yaml文件可以运行的环境:

项目 说明 支持的操作系统/环境
YAML 文件 一种平台无关的数据格式,用于配置和数据交换。 跨平台,可以在 Linux、Windows、macOS 等环境中使用。
执行环境 YAML 文件的执行依赖于 CI/CD 工具应用程序 依赖于 CI/CD 工具,支持多平台:Linux、Windows、macOS。
Linux 环境 大多数 CI/CD 工具运行在 Linux 系统上,尤其是在容器化环境中。 支持 :大部分 CI/CD 工具,如 GitLab CIJenkinsDockerKubernetes
Windows 环境 CI/CD 工具也支持在 Windows 系统上运行,可能需要通过 Docker 或 WSL 模拟 Linux 环境。 支持GitHub ActionsJenkins (通过 WSL 或 Docker)、Docker for Windows
macOS 环境 macOS 用户可以运行 CI/CD 工具和 Docker,通常依赖 Docker 来模拟 Linux 环境。 支持GitHub ActionsGitLab CIDocker DesktopJenkins
云环境 CI/CD 服务提供商如 GitHub Actions 和 GitLab CI 提供云端执行环境,通常运行在 Linux 中。 支持GitLab CI/CDGitHub ActionsCircleCI 等云平台。
执行工具示例 需要特定的 CI/CD 工具来解析和执行 YAML 文件中的配置。 GitLab CIGitHub ActionsJenkinsCircleCITravis CI 等。
操作系统依赖 YAML 文件本身不依赖操作系统,取决于工具的执行环境。 跨平台 ,取决于 CI/CD 工具,可以是 Linux、Windows 或 macOS。

2、基础的语法和示例

参考博客:www.ruanyifeng.com/blog/2016/0...

示例文件:

yaml 复制代码
# 定义 CI/CD 阶段
stages:
  - install
  - build
  - deploy

# 安装 Node.js 和依赖
install_job:
  stage: install  # 设置阶段为安装
  image: node:16  # 使用 Node.js 官方镜像,指定版本为 16
  # 运行脚本命令
  script:
    # 1. 安装 Node.js 的依赖
    - echo "安装 Node.js 依赖..."
    - npm install  # 安装项目的 Node.js 依赖
    # 2. 安装 Docker(如果 CI 环境中没有 Docker)
    - echo "安装 Docker..."
    - apt-get update && apt-get install -y docker.io  # 安装 Docker
    - docker --version  # 确认 Docker 安装成功

# 运行 shell 脚本(比如执行部署或配置脚本)
run_sh_script_job:
  stage: build  # 设置阶段为构建
  script:
    # 3. 运行自定义的 shell 脚本文件
    - echo "运行 shell 脚本 deploy.sh..."
    # ./deploy.sh : 指的是文件仓库的根目录
    - chmod +x ./deploy.sh  # 给 deploy.sh 脚本加上执行权限
    - ./deploy.sh  # 执行脚本

# 项目打包
build_job:
  stage: build  # 设置阶段为构建
  script:
    # 4. 打包 Node.js 项目
    - echo "打包项目..."
    - npm run build  # 运行项目的构建命令(例如打包)
    - echo "打包完成!"

# 部署到 Docker 容器中
deploy_docker_job:
  stage: deploy  # 设置阶段为部署
  script:
    # 5. 构建 Docker 镜像
    - echo "构建 Docker 镜像..."
    - docker build -t my-app-image .  # 使用 Dockerfile 构建镜像
    # 6. 运行 Docker 容器
    - echo "运行 Docker 容器..."
    - docker run -d -p 8080:80 my-app-image  # 在后台运行 Docker 容器,映射端口

2、docker镜像

官网:www.dockerdocs.cn/

参考博客:juejin.cn/post/752525...

三、阿里云➕GitHub 实现CICD自动部署

1、阿里云准备工作

1-1、 创建阿里云个人版镜像仓库

help.aliyun.com/zh/acr/user...

1-2、查验并验证镜像仓库

按照官方示例,登录自己的阿里云服务器进行验证

2、GitHub配置

2.1、设置 Actions

2.2、设置可以在yaml文件中读取的环境变量

2.3、编写yaml文件

(一)文件创建

方案一:本地代码仓库自定义创建

项目根目录创建 .github 文件夹 .github 文件夹下创建 main.yml文件【文件名自定义,尽量和分支保持一致】

方案二:在线编辑

(二)yml 文件编写

yml运行的环境是 github服务环境一切的操作和你的阿里云服务器没有关联

我们可以通过使用工具和脚本去和我们的阿里云服务作关联

yml 复制代码
# action名称
name: dev-cicd
# 监听的分支:                
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
# 设置文件全局变量
env:
  REPO_TAG: "fe-dev"
# 设定运行步骤
jobs:
  # 运行步骤配置
  build:
    # 运行环境
    runs-on: ubuntu-latest
    # 运行步骤
    steps:
    #  安装Node.js
      # First, check out your repository 【一定要有!!!】
    - name: Checkout repository
      uses: actions/checkout@v4
      # 选择node版本
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '20'
      # 运行打包脚本
    - name: Run build script
      run: npm install && npm run build  
      # 制作镜像
    # docker build
    - name: Build Docker image
      run: docker build . --file dockerFile --tag ${{env.REPO_TAG}}
    # docker 镜像推送仓库 
    # ${{secrets.USER_NAME}} 就是设置的环境变量
    # 登录阿里云镜像仓库
    - name: login Registry
      run: docker login -u=${{secrets.USER_NAME}} -p=${{secrets.PASS_WORD}} crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com
    # 设置镜像TAG
    - name: tag Image
      run: docker tag ${{env.REPO_TAG}} crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com/my_ljx_test/dev:${{env.REPO_TAG}}
    # 推送镜像到阿里云镜像仓库
    - name: docker Push 
      run: docker push crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com/my_ljx_test/dev:${{env.REPO_TAG}}
    # 登陆服务器使用脚本自动替换镜像,使用最新推送的镜像
    - name: Deploy to Aliyun Server
      uses: appleboy/ssh-action@v1.0.0
    # 链接阿里云服务器【该命令后所有的操作均在个人阿里云服务环境!!】
      with:
        host: ${{ secrets.SSHADDRESS }}
        username: 'root'
        password: ${{ secrets.SSHPASSWORD }}
        port: 22
        script: |
          set -e  # 遇到错误时停止执行
          
          echo "=== 开始部署 ==="
          echo "时间: $(date)"
                   
          # 登录阿里云容器镜像服务
          echo "=== 登录阿里云镜像仓库 ==="
          docker login -u=${{secrets.USER_NAME}} -p=${{secrets.PASS_WORD}} crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com
          # 拉取最新镜像
          echo "=== 拉取最新镜像 ==="
          docker pull crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com/my_ljx_test/dev:${{env.REPO_TAG}}
          # 停止并删除旧容器
          echo "=== 停止旧容器 ==="
          if docker ps -q --filter "name=${{ env.REPO_TAG }}" | grep -q .; then
            docker stop ${{ env.REPO_TAG }}
            echo "容器已停止"
          fi
          
          if docker ps -aq --filter "name=${{ env.REPO_TAG }}" | grep -q .; then
            docker rm ${{ env.REPO_TAG }}
            echo "容器已删除"
          fi
          
          # 启动新容器
          echo "=== 启动新容器 ==="
          docker run -d \
            -p 8080:80 \
            --name ${{ env.REPO_TAG }} \
            crpi-muyq5tde0d12r3tr.cn-beijing.personal.cr.aliyuncs.com/my_ljx_test/dev:${{ env.REPO_TAG }}
          
          # 等待容器启动
          echo "=== 等待容器启动 ==="
          sleep 10
          
          # 检查容器状态
          echo "=== 检查容器状态 ==="
          if docker ps --filter "name=${{ env.REPO_TAG }}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -q "${{ env.REPO_TAG }}"; then
            echo "✅ 容器启动成功"
            docker ps --filter "name=${{ env.REPO_TAG }}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
          else
            echo "❌ 容器启动失败"
            docker logs ${{ env.REPO_TAG }} --tail 50
            exit 1
          fi          
          echo "=== 部署完成 ==="
          echo "时间: $(date)"
      
(三)更新分支代码验证
相关推荐
小时前端1 分钟前
谁说 AI 历史会话必须存后端?IndexedDB方案完美翻盘
前端·agent·indexeddb
wordbaby6 分钟前
TanStack Router 基于文件的路由
前端
wordbaby11 分钟前
TanStack Router 路由概念
前端
wordbaby13 分钟前
TanStack Router 路由匹配
前端
cc蒲公英14 分钟前
vue nextTick和setTimeout区别
前端·javascript·vue.js
程序员刘禹锡19 分钟前
Html中常用的块标签!!!12.16日
前端·html
我血条子呢29 分钟前
【CSS】类似渐变色弯曲border
前端·css
DanyHope30 分钟前
LeetCode 两数之和:从 O (n²) 到 O (n),空间换时间的经典实践
前端·javascript·算法·leetcode·职场和发展
hgz071031 分钟前
企业级多项目部署与Tomcat运维实战
前端·firefox
用户18878710698431 分钟前
基于vant3的搜索选择组件
前端