---
layout: "@/layouts/BlogPostLayout.astro"
title: "利用Gitea actions创建项目部署的自动化流程"
description: "本文以部署一个前端项目为示例，手把手教你如何利用Gitea actions创建项目部署的自动化流程，对于不想使用Jenkins的小伙伴来说，Gitea actions是一个不错的CI/CD解决方案。"
date: "2023-12-15"
image: "https://images.unsplash.com/photo-1607799279861-4dd421887fb3?q=80&w=1470&auto=format&fit=crop"
tags: ["Gitea", "Actions", "CI/CD", "自动化部署"]
tagId: ["gitea", "actions", "cicd", "automation-deployment"]
category: "DevOps"
categoryId: "devops"
readTime: "10 min read"
---
本文以部署一个前端项目为示例，将手把手教你如何利用Gitea actions创建项目部署的自动化流程，对于不想使用Jenkins的小伙伴来说，Gitea actions是一个不错的`CI/CD`解决方案。

<!-- truncate -->

## 前言
在我们开发完一个项目后，需要将项目部署到服务器上，以便于用户可以访问。但是，每次部署都需要手动操作，这会浪费我们的时间和精力。因此，我们可以利用Gitea actions创建一个自动化流程，以便于我们快速部署项目。

## 什么是Gitea actions
Gitea actions是Gitea的一个功能，它允许我们创建自动化流程，以便于我们快速部署项目。Gitea actions可以执行各种任务，例如构建、测试、部署等。Gitea actions可以使用各种编程语言和工具，例如Python、Java、Docker等。并且Gitea actions在配置上尽量与GitHub actions的配置兼容，因此，如果你已经熟悉了GitHub actions，那么你也可以轻松地使用Gitea actions。
详见官方文档：[Gitea actions](https://docs.gitea.com/zh-cn/usage/actions/overview)

## 准备工作
在我们开始创建此流程前，首先你需要准备以下资料：
1. 一台服务器,最好拥有root权限（会安装一些工具）
2. 一个已部署的Gitea仓库,版本至少需要>=`v1.19`，官方强烈建议使用`v1.20`或更高版本
3. docker环境（非必须, 用在部署runner的主机上）

> ps: 作者这里服务器准备的是：一台打包服务器 + 一台部署（目标）服务器， 你可以只用一台服务器，但注意环境的隔离

请在进行后续步骤前，确保已完成所有的准备工作，具体的安装配置，请参考官方文档，这里我不会再赘述。[安装](https://docs.gitea.com/zh-cn/category/installation)

如果你使用**1panel面板**，可直接在应用商店中一键完成安装，作者就就是使用此方式。

>注意：在版本 < `v1.21.0`之前的版本，需要在配置文件中，开启`actions`功能，具体请参考官方文档[配置](https://docs.gitea.com/zh-cn/usage/actions/quickstart),之后的版本则是默认开启。

本教程使用的Gitea版本为`v1.22.6` !


## 配置Runner
在Gitea actions中，运行Job，都是通过Runner来执行的，因此，我们需要先配置Runner，以便于我们后续的部署流程。有两种安装方式，可直接安装到主机上，也可以通过docker容器中，这里作者将通过docker安装，为避免过多的资源消耗，可以将其安装到一个单独的主机中（ps：对于国内用户，可以选择一台香港服务器，这样运行job的速度会更快😄）, 作者选择的主机就是一台香港的VPS

### 下载act_Runner

首先我们需要下载此工具，用来注册或者生成配置[下载地址](https://gitea.com/gitea/act_runner/releases)，请在此页面中选择与你的系统对应的版本进行下载，下载完成后，上传到服务器中，这里我是上传到了服务器中的`/gitea_runner2`目录下。也可以使用`curl`等工具直接下载, 可直接使用以下命令，但注意名称和下载地址，我的系统是`Debain12 x86_64`,因此下载的是`act_runner-0.2.11-linux-amd64`。

```bash
curl -o act_runner2 https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
```
完成后，设置下执行权限
```bash
chmod +x act_runner2 # 注意文件名,请根据实际情况修改

./act_runner --version # 看到版本信息就代表成功了
```
### 生成配置
```
./act_runner2 generate-config > config.yaml
```
一般情况下默认的配置就够了，如果你有其他的需求请自行修改`config.yaml`。

**由于作者选用docker安装的方式，所以如果你选用直接在主机安装的方式，可以跳过后续的安装步骤，参考官方文档进行安装[直接安装](https://docs.gitea.com/zh-cn/usage/actions/quickstart)**

### 注册runner

这里我选择通过`docker-compose.yml`配置的方式进行注册

**注意： 将配置中的参数结合你自己的情况修改，以下配置仅供参考！！！**

```yaml
version: "3.8"
services:
  runner:
    image: gitea/act_runner:latest
    environment:
      CONFIG_FILE: /config.yaml
      GITEA_INSTANCE_URL: "<your_gitea.com>"
      GITEA_RUNNER_REGISTRATION_TOKEN: "<your_registration_token_here>"
      GITEA_RUNNER_NAME: "act_vps_runner2"
      GITEA_RUNNER_LABELS: "act_vps_runner2"
    volumes:
      - /gitea_runner2/config.yaml:/config.yaml
      - /gitea_runner2/runner_data/data:/data
      - /gitea_runner2/runner_data/cache:/root/.cache
      - /var/run/docker.sock:/var/run/docker.sock
```
### 配置说明

**GITEA_RUNNER_REGISTRATION_TOKEN** 此参数为注册令牌，需要从你的gitea中进行获取，一共有三个级别，我这里直接选用组织级别的，在组织设置页中进行获取，如下图所示：
![image](https://pic1.imgdb.cn/item/6779f8dfd0e0a243d4ef14ab.png)

其他的实例配置页面及说明请参考官方文档，有详细的说明

**如果您无法看到设置页面，请确保您具有正确的权限并且已启用 Actions, 检查Gitea版本 !!!**

### 运行并生成runner

由于作者使用1panel面板，因此直接在容器选项中编排即可，如果你没有使用此类的可视化工具，就需要手动执行``docker-compose up -d``

成功后，可查看容器的运行以及日志，日志中会显示注册成功的信息，如下图所示：

![image](https://pic1.imgdb.cn/item/677893b5d0e0a243d4eeccca.png)
![image](https://pic1.imgdb.cn/item/677893bad0e0a243d4eecccb.png)

然后我们回到你获取runner令牌的页面，进行刷新就能看到你的runner了，如下图所示：
![image](https://pic1.imgdb.cn/item/6779f844d0e0a243d4ef1478.png)
图中的名称是根据你注册配置时的名称

> 至此，我们的runner部署就算完成了，接下来可以去在项目中使用了。

## 使用actions

gitea actions的使用方式与github actions类似，如果你不熟悉这类配置，可以先去了解下**github actions**,
作者将使用一个`vitepress`项目作为示例

### 创建配置文件
1. 在项目根目录下创建`.gitea/workflows`目录
2. 在其目录中创建`deploy.yaml`配置文件
3. 我们先写个测试配置，用于测试环境变量，如下所示：
```yaml
name: Deploy Test

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Print Environment Variables
        run: env

      - name: Print Current Directory
        run: pwd

      - name: List Files in Working Directory
        run: ls -la
```
然后提交代码到仓库，我们应该就可以在仓库的actions中看到执行任务了，如下图所示:
![image](https://pic1.imgdb.cn/item/6779f972d0e0a243d4ef14da.png)

> **ps：如果你没有看到actions执行，甚至没看到actions这个选项，可能需要你在仓库、组织或管理页面中开启actions选项**
### 配置打包
我们修改`deploy.yaml`配置文件，添加打包步骤, 我这里使用的是pnpm，请根据自己的实际情况调整一些配置，这里不过多展开

````yaml
name: Deploy docs for project
run-name: ${{ gitea.actor }} is building out Gitea Actions 🚀
on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x]
    steps:
      # TODO 临时解决 https://github.com/go-gitea/gitea/issues/32481, 等待gitea发布1.23.0进行修复
      - name: Install git
        run: |
          if ! command -v git &> /dev/null; then
            apt-get update && apt-get install -y git
          else
            echo "git is already installed"
          fi

      - name: Checkout repository code
        uses: https://gitea.com/actions/checkout@v4
        with:
          ref: 'main'

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      # Skip pnpm cache to reduce overhead
      - name: Install pnpm
        run: |
          if ! command -v pnpm &> /dev/null; then
            npm install -g pnpm@9
          else
            echo "pnpm is already installed"
          fi

      - name: Check Node.js and pnpm versions
        run: |
          echo "pnpm version ===>" && pnpm -v
          echo "node version ===>" && node -v

      # Simplify node_modules handling without caching
      - name: Install dependencies
        run: |
          if [ ! -d "node_modules" ] || [ "$(find package.json -newer node_modules)" ]; then
            echo "Dependencies are outdated or missing, installing..."
            pnpm install
          else
            echo "Dependencies are up-to-date, skipping installation."
          fi

      - name: Build docs
        run: pnpm run docs:build
````

> **特意说明：安装git是为了修复目前gitea actions中无法通过`actions/checkout`检出代码的问题，此问题预计会在`v1.23.0`中修复，目前我们只能这样处理, 但据作者的观察发现好像与使用的镜像版本也有关系，如果是`ubuntu-latest`好像就不用安装，请以实际情况为准**

如果一切顺利，那么你应该可以看到工作流中完成了打包任务，如图所示
![image](https://pic1.imgdb.cn/item/677bcf9bd0e0a243d4f00c7a.png)

### 部署项目

部署代码的原理，实际上是通过`ssh`的方式连接到目标服务器并执行部署脚本，因此我们需要先配置好SSH，然后使用`actions` [easingthemes/ssh-deploy](https://github.com/easingthemes/ssh-deploy) 连接到目标服务器并推送代码即可

#### 配置SSH
这一步骤实际上是为服务器配置一个用户并支持`SSH`登录，也就是免密登录，因此我们在**目标服务器**依次使用以下命令，作者使用的`Debian 12`，请根据实际情况调整命令！

##### 创建用户(建议创建一个操作部署目录的用户，不要使用root用户！！！)
```bash
sudo adduser deployuser # 请根据自己实际情况修改用户名
```
创建成功后，可以查看是否存在`/home/deployuser`目录，不存在则可能需要手动创建

##### 创建密钥对
我们需要先将用户切换到`deployuser`用户下，然后执行以下命令
```bash
# 1. 创建公私钥
ssh-keygen -t rsa -b 4096 -C ""
# 将公钥内容添加到 authorized_keys 文件
echo ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# 设置正确的权限
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
```
##### 赋予特定目录的读写权限（可跳过）
这里需要`root`权限的用户操作
```bash
# 1. 创建目录
mkdir -p /var/www/html/project
# 2. 修改目录权限
sudo chown deployuser:deployuser /var/www/project
sudo chmod 700 /var/www/project
```
由于作者这里使用了`1panel`进行管理网站所以目录就是自动生成的目录，与此有所出入，但流程步骤一致，请根据自己实际情况修改

#### 在gitea中配置密钥信息

1. 在你的gitea的个人、组织或管理的actions页面中，点击`密钥`，将我们刚刚在服务器中生成的私钥复制到`密钥`中，然后点击`添加密钥`即可
2. 因为后续我们需要用到服务器IP、用户名，这里也建议配置到密钥或变量中，方便后续使用。

作者这里，将私钥、服务器IP、用户名配置到了密钥中，如图所示
![image](https://pic1.imgdb.cn/item/677bd9c0d0e0a243d4f011f2.png)

到这里我们就完成了部署项目所需要的配置了，接下来我们就可以开始部署流程了。

> ps：由于`easingthemes/ssh-deploy`需要使用`rsync`执行脚本命令，所以在镜像容器中或者目标服务器都需要依赖此工具，如果不存在，就需要提前安装好，特别是**目标服务器**, 一般需要用root用户或者有安装权限的用户操作

### 项目部署

我们在`deploy.yml`中，添加以下代码,注意格式！！！

````yaml
      - name: ssh deploy
        uses: easingthemes/ssh-deploy@v5.1.0
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SH_SSH_PRIVATE_KEY }}
          REMOTE_HOST: ${{ secrets.SH_REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.SH_REMOTE_USER }}
          SOURCE: "/.vitepress/dist/"
          TARGET: "/1Panel/1panel/apps/openresty/openresty/www/sites/demo.zhaoguiyang.cn/index/dist" # 请根据实际情况修改为你的部署目录
          EXCLUDE: "/node_modules/"
````
如果一切顺利的话，你就会看到actions执行成功，并且在你的部署目录下，有一个dist目录存在了，如下图所示：
![image](https://pic1.imgdb.cn/item/677bdd23d0e0a243d4f014a3.png)
![image](https://pic1.imgdb.cn/item/677bdd1bd0e0a243d4f014a1.png)

接下来，你就只需要使用`nginx`之类的工具指向此目录，就可以访问了。

> ps: 如果你在上面这个步骤出现了错误，请仔细查看错误日志，根据作者的经验来说，大概率是出现在ssh密钥和权限处理的这两个问题上，如果你使用的不是`ubuntu-latest`,那你可能还需根据报错信息，安装一些必须的工具，如:`git`、`rsync`等


### 完整配置

````yaml
name: Deploy docs for project
run-name: ${{ gitea.actor }} is building out Gitea Actions 🚀
on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x]
    steps:
      - name: Checkout repository code
        uses: https://gitea.com/actions/checkout@v4
        with:
          ref: 'main'

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      # Skip pnpm cache to reduce overhead
      - name: Install pnpm
        run: |
          if ! command -v pnpm &> /dev/null; then
            npm install -g pnpm@9
          else
            echo "pnpm is already installed"
          fi

      - name: Check Node.js and pnpm versions
        run: |
          echo "pnpm version ===>" && pnpm -v
          echo "node version ===>" && node -v

      # Simplify node_modules handling without caching
      - name: Install dependencies
        run: |
          if [ ! -d "node_modules" ] || [ "$(find package.json -newer node_modules)" ]; then
            echo "Dependencies are outdated or missing, installing..."
            pnpm install
          else
            echo "Dependencies are up-to-date, skipping installation."
          fi

      - name: Build docs
        run: pnpm run docs:build

      - name: ssh deploy
        uses: easingthemes/ssh-deploy@v5.1.0
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SH_SSH_PRIVATE_KEY }}
          REMOTE_HOST: ${{ secrets.SH_REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.SH_REMOTE_USER }}
          SOURCE: "/.vitepress/dist/"
          TARGET: "/1Panel/1panel/apps/openresty/openresty/www/sites/demo.zhaoguiyang.cn/index/dist" # 请根据实际情况修改为你的部署目录
          EXCLUDE: "/node_modules/"

````

