signal を http で受ける process wrapper 書いた

結局使わなかったので供養のためにブログ化しておく.

github.com

docker を始めとするコンテナ環境では,設定を適用するため signal を送ることで graceful reload をする仕組みは相性が悪いことがある.ホスト環境から動作中のコンテナに対してなんらかの働きかけが必要だからだ.なので,例えば systemd 環境下で動作しているアプリケーションをそのままコンテナ化することが難しかったりする. 特に,複数のアプリケーションが強調して動作する仕組みが必要である場合,side car コンテナなどでアプリケーションを分割すると途端に困難さが増す*1. アーキテクチャの刷新をするのが最も健全な手段であるが,そうもいかない場合に対処するため,signal のインターフェースを http に露出させるプロセスの wrapper を書いた.

mvp

signal を露出させたいプロセスの例として signal_echo.rb を用意

# signal_echo.rb

running = true

Signal.trap('INT') do |signo|
  puts 'Traped SIGINT'
  running = false
end

loop do
  break unless running
end

signal_echo.rb を http-signal-proxy から立ち上げる Dockerfile を用意

# Dockerfile

FROM ruby:2.5

RUN wget -q https://github.com/s4ichi/http-signal-proxy/releases/download/v0.1.0/http-signal-proxy_v0.1.0_linux_amd64.tar.gz && \
  tar -zxvf http-signal-proxy_v0.1.0_linux_amd64.tar.gz && \
  mv http-signal-proxy_v0.1.0_linux_amd64/http-signal-proxy /usr/local/bin/http-signal-proxy && \
  chmod +x /usr/local/bin/http-signal-proxy

COPY ./signal_echo.rb /signal_echo.rb
CMD ["http-signal-proxy", "--port=8080", "--command=ruby signal_echo.rb"]

実行

$ docker run -d --rm -p 8080:8080 -t http-signal-proxy-test:latest 
81f3d8507baa9c2a945c20d920824b6ca18f3be4ef04c7b853ac9b33c0480356

$ docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
81f3d8507baa        http-signal-proxy-test:latest   "http-signal-proxy -…"   4 seconds ago       Up 3 seconds        0.0.0.0:8080->8080/tcp   jolly_spence

$ curl http://localhost:8080/http-signal/sigint
Successed to proxy sigint to destination command%             

$ docker ps                                    
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

実装は entrykit とか supervisord を参考にした.entrykit はなかなか厳しそうなコードがそこそこあることがわかった.

push or pull

コンテナ外部から reload したいとき(push 型)はこういう手段がいいのかなぁと思って書いた.結局使わなかったというのは,コンテナ内部で reload が必要かどうかを polling すれば(pull 型)十分であることがわかったからだ.push 型はいつか必要になるのかな….