惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
Docker
酷 壳 – CoolShell
酷 壳 – CoolShell
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
美团技术团队
量子位
M
MIT News - Artificial intelligence
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
小众软件
小众软件
博客园 - 司徒正美
罗磊的独立博客
云风的 BLOG
云风的 BLOG
B
Blog RSS Feed
博客园 - 聂微东

Mikuの极光星

用 Codex 写了一个 Noctalia 插件 Process Reporter | Mikuの极光星 荣耀 X16 锐龙版(2024)运行 Linux 问题和修复 | Mikuの极光星 Noctalia Plugin Linuxwallpaperengine | Mikuの极光星 Love Love School Days 在 Linux 下游戏汉化补丁安装使用 | Mikuの极光星 Fedora Silverblue 安装记录和不可变 Linux 个人杂谈 | Mikuの极光星 国内外主流对象存储价格对比 | Mikuの极光星 随笔:逝去的一段时光 | Mikuの极光星 Riddle Joker:剧情不足,人设也不足 | Mikuの极光星 在 CachyOS Handheld 下恢复 Steam Input 中文输入 | Mikuの极光星 Fedora Cosmic desktop Beta 一日游 | Mikuの极光星 博客~真周年随笔(大概是一周年) | Mikuの极光星 Waline-Mini 部署体验:基于 Rust 的 Waline 评论系统? | Mikuの极光星 迟来的个人对《拔作岛》第一部游戏动漫杂谈 | Mikuの极光星 OtterWiki 部署:基于 Python 的轻量知识库系统 | Mikuの极光星 Mikuの极光星 Mikuの极光星 Mikuの极光星 Mikuの极光星 Mikuの极光星 我的 KDE Plasma 6 美化方案分享 | Mikuの极光星 Mikuの极光星 自建一个 Fediverse 实例,我们需要准备什么? | Mikuの极光星 Decky Loader——Linux下 Steamdeck 和大屏幕模式的最佳伴侣 | Mikuの极光星 更换网站字体为霞鹜文楷屏幕阅读版(LXGW WenKai Screen) | Mikuの极光星 《Clannad》HD 官方中文版和 Full Voice 汉化版 Linux 运行 | Mikuの极光星 《恋爱与选举与巧克力》携带版试玩体验 | Mikuの极光星 我又用了一段时间 Misskey,发现和 Sharkey 存在一些区别和不足 | Mikuの极光星 Misskey/Sharkey 工具栏:强大且精心的小功能 | Mikuの极光星 浅谈个人与 Fediverse 的过往历史和现状 | Mikuの极光星 《爱上火车》在 Linux 下的视频播放修复 | Mikuの极光星
GitHub Action 构建 Shiroi Docker 镜像 | Mikuの极光星
Mikuの鬆, admin@sotkg.com · 2024-10-21 · via Mikuの极光星

前言

Mix-Space 是一个前后端分离的博客系统,你可以将前端和后端分别部署在不同的位置。此前,你可以将前端部署在 Vercel 云函数上,以缓解服务器压力并提升访问速度。

但随着 Vercel 调整 Hobby 免费套餐的额度,免费额度已越来越不够用。此时,我们可以通过 Docker 将 Shiro 部署到自己的服务器上来解决问题。然而,在使用 Shiroi(Shiro 的闭源捐赠版)时,原作者 innei 并未提供可用的 Docker 镜像。

这意味着你需要在自己的服务器上构建 Shiroi,但对于配置较低(低于 2G 内存)的云服务器来说,这很困难,基本会导致服务器爆内存假死。

Innei 给出的解决方案是使用 Github Action 完成构建,并将构建产物直接推送到你的服务器上,从而减轻服务器压力。

不过,这个方案在我看来有以下局限性:

  • 需要在服务器安装相关依赖:Node.js、PM2、Sharp,但部分用户(比如我)使用的是 1Panel 管理服务器,不希望安装额外依赖
  • 输出目录被固定在服务器的 root 目录,不易更改
  • 需要在 Github 仓库存储服务器登录信息,如 SSH 密钥等
  • 项目本身有回滚功能,但一般用户可能不需要,也会占用大量服务器空间

总之,我并不想折腾这套方案。那么,有没有更好的办法?

欸,你说 Docker 部署不就行了?虽然 Innei 没给 Docker 镜像,但我们可以自己造!

思路

我们当然不能直接在自己的服务器上构建镜像,构建 Docker 镜像的资源占用并不会比直接构建站点静态文件少。

那我们可以借鉴 innei 的思路,用 Github Action 进行 Docker 镜像构建,不就可以了吗?

但仅仅构建还不够,还需要有地方存放镜像。我也不想用直接推送到服务器的办法,这同样需要在 Github 存储服务器登录信息。虽然用 secret 存储理论上安全,但谁能保证呢?

而且部分用户的服务器在国内,Github Action 主动推送的速度也未必理想。

选择

最终,我选择用 Github Action 构建镜像,然后上传到 Github Packages。Github Packages 默认会对私有库镜像进行私有保护,保障镜像不会泄露。

Docker 对镜像仓库的管理分为 3 个层级:命名空间(namespace)、镜像仓库(repository)、标签(tag):

  • 命名空间以名称为标识,一个命名空间可管理多个镜像仓库
  • 镜像仓库通过名称标识,一个仓库可保存一个镜像的多个版本
  • 镜像版本通过标签区分

基于以上层级关系,一个完整的镜像路径 {namespace}/{repository}:{tag} 可以唯一确定一个镜像。

新建一个私有库,并在 .github/workflows 目录下新建 yml 工作流文件,填入如下内容:

yaml
name: Docker Build

on:
  push:
    branches:
      - main
  schedule:
    - cron: '0 3 * * *'

  repository_dispatch:
    types: [trigger-workflow]

