巧用GitHub的CICD功能免费打包部署前端Node项目

近年来,随着前端技术的发展,前端项目的构建和打包过程变得越来越复杂,占用的资源也越来越多。我有一台云服务器,原本打算使用Docker进行部署,以简化操作流程。然而,只要执行sudo docker-compose -f deploy/docker-compose/docker-compose.yaml up命令,服务器就直接卡死,CPU占用率飙升至100%,导致我无法正常使用。

经过一番思考和尝试,我决定借助GitHub的CICD功能来解决这个问题。通过利用免费的GitHub的服务器资源,我可以只将打包好的文件部署到我的后台服务器上,简直不要太方便啦!下面详细介绍具体步骤。

背景

在使用Docker进行前端项目和后端服务的部署时,我遇到的问题主要出在资源占用上。由于我的云服务器配置较低,同时执行多个Docker容器的构建和启动指令,导致服务器资源被瞬间耗尽。因此,我决定寻找一种更高效的方式来完成前端项目的构建和打包,而无需占用本地服务器的大量资源。GitHub的CICD功能恰好可以满足这一需求,它提供了一个强大的云端构建环境,可以轻松地完成项目的构建和打包工作。
在这里插入图片描述

准备工作

  1. GitHub账户:确保你有一个GitHub账户,并且已经创建了一个仓库来存放你的前端项目代码。
  2. 部署服务器:准备好你的部署服务器,确保服务器可以访问GitHub,并且已经做好了相应的部署准备工作。
  3. 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 标签下找到对应的运行记录,并下载构件。具体操作如下:

  1. 打开GitHub 项目页面,在左侧菜单中点击 Actions
  2. 找到触发的构建工作流,点击对应的运行记录。
  3. 在运行记录页面的右上角,会看到 Artifacts 标签,点击它。
  4. 点击上传的构件名称(如 frontend-build),就可以开始下载。

6. 自动化部署到后台服务器

为了进一步提升效率,可以借助 scprsync 将构件从 GitHub Actions 自动部署到云服务器。这里以 scp 为例,需要配置 SSH 密钥,并在 GitHub Secrets 中设置服务器的访问凭据。

配置 SSH 密钥
  1. 在本地生成 SSH 密钥对(如果还没有的话),使用命令 ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
  2. 将生成的公钥添加到云服务器的 ~/.ssh/authorized_keys 文件中。
  3. 将私钥添加到 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

确保将上述命令中的 useryour_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方式上传至部署服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/972929.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web 通识3

目录 6 通向3.0区块链技术前沿发展 7.主流区块链项目介绍 9.区块链行业应用总览 6 通向3.0区块链技术前沿发展 隔离见证:将一部分信息放在别的地方,这样原本的地方就可以容纳更多的东西 隔离见证和树图都是通过扩大容量来提高性能 闪电网络&#xf…

Hadoop一 HDFS分布式文件系统

一 分布式文件存储 了解为什么海量数据需要使用分布式存储技术 100T数据太大,单台服务器无法承担。于是: 分布式服务器集群 靠数量取胜,多台服务器组合,才能Hold住,如下 分布式不仅仅是解决了能存的问题&#xff…

java练习(33)

ps:题目来自力扣 最强回文子串 给你一个字符串 s&#xff0c;找到 s 中最长的 回文 子串。 class Solution {public String longestPalindrome(String s) {if (s null || s.length() < 1) {return "";}int start 0, end 0;for (int i 0; i < s.length();…

分布式大语言模型服务引擎vLLM论文解读

论文地址&#xff1a;Efficient Memory Management for Large Language Model Serving with PagedAttention 摘要 大语言模型&#xff08;LLMs&#xff09;的高吞吐量服务需要一次对足够多的请求进行批处理。然而&#xff0c;现有系统面临困境&#xff0c;因为每个请求的键值…

日期类(完全讲解版)

1. 类的设计思想 Date 类的设计目的是为了封装和处理日期信息&#xff0c;它提供了对日期的基本操作&#xff0c;如日期加减、日期比较、日期合法性检查等。类中的私有成员 int _year, int _month, int _day 存储了日期的年、月、日。 类的声明和构造 Date 类的声明&#xff1…

微信小程序(uni)+蓝牙连接+Xprint打印机实现打印功能

1.蓝牙列表实现&#xff0c;蓝牙设备展示&#xff0c;蓝牙连接 <template><view class"container"><view class"container_top"><view class"l">设备名称</view><view class"r">{{state.phoneNam…

zookeeper集群配置

配置 一、配置myid文件 # 进入解压好的文件夹下面 touch myid vim myid # master节点写0&#xff0c;slave1节点写1&#xff0c;slave2节点写2二、配置zoo.cfg文件 1.在master节点编辑zookeeper配置文件 # 进入解压好的文件夹下面 cd conf/ cp zoo_sample.cfg zoo.cfg vim …

