近年来,随着前端技术的发展,前端项目的构建和打包过程变得越来越复杂,占用的资源也越来越多。我有一台云服务器,原本打算使用Docker进行部署,以简化操作流程。然而,只要执行
sudo docker-compose -f deploy/docker-compose/docker-compose.yaml up
命令,服务器就直接卡死,CPU占用率飙升至100%,导致我无法正常使用。
经过一番思考和尝试,我决定借助GitHub的CICD功能来解决这个问题。通过利用免费的GitHub的服务器资源,我可以只将打包好的文件部署到我的后台服务器上,简直不要太方便啦!下面详细介绍具体步骤。
背景
在使用Docker进行前端项目和后端服务的部署时,我遇到的问题主要出在资源占用上。由于我的云服务器配置较低,同时执行多个Docker容器的构建和启动指令,导致服务器资源被瞬间耗尽。因此,我决定寻找一种更高效的方式来完成前端项目的构建和打包,而无需占用本地服务器的大量资源。GitHub的CICD功能恰好可以满足这一需求,它提供了一个强大的云端构建环境,可以轻松地完成项目的构建和打包工作。
准备工作
- GitHub账户:确保你有一个GitHub账户,并且已经创建了一个仓库来存放你的前端项目代码。
- 部署服务器:准备好你的部署服务器,确保服务器可以访问GitHub,并且已经做好了相应的部署准备工作。
- SSH密钥:为GitHub配置SSH密钥,以便能够通过SSH连接到你的部署服务器。
步骤
1. 编写Dockerfile
首先,确保你的前端项目有一个Dockerfile,用于构建前端项目的镜像。以下是一个简单的Dockerfile示例:
# 使用官方Node镜像作为构建环境
FROM node:20-slim AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 使用官方Nginx镜像作为运行环境
FROM nginx:alpine AS production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2. 创建GitHub Actions Workflow
在GitHub仓库中创建一个.github/workflows
文件夹,然后在文件夹中创建一个YAML文件,例如ci-cd.yml
。这个文件将定义GitHub Actions的工作流程。
name: CI/CD for Frontend Project
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Run build script
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-build
path: ./dist
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: frontend-build
path: ./dist
- name: Deploy to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
password: ${{ secrets.SERVER_PASSWORD }}
port: ${{ secrets.SERVER_PORT }}
source: "dist"
target: "/root/build"
3. 配置GitHub Secrets
在GitHub仓库设置中,配置以下Secrets:
SERVER_HOST
:你的服务器IP地址SERVER_USERNAME
:你的服务器用户名SERVER_PASSWORD
:你的服务器密码SERVER_PORT
:你的服务器SSH端口(默认为22)
这些Secrets用于在GitHub Actions Workflow中安全地存储和使用敏感信息,如服务器的登录凭证。
4. 配置服务器
确保服务器已经配置好Nginx,并且可以通过SSH访问。将前端项目的构建输出目录(例如dist)上传到服务器后,Nginx需要配置为指向这个目录以提供静态文件服务。
5. 下载构件
当工作流运行完成后,构建好的前端文件会被上传为构件。可以在 GitHub 项目的 Actions 标签下找到对应的运行记录,并下载构件。具体操作如下:
- 打开GitHub 项目页面,在左侧菜单中点击
Actions
。 - 找到触发的构建工作流,点击对应的运行记录。
- 在运行记录页面的右上角,会看到
Artifacts
标签,点击它。 - 点击上传的构件名称(如
frontend-build
),就可以开始下载。
6. 自动化部署到后台服务器
为了进一步提升效率,可以借助 scp
或 rsync
将构件从 GitHub Actions 自动部署到云服务器。这里以 scp
为例,需要配置 SSH 密钥,并在 GitHub Secrets 中设置服务器的访问凭据。
配置 SSH 密钥
- 在本地生成 SSH 密钥对(如果还没有的话),使用命令
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
。 - 将生成的公钥添加到云服务器的
~/.ssh/authorized_keys
文件中。 - 将私钥添加到 GitHub 项目的 Secrets 中,设置为
SSH_PRIVATE_KEY
。
修改工作流文件以支持自动部署
在build.yml
文件中添加部署步骤:
- name: Install SSH Client
uses: webfactory/ssh-agent@v0.5.4
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy to Remote Server
run: |
scp -r ./build user@your_server_ip:/path/to/deploy
确保将上述命令中的 user
、your_server_ip
和 /path/to/deploy
替换为你的服务器用户名、服务器 IP 地址和你想部署到的路径。
为了使上述命令能够顺利执行,需要在GitHub仓库的“Settings” -> “Secrets”中添加SSH_PRIVATE_KEY和服务器的IP地址等信息,将本地生成的私钥内容复制到该Secret中。
总结需要确认以下三点:
- 确认公钥已经正确添加到云服务器的
~/.ssh/authorized_keys
文件中。 - 在GitHub仓库的“Settings” -> “Secrets”中添加SSH_PRIVATE_KEY。将本地生成的私钥内容复制到该Secret中。
- 添加SERVER_IP,将你的云服务器的IP地址添加到该Secret中。
通过上述步骤,利用 GitHub Actions 的免费 CI/CD 资源编译打包前端项目,并将结果自动部署到你的云服务器上,无需占用本地服务器的资源。这样不仅提高了效率,还简化了部署流程,太美啦。
注: 在使用 GitHub Actions 实现 CI/CD 自动化部署时,将生成的公钥添加到云服务器的 ~/.ssh/authorized_keys
文件中是推荐的做法,这样可以实现无密码的自动化部署。这样 GitHub Actions 在执行部署时就可以使用私钥进行身份验证,而无需每次都输入密码。这不仅提高了部署的效率,也增强了安全性,因为私钥的存储和使用可以被更好地控制。
结论
通过GitHub的CICD功能,我们可以利用其强大的云端构建环境来完成前端项目的构建和打包工作,而无需占用本地服务器的大量资源。这样不仅可以提高构建效率,还可以降低服务器的负担,使我们的开发和部署过程更加流畅。
附:我的Dockerfile:
# 如果需要用 cicd ,请设置环境变量:
# variables:
# DOCKER_BUILDKIT: 1
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod
FROM base AS build
COPY --from=prod-deps /app/node_modules /app/node_modules
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install && pnpm run build
FROM nginx:alpine
LABEL MAINTAINER="bypanghu@163.com"
COPY --from=base /app/.docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf
COPY --from=build /app/dist /usr/share/nginx/html
RUN ls -al /usr/share/nginx/html
我的docker-compose.yaml文件:
version: "3"
# 声明一个名为network的networks,subnet为network的子网地址,默认网关是177.7.0.1
networks:
network:
ipam:
driver: default
config:
- subnet: '177.7.0.0/16'
# 设置mysql,redis持久化保存
volumes:
mysql:
redis:
services:
web:
build:
context: ../../web
dockerfile: ./Dockerfile
container_name: gva-web
restart: always
ports:
- '8080:8080'
depends_on:
- server
command: [ 'nginx-debug', '-g', 'daemon off;' ]
networks:
network:
ipv4_address: 177.7.0.11
server:
build:
context: ../../server
dockerfile: ./Dockerfile
container_name: gva-server
restart: always
ports:
- '8888:8888'
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
links:
- mysql
- redis
networks:
network:
ipv4_address: 177.7.0.12
mysql:
image: mysql:8.0.21 # 如果您是 arm64 架构:如 MacOS 的 M1,请修改镜像为 image: mysql/mysql-server:8.0.21
container_name: gva-mysql
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci #设置utf8字符集
restart: always
ports:
- "13306:3306" # host物理直接映射端口为13306
environment:
#MYSQL_ROOT_PASSWORD: 'Aa@6447985' # root管理员用户密码
MYSQL_DATABASE: 'qmPlus' # 初始化启动时要创建的数据库的名称
MYSQL_USER: 'gva'
MYSQL_PASSWORD: 'Aa@6447985'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "gva", "-pAa@6447985"]
interval: 10s
timeout: 5s
retries: 3
volumes:
- mysql:/var/lib/mysql
networks:
network:
ipv4_address: 177.7.0.13
redis:
image: redis:6.0.6
container_name: gva-redis # 容器名
restart: always
ports:
- '16379:6379'
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG || exit 1"]
interval: 10s
timeout: 5s
retries: 3
volumes:
- redis:/data
networks:
network:
ipv4_address: 177.7.0.14
最后,附上我的cicd脚本代码(测试ok,完全可用):
.github\workflows\ci-cd.yml
name: CI-CD Build and Deploy Frontend
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
steps:
- uses: actions/checkout@v4
- name: set Node.js version
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: cache Node.js module
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: install dependencies
run: npm install
- name: Create build directory
run: mkdir -p ./dist
- name: Build project
run: npm run build
- name: upload Artifact
uses: actions/upload-artifact@v4
with:
name: build result
path: ./dist
- name: Install SSH client
run: sudo apt-get install -y openssh-client
- name: Create a text file for testing
run: touch ./dist/text.txt
- name: Set up SSH keys
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -t ed25519 120.27.146.247 >> ~/.ssh/known_hosts
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy to Remote Server
run: |
scp -r ./dist root@120.27.146.247:/root/build
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
参考资料
- GitHub Actions
- Docker Compose
- SCP Action
注:文中提到的docker-compose.yaml
内容,主要用于本地开发环境的构建和部署,可以按照实际需求进行调整。在CICD流程中,我们主要是利用Docker来构建前端项目的镜像,然后将构建好的静态文件通过SCP方式上传至部署服务器。