deployerで環境毎env反映とDB・storageのコピー
個人開発でゴニョゴニョ作ったのでしばらくLaravelネタが増えそうな?気がしてます。
今回はLaravelというよりはdeployerです。
Deployer
デプロイツールって言い方が多分普通?な気がするけど
細かい事とか厳密な事はよくわかってません。
とりあえずPHP製
サーバーにデータ手動でアップ->composer install->マイグレーション->〇〇する->〇〇する
みたいな手順をコマンドで自動化するっていうツール。だと思っている。
因みに別にLaravel専門って訳では無い様子。
railsいう所のCapistranoみたいな物。だと思っている。
Capistranoでも別に出来るっぽいけど
せっかくなので使ってみました。
ちょっと設定手間なのだけれども
慣れれば確実に便利だと思います。
npmとか.envとDBとstrage等の処理いれたオレオレdeployer(Laravel)
Laravelもdeployerも利用歴浅っいので
もっといいやり方ある可能性大ですが
とりあえず個人で利用する分には困っていないので
何かの参考になりましたら幸いです。
とりあえずdeploy.phpの全体
<?php
namespace Deployer;
require 'recipe/laravel.php';
set('application', "アプリの名前");
set('repository', 'git@bitbucket.org:hoge/hoge.git');
// Shared files/dirs between deploys
add('shared_files', ['.env']);
add('shared_dirs', [
'storage',
]);
// Writable dirs by web server
add('writable_dirs', [
'bootstrap/cache',
'storage',
' | echo',
]);
// deploy:writableがエラーで止まるって困ってたけども
// 最後に' | echo',つけると止まらなくなるらしい。
set('writable_mode', "chmod");
// デフォルトがsetfacl使うようになっているので環境によって変える
set('writable_chmod_mode', "0755");
// これで多分writable_dirsのパーミッション変えれる
// Hosts
host('sample.com')
->stage('production')
->user('user')
->port(22)
->identityFile('~/.ssh/id_rsa')
->set('deploy_path', '/var/www/html/hoge');
// build -------------------
task('build', function () {
run('cd {{release_path}} && build');
});
// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');
// Migrate database before symlink new release.
before('deploy:symlink', 'artisan:migrate');
// Tasks
// npm -------------------
before('deploy:prepare', 'npm:run');
task('npm:run', function () {
run('npm run production');
})->local();
// deploy:prepareの前にnpmでproduction用のアセットとか出力する
// push -------------------
after('npm:run', 'git:push');
task('git:push', function () {
run('git add .');
run("
if ! git diff-index --quiet HEAD --; then
git commit -m deployer
fi
");
run('git push origin master');
})->local();
// 変更があればpush
// env -------------------
before('deploy:shared', 'upload-env');
task('upload-env', function () {
$stage = get('stage');
$src = ".env.${stage}";
$deployPath = get('deploy_path');
$sharedPath = "${deployPath}/shared";
upload(__DIR__ . "/" . $src, "${sharedPath}/.env");
});
// .env.productionとかを.envにリネームしてリモートにuploadする
// set -------------------
$date = date("Ymd_His");
set('date', $date);
$dbbkup_file = "/var/www/html/hoge/backup/data${date}.sql";
set('dbbkup_file', $dbbkup_file);
// DBバックアップ&同期 -------------------
after('upload-env', 'db:backup');
task('db:backup', function () {
$pass = 'password';
$dbbkup_file = get("dbbkup_file");
run("/usr/bin/mysqldump -u root -p${pass} hoge > ${dbbkup_file}");
});
// .バックアップというかsqlとしてエクスポートする、場所とかファイル名は$dbbkup_fileから
// 多分もっといい方法ありそう
after('db:backup', 'db:local');
task('db:local', function () {
$dbbkup_file = get("dbbkup_file");
$date = get("date");
run("scp -P 22 user@sample.com:${dbbkup_file} /Users/user/path/to/sql/");
run("/Applications/MAMP/Library/bin/mysql -uroot -proot dbname < /Users/user/path/to/sql/data${date}.sql");
})->local();
// sqlをscpでリモート > ローカルにダウンロードしてmampにコピー(インポート)
// storageの同期 (リモート > ローカル) -------------------
after('db:local', 'storage:rsync');
task('storage:rsync', function () {
run("rsync -avz -e 'ssh -p 22' --delete user@sample.com:/var/www/html/hoge/shared/storage/app/public/ /Users/user/path/to/app/storage/app/public/
");
})->local();
// これもstrageの画像とかrsyncでリモートからローカルに同期
// php-fpm -------------------
after('deploy', 'php-fpm:restart');
task('php-fpm:restart', function () {
run('sudo /etc/init.d/php-fpm restart');
})->desc('Restart PHP-FPM service');
// php-fpmリスタートしないと
// 更新されない事があるのでやっておく
// visudoでパスなしsudoの設定する必要あり
です。
Task毎の補足等
あとは少し補足等入れてみます。
npm:run
before('deploy:prepare', 'npm:run');
task('npm:run', function () {
run('npm run production');
})->local();
いちいちnpm run productionするのって個人的には本番に反映する前だけなので
deployerのtaskにいれてしまう。
task()->local();
でローカルでの処理になるっぽい。
git:push
run productionしたらpushしないと
デプロイに反映されないので
pushします。
after('npm:run', 'git:push');
task('git:push', function () {
run('git add .');
run("
if ! git diff-index --quiet HEAD --; then
git commit -m deployer
fi
");
run('git push origin master');
})->local();
if ! git diff-index –quiet HEAD –;
if ! git diff-index –quiet HEAD –;とかって書いているのは
git commitの時に変更が無いとコミット出来なくて
エラーで止まっちゃうので判定してます。
env
before('deploy:shared', 'upload-env');
task('upload-env', function () {
$stage = get('stage');
$src = ".env.${stage}";
$deployPath = get('deploy_path');
$sharedPath = "${deployPath}/shared";
upload(__DIR__ . "/" . $src, "${sharedPath}/.env");
});
envは多分gitignoreするのが普通っぽい気がするので
ローカルからuploadしちゃってます。
staging/productionとかでアップする
envを切り替えつつリネームしてアップ。
DBバックアップ
task('db:backup', function () {
$pass = 'password';
$dbbkup_file = get("dbbkup_file");
run("/usr/bin/mysqldump -u root -p${pass} hoge > ${dbbkup_file}");
});
mysqldumpでデプロイ毎にsqlにエクスポートしておく。
多分cronとかでやったほうがいいのかもしれないけど
そんな本格的にやるまでもない気がしてるのでついでバックアップ。
次のローカルDBインポートにも使う。
db:local(MAMPとかDockerにインポート)
task('db:local', function () {
$dbbkup_file = get("dbbkup_file");
$date = get("date");
run("scp -P 22 user@sample.com:${dbbkup_file} /Users/user/path/to/sql/");
run("/Applications/MAMP/Library/bin/mysql -uroot -proot dbname < /Users/user/path/to/sql/data${date}.sql");
})->local();
別に必要ないのだけれでも
何となくリモート->ローカルに同期しておこうと思って
やってみた
scpでさっきのバックアップ用に書き出したsqlをリモート->ローカルにコピー。
してからmampのmysqlにインポート。
Dockerの場合追記
ローカルでssl使いたくてなんかmampだと面倒そうな感じがしたので
docker(laradock)に移行したのだけれども
この部分やたら苦戦したので追記。
task('db:local', function () {
$dbbkup_file = get("dbbkup_file");
$date = get("date");
run("scp -P 22 user@sample.com:${dbbkup_file} /Users/user/path/to/sql/");
set('latest_file', run("cd /Users/user/path/to/sql/ && ls -lt *.sql | head -n 1 | awk '{print $9}'"));
$latest_file = get("latest_file");
// // dockerのコンテナ内にコピー
run("docker cp /Users/user/path/to/sql/${latest_file} laradock_mysql_1:/tmp/${latest_file}");
$bash = "MYSQL_PWD='password' mysql -u username table < ./tmp/${latest_file}";
run("docker exec laradock_mysql_1 bash -c '${bash}'");
})->local();
latest_file
指定ディレクトリでの最新ファイル取得したかったのだけれども
多分なんか上手い書き方ありそうなもんだけどcd /path/ &&でやってしまった。
docker cp
dockerってコンテナ毎にcpしないとなのか?
workspace内からデータインポートしようとしたら参照できません的なエラー出て
結構困ってたけどmysqlのコンテナにcpすれば一応動いた。
bash
mysqlのバージョンによっては話だとおもいますが
Using a password on the command line interface can be insecure.
とかででパスワードとかはmy.conf書いて読めばいいって事らしいけども
ローカルに置けばいいのかコンテナ内におくのかよくわからん。
とりあえずうまく読めないのであきらめて
MYSQL_PWDでやろうと思った次第ですが、それもdocker execで結構困ってました。
bash -c “”でコンテナでのコマンド渡せるっぽい。
storage:rsync
task('storage:rsync', function () {
run("rsync -avz -e 'ssh -p 22' --delete user@sample.com:/var/www/html/hoge/shared/storage/app/public/ /Users/user/path/to/app/storage/app/public/
");
})->local();
DBインポートするとローカルに無い画像が溢れ出てくるので
storageもrsyncでリモート->ローカル同期する。
php-fpm:restart
task('php-fpm:restart', function () {
run('sudo /etc/init.d/php-fpm restart');
})->desc('Restart PHP-FPM service');
php-fpm使ってる場合は多分restartしないと更新が反映されない事が
あるみたいなのでデプロイしたらリスタートします。
visudo
runでsudo使うのでパスなしのsudo許可が必要になるみたい。
個人的にここが地味に面倒くさかったです。
Capistranoだと必要なかったような?
sshkit/sudoのおかげ?
多分もっとスマートな方法があると思います。
以上です。
とりあえず動いてるよってだけで
もっとスマートな方法は色々あると思うので
気になる方は方法探すかスルーしてください。
参考になりましたら幸いです。
ディスカッション
コメント一覧
まだ、コメントがありません