C++ Primer 类的静态成员

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

Ubuntu 服务器Llama Factory 搭建DeepSeek-R1微调训练环境

1.首先了解一下什么是LLM微调 LLM 微调指的是在已经预训练好的大型语言模型基础上&#xff0c;使用特定的任务数据或领域数据&#xff0c;通过进一步的训练来调整模型的参数&#xff0c;使其在特定任务或领域上能够表现得更好。简单来说&#xff0c;就是对一个已经具备了丰富语…

C++17 中的 std::to_chars 和 std::from_chars:高效且安全的字符串转换工具

文章目录 1. 传统转换方法的局限性2. std::to_chars&#xff1a;数值到字符串的高效转换函数原型&#xff1a;返回值&#xff1a;示例代码&#xff1a;输出&#xff1a; 3. std::from_chars&#xff1a;字符串到数值的高效解析函数原型&#xff1a;返回值&#xff1a;示例代码&…

【Alertmanager】alertmanager告警系统原理剖析与应用实战,应有尽有非常全面

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

VScode 使用Deepseek又方便又好用的另一款插件

一、Continue continue类似于copilot&#xff0c;包含5大核心功能&#xff1a;AI对话编程、代码自动补全、代码智能编辑、上下文提供器、快捷键操作&#xff0c;能满足编程的大部分需求。 在AI大模型的支持上&#xff0c;continue能连接包括DeepSeek、OpenAI、Claude在内的十…

互联网 Java 工程师面试题(Java 面试题五)

JVM 底层 与 GC&#xff08;Garbage Collection&#xff09; 的面试问题 31、64 位 JVM 中&#xff0c;int 的长度是多数&#xff1f; Java 中&#xff0c;int 类型变量的长度是一个固定值&#xff0c;与平台无关&#xff0c;都是 32 位。意思就 是说&#xff0c;在 32 位 和 6…

【设计模式精讲】创建型模式之工厂方法模式(简单工厂、工厂方法)

文章目录 第四章 创建型模式4.2 工厂方法模式4.2.1 需求: 模拟发放奖品业务4.2.2 原始开发方式4.2.3 简单工厂模式4.2.3.1 简单工厂模式介绍4.2.3.2 简单工厂原理4.2.3.3 简单工厂模式重构代码4.2.3.4 简单工厂模式总结 4.2.4 工厂方法模式4.2.4.1 工厂方法模式介绍4.2.4.2 工厂…

pytorch cnn 实现猫狗分类

文章目录 [toc] 1. 导入必要的库2. 定义数据集类3. 数据预处理和加载4. 定义 CNN 模型5. 定义损失函数和优化器6. 训练模型7. 保存模型8. 使用模型进行预测9 完整代码10. 总结 1. 导入必要的库 import torch import torch.nn as nn import torch.optim as optim from torch.ut…

linux学习【7】Sourc Insight 4.0设置+操作

目录 1.Source Insight是什么&#xff1f;2.需要哪些配置&#xff1f;3.怎么新建项目4.一些问题的解决1.中文乱码问题 按照这个设置就可以了&#xff0c;下面的设置会标明设置理由。 1.Source Insight是什么&#xff1f; 阅读源码&#xff0c;编辑源码&#xff0c;不能编译&am…

有序分数,递归stern-Brocot Tree

题目&#xff1a; 1360. 有序分数 题目 提交记录 讨论 题解 视频讲解 给定一个整数 NN&#xff0c;请你求出所有分母小于或等于 NN&#xff0c;大小在 [0,1][0,1] 范围内的最简分数&#xff0c;并按从小到大顺序依次输出。 例如&#xff0c;当 N5N5 时&#xff0c;所…

一批起飞猪名单配图

好久没有使用风口猪选股指标了&#xff0c;今天去玩了一把&#xff0c;发现起飞猪指标显示了好多一批猪票 华曙高科 汉威科技 双林股份 曼恩斯特 长盈精密 江苏雷利 双飞集团 奥飞数据 硅宝科技 水晶光电 长盈精密

跳表(Skip List)详解

一、什么是跳表&#xff1f; 跳表是一种基于有序链表的高效数据结构&#xff0c;通过建立多级索引实现快速查询。它在平均情况下支持O(log n)时间复杂度的搜索、插入和删除操作&#xff0c;性能接近平衡树&#xff0c;但实现更为简单。 二、核心原理 1. 层级结构 底层为完整…

Pycharm中查找与替换

1、Edit -> Find -> Find 在当前文件中查找 2、Edit -> Find -> Find in Files 在所有文件中查找 3、Edit -> Find -> Replace 在当前文件中执行替换 4、Edit -> Find -> Replace in Files 在所有文件中执行替换