今回はECS/FargateでRailsログをCloudWatch Logsに出力したい場合もろもろハマったので、ブログしたいと思います。まず前提として環境は以下となります。
■Environment
- unicornはrootユーザーで動作
- NginxやunicornはSupervisorで動作
- /var/log/nginx/access.log,error.log
- unicorn.stdout.log
- アプリケーションログ(stg.log)
- CloudWatch Logsに出力
まずはNginxのログをSupervisorを使って標準出力してみます。
■Dockerfile/Supervisor
- Dockerfile
1 2 3 4 5 |
~省略~ # link logs RUN ln -sf /dev/stdout /var/log/nginx/access.log RUN ln -sf /dev/stderr /var/log/nginx/error.log |
- /etc/supervisor/conf.d/app.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[supervisord] nodaemon=true [program:app] command=bundle exec unicorn_rails -c config/stg_unicorn.rb -E stg autostart=true autorestart=true stopsignal=TERM user=root directory=/var/www/app/ stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:nginx] command=/usr/sbin/nginx -g "daemon off;" autostart=true autorestart=true stopsignal=TERM user=root stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 |
command=/usr/sbin/nginx -g "daemon off;"
ですが、Dockerはプロセスがフォアグラウンドで動いていないとコンテナが落ちるので、通常Nginxはデフォでデーモンで動作し、バックグラウンド実行になるのでコンテナが終了します。なので、 daemon off
でフォアグラウンドで実行するようにしています。
ちなみにRailsのアプリですが、特定のユーザの場合だと、シンボリックリンクを貼り、 /usr/bin/supervisord
を手動で実行すると以下のように権限エラーになります。
1 2 |
bundler: failed to load command: unicorn_rails (/home/adachin/vendor/bundle/ruby/2.x.x/bin/unicorn_rails) Errno::EACCES: Permission denied @ rb_sysopen - /var/www/app/log/unicorn.stderr.log |
そうなってしまいますとアプリケーションのログが標準出力できないので、プログラミング言語が用意している標準出力用streamへ向けてログを吐くようにすればOKです。
■Logger
- config/stg_unicorn.rb
1 2 3 4 5 6 7 8 9 10 |
worker_processes 2 app_path = '/var/www/app' working_directory = app_path listen File.expand_path('/root/tmp/unicorn.sock', app_path) pid File.expand_path('/root/tmp/unicorn.pid', app_path) stderr_path = $stderr stdout_path = $stdout ~省略~ |
- config/environments/stg.rb
1 2 3 4 5 6 7 8 |
require Rails.root.join('config', 'environments', 'production') Rails.application.configure do # Set to :debug to see everything in the log. config.log_level = :debug config.logger = Logger.new STDOUT end |
■Run supervisord
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# /usr/bin/supervisord 2020-01-xx 07:05:18,447 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message. 2020-01-xx 07:05:18,447 INFO Included extra file "/etc/supervisor/conf.d/app.conf" during parsing 2020-01-xx 07:05:18,458 INFO RPC interface 'supervisor' initialized 2020-01-xx 07:05:18,458 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2020-01-xx 07:05:18,458 INFO supervisord started with pid 39418 2020-01-xx 07:05:19,493 INFO spawned: 'nginx' with pid 39421 2020-01-xx 07:05:19,496 INFO spawned: 'app' with pid 39422 I, [2020-01-xxT07:05:20.080660 #39425] INFO -- : Refreshing Gem list 2020-01-xx 13:14:56,630 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2020-01-xx 13:14:56,630 INFO success: app entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) I, [2020-01-xxT07:05:20.080660 #13] INFO -- : listening on addr=/home/adachin/unicorn.sock fd=10 I, [2020-01-xxT07:05:20.080660 #15] INFO -- : worker=0 ready I, [2020-01-xxT07:05:20.080660 #13] INFO -- : master process ready I, [2020-01-xxT07:05:20.080660 #18] INFO -- : worker=1 ready [nginx] 10.x.xxx.xxx - - [27/Jan/2020:13:15:09 +0000] "GET / HTTP/1.1" 302 108 "-" "ELB-HealthChecker/2.0" "-" D, [2020-01-xxT07:05:20.080660 #17] DEBUG -- : [1m[36mUser Load (0.2ms)[0m [1mSELECT `hoge`.* FROM xxxxxxxxxxxxxxxxx LIMIT 1[0m |
これでNginxのログ、unicornログ、アプリケーションのログ(DEBUG)3つがSupervisor実行時に標準出力されるようになったので、あとはCloudWatch Logsで出力されていればOK。
- CloudWatch Logs
■まとめ
ECSだとSSHができないので、デバッグがし難い!!(知見が少ないだけ)コンテナでのログベストプラクティスはもっと勉強せねば!
0件のコメント