面倒くさい作業をCircleCIに押し付けたお話

三日坊主のにょろんです。

昨日から引き続きブログの改善に一日を使っています。

1日1本ペースで記事を書けるほどのネタはないので、とりあえずGitHubのContributionが緑っぽく見えるように何か続けていきたい所存です。

今日は面倒くさくてサボりがちな、ブログのデプロイ作業をCircleCIに押し付けます。

何が面倒か

突然ですが、このブログはAWS上に置いています。そしてAWSアカウントの利用料は僕のお財布から抜かれていきます。

AWS最大のメリットである「使った分だけ請求」は、逆に言うと「無駄なリソースはすべてお財布へのダメージ」となります。1

「ブログは自動生成してるんだからそんなにムダもないでしょ」という感じもします。しかし、テーマによっては無駄にCSSやらJSをローカルに持っていたり、無駄な空行があったり、コメントがやたらくっついていたりします。

新しい記事を書いてページを生成するたびに、それらのファイルを削除したり、エディタで開いて改行を全部消したり、特定の記述を置換していたりすると、また心が折れてブログを放置…なんてことになります。

ということで、心が折れそうな面倒な作業(Minifying)のすべてとデプロイをCircleCIに押し付けます。

CircleCIってなんぞや

継続的インテグレーション(CI)を簡単に、しかもむちゃくちゃ強力に支援してくれるサービスです。

要は、みんなが大嫌いなテスト作業とかデプロイ作業を、コードが更新されるたびに自動的にやってくれます。

CircleCIには結構いろいろな設定がデフォルトで入っているので、WebUIからの設定だけで終わったり、そうでなければcircle.ymlを数十行ちょちょいと書くだけでCIできます。

