GitHub ActionsでホームページのCIを確立した


話題の旬を逃していますが、GitHub Actionsに入門しhttps://e-yuuki.orgの継続的インテグレーション(CI)を確立させることができました。非常に便利な反面、GitHub/Microsoftによるベンダーロックインがさらに加速し、インフラストラクチャがますます秘匿される時代になったのだなとも思い知らされました。

  1. GitHub Actionsとは
  2. 事例: e-yuuki.org
    1. いままでのデプロイ手順
    2. GitHub Actions導入によるデプロイ自動化
  3. ロックインへの危機感
  4. おわりに

GitHub Actionsとは

GitHub ActionsGitHub, Inc.が提供しているCIサービスです。オンプレミスで動かすCIサービスはBuildbotJenkinsといったFLOSSが著名です。しかしCIサービスは必ずしもオンプレミスで稼働させるものではなく、Travis CICircleCIのようにサービス提供者がホスティングしているサーバを使うものもあります。GitHub Actionsは後者のサービスです。Windows Server・Ubuntu・macOSをGitHub, Inc.がホスティングしているサーバ上で仮想マシンとして動かし、アクションとして定義されているDockerコンテナやJavaScriptを実行できます。

僕が使ってみたかぎり、GitHub Actionsは以下の点で優れています。

要するにGitHubのエコシステム内で開発からデプロイまでを完結できるようになったということです。

事例: e-yuuki.org

ここではGitHub Actionsを導入する前後で記事執筆がどう変わったかを紹介します。

記事を執筆するうえで次の4つの手順を踏んでいました。

  1. HTMLで書く
  2. textlintで日本語を校正する
  3. Nu Html CheckerでHTMLを検査する
  4. Webサーバへデプロイする

いままでのデプロイ手順

日本語校正とHTMLの検査は.git/hooks/pre-commitにスクリプトを書きローカルで実行していました。上記の2と3にあたります。次にgit pushしたあと手動でWebサーバにログインし、git pullでGitHubのリポジトリから修正を取ってきていました。これは上記の4にあたります。

GitHub Actionsを知るまではこの手順でも特に不便を感じていませんでした。ただし、問題点がないわけではありませんでした。

第一にデプロイを忘れることがたびたびありました。手動でやる以上忘れるのは当然と言えます。第二に、textlintはnpmからインストールするためどんな環境でもnpmさえインストールできれば動かせました。しかしNu Html CheckerはOpenJDKを使って手元でビルドする必要があります。執筆環境が変わるたびに毎回OpenJDKをインストールしてビルドするのは面倒でした。

一時期はBuildbotを使ってHTML検査とデプロイの自動化を試みたこともありますが、リポジトリへのpushをトリガーにビルドが走るよう設定できず、高機能なcronとして使わざるをえなかった経緯もあります。

GitHub Actions導入によるデプロイ自動化

GitHub Actionsならpushした時点でなにかを処理できます。まずはSSHを使ってデプロイだけでもできないものかとアクションを調べていると、Install SSH keyアクションを見つけました。これは秘密鍵・公開鍵・known_hosts・ssh_configをGitHubリポジトリのSecretsとして登録しておくことで、コンテナの~/.sshにそれをインストールしてくれるアクションです。秘密鍵はPEM形式で登録しないとエラーになる点だけ注意すれば特に問題なく利用できました。これでデプロイを忘れる問題は解消されました。

次にHTMLの検査もしたいと思い調べると、HTML5 Validator Actionを見つけました。これはNu Html Checkerを実行してくれるアクションです。これで環境ごとにビルドが必要な問題も解消できたわけです。

最終的に、以下のようにワークフローを書いてHTMLの検査とデプロイを自動化させました。ワークフローはGitHubのWebコンソールから作るか、リポジトリの.github/workflows/main.ymlに書きます。ファイル名は任意で大丈夫らしいですが、ディレクトリ名は.github/workflows固定です。

name: CI

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Validate HTML5
        uses: Cyb3r-Jak3/html5validator-action@v0.1
        with:
          root: .
      - name: Install SSH Key for Deploy
        uses: shimataro/ssh-key-action@v1
        with:
          private-key: ${{ secrets.SSH_KEY }}
          public-key: ${{ secrets.SSH_KEY_PUBLIC }}
          known-hosts: ${{ secrets.KNOWN_HOSTS }}
          config: ${{ secrets.SSH_CONFIG  }}
      - name: Deploy to e-yuuki.org
        run: ssh e-yuuki.org "cd www && git pull"

このファイルがある状態でgit pushをすると、ソースコードのチェックアウトからデプロイまでがUbuntu上で自動的に実行されます。

CI

結果どうなったか?どんな些細なことでも自動化できると気持ちよいものです。ブログでテキストボックスに文章を書いて「投稿」ボタンを押すのと同じ感覚で、文章をテキストエディタで書いてgit pushできるようになりました。

ロックインへの危機感

すばらしい体験を享受したはいいものの、FLOSSに携わる者としてGitHub, Inc.とそれを買収したMicrosoftという巨大な中央集権のロックインは気になるところです。これまでオンプレミスでBuildbotやJenkinsを動かしてきた経験からするとあまりにもGitHub Actionsは便利すぎるところがあります(BuildbotやJenkinsを上手に扱えられなかっただけかもしれませんが)。生産的なのは間違いないのですが、それと引き換えになにを失いなにが制限されるのかを、現場へ導入するときに検討してみる必要があります。

またGitHub Actionsはインフラを隠し「アクション」としてより高い抽象度のサービスを提供している点が「うまい」と感じました。なにかしらのサービスを使うにはこのパッケージをインストールしてこういう設定をして……というような時代はGitHub Actions登場以前に終わり少数勢力となっています。代わりにコンテナがそれを秘匿し、ユーザはサービスだけを受け取るようになったのです。しかしGitHub Actionsは「アクション」でそれをもう一段高いレイヤーに押し上げたのではないでしょうか。もはやコンテナが動いているのかJavaScriptが動いているのか意識することなく、単にマーケットプレイスから好きなサービスを選ぶだけでよくなりました。

おわりに

GitHub Actionsで簡単にCIを導入できました。GitHubでブログ記事やWebサービスのソースコードを管理している方にとって、GitHub Actionsはlintからデプロイまでを簡単に自動化できる優れものです。

反面、ロックインやプロプライエタリなサービス(GitHub自体そうですが)をなるべく避けたい方は注意が必要でしょう。