reloadできるunicorn+railsのDockerイメージを作れそうだったので作ってみた。
以下、登場人物。
Dockerfile
FROM ubuntu:xenial MAINTAINER Genki Sugawara <sgwr_dts@yahoo.co.jp> USER root WORKDIR / RUN apt-get update RUN apt-get install -y ruby RUN apt-get install -y ruby-dev RUN apt-get install -y build-essential RUN apt-get install -y zlib1g-dev RUN apt-get install -y libxml2-dev RUN apt-get install -y libsqlite3-dev RUN apt-get install -y nodejs RUN gem install rails RUN rails new hello --skip-bundle RUN sed -i '/puma/d' hello/Gemfile RUN echo 'gem "unicorn"' >> hello/Gemfile RUN bundle config --global silence_root_warning 1 RUN cd /hello && bundle ADD unicorn.conf.rb /hello/config/ ADD init.sh / RUN chmod +x /init.sh EXPOSE 8080 CMD ["/init.sh"]
init.sh
#!/bin/bash RUNNING=1 function unicorn_pid() { cat /hello/tmp/pids/unicorn.pid } function stop() { SIGNAL=$1 PID=$(unicorn_pid) send_signal $SIGNAL for i in {1..60}; do ps -eo pid | egrep -q "^ +$PID$" [ $? -ne 0 ] && break echo -n . sleep 1 done RUNNING=0 } function send_signal() { SIGNAL=$1 kill -$SIGNAL $(unicorn_pid) } for SIGNAL in $(trap -l | awk -v RS='[\t\n]' '$0 != ""{print $2}'); do case $SIGNAL in SIGINT | SIGKILL | SIGTERM) trap "stop $SIGNAL" $SIGNAL ;; SIGWINCH) ;; *) trap "send_signal $SIGNAL" $SIGNAL ;; esac done cd /hello bundle exec unicorn_rails -c config/unicorn.conf.rb -E production -D while true; do if [ $RUNNING -eq 0 ]; then break; fi sleep 1 done echo unicorn has stopped
unicorn.conf.rb
rails_root = File.expand_path('../..', __FILE__) worker_processes 4 listen 8080, :tcp_nopush => true timeout 30 pid "#{rails_root}/tmp/pids/unicorn.pid" stderr_path "#{rails_root}/log/unicorn.stderr.log" stdout_path "#{rails_root}/log/unicorn.stdout.log" preload_app true check_client_connection false run_once = true before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! if run_once run_once = false end old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU Process.kill(sig, File.read(old_pid).to_i) rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
reloadしてみる
まずdocker build
。
$ docker build -t app .
起動して中身を確認。
$ docker run --name my-app app
$ docker exec my-app ps awxuf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 123 0.0 0.1 34424 2872 ? Rs 18:32 0:00 ps awxuf root 1 0.1 0.1 18056 2848 ? Ss 18:31 0:00 /bin/bash /init.sh root 14 3.9 3.5 195808 72116 ? Sl 18:31 0:02 unicorn_rails master -c config/unicorn.conf.rb -E production -D root 17 0.0 3.2 195808 67080 ? Sl 18:31 0:00 \_ unicorn_rails worker[0] -c config/unicorn.conf.rb -E production -D root 20 0.0 3.2 195808 67080 ? Sl 18:31 0:00 \_ unicorn_rails worker[1] -c config/unicorn.conf.rb -E production -D root 23 0.0 3.2 195808 67016 ? Sl 18:31 0:00 \_ unicorn_rails worker[2] -c config/unicorn.conf.rb -E production -D root 26 0.0 3.2 195808 67080 ? Sl 18:31 0:00 \_ unicorn_rails worker[3] -c config/unicorn.conf.rb -E production -D root 122 0.0 0.0 4380 708 ? S 18:32 0:00 sleep 1
masterのpidは14
。
reloadしてみる。
$ docker kill -s USR2 my-app my-app
$ docker exec my-app ps awxuf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 231 0.0 0.1 34424 2944 ? Rs 18:33 0:00 ps awxuf root 1 0.0 0.1 18060 2860 ? Ss 18:31 0:00 /bin/bash /init.sh root 182 7.2 3.5 195812 73632 ? Sl 18:32 0:02 unicorn_rails master -c config/unicorn.conf.rb -E production -D root 188 0.0 3.3 195812 68044 ? Sl 18:32 0:00 \_ unicorn_rails worker[0] -c config/unicorn.conf.rb -E production -D root 191 0.0 3.2 195812 67336 ? Sl 18:32 0:00 \_ unicorn_rails worker[1] -c config/unicorn.conf.rb -E production -D root 194 0.0 3.2 195812 67340 ? Sl 18:32 0:00 \_ unicorn_rails worker[2] -c config/unicorn.conf.rb -E production -D root 197 0.0 3.2 195812 67344 ? Sl 18:32 0:00 \_ unicorn_rails worker[3] -c config/unicorn.conf.rb -E production -D root 230 0.0 0.0 4380 676 ? S 18:33 0:00 sleep 1
masterのpidは182
。
pidが変わっていることを確認。
SIGTERMでgracefulな終了。
$ docker kill -s TERM my-app
$ docker run --name my-app app
.unicorn has stopped