はじめに
[UNMAINTAINED]
になった Capistrano2
+ Capifony
プラグインから、Capistrano3
+ capistrano/symfony
プラグインに切り替えたら、キャッシュ周りで数時間ハマりました。
何が起きたか
Capistrano3
+ capistrano/symfony
プラグインに切り替えて、デプロイしたところ、直後のアクセスでApache
が下記のようなエラーを吐きました。
request.CRITICAL: Exception thrown when handling an exception (InvalidArgumentException: The directory "{/path/to/app}/releases/{timestamp}/app/cache/prod/jms_serializer" is not writable. at {/path/to/app}/releases/{timestamp}/vendor/jms/metadata/src/Metadata/Cache/FileCache.php line 17) {"exception":"[object] (InvalidArgumentException(code: 0): The directory \"{/path/to/app}/releases/{timestamp}/app/cache/prod/jms_serializer\" is not writable. at {/path/to/app}/releases/{timestamp}/vendor/jms/metadata/src/Metadata/Cache/FileCache.php:17)"} []
前置きしておきますが、jms_serializer
は無関係です。
他のライブラリも同様に、app/cache
に書き込みできなくて、エラーを吐きます。
app/cache
は 0777
に設定しているはず
config/deploy.rb
には、下記のように、app/cache
を0777
にしているつもりでした。
# config/deploy.rb
# Set correct permissions between releases, this is turned off by default
set :file_permissions_paths, ["app/cache"]
set :file_permissions_users, ["apache"]
set :file_permissions_chmod_mode, "0777"
set :permission_method, :acl
after "deploy:updated", "deploy:set_permissions:acl"
Symfony的には、ACLを使うべし
ファイルのパーミッションについて、Symfonyの公式ドキュメントに詳しい説明があります。
$ HTTPDUSER=$(ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1)
# # if this doesn't work, try adding `-n` option
$ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX var
$ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX var
setfacl
コマンドによって、Webサーバの実行ユーザー(apache, www-dataなど)とパーミッションを設定するユーザー($(whoami))双方にフルアクセスを与えるコマンド例が記載されています。
setfacl
は実行されている
Capistrano::FilePermissions
のREADMEを見ると、下記のようにコマンドを実行していることが説明されています。
[..] setfacl -Rn -m u:www-data:rwX -m u:<deploy-user>:rwX <path-to-app>/shared/app/logs <path-to-app>/<release>/app/cache
実際、デプロイ時のコンソールログを見ると、下記のようにsetfacl
コマンドが実行されています。
00:06 deploy:set_permissions:acl
01 setfacl -Rn -m u:{web server user}:rwX -m u:{deploy user}:rwX {/path/to/app}/releases/{timestamp}/app/cache
✔ 01 {deploy user}@{web server} 0.047s
02 setfacl -dRn -m u:{web server user}:rwX -m u:{deploy user}:rwX {/path/to/app}/releases/{timestamp}/app/cache
✔ 02 {deploy user}@{web server} 0.047s
しかし、パーミッションは0777
になっていない
確認してみると、パーミッションは0777
になっていないことに気付きます。
[{deploy user}@{web server} {/path/to/user}]$ ls -la current/app/cache
drwxr-xr-x+ 3 {deploy user} {group} 4096 5 25 19:42 2017 .
drwxr-xr-x 5 {deploy user} {group} 4096 5 25 19:42 2017 ..
drwxr-xr-x+ 9 {deploy user} {group} 4096 5 25 19:42 2017 prod
[{deploy user}@{web server} {/path/to/user}]$ getfacl current/app/cache/*
# file: current/app/cache/prod
# owner: {deploy user}
# group: {group}
user::rwx
group::r-x
other::r-x
既知の問題ではある
おかしいですね。だけど、これはみんな踏んでいる地雷なのでは?ということで、Githubを見ていると、下記のPRを発見しました。
詳しいことは理解しきってはいないですが、どうやら、setfacl
のn
オプションが不要だったみたいです。
あれ、これ、Merged
になっているけれども...
修正はされているけれど、リリースされていない
そう、このPRがマージされたのは、2016-6-29
で、最新のcapistrano-file-permissions 1.0.0
は、2016-1-15
のままなんですよね。
これに気付くのに、もう小一時間かかりました。
で、早くリリースしてくれっていうissueが2017-5-3
にすでに切られてました。
umask
を使うことに
ACLによるファイルパーミッションをあきらめるとなると、umask
を使う方法がSymfonyの公式で紹介されています。
If none of the previous methods work for you, change the umask so that the cache and log directories are group-writable or world-writable (depending if the web server user and the command line user are in the same group or not).
To achieve this, put the following line at the beginning of the bin/console, web/app.php and web/app_dev.php files:
bin/console
(symfony2はapp/console
)、web/app.php
、web/app_dev.php
のエントリポイントとなるファイルの先頭で、umask(0000);
としておくと、ファイルパーミッションが0777
になるよと説明されています。
実際、app/console
にも下記のコメントが既に埋まっていたりします。
// app/console
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
umask(0000); // 今回ここのコメントを解除しました
おわりに
まとめると、下記2つの対応をすることでapp/cache
に書き込めない問題を回避しました。
-
Capistrano
のdeploy:set_permissions:acl
は削除(何もしないようにする) -
app/console
、web/app.php
、web/app_dev.php
の先頭にumask(0000);
を追加
世界中のSymfonyユーザーのために、capistrano-file-permissions
の新バージョンがリリースされることを希望します。
(みんな、umask使っているのかな。ひょっとして常識?)
ではでは。