GitHub Actionsで始めるお手軽Jamstack

先日、2020年1月30日に行われたイベント「JAMSTACK Meetup #1 with microCMS」で「GitHub Actionsで始めるお手軽Jamstack」というお題でLTを行ってきましたのでスライドと喋った内容を補足として解説したいと思います。

今回のお題はJamstackのデプロイ方法について、直前のセッションでもJamstackのデプロイ方法にはついては色々と語られていたので、LTではお手軽に始められるデプロイ方法について紹介しようと思いました。

デプロイ方法の前にデプロイについてざっくり簡単に説明します。

コードなどを修正してGitなどのリポジトリーにpushするとCIなどがコンテナなどを立ち上げて git clonenpm cinpm run buildなどを行い最終成果物のHTMLやCSS / JSなどを作成してホスティングサーバーに反映させる行為をdepolyといいます。(厳密ではなく超ざっくりとした説明として

Jamstackに限らずSPAやSSRなどでもこのフローは取られるのですが、Jamstackだとフロントエンドエンジニアがデプロイフローの構築まで担当することが多いように感じます。

よく使われるGitサービスにはGitHubGitLabBitbucketBacklogのGitなどがありますね。

よく使われるCIサービスでは、みんな大好きCircleCIや最近あまり見かけなくなりましたがJenkinsなどがあるかと思います。

GitHubGitLabは最近は独自にCI機能を内包するようになりました。会社としてはGitLabをよく使いますが今回はGitHubのお話をしようと考えております。

AWSやCGPを利用している場合はCodeDeployやColudBuildといった機能をGitHubなどと連携させてデプロイすることも可能です(もう少し細かい機能を連携させてなのですがそこの説明は割愛)。使ったことないけどMicrosoft Azureでもなんかあるんじゃないかと思います。

Jamstack文脈ですとNetlifyがよく登場しますね。ホスティングからCI、ヘッドレスCMS機能にフォーム送信までオールマイティーでカバーする優秀なサービスです。このサービスを利用している場合は今回の記事は読まななくて良いでしょう。本メディアでも別の記事で「Gatsby と Netlify で Jamstack 構成のブログサイトを作ろう」というのが投稿されているのでそちらを読んでください。

最近はZEITなんかの利用例もよく見かけますね。

ホスティング先は色々とありますね。こういったデプロイを前提としたホスティング先を利用している場合はデプロイフローの構築は難しくありません。SSHが利用できるサーバーでしたらrcyncやSCPを利用したデプロイも検討することができます。

ここらへんは慣れていない人だとどのツールを使うべきか、どう組み合わせるべきか色々と悩むことも多いと思います。

そして何より小さい案件だとホスティングの自由度等もなくどのようにデプロイするかわからずに諦めてがちです。

小さい案件だとデプロイ先のホスティングがftpでしか上げれないなんかもよくあります。

ただし、Jamstackでは最終的に出力されるのはHTML/CSS/JSなどの静的ファイルなのでデプロイ先に縛られることはないはず。

むしろ、ただのお知らせを出力するなどのほうが既存のページに組み込みやすくお手軽に始められるのではないか?

簡単なお知らせ出力のためにわざわざCMSなどを導入するのは煩わしいし、使い慣れたJavaScriptで出力できるツールを使いたい人も多いはず。

前置きが長くなりましたが、GitHub Actionsを使ってプッシュされたコードをFTPでアップする方法についてご紹介します。

GitHubでは.gitHub/workflows/xxxx.ymlとファイルを設置することでGitHub Actionsのワークフローを定義することができます。

name: Deploy master

on:
 repository_dispatch:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js 10.16.3
        uses: actions/setup-node@v1
        with:
          node-version: "10.16.3"
      - name: npm install, build
        run: |
          npm ci
          npm run build --if-present
        env:
          CI: true

      - name: FTP-Deploy-Action
        uses: SamKirkland/FTP-Deploy-Action@2.0.0 # FTPを使ってサーバーにDeployするアクションを実行
        env: # FTP環境の設定を行う
          FTP_SERVER: ${{ secrets.FTP_SERVER }} # FTPサーバーのURLを設定
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }} # FTPのユーザー名を設定
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} # FTPのパスワードを設定
          LOCAL_DIR: public # どのディレクトリのデータをアップロードするか
          REMOTE_DIR: / # リモートのどのディレクトリにアップロードするか
          ARGS: --delete --parallel=20 -x media

