MiddlemanのVPSへのデプロイにWerckerを使ってみた
自動化のきっかけのようなもの
去年11月末頃、OctpressからMiddlemanに移行したのだけど、昨日サーバの整理をしているときにブログの状況をチェックしてみると、一部リンクが見れなかった…。その修正ついでに自動化もやってしまおうと思い立ち、その状況を記録してメモ代わりに。
いざやろうとしてググったりしたけど、MiddlemanとWerckerを使ったデプロイはS3へのアップロードかgithub-pagesへばかりがヒットして、普通のVPSなどのサーバへのデプロイ方法については、検索条件をいろいろ変えてみても見当たらない。旬な方法ではないのだろうな、とは思ってもVPSへのデプロイで調整してみました。
TL;DR
wercker.ymlは最終的に下記のようになった。
box: ruby
build:
steps:
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman build
code: bundle exec middleman build
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
deploy:
steps:
- install-packages:
packages: rsync
- add-ssh-key:
keyname: DEPLOYKEY
host: blog.d6rkaiz.com
- add-to-known_hosts:
hostname: blog.d6rkaiz.com
fingerprint: 83:05:1c:2b:c9:c9:f0:c0:22:72:ac:1a:ce:1e:d9:63
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman deploy
code: bundle exec middleman deploy
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
デプロイする際のsshの鍵を登録するステップとknownhostsに登録するステップがちょっと冗長に見えるのと、rsyncのインストールが必要だったという点くらいで、非常にスッキリとしている。 そのあたりを含め少し詳しく書いていく。
まずビルド
Werckerにログインし、Create から Application を選択し、ウィザードに従いセットアップを続けると、 wercker.yml のテンプレートが出てくるので、それをコピーしてファイルを作成し、最初のビルド実行だけの状態にしたのが下記。
box: ruby
build:
steps:
- bundle-install
- script:
name: middleman build
code: bundle exec middleman build
このファイルをMasterブランチのルートに配置して、 git push。
そうしたら ExecJS で下記のようなエラー。
Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
今は therubyracer の方がパフォーマンスが良いとのことなので、Gemfileに下記を追加。
# execjs
gem "therubyracer"
そして git push すると成功した。
ついでにslackにも通知してやろうということで、werckerの設定の Environment variables にSlackのWebhook URLをSLACK_URL
として保存し、wercker.yml に下記を追加。
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
これでビルド部分は終了。 だけど bundle install
がえらく遅い。bundleは、v1.4.0.preから並列実行できるようになっているので、werckerでのオプションを調べたところ、ここにレポジトリがあった。
Optionsにjobsを見つけたので、下記のように変更。
box: ruby
build:
steps:
- bundle-install:
jobs: 4
- script:
name: middleman build
code: bundle exec middleman build
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
実行してみると、下記のようなエラーが出ていた。(ビルド自体は成功していたが、並列実行はされていなかった)
run.sh: line 47: [: false: integer expression expected
エラー箇所はこの部分。ちゃんとオプションは渡っているのだけど、渡し方が間違っているようだ。整数として渡っていないようなので、wercker側の設定で環境変数BUNDLEJOBSとして保存して、下記のようにしてみた。
box: ruby
build:
steps:
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman build
code: bundle exec middleman build
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
結果、実行logを確認すると下記のように反映された。
...
Gemfile found. Start bundle install.
bundler gem is available, and will not be installed by this step
type bundle: bundle is /usr/local/bundle/bin/bundle
bundle version: Bundler version 1.10.5
bundle install --path /cache/bundle-install/ --jobs=4
...
めでたしめでたしと思って実行時間を見てみると、2分30秒前後だったのが2分10秒くらいに縮まってた。あまり変わってない気もするけど、20秒も違うのなら良いかもしれない。実行仮想環境(Docker)でのプロセス数が幾つか見てないので、このあたりはあとで要調整。
次にデプロイ設定
wercker.ymlに下記を追加。
deploy:
steps:
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman deploy
code: bundle exec middleman deploy
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
werckerからVPSにログインできるように、まずはwerckerでSSHの鍵を作成。
作成手順は
- Application settings の SSH keys からGenerate new key pair をクリック
- キーを作成し、名前を付けて保存
自分の場合は単純に werckerkey とした。作成したキーの公開鍵をVPSサーバにデプロイするユーザの ~/.ssh/authorized_keys
に保存。 そしてこの鍵をwerckerのデプロイプロセスで使えるようにするために、環境変数として下記のように設定。
- Environment variables で、Add new variableをクリック
- SSH Key pair から先ほど保存したキーのwerckerkeyを選択し、環境変数名を付けて保存
ここでも単純に DEPLOYKEY とした。
次にSSHの秘密鍵指定のための設定を、こちらのブログを参考に下記の通りwercker.ymlに追加。
- script:
name: make .ssh directory
code: mkdir -p "$HOME/.ssh"
- create-file:
name: write ssh key
filename: $HOME/.ssh/id_rsa
overwrite: true
hide-from-log: true
content: $DEPLOYKEY_PRIVATE
- script:
name: set permissions for ssh key
code: chmod 0400 $HOME/.ssh/id_rsa
また、werckerのSSHのドキュメントから下記を追加。
- add-ssh-key:
keyname: DEPLOYKEY
host: blog.d6rkaiz.com
- add-to-known_hosts:
hostname: blog.d6rkaiz.com
fingerprint: 83:05:1c:2b:c9:c9:f0:c0:22:72:ac:1a:ce:1e:d9:63
ここまでのデプロイの設定は下記のようになった。
deploy:
steps:
- add-ssh-key:
keyname: DEPLOYKEY
host: blog.d6rkaiz.com
- add-to-known_hosts:
hostname: blog.d6rkaiz.com
fingerprint: 83:05:1c:2b:c9:c9:f0:c0:22:72:ac:1a:ce:1e:d9:63
- script:
name: make .ssh directory
code: mkdir -p "$HOME/.ssh"
- create-file:
name: write ssh key
filename: $HOME/.ssh/id_rsa
overwrite: true
hide-from-log: true
content: $DEPLOYKEY_PRIVATE
- script:
name: set permissions for ssh key
code: chmod 0400 $HOME/.ssh/id_rsa
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman deploy
code: bundle exec middleman deploy
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
で、ここで公式のadd-ssh-key
が何をやってるのかを確認してみると、keyname に指定したSSH鍵を元に~/.ssh/config
にIdentiyFileを指定する内容になっていた。sshのconfigに鍵の指定をした後に、秘密鍵を作成してるという無駄なことをやってることがわかったので、ばっさりとカット。
deploy:
steps:
- add-ssh-key:
keyname: DEPLOYKEY
host: blog.d6rkaiz.com
- add-to-known_hosts:
hostname: blog.d6rkaiz.com
fingerprint: 83:05:1c:2b:c9:c9:f0:c0:22:72:ac:1a:ce:1e:d9:63
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman deploy
code: bundle exec middleman deploy
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
これで実行したところsh: 1: rsync: not foundと言われてしまう。middlemanのデプロイにはrsyncを使う設定になっているが、rsyncがないと言われるので、ここを参考にrsyncのインストールを追加して、デプロイの設定は下記のようになった。
deploy:
steps:
- install-packages:
packages: rsync
- add-ssh-key:
keyname: DEPLOYKEY
host: blog.d6rkaiz.com
- add-to-known_hosts:
hostname: blog.d6rkaiz.com
fingerprint: 83:05:1c:2b:c9:c9:f0:c0:22:72:ac:1a:ce:1e:d9:63
- bundle-install:
jobs: $BUNDLEJOBS
- script:
name: middleman deploy
code: bundle exec middleman deploy
after-steps:
- slack-notifier:
url: $SLACK_URL
channel: work
username: werckerbot
これで実行したところ、うまくデプロイも終えることができ、これでgitレポジトリにpushすれば自動でデプロイまでやってくれるようになった。いろいろと紆余曲折してしまったけれど、なんとかできたので良しとする。
ちなみに以下のlogから分かる通り、werckerのruby boxはdebianのjessieを利用しているようだ。
Get:1 http://security.debian.org jessie/updates InRelease [63.1 kB]
Get:2 http://httpredir.debian.org jessie InRelease [134 kB]
Get:3 http://httpredir.debian.org jessie-updates InRelease [133 kB]
Get:4 http://security.debian.org jessie/updates/main amd64 Packages [143 kB]
Get:5 http://httpredir.debian.org jessie/main amd64 Packages [9038 kB]
Get:6 http://httpredir.debian.org jessie-updates/main amd64 Packages [3616 B]
Fetched 9515 kB in 8s (1175 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:
libpopt0
Suggested packages:
openssh-server
The following NEW packages will be installed:
libpopt0 rsync
0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded.
Need to get 439 kB of archives.
After this operation, 884 kB of additional disk space will be used.
Get:1 http://httpredir.debian.org/debian/ jessie/main libpopt0 amd64 1.16-10 [49.2 kB]
Get:2 http://httpredir.debian.org/debian/ jessie/main rsync amd64 3.1.1-3 [390 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 439 kB in 1s (353 kB/s)
Selecting previously unselected package libpopt0:amd64.
(Reading database ... 20968 files and directories currently installed.)
Preparing to unpack .../libpopt0_1.16-10_amd64.deb ...
Unpacking libpopt0:amd64 (1.16-10) ...
Selecting previously unselected package rsync.
Preparing to unpack .../rsync_3.1.1-3_amd64.deb ...
Unpacking rsync (3.1.1-3) ...
Processing triggers for systemd (215-17+deb8u1) ...
Setting up libpopt0:amd64 (1.16-10) ...
Setting up rsync (3.1.1-3) ...
invoke-rc.d: policy-rc.d denied execution of restart.
Processing triggers for libc-bin (2.19-18) ...
Processing triggers for systemd (215-17+deb8u1) ...