Closed16

rubocop-daemonはdocker-compose環境で動くか?

inomotoinomoto

docker-compsoe.ymlにて

  rubocop_daemon:
    build:
      context: ./backend
    command: bundle exec rubocop-daemon start --no-daemon
    volumes:
      - /app/.bundle
    logging:
      driver: none

とした上でdocker-compose exec rubocop_daemon bundle exec rubocop-daemon execとすればひとまず動く。
vscodeならこれをshellスクリプトにでもしてPATH通せばよいはず。

※なおディレクトリ構成は以下

/project-root/
  - docker-compose.yml
  - backend/
      - Gemfile
inomotoinomoto

しかしこれでは起動オーバーヘッドが大きく、「daemonにしなくてもdocker-compose execでrubocop動かせば良くない?」となる。

やはりrubocop-daemon-wrapper版を動かしたい。

inomotoinomoto

shellscriptは色々やっていてよくわからんのだが、要するに"TOKEN APP_ROOT_PATH COMMAND ARGS"がTCPで送信できればよい。
netcatだと例えばecho '1c1cf8a8 /app exec' | nc 127.0.0.1 43537てな感じ。

OSやLinuxディストリによってncコマンドにオプションが必要だったりするので分岐が入っている。
またTOKENはdaemon実行したユーザの$HOME/.cacheあたりに入っているので取り出している。

inomotoinomoto

なおrubyだとこんな感じ。結果の読み出しがちと雑だが...

require 'socket'

Socket.open(:INET, :STREAM) do |sock|
  addr = Socket.sockaddr_in(DAEMON_PORT, DAEMON_HOST)
  sock.connect addr
  sock.write "#{DAEMON_TOKEN} #{APP_ROOT} exec"
  sock.shutdown(Socket::SHUT_WR);
  loop do
    s = sock.gets(chomp: true)
    break unless s
    p s
  end
end
inomotoinomoto

bind問題は一旦後回しとして、docker-composeで起動&外からアクセスする場合、

  • 待ち受けポートの固定
  • ホストのディレクトリを$HOME/.cache/rubocop-daemonにマウント

が必要。つまり

  rubocop_daemon:
    build:
      context: ./backend
    command: bundle exec rubocop-daemon start --no-daemon --port 3001
    volumes:
      - "./backend/tmp/rubocop-daemon:/root/.cache/rubocop-daemon"
      - /app/.bundle
    ports:
      - "3001:3001"
    logging:
      driver: none

という感じ。

inomotoinomoto

ところで、頑張って外からncするのかdocker-compose execでncするのと、どのくらい速度差があるだろうか?

ちなみに他の方法だと compose経由rubocop-daemon exec >> rubyスクリプト(socket) > nc

inomotoinomoto

うむ。docker-compose execの起動はなかなかに遅かった。

inomotoinomoto

daemonの待ち受けアドレスの変更はpullreqするとして、クライアント側のスクリプトはこんな感じになりそう。

rubocop
#!/bin/bash

set -eu
cd $(dirname $0)

NETCAT_COMMAND="nc -N" # 適当に変えるなり分岐するなり

echo $(cat tmp/rubocop-daemon/app/token) /app exec $@ | $NETCAT_COMMAND 127.0.0.1 $(cat tmp/rubocop-daemon/app/port)

exit $(cat tmp/rubocop-daemon/app/status)

※適当に書いて確認してないので注意

inomotoinomoto

オリジナルのrubocop-daemon-wrapperはかなり色々なことをやっていて、適当に並べると

  • daemonのコマンドが存在するか確認
  • ncコマンドのオプション判別
  • ルートディレクトリ名の判別
  • stdinを取り回す機能
  • daemonが起動してなかったら起動する
  • 全てにおいてエラーハンドリング&メッセージ出し

という感じ。利用環境をある程度確定させると殆どの処理は不要になるので、プロジェクトごとに自分で書いたほうがスッキリする。
またdocker-compose環境ではルートディレクトリ名の判別が足枷になってしまう(daemonとwrapperで実行環境が違うため)。

inomotoinomoto

あとは

  • daemonの待ち受けアドレス問題をなんとかする
  • ↑のshellscriptの検証・整理する

したら適当に記事にしたためて終了。

inomotoinomoto

vscodeのformatterとして指定すると対象ファイル名をフルパスで指定されるためにコンテナ内のパスと合わない。

inomotoinomoto

パス問題:

OPTIONS=$(echo "$@" | sed "s|$PWD|\.|g")

stdin -> vscodeは確定で'-s'なので決め打ちでcatしておく

このスクラップは2020/12/26にクローズされました