HakyllブログをCircleCIつかってNetlifyにデプロイするための設定

静的サイトジェネレーターであるHakyllを使ってブログを構築しました. NetlifyにはCD(継続的デプロイ)の機能がありますが, Haskellには標準対応してないみたいです. ならば外部のCIサービスを利用するしかないわけですが, CircleCIを採用しました. 本記事ではHakyllブログをNetlifyにデプロイするためのCircleCIの設定を解説します.

本記事はこちらの記事を参考にさせてもらいました. この記事さまさまです.

ではやっていきましょう.

前提

lts-12.26の環境でHakyllブログを構築していることを前提とします. lts-13台にはhakyllが含まれていないため, lts-12台の暫定最新版であるlts-12.26を使っていくことにします. CircleCIで使うDockerイメージもこのスナップショットに合わせて作ってあります.

また, Netlifyには既にHakyllリポジトリに紐付けられたサイトが登録されているものとします. サイト固有のAPI IDを後で使うので, ここまでは終わらせておきましょう.

あとは当然のことですが, CircleCIへの登録も済ませておきましょう.

CircleCIにリポジトリを登録

CircleCIにログインしたあとのページの左のカラムから, 「ADD PROJECTS」をクリックします. 自分のリポジトリが一覧になっているので, Hakyllブログのリポジトリを「Set Up Project」しましょう.

下のほうにある「Start building」をクリックします. するとビルドは失敗します. 当たり前ですね. なぜなら設定ファイルを追加していないからです.

どうしてわざわざビルドを失敗させたのかというと, プロジェクトの設定画面へ行くためです. 一度でもビルドを試みたことがあるリポジトリしか, 個別の設定画面へは行けない仕様になっているようです. ここは改善してほしいところですね…

環境変数の設定

左のカラムから「JOBS」を選択します. さきほどビルドを失敗させたおかげで, Hakyllブログのリポジトリ名が表示されているはずです. その隣にある歯車マークをクリックしましょう.

「Environment variables」へ進みます. 「Add Variable」から, 新たな環境変数を追加することができます.

設定すべき環境変数は以下の2つです.

  • NETLIFY_AUTH_TOKEN
  • NETLIFY_SITE_ID

前者はNetlifyのチーム(私の場合はGitHubに登録した本名になっています)に紐付いたもので, 後者はサイトに紐付いたものです.

NETLIFY_AUTH_TOKENはOAuth applicationsから追加できます(詳しくはこちら).

NETLIFY_SITE_IDはSite settingsのAPI IDです(詳しくはこちら).

これら2つをCircleCIの環境変数へと追加しましょう.

CircleCI用の設定ファイル

あとやることは設定ファイルを追加するだけです.

Hakyllブログのプロジェクトルートに.circleciというディレクトリを作成し, その中に設定ファイルを作成します. 私の設定ファイルをほとんどそのまま利用できるので, プロジェクトルートで以下を実行してもらうのが早いと思います.

$ curl -o .circleci/config.yml --create-dirs https://raw.githubusercontent.com/logicoffee/sharpknock/master/.circleci/config.yml

こんな設定ファイルが作成されるかと思います.

version: 2
jobs:
  build:
    docker:
      - image: logicoffee/hakyll_netlify:lts-12.16
    steps:
      - checkout
      - restore_cache:
          name: Restore Cached Dependencies
          keys:
            - stack-{{ .Branch }}-{{ checksum  "stack.yaml" }}
            - stack-{{ .Branch }}-
            - stack-
      - run:
          name: Resolve Dependencies
          command: stack build --dependencies-only
      - save_cache:
          name: Cache Dependencies
          key: stack-{{ .Branch }}-{{ checksum "stack.yaml" }}
          paths:
            - ~/.stack
            - ./.stack-work
      - run:
          name: Build Site App
          command: stack build --pedantic
      - run:
          name: Generate Static Site
          command: stack exec [command name] build ### ここを修正!
      - run:
          name: Publish to Netlify
          command: netlify deploy --dir=_site --prod

修正すべき点は下のほうにあるサイトのビルドコマンド名です. 上のcurlコマンドでコピーした場合, ビルドコマンド名はこのブログの名前であるsharpknockになっています. これをcabalファイルのexcutableの欄に書かれているものに修正しておいてください.

設定ファイルが用意できたらgit commitしてgit pushしましょう. すると自動的にビルドが開始されるはずです. 最初は多少時間がかかるかもしれません. これでデプロイが済んでるはずですがどうでしょうか? うまくいかなかった場合はエラーメッセージを見て個別に対応していくしかないでしょう.

config.yml解説

最後に上のファイルにはなにが書かれているのかを解説しておきます. 設定を修正する際に参考にしてください.

もっと詳しく知りたい場合は公式ドキュメントを参照してください.

version

CircleCIのバージョンです.

jobs

ビルドやデプロイなどの一連の流れをjobと呼んでいます.

build

これはjobの名前です. 自分で好きに決められます. もし複数のjobを定義する場合は重複してはなりません.

docker

CircleCIにはexecuterという概念が存在します. 簡単に言うと「各ステップを行う場所」のことです. executerは3種類あります.

  • docker
  • machine
  • macos

2つめのmachineというのはLinuxのVirtual Machineのことみたいですね. 詳しくはこちらを参照してください.

ここではDockerを使いたいので, Dockerイメージとともにdockerを指定しています. 指定されたDockerイメージは私が作ったものです.

steps

ひとつのjobをいくつかのステップに分けることができます. たくさんのコマンドで1つのステップにすることもできますし, 1つのコマンドで1つのステップにすることもできます. 各ステップには名前をつけることができるので, 自分が分かりやすいようにしておけば良いでしょう.

checkout

これは特別に用意されたステップです. git checkoutと同じ感じですね. Working directoryがプロジェクトルートに移動するだけです.

restore_cache, save_cache

CircleCIではビルドやデプロイの時間を短縮するためにキャッシュを使っています. save_cacheまでのステップがキャッシュされ, 次回のビルドに利用されます. restore_cacheのタイミングで, 前回のビルドのキャッシュを利用します.

run

各コマンドを実行しています.

さいごに

もっといろいろ最適化できそうな感じがします. とくにビルドキャッシュのところ. Dockerイメージも普通のHaskellのやつでもいいのかなあ…? Haskellの難しさのひとつが情報の少なさですね.