65.9K
CodeProject 正在变化。 阅读更多。
Home

通过 GitHub Actions 构建和部署 Jekyll 站点

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2020 年 5 月 3 日

CPOL

5分钟阅读

viewsIcon

5108

如何通过 GitHub Actions 构建和部署 Jekyll 站点

到目前为止,我的博客的源代码一直在 Bitbucket 上,每次提交,网站都会使用 Jekyll 构建,然后通过 rsync over SSH 部署到我的 webspace,这一切都通过 Bitbucket Pipelines 完成。

最近,我将仓库迁移到了 GitHub… 因为它是一个 Mercurial 仓库,而 Bitbucket 将在几周后停止支持 Mercurial。我决定将仓库迁移到 GitHub,并学习如何在 GitHub Actions 中设置相同的构建/部署流程。

与上一篇文章 中解释了我如何使用 Bitbucket Pipelines 设置此功能 类似,这篇是我希望我能拥有的教程。

我已经拥有的

构建和部署此网站的“逻辑”大部分已经包含在两个 shell 脚本中。流程如下:

  • ci-build.sh (源代码)
    • 在 CI 服务器上运行
    • 执行 Jekyll 构建网站(并期望在已预先安装好 Jekyll 的环境中运行!)。
    • 将结果保存到 .tar.gz 归档文件。
  • CI 服务器通过 rsync over SSH 将归档文件复制到我 webspace 上的一个 temp 文件夹。
  • ci-deploy.sh (源代码)
    • 由 CI 服务器 **通过 SSH 直接在我 webspace 上执行(而不是在 CI 服务器上!)**
    • 将归档文件解压到另一个 temp 文件夹,然后使用 rsync 将其同步到我的域名指向的文件夹。

有关更详细的解释(以及脚本中解释每行代码的注释版本),请阅读 第一篇文章

shell 脚本的存在是为了让我可以在切换 CI 提供商时重用它们…因此,在迁移到 GitHub Actions 时,我无需更改它们,只需要替换“调用”脚本的提供商特定配置文件。

现有的 Bitbucket 的 YAML 文件 非常直接

步骤 1:使用 jekyll/builder Docker 镜像 运行 ci-build.sh,并将 build 目录保存为 artifact。

步骤 2:使用 rsync 将步骤 1 中的 artifact 同步到 webserver 并执行 ci-deploy.sh

两部分都很简短,因为 Bitbucket Pipelines 在后台处理了很多底层工作。

  • 对于 Docker,我只需要提供镜像名称。
  • 对于 SSH,我无需进行任何设置,只需在 Bitbucket 的 UI 中保存我的密钥即可——所有其他工作都将在后台自动完成。

使用 GitHub Actions 创建相同功能

最终,我成功了——但与 Bitbucket Pipelines 相比,在 GitHub Actions 中执行相同的步骤感觉“不够完善”(稍后会详细介绍)。

a) 构建 Jekyll 网站

这相当直接,除了 GH Actions 不允许你像这样指定任何 Docker 镜像的名称来执行构建……只有“默认”的 Windows/Linux/Mac 虚拟机可用。

我不想手动编写脚本在那个机器上安装 Jekyll,所以我搜索了 jekyll/builder Docker 镜像的示例,并在 GH Actions 的 starter workflows 仓库 中找到了解决方案。

steps:
- uses: actions/checkout@v2
- name: Build the site in the jekyll/builder container
  run: |
    docker run \
    -v $:/srv/jekyll -v $/_site:/srv/jekyll/_site \
    jekyll/builder:latest /bin/bash -c "chmod 777 /srv/jekyll && jekyll build --future"

我只需要添加对 ci-build.sh 的调用并选择正确的 Jekyll 版本,所以我将 docker run 行修改如下:

  run: |
    docker run \
    -v $:/srv/jekyll -v $/_site:/srv/jekyll/_site \
    jekyll/builder:3.2.1 /bin/bash -c "chmod +x ci-build.sh && ./ci-build.sh"

(注意:3.2.1 是我正确的 Jekyll 版本,因为它与我在 Windows 机器上本地使用的便携式 Jekyll 版本匹配,请参阅 第一篇文章 中的说明。)

这看起来比它的 Bitbucket 对等项复杂一点……但另一方面,我无需自己想出这个调用,这两种情况(Bitbucket 和 GitHub)我都是复制粘贴的结果。

