CakePHP
CakePHPDay 14

Git PUSH時に自動デプロイする CakePHP2編

More than 3 years have passed since last update.

CakePHP3を控えてCakePHP2ネタもいまさら感ありますが最近苦労したところのまとめです。


環境


開発


  • CakePHP2でWebシステムを開発。

  • 開発者はそれぞれGitリモートリポジトリをクローンして手元で開発をしている。


サーバ構成


  • GitリモートリポジトリはGitLabを使って社内ネットワークに設置。

  • 本番サーバはインターネット上(AWS)に2台ある。

  • 2台の本番サーバは一部のディレクトリを共有してファイルアップロードに使用している。

  • 本番サーバはGitLabサーバのインストールされたサーバからChefを使って管理している。


やりたいこと


  • Gitリモートリポジトリの特定ブランチに更新をPUSHした時にファイルを本番環境に反映したい。

  • CakePHPのモデル等キャッシュを削除するためにファイルの本番環境反映後に本番サーバ上でシェルスクリプトを実行したい。

SS 2014-12-14 15.39.13.png


設計


  • chefユーザは対象のサーバにパスワードなしでログイン可能 & パスワードなしでsudo可能になっているので、chefユーザを使ってデプロイすることにする。

  • chefユーザであらかじめリポジトリをクローンし、それをWeb1, Web2にrsyncでファイル転送することにする。

  • リモートリポジトリの特定ブランチにPUSHされた時のpost-updateフックにデプロイシェルの起動を設定。

  • デプロイシェルでは以下の処理を実行。


    • クローンしたローカルリポジトリの内容を最新化

    • ファイル転送

    • 本番サーバ上でシェルを実行




実装

以下の形にファイルを配置しています。

このディレクトリはchefユーザの持ち物です。

┬ deploy.sh

├ repo_name/
│ ├ .editorconfig
│ ├ .git/
│ ├ .gitignore
│ ├ .gitmodules
│ ├ .htaccess
│ ├ CONTRIBUTING.md
│ ├ README.md
│ ├ app

│ ├ reset.sh

ファイル名
内容

deploy.sh
デプロイシェル。

repo_name
リモートリポジトリをクローンしたもの。

reset.sh
デプロイ後にサーバで実行するシェル。キャッシュ削除などする。


デプロイシェル deploy.sh

#!/bin/bash

# 本番環境デプロイ

# このスクリプトが存在するディレクトリ
script_dir="$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd)"
# デプロイ対象のローカルリポジトリ
repo_name="repo_name"
repo_dir="${script_dir}/${repo_name}"
# .gitディレクトリの場所
git_dir="${repo_dir}/.git/"

echo "script_dir: ${script_dir}"
echo "repo_dir: ${repo_dir}"
echo "git_dir: ${git_dir}"

# ローカルリポジトリの状態を最新にする
cd ${repo_dir}
git --git-dir=${git_dir} checkout master
git --git-dir=${git_dir} reset --hard
git --git-dir=${git_dir} pull
# サーバで起動するシェルに実行権限を付ける
chmod 755 ${repo_dir}/reset.sh

cd ${script_dir}

# ファイルを転送する
rsync -avzr --delete --exclude ".git/" --exclude "/images/" --exclude "/app/tmp" ./${repo_name}/ [Web1ホスト名]:/path/to/deploy/
# サーバでシェルを実行する
ssh -t -t [Web1ホスト名] "cd /path/to/deploy;sudo ./reset.sh"

# ファイルを転送する
rsync -avzr --delete --exclude ".git/" --exclude "/images/" --exclude "/app/tmp" ./${repo_name}/ [Web2ホスト名]:/path/to/deploy/
# サーバでシェルを実行する
ssh -t -t [Web2ホスト名] "cd /path/to/deploy;sudo ./reset.sh"

前半はGitリモートリポジトリからmasterの最新状態に反映しています。rsync--deleteオプションを付けているので転送元に無いファイルは削除されます。/images/ディレクトリはこのサイトのユーザからのアップロードファイルを受け取るディレクトリなので対象外にしています。その他、.gitディレクトリと、CakePHPのtmpディレクトリも対象外にしています。

後半ではサーバごとにファイルをrsyncで転送し、sshコマンドでサーバに転送されたreset.shを起動しています。sshコマンドでリモートのコマンドを実行する場合、ttyが無いとsudoコマンドが実行できません。そのために-t -tオプションを付けてttyを割り当ててあげています。


デプロイ後にサーバで実行するシェル reset.sh

#!/bin/bash

# CakePHPキャッシュを削除する
rm -f app/tmp/cache/models/cake_model_* 2> /dev/null
rm -f app/tmp/cache/models/myapp_cake_model_* 2> /dev/null
rm -f app/tmp/cache/persistent/cake_core_* 2> /dev/null
rm -f app/tmp/cache/persistent/myapp_cake_core_* 2> /dev/null
rm -f app/tmp/cache/views/*.php 2> /dev/null
rm -f app/tmp/cache/cake_* 2> /dev/null

# cakeに実行権限付与
chmod +x app/Console/cake

こちらはシンプルですね。app/tmp配下のキャッシュを削除して、コンソール用のcakeに実行権限を与えています。


Gitのhook設定

ここまで準備ができたらdeploy.shをGitへのPUSH時に実行すればOKです。

Gitのリモートリポジトリ内、hooks/post-updateに以下を置きます。

#!/bin/sh

# push されたブランチ名が BRANCH に入る
BRANCH=$(git rev-parse --symbolic --abbrev-ref $1)

case "$BRANCH" in
"develop")
# develop用の処理
;;
feature*)
# feature用の処理
;;
release* | hotfix*)
# release, hotfix用の処理
;;
"master")
# master用の処理
sudo -u chef -E /path/to/script_master/deploy.sh
;;
esac

この様にしておくと、masterブランチに更新がプッシュされた時に指定されたスクリプトが実行されます。

この環境ではGitはgitユーザの権限で動作しています。前述のとおりdeploy.shはchefユーザで起動したいのでsudoコマンドにパラメタを与えてそれを実現しています。

以上で「Git PUSH時に自動デプロイする」が完成しました。


メモ


  • デプロイ時にrsyncsshでコマンド実行、としているけど、コマンド実行出来るのであればWebサーバ側でgit pullしても良いかも。

  • Gitのドキュメントを読んでいるとフックはpost-receiveの方が良さそうだけどpost-receiveに書いても起動しなかった。研究の余地アリ。