状況
-
/etc/profile.d/proxy.sh
でexport HTTP_PROXY=http://proxy.example.com:8080
している - PassengerでRailsアプリを動かしている
- そのRailsアプリでelasticsearch-railsを使っていて、localhost:9200にあがっているElasticSearchに接続したいが何故かproxy経由になってしまってうまく動かない
- CentOS 7 + Apache + Passenger 5
結論
アプリを起動しているユーザーの.bashrc
に以下の内容を追加する。
trace_parents() {
local pid=$$ cmd
while true; do
cmd=$(cat /proc/$pid/cmdline | tr '\0' ' ')
echo $cmd
[ $pid -eq 1 ] && break
pid=$(awk '/^PPid:/{print $2}' /proc/$pid/status)
done
}
trace_parents | grep "^Passenger core$" && {
unset HTTP_PROXY
unset http_proxy
unset HTTPS_PROXY
unset https_proxy
unset NO_PROXY
unset no_proxy
}
上記の例ではproxy関連の環境変数をunset
しているが、消したい環境変数なんでも好きなものを列挙すればよい。
trace_parents()
は以下のサイトを参考にした。
何が問題か
elasticsearch-railsは内部でfaradayを使っているが、こいつが環境変数no_proxyを無視する。というか正しくは未だ対応していない。
つまり環境変数http_proxyがセットされている場合、localhostや127.0.0.1含め、どこだろうが全てそのproxy経由接続になってしまい、それを回避する方法がない。
そもそもsystemdで起動しているhttpd(apache)から起動されるpassengerで、なんで/etc/profile.d/
以下に書いてある環境変数が読み込まれているのか謎だったが、調べてみるとPassengerのドキュメントにちゃんと書いてあった。
Through your bashrc. Starting from version 4.0, Passenger 4.0 spawns applications through bash and inherit all bash environment variables. Passenger Standalone tends to be started from the shell and thus inherits all environment variables set by the shell.
先程のtrace_parents
の結果を見てみると、たしかにPassengerからアプリ起動時にbash -lc
が実行されている。で、CentOSの場合、デフォルトの/etc/bashrc
ではインタラクティブシェルじゃない場合にも/etc/profile.d/*.sh
を読み込む記述になっていて、これでPassengerがRailsアプリをロードする時に環境変数が読み込まれていた、ということだった。
自分が直面したケースでは、Passengerから呼び出される時のみproxy関連の環境変数を削除することで対応可能だったので、.bashrc
内で呼び出し元をトレースしてPassengerだった場合のみunsetするようにして対処した。
学び、他
-
/proc/$pid/environ
を見ると、そのプロセスの環境変数が見れる。これは知らなかった。- cronで環境変数絡みのdebugするのどうするかいつも悩んでいたが、
sleep 60
的なことをしてここを確認すれば捗るような気がした。
- cronで環境変数絡みのdebugするのどうするかいつも悩んでいたが、
- そもそもfaradayで
no_proxy
対応してくれないと困る- 同じアプリ内で自分たちで書いている部分はtyphoeusを使っていて、こっちはlibcurlを使っているのでno_proxyに対応している。ちぐはぐ。