docker-composeのコンテナ内でcronを動かせたけど、railsのrakeタスクが実行できない
昨日、コンテナ内でcronを実行すること自体は成功したのだが、どうもrailsアプリのrakeタスクを実行する際に、(おそらく)権限の問題で実行できていなかったので、それを修正する。
目標は1時間以内(本当は30分で終わらせたいところ)
まずは現状を確認。 containerにexecする。ホストにて。
$ docker-compose exec app bash
rootでbashにログインできました。私はrootです。
# whoami root
crobntabを確認する
crontab -e
→なにもない。(コメントがありますが、有効な記述はない。)
次に、/etc/cron系を調べてみます。
/etc/crontab
SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 17 * * * * root cd / && run-parts --report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --reporrt /etc/cron.daily ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --reporrt /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --reporrt /etc/cron.monthly)
これはデフォルトで入っていたやつでした。
他の/etc/cron系のファイルを見てみても、(見てないですが)なさそうだったので、特にcron系は設定されていない状態なはずです。
ここから、一つずつ動作を確かめていきませう。
進め方を決めます。
テスト環境にて
1. crontabの動作を確認する(権限必要ないファイルに書き込み)
2. railsのdummyのrakeタスクを実行.ログをファイル出力
3. 本番のrakeタスクを実行。
4. Dockerfile変更→build→run→cronの動作確認
5. 本番に反映
テスト(ローカル)環境と本番環境をごっちゃにしていたので、どこのcrnotabが有効かわからなくなってしまっていた。
テスト環境のコンテナのcronの状況確認
crontab -l
* * * * * echo "Hello $(date)" >>/var/log/cron.log 2>&1 * * * * * /usr/local/bundle/bin/rake status:testman >>/var/log/cron.log 2>&1 * * * * * pwd >> /var/log/cron.log 2>&1
一番上を確認する。 これ以外は一旦コメントアウトにする。
* * * * * echo "Hello $(date)" >>/var/log/cron.log 2>&1
出力先をきれいにしておきます
rm -rf /var/log/cron.log
cron実行想定時間後
# cat /var/log/cron.log Hello Wed Sep 5 14:59:01 UTC 2018
OKです。ファイルの書き込み(なければ作成)もOKでした。 以下のcronだけを残します。
* * * * * /usr/local/bundle/bin/rake status:testman >>/var/log/cron.log 2>&1
ちなみにrakeタスクのstatus:testman
は以下
desc "test" task :testman => :environment do File.open("db/hoge.csv","a") do |f| f.puts(Time.now) end end
コレ自体はちゃんと動作することは確認した。
しかし、cronが動かない。
出力先の/var/log/cron.log
を見てみると、
/usr/bin/env: 'ruby': No such file or directory
予想: rakeタスクのパスがなんかどっかおかしいんだろ?
↓
それっぽいstack overflow
やっぱりそれっぽいことを言われている。
$HOMEにpathを追加すれば行けるよ的なこと言っているが、あんまりいじりたくない。いじったらその分Dockerfileもいじらなくてはいけなくなるので、厄介。絶対厄介。
まずコンテナ内のrubyのパスを確認してみる。
# which ruby /usr/local/bin/ruby
...しかしこれがわかって何になるのか。
?
bundle execすればいい話?
ちょっとdocker-composeのマウントとかにいろいろ紛れてvendorの場所をあまり意識していなかったが、それか?
printenv
で表示されるpathに
/usr/local/bin
は含まれているので、rubyを探せる。
あ、よし。
cronにprintenv
させればいいのだな。
HOME=/root LOGNAME=root PATH=/usr/bin:/bin SHELL=/bin/sh PWD=/root
やはり、pathがなかった。
正当な解決までの道のりは遠そうだったので、次の方針で進める。
cronでsh /opt/hoge.sh >> /var/log/cron.log
として、
/opt/hoge.sh
ファイルにて
export PATH=/usr/local/bundle/bin:/usr/local/bundle/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /usr/local/bundle/bin/rake status:testman
これで行けそう。
# sh /opt/cron.sh
これは成功した!
次に、cronから呼び出す。
↓
だめ。
/var/log/cron.log
rake aborted! No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)
おっとこれは、rakeファイルを実行する場所が悪かったようでした。
/opt/cron.sh
export PATH=/usr/local/bundle/bin:/usr/local/bundle/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin cd /webapp /usr/local/bundle/bin/rake status:testman
場所を移動して実行するように変更.
rake aborted! Bundler::GemNotFound: Could not find rake-12.3.1 in any of the sources /webapp/config/boot.rb:3:in `<top (required)>' /webapp/config/application.rb:1:in `require_relative' /webapp/config/application.rb:1:in `<top (required)>' /webapp/rakefile:4:in `require_relative' /webapp/rakefile:4:in `<top (required)>' (See full trace by running task with --trace)
わからん。
bundle execしないとだめってこと?
一旦それでやってみるよ?
/opt/cron.sh
を以下に変更
export PATH=/usr/local/bundle/bin:/usr/local/bundle/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin cd /webapp /usr/local/bin/bundle exec rake status:testman
結果、だめ。
/var/log/cron.log
bundler: failed to load command: rake (/usr/local/bundle/bin/rake) Bundler::GemNotFound: Could not find rake-12.3.1 in any of the sources /usr/local/lib/ruby/site_ruby/2.5.0/bundler/spec_set.rb:91:in `block in materialize' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/spec_set.rb:85:in `map!' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/spec_set.rb:85:in `materialize' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/definition.rb:171:in `specs' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/definition.rb:238:in `specs_for' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/definition.rb:227:in `requested_specs' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/runtime.rb:108:in `block in definition_method' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/runtime.rb:20:in `setup' /usr/local/lib/ruby/site_ruby/2.5.0/bundler.rb:107:in `setup' /usr/local/lib/ruby/site_ruby/2.5.0/bundler/setup.rb:20:in `<top (required)>' /usr/local/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' /usr/local/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
これはなんだ。
これは/otp/cron.sh
が悪い。
そもそも、bashからsh /opt/cron.sh
を実行しても同様のエラーになるので、cornの罠とかじゃなく、bundle exec とかは必要ないはず。
ってかそもそもbundle execなしで普通にbashからrakeタスク実行できていたので、同じrootユーザーなのでできるはず。
考えよう。
↓
考えてもわからん。
無能すぎて泣ける。
明日は時間トレなさそうなのでもう諦める。
むしろ一回一回コンテナを起動してしまうことは甘んじて受け入れて、ホストのcronで不なコンテナを消し込みに行こうかな。
全然解決できなさすぎて、セーブポイントから結構進めてたどり着く最初の中ボスみたいなの10回くらい倒せなくて諦めた小5くらいにやってた犬夜叉のゲーム思い出したわ。