オープンソースのPaaSソフトウェア CloudFoundry の技術情報やイベント告知などを掲載します

2015-10-28

Hugo を Cloud Foundry で動かす

「Cloud Foundry 百日行」第88日目,今日は3回シリーズ「静的サイト・ジェネレーター」の2日目, Golang ベースで高速性が特徴の Hugo です。

基本情報

手順の概要は以下の通りです。

  • 1) 静的サイトのサンプルの取得
  • 2) Cloud Foundry 向けの修正/カスタマイズ
  • 3) Cloud Foundry へのデプロイ
  • 4) 動作確認
  • 5) まとめ

1. 静的サイトのサンプルの取得

前回 の Jekyll 同様,Cloud Foundry にデプロイするサイトのサンプルとして,百日行シリーズの最初の2つの記事を使います。

サンプルは GitHub に置いてあるので,試してみられる方は以下の手順で clone してください。このリポジトリーはテーマのリポジトリーを submodule として持つので,clone の際に --recursive が必要です。

$ git clone --recursive https://github.com/nota-ja/cf-hugo-example.git
..
$ cd cf-hugo-example/

2. Cloud Foundry 向けの修正/カスタマイズ

今回のデプロイでは,heroku-buildpack-hugo を使います。この buildpack を使えば,通常はほとんど何もしなくても Hugo でサイトを生成して serve することができるはず,なのですが,今回は以下の理由で修正/カスタマイズを行いました。

  1. heroku-builcpack-hugo の bin/ 下のスクリプトに実行権が付与されていないためステージングに失敗する
    → buildpack を修正して実行権を付与
  2. サイトを Python の Web サーバーではなく Hugo 自身で serve させたい
    → buildpack の release スクリプトをカスタマイズ
  3. Golang の net/url の問題でパスの先頭に // がある URL リダイレクトが正常に機能しない
    → テーマのコード内のパスを修正

2.1. スクリプトに実行権を付与

今回使用する heroku-buildpack-hugo では, bin/ 下の3つのスクリプト (detect, compile, release) に実行権が付いていません。 Heroku ではこれで問題ないのかもしれませんが(未確認),(少なくとも今回利用した) Cloud Foundry 環境では BuildpackCompileFailed というエラーが出てステージングに失敗するので,実行権を付与します。

$ chmod a+x bin/*

2.2. サイトを Hugo で serve

オリジナルの heroku-buildpack-hugo では,生成したサイトを Python の Web サーバーで serve するようになっています。

https://github.com/roperzh/heroku-buildpack-hugo/blob/b678e649e9b8d0529a9f65525ad1946b5a1cca42/bin/release#L6

  web: "cd public && python -m SimpleHTTPServer \$PORT"

しかし,せっかくシンプルだが高性能な Web サーバー である hugo があるのに,それを使わない手はありません。ということで,ここを hugo server を使うように書き換えます。ついでに,baseUrl と theme をそれぞれ環境変数 HUGO_BASE_URL, HUGO_THEME から取得するようにしました。

https://github.com/nota-ja/heroku-buildpack-hugo/commit/d155fbccdd2cdb87ce18fd83f74ca0f73471a194

 cat << EOF
 ---
 default_process_types:
-  web: "cd public && python -m SimpleHTTPServer \$PORT"
+  web: "./hugo server --baseUrl=\$HUGO_BASE_URL --bind=0.0.0.0 --port=\$PORT --appendPort=false --log=true --theme=\$HUGO_THEME"
 EOF

2.3. テーマのコード内のパスを修正

Golang の net/url に存在する問題 により,Golang で書いたプログラムでは,パス部分の先頭に // がある URL が正常に解釈されません。 Cloud Foundry の Gorouter もその影響を受ける ため,該当 URL のリダイレクトに失敗します。

本質的な解決は Golang 自体の修正を待つしかないので,workaround として URL に // が含まれないよう,該当箇所を修正することにしました。調査の結果,該当箇所は,今回 Hugo のテーマとして使っている material-design 内にあることがわかったので,そこを全て修正しました。

具体的な修正内容については以下の URL をご覧ください (修正箇所が多く,かつ単純なので,ここに記載するよりリンク先を見ていただいた方が良いと判断しました)。

https://github.com/nota-ja/material-design/commit/4c96e2b868ca938855ab39f0747a4ae0c20ffb33

2.4. その他 optional だが利便性向上のためのカスタマイズ

.cfignore の追加

不要なファイルが Cloud Foundry にアップロードされるのを避けるため,cfignore を追加しました。

$ cat .cfignore
/public
*~
.*~

manifest.yml の追加

今回,push前/push時の設定が多い (buidlpack 及び環境変数 HUGO_BASE_URL, HUGO_THEME) ので,manifest.yml にまとめました。

$ cat manifest.yml
---
applications:
  - name: hugo-example
    domain: 10.244.0.34.xip.io
    buildpack: "https://github.com/nota-ja/heroku-buildpack-hugo.git#cf-100-day-challenge-088"
    env:
      HUGO_BASE_URL: http://hugo-example.10.244.0.34.xip.io
      HUGO_THEME: material-design

3. Cloud Foundry へのデプロイ

以上で準備が整ったので,Cloud Foundry にデプロイします。manifest.yml があるので, cf push だけで OK です。

$ cf push
Using manifest file /home/nota-ja/repos/cf-hugo-example/manifest.yml

Creating app hugo-example in org nota-ja / space prod as nota-ja...
OK
..
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: hugo-example.10.244.0.34.xip.io
last uploaded: Tue Oct 27 18:42:13 UTC 2015
stack: cflinuxfs2

     state     since                    cpu    memory        disk      details
#0   running   2015-10-28 03:42:32 AM   0.0%   30M of 256M   0 of 1G

起動しました。メモリはデフォルトの 256MB のままにしていますが,減らしても良さそうです。

4. 動作確認

ブラウザーでアクセスしてみた時のトップ画面はこんな感じです:

各ページを表示させてみます:

画像も表示されていることを確認しました:

以上で動作確認は終わりです。

5. まとめ

「静的サイト・ジェネレーター」シリーズ第2弾,今回は Hugo サイトを生成&表示してみました。

本記事では heroku-buildpack-hugo をカスタマイズし, hugo 自身を使ってサイトを serveしました。カスタマイズの結果,ステージング時と起動時の2回,サイトのビルドが行われることになってしまいました。Hugo はサイトのビルドが非常に高速なので,起動時のビルド自体は問題ないと考えているのですが,ステージング時に無駄にビルドしているのが少し気になっています。気が向いたらその辺の修正を行うかもしれませんが,今回はここまでとしたいと思います。

今回使用したソフトウェア