IdeaWorlds 前端开发笔记(三)

本篇目标:介绍本项目的前端自动化部署。

趁 618 买了台腾讯云的服务器折腾了下,因此先提前写下前端部署的笔记,完整流程:

  1. 开通容器镜像服务 -> 创建命名空间 ideaworlds -> 创建两个镜像仓库 www、console
  2. 服务器安装 Docker -> 登录私服
  3. 服务器安装 Nginx 并反向代理前端目录
  4. GitHub Action 监听部署分支

1. 前端工程

1.1 GitHub Action 流程配置

  • 自动部署流程
    • 从分支名解析出当前要部署的项目(例:release/www -> 部署www
    • 设置 Docker 镜像名:{私有仓库}/{命名空间}/{项目名}
    • 获取当前日期、checkout 最新代码、设置 nodejs 环境
    • npm 打包要部署的项目,并将打包后的文件移到./deploy/dist/
    • Docker 打包./deploy/:{镜像名}:latest、{镜像名}:当前日期
    • Docker 登录私有仓库,推送刚打包的两个镜像到仓库
    • ssh 登录服务器(注意:该服务器需先手动登录 Docker 私有仓库)
      • 创建前端目录:/app/{命名空间}/{项目名}
      • 拉取刚推送的镜像:镜像名:latest
      • 映射前端目录启动一个临时容器,执行成功后将在前端目录创建三个子目录
        • prev (存放上次的文件,即先从 latest/ 移到 prev/ )
        • latest (存放最新的文件)
        • latest_bak (存放最新的文件)
      • 删除镜像
    ./.github/workflows/deploy.yml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    
    name: deploy
    
    on:
      push:
        branches: [ "release/*" ]
      workflow_dispatch:
    
    env:
      docker-registry: ccr.ccs.tencentyun.com
      docker-namespace: ideaworlds
      remote-workdir: /app
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - name: Set env.project
            run: |
                        echo "project=${GITHUB_REF#refs/heads/release/}" >> $GITHUB_ENV
    
          - name: Set env.image
            run: |
                        echo "image=${{ env.docker-registry }}/${{ env.docker-namespace }}/${{ env.project }}" >> $GITHUB_ENV
    
          - name: Get Time
            id: time
            uses: nanzm/get-time-action@v1.1
            with:
              timeZone: 8
              format: 'YYMMDD'
    
          - uses: actions/checkout@v3
          - uses: actions/setup-node@v3
            with:
              node-version: 18
              cache: 'npm'
    
          - name: npm build
            run: |
              npm ci
              npm run build:${{ env.project }}
              mv ./dist/${{ env.project }}/ ./deploy/dist/          
    
          - name: docker build
            run: |
              cd ./deploy
              docker build -t ${{ env.image }}:latest .
              docker tag ${{ env.image }}:latest ${{ env.image }}:${{ steps.time.outputs.time }}          
    
          - name: Login to Docker Registry
            uses: docker/login-action@v2
            with:
              registry: ${{ env.docker-registry }}
              username: ${{ secrets.DOCKER_USER }}
              password: ${{ secrets.DOCKER_TOKEN }}
    
          - name: Push to Docker Registry
            run: |
              docker push ${{ env.image }}:latest
              docker push ${{ env.image }}:${{ steps.time.outputs.time }}          
    
          - name: Run Docker Image
            uses: appleboy/ssh-action@master
            with:
              host: ${{ secrets.REMOTE_HOST }}
              username: ${{ secrets.REMOTE_USER }}
              key: ${{ secrets.REMOTE_KEY }}
              script_stop: true
              script: |
                mkdir -p ${{ env.remote-workdir }}/${{ env.docker-namespace }}/${{ env.project }}
                docker pull ${{ env.image }}:latest
                docker run --rm -v ${{ env.remote-workdir }}/${{ env.docker-namespace }}/${{ env.project }}:/app/data ${{ env.image }}:latest
                docker rmi ${{ env.image }}:latest            

1.2 Angular 打包

  • 开启 gzip

    1
    2
    
    npm install --save-dev gulp-gzip
    npm install --save-dev gulp
    ./gulpfile.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    // gulpfile.js 与 package.json 同级
    let gulp = require('gulp');
    let gzip = require('gulp-gzip');
    
    gulp.task('compress', function () {
      return gulp.src(['./dist/**/*.js', './dist/**/*.css'])
        .pipe(gzip())
        .pipe(gulp.dest('./dist'));
    });
  • 修改部署包大小限制

    Angular 默认打包大小超过 1m 会失败,我们的原部署包刚好超过 1m 一点点,gzip 压缩后不到 200k,因此需要放开这个限制。

    ./angular.json
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    {
      "projects": {
        "www": {
          "architect": {
            "build": {
              "configurations": {
                "production": {
                  {
                    "type": "initial",
                    "maximumWarning": "1mb",
                    "maximumError": "2mb"    修改这个
                  }
        },
        "console": 同上面 
    }
  • 编写打包脚本

    ./package.json
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    {
      "scripts": {
        "ng": "ng",
        "start:www": "ng serve --project www --open",
        "build:www": "ng build --project www && gulp compress",
        "start:console": "ng serve --project console --open",
        "build:console": "ng build --project console && gulp compress",
        "build": "npm run build:www && npm run build:console"
      }
    }

1.3 Docker 打包

  • Dockerfile
    ./deploy/Dockerfile
    1
    2
    3
    
    FROM alpine:latest
    COPY . /app
    ENTRYPOINT ["sh", "/app/docker-entrypoint.sh"]
  • Docker 容器内自动执行脚本
    ./deploy/docker-entrypoint.sh
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    #!/bin/sh
    
    mkdir -p ./app/data/prev/
    mkdir -p ./app/data/latest/
    mkdir -p ./app/data/current/
    rm -rf ./app/data/current/
    mv ./app/dist/ ./app/data/current/
    rm -rf ./app/data/prev/
    mv ./app/data/latest/ ./app/data/prev/
    mv ./app/data/current/ ./app/data/latest/

2. 服务器

2.1 安装 Docker

2.2 配置 Nginx

使用docker compose启动 Nginx 服务

  • 创建 Nginx 目录和默认配置
    1
    2
    3
    4
    5
    
    mkdir -p /data/nginx/conf.d
    docker run --name tmp-nginx -d nginx:latest
    docker cp tmp-nginx:/etc/nginx/nginx.conf /data/nginx/nginx.conf
    docker cp tmp-nginx:/etc/nginx/conf.d/default.conf /data/nginx/conf.d/default.conf
    docker rm -f tmp-nginx
  • 配置前端服务
    • 软链接前端目录
      1
      2
      3
      
      mkdir -p /data/nginx/html
      ln -s /app/ideaworlds/www /data/nginx/html/www.ideaworlds.info
      ln -s /app/ideaworlds/console /data/nginx/html/console.ideaworlds.info
    • ./conf.d/目录下新建 Nginx 配置文件并编辑
      1
      
      vi /data/nginx/conf.d/ideaworlds.info.conf
      /data/nginx/conf.d/ideaworlds.info.conf
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      server {
          listen       80;
          listen  [::]:80;
          server_name  ideaworlds.info www.ideaworlds.info;
      
          location / {
              root   /html/www.ideaworlds.info/latest;
              try_files $uri $uri/ /index.html?$query_string;
          }
      }
      
      server {
          listen       80;
          listen  [::]:80;
          server_name  console.ideaworlds.info;
      
          location / {
              root   /html/console.ideaworlds.info/latest;
              try_files $uri $uri/ /index.html?$query_string;
          }
      }
  • 编写 Docker Compose 配置
    /data/nginx/docker-compose.yml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    version: '3.0'
    
    services:
      nginx:
        restart: always
        image: nginx:latest
        container_name: nginx
        environment:
          TZ: Asia/Shanghai
        ports:
          - 80:80
          - 443:443
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
          - ./conf.d:/etc/nginx/conf.d
          - ./logs:/var/log/nginx
          - ./html/www.ideaworlds.info:/html/www.ideaworlds.info
          - ./html/console.ideaworlds.info:/html/console.ideaworlds.info

    使用nginx:latest镜像启动一个名为nginx的容器,并映射服务器的 80 和 443 端口。

  • 启动 Nginx 服务
    1
    
    docker compose up -d

    后续若修改docker-compose.yml配置文件,重启服务的命令如下:

    1
    2
    
    docker compose down
    docker compose up -d

2.3 生成密钥

腾讯云文档

3. GitHub

进入 远程仓库的设置选项Secrets/actions添加几个仓库的密钥

key说明
DOCKER_USERDocker 私服用户名
DOCKER_TOKENDocker 私服用户密码
REMOTE_HOST远程服务器 ip
REMOTE_USER远程服务器 ssh 用户名
REMOTE_KEY远程服务器 ssh 私钥

4. 总结

以上全部为一次性配置后续无需再修改,前端工程中推送代码到 release/ 开头的分支将触发 GitHub Action 部署流程,自动打包前端代码更新到服务器对应的目录下。