b) 通过 SSH 连接到我的服务器并进行部署

这花费了我很长时间,也让我非常沮丧。我不是 SSH 专家,正如上面提到的,Bitbucket Pipelines “保护”了我免受大部分复杂性的影响,尤其是在构建机器上正确设置密钥。

对于 GH Actions,社区制作了许多 用于 执行 SSH 操作

我尝试了所有这些,但都无法正常工作,总是收到“Host key verification failed”错误。

最后,我 找到了这个解决方案

- name: "Prepare SSH key and known hosts"
  run: |
    mkdir -p ~/.ssh
    echo "$" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan github.com >> ~/.ssh/known_hosts
    ssh-keyscan git.eu.s5y.io >> ~/.ssh/known_hosts

我尝试过其他类似的“手动”解决方案,它们将密钥保存在文件中并执行 ssh-keyscan……但语法和/或命令总是略有不同,这个解决方案最终对我起作用了。以下是我基于此修改的步骤:

- name: "Prepare SSH key and known hosts"
  run: |
    mkdir -p ~/.ssh
    echo "$" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan $ >> ~/.ssh/known_hosts
- name: Run deploy script
  run: |
    rsync -rSlh --stats build/ $@$:$/tar
    ssh -o StrictHostKeyChecking=yes $@$ 'bash -s' -- < build/ci-deploy.sh $

当然,一些变量必须保存在仓库的 secrets 中(https://github.com/USER/REPO/settings/secrets)。

secrets

  • KEY:我的私有 SSH 密钥
  • HOSTchristianspecht.de (所以实际上,它不是秘密…)
  • USERNAME:我 webspace 上的 SSH 用户名
  • WEBPATH:webspace 上的完整路径,类似于 /www/htdocs/MY_ACCOUNT_NAME/blog

完整解决方案

就是这样——这是 完整工作的 ci.yml 文件

name: Jekyll site CI

on:
  push:
    branches:    
      - master   

jobs:
  build_job:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Build site
      run: |
        docker run \
        -v $:/srv/jekyll -v $/_site:/srv/jekyll/_site \
        jekyll/builder:3.2.1 /bin/bash -c "chmod +x ci-build.sh && ./ci-build.sh"
    - name: Upload artifact
      uses: actions/upload-artifact@v1
      with:
        name: build
        path: build
        
  deploy:
    runs-on: ubuntu-latest
    needs: build_job
    steps:
    - uses: actions/download-artifact@v1
      with:
        name: build
    - name: "Prepare SSH key and known hosts"
      # https://github.com/symfony/cli/issues/227#issuecomment-601680974
      run: |
        mkdir -p ~/.ssh
        echo "$" > ~/.ssh/id_rsa
        chmod 600 ~/.ssh/id_rsa
        ssh-keyscan $ >> ~/.ssh/known_hosts
    - name: Run deploy script
      run: |
        rsync -rSlh --stats build/ $@$:$/tar
        ssh -o StrictHostKeyChecking=yes $@$ 'bash -s' -- < build/ci-deploy.sh $

在一切都工作正常后,我决定在网站页脚添加一行“Built from commit xyz with build number 123”。

从 Jekyll 的角度来看,这很简单。它就是:

  • 在主 _config.yml 中为 commit id 添加一个新的站点变量(带有虚拟值),并在网站的某个地方显示其内容。
  • 在构建时,动态创建一个额外的 _config-github.yml 文件,其中包含实际的 commit ID,并将其传递给 Jekyll 调用(放在原始配置文件之后),这样 commit ID 就会覆盖主配置文件中的值。
  • 实际的 commit ID 来自构建运行程序设置的环境变量。对于 GitHub Actions,它是 $GITHUB_SHA,其中包含 commit ID

这是包含这些更改的提交——但它并没有按预期工作。构建成功了,但最终网站上的 commit ID 为空。

事实证明,罪魁祸首是我在 Docker 容器中运行构建。实际的 GitHub Actions “runner”(运行整个 action 的虚拟 Ubuntu 机器)知道环境变量,但它不会自动将它们传递给我使用的 Docker 容器(该容器实际构建 Jekyll 网站)。

解决方案是在我执行 Docker 的那一行中,将变量直接传递给 ci-build.sh

© . All rights reserved.