詳しい説明は省きますが、これはGitHubのリポジトリのmasterにプッシュされた際にコンテナを用意して、最新のリポジトリをチェックアウトしてnpm ciとnpm run buildを実行するワークフローです。

26行目らのFTP-Depoly-ActionがポイントでGitHub Actionsでは既に用意されているアクションを読み込んで利用することができ、FTP系ではSamKirkland/FTP-Deploy-Actionが一番良く使われているアクションです。

ポイントはARGSの設定でオフィシャルのドキュメントには深く言及されていませんが、こちらにはlftpのオプションパラメーターを渡すことができます。

今回は

  • — delete 指定したディレクトリの内容を空にしてからアップロードする
  • –parallel=20 20ファイルを並列でアップロードする
  • -x 削除する際に除外するディレクトリを指定する

と行った設定を行っています。parallelの数でアップロード時間が劇的に変わってきてデフォルトの–parallel=1だと40分ほどかかったアップロードが–parallel=20だと数分で終わるようになります。

GitHub Actionsは実行時間課金のため実行時間は極力短くなるように調整するのがよいでしょう。(無料のリポジトリだと月間2,000分までは無料で以降はコンテナの種類によって値段が変わりますが課金されていきます)

FTP情報などはyml内に記述せずにSecretsで管理するとよいでしょう。そうするとFTP情報を教えなくてもプッシュ権限があるアカウントのみがデプロイ可能で作業がおわれば権限を外せばよいだけなので外部パートナーとの連携も楽になります。

デプロイされるブランチにprotectionを設定しておきPR以外の直接のpushなどを防いでおくと予期せぬタイミングでのデプロイなどを防ぐことができます。

Jamstackではデプロイのタイミングはpush時つまりソースコードの更新のタイミングだけでなくヘッドレスCMSで記事の投稿や更新された場合にも必要になってきます。

ポイントはonに設定しているrepository_dispatch。こちらを設定しておくと外部から直接 webhookを使ってワークフローを実行することができます。

ただ、webhookの叩き方がちょっと複雑でこちらを直接叩いてくれるヘッドレスCMSはほとんどありません。シンプルなURLを叩いてくれるやつがほとんどです。(セミナー後の懇親会でmicroCMSさんはGitHub ActionsのWebhookの機能との連携は検討してくれるとのことでした。)
2020/3/18 追記: microCMSさんがGitHub ActionsへのWebhook通知に対応しました

他のCIなどを入れて叩くこともできますがちょっとお手軽とは言いにくいですね。。

FTPで上げるサーバーがサーバーサイドのスクリプトを利用できればお手軽にシンプルなURLでwebhookに連携させることも可能です。

次のコードを利用するとPHPを利用してwebhookを直接叩くことができます。

<?php
exec('curl \
-H "Authorization: token {個人設定よりアクセストークンを取得} \
-H "Accept: application/vnd.github.everest-preview+json" \
"https://api.github.com/repos/{アカウント}/{リポジトリ名}/dispatches" \
-d \'{"event_type": "build"}\'’);

上記のファイルはなるべく第三者のわかりにくいURLにして配置してください。トークン内容が含まれるのでGitなどでは管理しないほうがよいでしょう。

またセッション後に質問を頂いたのですがアップロード中は一瞬サイトが表示されなくなるやデプロイに失敗した場合は再度デプロイが必要になるなど安定度という点では他のデプロイ方法より劣ってしまうのはで注意してください。

ただ、この方法ですとロリポップさくらのレンタルサーバーなどのお手軽サーバーでもJamstackの導入が可能になりますのでちょっと試して見る分にはよいでしょう。

それでは素晴らしいJamstackライフを

ご清聴ありがとうございました。