Github Action + docker 实现自动化部署

当一个项目开发完,需要部署到服务器时,如果直接在服务器上拉取代码、打包运行,就需要服务器环境与本地保持一致,不然就会出现本地能跑服务器跑不了的情况,想想就让人头疼。

使用docker部署就不需要再为环境考虑了,还支持版本管理,并且还有docker-compose等编排工具提供多容器的统一管理。使用docker部署仅需三步:

  1. 打包镜像
  2. 发布镜像
  3. 拉取镜像并执行

下面就以一个前端Vue项目为例,用 Github Actoin 来实现docker的自动部署流程。

编写Dockerfile

首先要为项目编写Dockerfile,前端通常使用nginx进行部署:

bash 复制代码
FROM node:18.20-alpine3.21 as build-stage

WORKDIR /app

COPY package.json .

# 配置npm和pnpm
RUN npm config set registry https://registry.npmmirror.com/
RUN npm install pnpm -g
RUN pnpm config set registry https://registry.npmmirror.com/
RUN pnpm install

COPY . .

RUN pnpm build

# production stage
FROM nginx:stable as production-stage

COPY --from=build-stage /app/dist /usr/share/nginx/html

EXPOSE 443

CMD ["nginx", "-g", "daemon off;"]

这里采用分阶段打包,只需要将dist打进镜像,放入到nginx的资源目录下,暴露443端口(如果不是https就配置80端口)并设置nginx启动指令。Dockerfile的编写很简单,直接交给GPT生成即可。

编写发布docker脚本(可选)

镜像仓库的地址可能会比较长,所以打包、发布的指令也会很长,写个shell脚本自动执行这两个步骤比较省事:

bash 复制代码
# 先构建镜像并打标签
docker build -t registry.xxx.com/xxx/xxx:latest . || {
  echo "Docker构建失败"
  exit 1
}

# 检查镜像是否存在
docker images | grep registry.xxx.com/xxx/xxx:latest || {
  echo "构建的镜像不存在"
  exit 1
}

# 推送镜像
docker push registry.xxx.com/xxx/xxx:latest || {
  echo "Docker推送失败"
  exit 1
}

仓库地址替换为最终要上传的镜像仓库地址,例如dockerhub或阿里云镜像仓库等。

编写workflow

要触发github action只需要在项目根目录下 .github/workflows 文件夹里添加对应的流程配置文件,这里我们添加一个deploy.yml配置:

yml 复制代码
name: Deploy Frontend to Server

on:
  push:
    branches:
      - release # 当代码推送到 release 分支时触发

jobs:
  build-and-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest # 使用最新的 Ubuntu Runner
    steps:
      - name: Checkout code
        uses: actions/checkout@v4 # 检出你的代码

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3 # 设置 Docker Buildx 以便构建镜像

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: registry.xxx.com # 你的镜像仓库地址
          username: ${{ secrets.DOCKER_USERNAME }} # 从 GitHub Secrets 读取 Docker 用户名
          password: ${{ secrets.DOCKER_PASSWORD }} # 从 GitHub Secrets 读取 Docker 密码

      - name: Build and push Docker image using deploy.sh
        run: |
          chmod +x ./deploy.sh # 赋予 deploy.sh 执行权限
          ./deploy.sh # 执行构建和推送脚本
        shell: bash # 指定使用 bash shell

  deploy-remote:
    name: Deploy to Remote Server
    runs-on: ubuntu-latest
    needs: build-and-push # 依赖于 build-and-push 任务成功完成
    steps:
      - name: Deploy to Remote Server via SSH
        uses: appleboy/ssh-action@master # 使用社区提供的 SSH Action
        with:
          host: ${{ secrets.REMOTE_HOST }} # 从 GitHub Secrets 读取远程服务器 IP 或主机名
          username: ${{ secrets.REMOTE_USER }} # 从 GitHub Secrets 读取远程服务器登录用户名
          key: ${{ secrets.SSH_PRIVATE_KEY }} # 从 GitHub Secrets 读取 SSH 私钥
          script: |
            echo "Connecting to remote server..."
            # 进入 docker-compose.yml 文件所在的目录
            cd /root/deploy
            echo "Pulling latest image..."
            docker-compose pull frontend || { echo "Docker Compose pull failed"; exit 1; }
            echo "Starting container..."
            docker-compose up -d --no-deps frontend || { echo "Docker Compose up failed"; exit 1; }
            echo "Deployment successful!"

示例中使用docker-compose管理前后端docker服务,需要配置docker-compose.yml。也可以直接使用docker管理单个容器。

例如私钥、密码等重要信息不要明文写在配置中,github action提供secrets变量存储,将重要信息保存在这里,通过secrets访问:

ssl登录服务器有两种方式,可以通过密码登录,也可以通过密钥登录。推荐使用密钥登录,明文保存密码不太安全。

密钥登录需要通过ssh-keygen生成一个密钥对,公钥存放到服务 ~/.ssh/authorized_keys 文件中(一行一个密钥),没有这个文件就自己创建一个,私钥就存放在secrets中。这个配置是不是似曾相识,其实就是本地与github通讯配置的ssh key,所以这里可以复用已有的ssh key,将公钥 ~/.ssh/id_dsa.pub 内容复制到上面提到的authorized_keys文件中,私钥 ~/.ssh/id_dsa 内容复制粘贴到secrets.SSH_PRIVATE_KEY中即可。

到这里配置就结束了,提交点内容到release分支测试下,看对应的工作流是否跑通。

相关推荐
不想上班只想要钱1 小时前
vue3使用<el-date-picker分别设置开始时间和结束时间时,设置开始时间晚于当前时间,开始时间早于结束时间,结束时间晚于开始时间
前端·javascript
Li_Ning212 小时前
为什么 Vite 速度比 Webpack 快?
前端·webpack·node.js
2501_915373882 小时前
Electron 入门指南
前端·javascript·electron
同志327133 小时前
用HTML+CSS做了一个网易云音乐客户端首页
前端·css
小猪欧巴哟3 小时前
pnpm install 安装项目依赖遇到 illegal operation on a directory, symlink 问题
前端·vue.js
独角仙梦境3 小时前
🚀🚀🚀学习这个思路,你也能手撸自己的专属vip脚手架🚀🚀🚀
前端
关山3 小时前
在TS中如何在子进程中动态实例化一个类
前端
吃瓜群众i3 小时前
兼容IE8浏览器的8个实用知识点
前端·javascript
前端烨3 小时前
vue3子传父——v-model辅助值传递
前端·vue3·组件传值