ちなみに無料。有料プランもあるけど使いみちがまだみえn(ry

アカウント作るだけ作って、GitHubと連携するだけして放置すると、中の人から「大丈夫?設定手伝ったほうが良い?」というメールが飛んできたりします。その優しさに涙が出そう。

この記事では登録方法とか細かい使い方とかの説明はしませんが、その辺に関しては中の人の優しさが溢れている公式ドキュメントをご覧ください。

さっそく作業を押し付ける

CircleCIに登録して、プロジェクトの設定を済ませて、特にエラーもなく(テストがないから赤いけど)↓のような感じにビルドが済むようであれば、やらせたい作業をcircle.ymlに書くお時間です。

CircleCI build result

出来上がったcircle.ymlこちらになります。リポジトリのルートディレクトリに置いてください。

ここから下は作ったcircle.ymlの解説をしていきます。

何となくタイムゾーン設定

machine:
  timezone: Asia/Tokyo

Hugoがどのように日時を扱うのかは知りませんが、とりあえず日本に住んでいるのでタイムゾーンを設定します。

「タイムゾーンの一覧はこの辺を見ると良いよ」って公式ドキュメントに書いてありました。

存在をよく忘れるsubmodules

checkout:
  post:
    - git submodule sync
    - git submodule update --init --recursive

僕はHugoのテーマをgit submodule addで追加したので、上記の記述が必要になります。これを忘れるとビルドが終わっても寂しい見た目になるので気をつけましょう。

テーマの説明通りにインストール(git cloneを使う方)した場合は必要ありません。

必要なソフトウェアをインストール

dependencies:
  pre:
    - go get -v github.com/spf13/hugo github.com/tdewolff/minify/cmd/minify
    - sudo pip install awscli

今回はHugoでページを生成して、生成されたものをMinifyしたいので、HugoMinifyのコマンドライン版をインストールします。

あと、生成したページをS3にデプロイしたいので、AWS CLIを入れておきます。

ステータスが赤いとなんか許せない

test:
  override:
    - hugo

上記の記述で、Hugoを使ってページを生成します。

test:配下に入れなくても良いような気もしますが、テストが何もないとビルド結果が黄色とか赤色になりそうなのでここに入れました。

overrideにしたのはCircleCIが用意してくれてるテストが別に必要ないからです。てへぺろ。

どこまで押し付けるかはアナタ次第

deployment:
    production:
        branch: master
        commands:
            - rm -rf ./public/js ./public/fonts
            - ls -d ./public/css/* | grep -v -E 'phlat.css$' | xargs rm -r
            - minify -v -a -r --html-keep-document-tags --match '\.(htm|html)$' -o ./public/ ./public
            - minify -v -a -r --match '\.xml$' -o ./public/ ./public
            - minify -v -a -r --match '\.css$' -o ./public/ ./public
            - aws s3 sync ./public/ s3://${s3_bucket}/ --delete --region ${aws_region}

ここが本体。デプロイ処理の内容を記述します。

production:はラベルみたいなものです。名前はなんでもいいですが、同じ名前を2回以上使うことはできません。

branch:にGitのブランチ名を指定することで「productionではこのブランチを使うぜ!」的なことを指定します。今回はmasterです。記事を書いたりブログいじったりするのは今のところ一人ですし。

commands:には処理をどんどん書いていきます。

  • 1-2行目: 余分なファイルの削除
  • 3-5行目: Minifyで処理するところ
  • 6行目: S3へファイルをデプロイ

6行目を見るとわかりますが、環境変数を利用することが出来ます。

Environment variables

これを使うことでS3のバケット名が変わったり、リージョンが変わったりしても、CircleCIの設定画面から対応できます。

また、CircleCIの設定画面にAWSのアクセスキーを設定することで、AWSへのアクセス周りをいろいろ良い感じに処理してくれます。

AWS access keys

環境変数もアクセスキーも、上記の画像のように自動的にマスキングしてくれるのでスクリーンショットを撮るときや、複数人でCircleCIを利用する際は非常に助かりますねー。2

ついでに$ twitter "なんかつぶやく内容"みたいなコマンドを作ってデプロイ処理に挟めば、「ブログの更新情報をTwitterでつぶやく」という作業もCircleCIに押し付けられますね。

しかもリアルタイム。夢が広がる。

あとはブログを書きまくるだけ

以上で設定は終わりです。

hugo new post/[ファイル名].mdしてページを作成し、

Create new post

お気に入りのエディタを使って記事をMarkdownでゴリゴリと書いて、

Writing article

書き終わったらgit add git commit git pushするだけで、

Add article to GitHub

CircleCIがビルドとMinifyingとデプロイをやってくれて、

CircleCI building

ブログが更新されます。

Blog updated

これは捗りますわ…。やべぇ…やべぇ…。

おまけ

今回の頑張りのおかげで、ページ表示速度は結構いいスコアがでます。

PageSpeed Insights Result

たのしい。ごっさ楽しい。

追記: 2016/11/20

この記事を書いたあとにちょうどAWS CLIが更新されたためか、AWS CLIのインストールに失敗するようになってしまいました。

ということで、CircleCI上でちゃんとAWS CLIをインストールできるようにcircle.yml更新しました

本来、依存している外部ツールのバージョンは設定ファイル等々で明示的に指定しておいて、更新については定期的に自分で確認すべきです。

  1. 外部依存しているツールの更新履歴を確認する
  2. アップデートした状態ですべての要素が正しく動くことを確認
    (または、アップデートがなかったことにする)
  3. 動作確認が終わってからCIツール上で使うように変更

が、そんな運用を守れるわけもなく、手順2で後回しにした結果放置されることが目に見えているので、毎回最新にするようにしています。

ビルドがコケたときだけ確認すればいいやーってスタイルです。

そうすれば、

  1. ビルドがコケると困るので速攻で直すようになる
  2. 依存関係は常に最新
  3. 後方互換がなくなったときの変更が結果的に少なくなる

…となるんじゃないかなって妄想してます。


  1. GitHub Pagesに置けばタダじゃね?というツッコミはなしの方向で [return]
  2. とはいえ、SSHすると覗けるんじゃないかな [return]