読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

Chef で CentOS に Playframework2.2.x アプリをデプロイする

OSS Tips Server Playframework

CentOS5.10 で動作確認。多分 CentOS 6.x もそんな変わらない筈。

段階を踏もうか。

  1. Play アプリをリリース用にコンパイルする
  2. Chef を使ってJavaを突っ込む
  3. Chef でデプロイ用 Cookbook を作って配置する
  4. 起動スクリプトを書いてデプロイする
  5. knife solo cook xxxx でぶち込む

という順番。

Play アプリをリリース用にコンパイルする

これは簡単。

アプリケーションホームディレクトリで play clean dist と叩くだけ。

すると、コンパイルした上で、配布用の zip を target/universal ディレクトリに applicationName-Version.zip なファイルが出来上がる。

デプロイするときにバージョン名は地味に邪魔だけど、まぁこれは Chef 側の設定でどうにかする。

尚、この zip を解凍して bin/applicationName を叩くとサーバが起動する。

残念な事に、デーモン起動ではないので、終了までコントロールを奪ってくれる素敵仕様だ。

これはログ設定で標準出力には吐かず、ログにだけメッセージを吐くようにし、bin/applicationName &で逃れる。

PID ファイルとかは Play が勝手に吐くので気にしない。

Chef を使って Java を突っ込む

まずは chef リポジトリ(kitchen)を作る。

前提:chef + knife solo + Berkshelf インストール済み。Ubuntu ホストはこっち参照

knife solo init chef とでも叩くと、chef ディレクトリが作られて、そこに kitchen が作られる。

とりあえずは Java を突っ込もうか。

chef/Berksfile が作られてる筈なので、これを開いて編集。

source "https://api.berkshelf.com"

cookbook 'yum'
cookbook 'java'

コンソール上で下記を叩く。

cd chef
berks vendor cookbooks

すると、berkshelf が Java の cookbook を落としてくる。

次に、chef/nodes ディレクトリに、インストール設定を突っ込む。

vi nodes/default.json
{
  "java":{
    "jdk_version":"7"
  },
  "run_list":[
    "recipe[java]"
  ]
}

これで knife solo cook [user]@[server] default.json と実行すれば、OSはともかく Java7 が入る。

詳細オプションは opscode community 見てほしい。

Chef でデプロイ用 Cookbook を作って配置する

次にデプロイ用 cookbook を作ろうか。

まず、chef ディレクトリ上で下記のコマンドを叩こう。

knife cookbook create app -o site-cookbooks/

すると、chef/site-cookbooks/app ディレクトリが作られている筈。

このディレクトリが cookbook の一つの単位。

ここの、chef/site-cookbooks/app/files/default ディレクトリに、最初の手順で作成した applicationName-version.zip をデプロイしてしまおう。

で、もちろんこの「-version」の部分はバージョンアップの度に変わるので、設定ファイルに吐き出してしまう。

vi chef/site-cookbooks/app/attributes/default.rb

default['app'][:version] = "0.1-Beta"

もちろん、これは前述の nodes/default.json で下記のように書いてもいい。

{
  "java":{
    "jdk_version":"7"
  },
  "app":{
    "version":"0.1-Beta"
  },
  "run_list":[
    "recipe[java]",
    "app"
  ]
}

次に、このファイルをデプロイするコードを書く。

参考:ChefでCookbookを作成するときのちょっとしたコツ 9選 - インフラエンジニアway - Powered by HEARTBEATS

vi chef/site-cookbooks/app/recipes.default.rb

#
# Cookbook Name:: app
# Recipe:: default
#
# Copyright 2014, white-azalea.net
#
# All rights reserved - Do Not Redistribute
#

# ディレクトリは無ければ作る
directory "/opt" do
  owner "root"
  group "root"
  mode 00600
  action :create
end

directory "/opt/app" do
  owner "root"
  group "root"
  mode 00644
  action :create
end

# node プロパティに設定が入っている
fileName = "applicationName-" + node.app.version + ".zip"
deployName = "/opt/app/" + fileName

# cookbook_file で files 内のファイルをデプロイ
# あれば何もしない
cookbook_file deployName do
  source fileName
  mode "0755"
  action :create
  not_if { File.exist?(deployName) }
end

# 解凍、execute で shell 叩ける
# 解凍済みなら README があるので、その場合は何もしない
execute ("unzip " + deployName) do
  cwd    "/opt/app/"
  action :run
  not_if { File.exist?("/opt/app/applicationName-" + node.app.version + "/README") }
end

起動スクリプトを書く

これが一番難儀した。

参考:

CentOSでデーモンの起動スクリプトを書く | taichino.com

Technical Memorandum: CentOS-5 起動スクリプトのスケルトン

まずは、chef/site-cookbooks/app/templates/default/appservice.erb を下記の内容で作成した。

#!/bin/bash
# chkconfig: 345 98 20
# description: application service start script.
# processname: appservice
#
#       /etc/rc.d/init.d/appservice
#
#       Sample application service start script.
#

# Source function library.
. /etc/init.d/functions

SERVER_PATH="/opt/uptext/applicationName-<%= node['app']['version'] %>"
SERVER_BIN=$SERVER_PATH + "/bin/applicationName"
PID_PATH=$SERVER_PATH + "/RUNNING_PID"

start() {
        echo -n "Starting applicationName: "
        if [ -f $PID_PATH ]
        then
          echo "Server already running"
        else
          `$SERVER_BIN &`
        fi
        return 0
}

stop() {
        echo -n "Shutting down applicationName: "
        kill `cat $PID_PATH`
        return 0
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    *)
        echo "Usage: appservice {start|stop|restart}"
        exit 1
        ;;
esac
exit $?

基本的に erb なので分かるはず。

尚、「chkconfig」からの3行のコメントはおまじない。これを設定しないと、自動起動に登録できません。

次に、この設定をデプロイと起動、OS起動時の自動起動まで指定する。

chef/site-cookbooks/app/recipes.default.rb に下記を追記。

# appservice を起動スクリプトディレクトリに配置
template "/etc/init.d/appservice" do
  group  "root"
  owner  "root"
  mode   0744
  source "appservice.erb"
end

# appservice を起動
service "appservice" do
  action :start
end

# OS 起動時に appservice を起動するよう指定
service "appservice" do
  action :enable
end

knife solo cook xxxx でぶち込む

後は分かるはず。