permissions: write-all
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  PNPM_VERSION: 9.x.x
  HASH_FILE: build_hash

jobs:
  prepare:
    name: Prepare
    runs-on: ubuntu-latest
    if: ${{ github.event.head_commit.message != 'Update hash file' }}

    outputs:
      hash_content: ${{ steps.read_hash.outputs.hash_content }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Read HASH_FILE content
        id: read_hash
        run: |
          content=$(cat ${{ env.HASH_FILE }}) || true
          echo "hash_content=$content" >> "$GITHUB_OUTPUT"
  check:
    name: Check Should Rebuild
    runs-on: ubuntu-latest
    needs: prepare
    outputs:
      canceled: ${{ steps.use_content.outputs.canceled }}

    steps:
      - uses: actions/checkout@v4
        with:
          repository: innei-dev/shiroi
          token: ${{ secrets.GH_PAT }}
          fetch-depth: 0
          lfs: true

      - name: Use content from prev job and compare
        id: use_content
        env:
          FILE_HASH: ${{ needs.prepare.outputs.hash_content }}
        run: |
          file_hash=$FILE_HASH
          current_hash=$(git rev-parse --short HEAD)
          echo "File Hash: $file_hash"
          echo "Current Git Hash: $current_hash"
          if [ "$file_hash" == "$current_hash" ]; then
            echo "Hashes match. Stopping workflow."
            echo "canceled=true" >> $GITHUB_OUTPUT
          else
            echo "Hashes do not match. Continuing workflow."
          fi

  build:
    name: Build artifact
    runs-on: ubuntu-latest
    needs: check
    if: ${{needs.check.outputs.canceled != 'true'}}

    outputs:
      sha_short: ${{ steps.store.outputs.sha_short }}
      branch: ${{ steps.store.outputs.branch }}

    steps:
      - uses: actions/checkout@v4
        with:
          repository: innei-dev/shiroi
          token: ${{ secrets.GH_PAT }}
          fetch-depth: 0
          lfs: true

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build Docker Image
        run: |
          docker build -t ghcr.io/${{ secrets.DOCKER_NAMESPACE }}/shiroi:latest .

      - name: Push Docker Image to Github
        run: |
          docker push ghcr.io/${{ secrets.DOCKER_NAMESPACE }}/shiroi:latest

      - name: Store artifact commit version
        shell: bash
        id: store
        run: |
          sha_short=$(git rev-parse --short HEAD)
          branch_name=$(git rev-parse --abbrev-ref HEAD)
          echo "sha_short=$sha_short" >> "$GITHUB_OUTPUT"
          echo "branch=$branch_name" >> "$GITHUB_OUTPUT"
  store:
    name: Store artifact commit version
    runs-on: ubuntu-latest
    needs: [build]
    steps:

      - name: Checkout
        uses: actions/checkout@v4
        with:
          persist-credentials: false
          fetch-depth: 0

      - name: Use outputs from build
        env:
          SHA_SHORT: ${{ needs.build.outputs.sha_short }}
          BRANCH: ${{ needs.build.outputs.branch }}
        run: |
          echo "SHA Short from build: $SHA_SHORT"
          echo "Branch from build: $BRANCH"

      - name: Write hash to file
        env:
          SHA_SHORT: ${{ needs.build.outputs.sha_short }}

        run: |
          echo "SHA_SHORT: $SHA_SHORT"
          echo $SHA_SHORT > ${{ env.HASH_FILE }}

      - name: Commit files
        run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add ${{ env.HASH_FILE }}
          git status
          git commit -a -m "Update hash file"

      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}

这样就可以实现简单的构建并上传 Github Registry 镜像。你需要在仓库的 secret 设置中配置以下机密变量:

  • GH_PAT:有权限访问 Shiroi 仓库的 Github Access Token
  • DOCKER_NAMESPACE:镜像命名空间,全部小写,建议用个人 Github 用户名

由于 Github Action 的限制,仓库 3 个月无活动时,工作流会被禁用。 @innei

我们采用 innei 的办法,每次构建结束后上传一个存储哈希值的文件,保持仓库活跃。同时,构建前对仓库哈希值进行对比,避免重复构建。

参考上述修改环境 secret 后,运行工作流(注意先开启仓库设置中 Github Action 写入文件的权限),即可生成哈希值文件并构建镜像。

使用

保存工作流文件,等待运行完毕后,你应该可以在仓库侧边栏的 Packages 或个人 Github 主页的 Package 里找到镜像文件。

在服务器上拉取镜像前,需要先配置 Docker 私有仓库。注意,Gitea 实例必须为 HTTPS 地址,否则 Docker 会拒绝拉取不安全的私有仓库。

在服务器上输入以下指令登录 Github Registry 私有仓库:

bash
docker login ghcr.io

输入账号和有访问权限的 Github Access Token,确认登录后即可拉取私有仓库镜像。如果你用的是 1Panel,可以在容器仓库设置中直接配置私有仓库。

你也可以用如下 compose 文件配置安装 Shiroi:

yaml
services:
  shiro:
    container_name: Shiroi
    image:
    restart: always
    environment:
      - NEXT_SHARP_PATH=/usr/local/lib/node_modules/sharp
      - NEXT_PUBLIC_API_URL=https://api.example.com/api/v2
      - NEXT_PUBLIC_GATEWAY_URL=https://api.example.com
    ports:
      - 127.0.0.1:2323:2323
    networks:
      - mx-network

image 填写你在软件包仓库看到的容器镜像信息。

后话

这样你就算是简单完成了,本文本质上偏专业系,而非喂饭文。

如有疑问,欢迎在评论区提问或结合搜索引擎查阅本文。