先日、ハマったproxy関連の対応についての続報。
Ubuntu デスクトップ(19.04)でdnsの参照先が自身のIPアドレスしかない場合、コンテナ内の「/etc/resolv.conf」には勝手に「nameserver 8.8.8.8」「nameserver 8.8.4.4」が追加される。
そして、Proxy環境下ではこの設定が邪魔をして、elixirのmixコマンドが実行できなかった。
これに対応する場合の処理を見つけたので記述しておく。
続きを読むよくある「Proxy環境下」でハマった話。
ElixirのPhoenix Frameworkの開発環境を作ろうと思い、Dockerfileを用意。
だが、同じDockerfileを使ってイメージ/コンテナを作成したにも関わらず、ホストマシンのOSの違いで「mix local.hex」コマンドが実行できる/できないが発生した。
どちらのDockerコンテナ内からも、curl、wget、aptの実行は可能だった。
利用したホストマシンと実行結果は以下の通り。
失敗時のエラー内容は、以下の通り。
コンテナ内で設定しているProxyを経由して外に出ようとしているが、何かしらの要因で外に出られない様子。
# mix local.hex ** (Mix) httpc request failed with: {:failed_connect, [{:to_address, {'proxy.local.jp', 8080}}, {:inet, [:inet], :nxdomain}]} Could not install Hex because Mix could not download metadata at https://repo.hex.pm/installs/hex-1.x.csv.
エラーメッセージ中の「 {'proxy.local.jp', 8080}」はProxyサーバとポートの組み合わせ。
環境変数にhttp_proxyやhttps_proxyを追加する前は「{'repo.hex.pm', 443}」だったので、メッセージの1行目はto_addressに到達できない、という意味合いのエラーメッセージと考えられる。
ホストマシンが「Ubuntu 19.04」側のコンテナで、「/etc/resolv.conf」を修正したことで、エラーが解消できた。
※本記事は、2019.07.15時点の情報で記述しています。
備忘。
「mix local.nerves」コマンドを実行してnerves_bootstrap のバージョンを上げてしまい、「mix nerves.new」コマンドが実施できなくなった。
バージョンアップしたnerves_bootstrapが利用できるElixirのバージョンにするか、現在のElixirで利用できるバージョンのnerves_bootstrapに戻す必要があります。今回は前者で対応しました。
続きを読む気づくに小一時間かかったので、備忘の意味で記述。
「 /etc/hosts.allow 」にsnmpdのアクセス制限を設定していたため。
dockerに割り当てられていたIPアドレス(今回の場合、172.17.0.0/16)を「/etc/hosts.allow」に追記したら、あっさりと応答してくれた。
snmpd: 172.17.0.0/255.255.0.0
dockerコンテナ中にsnmpマネージャを構築。dockerコンテナのホストはCentOS7。
試しに、コンテナのホストに対してsnmpwalkコマンドでsnmpを投げてみるも、応答が戻って来ずにTimeoutが発生。
なお、「172.17.0.1」がコンテナ(snmpマネージャ)側から見たホストのIPアドレス。(いわゆるDockerにおける仮装ブリッジdocker0のIPアドレスである。)
# snmpwalk -v 2c -c public 172.17.0.1 .1.3.6.1.2.1.1 Timeout: No Response from 172.17.0.1
snmpwalkの宛先をホストサーバ自身が持つ別のIPアドレスで実施しても結果は同じ。
なお、ホストサーバ自体にはsnmpdを設定しているし、コンテナ外からホストにsnmpすると応答が返ってくるのは確認済み。
また、コンテナからホスト向けに発行したpingの応答は返ってくる。
このことから、「コンテナからホストへのsnmpリクエスト」か「ホストからコンテナへのsnmpレスポンス」のどちらかで通信できていないと仮定。
順に確認していく。
まず、「コンテナからホストへのリクエスト」の確認。
コンテナのイメージも自分で作成していたので、まずはDockerfileの定義から確認。
snmpは通常「ポート161」を「UDP」で利用する。そのため、「161/udp」の穴あけが必要。
Dockerfile には「 EXPOSE 161/udp 」を設定していたので、大丈夫そう。
次に、docker run時には「 -p 10161:161/udp 」も付与して実行し、コンテナでポート161が通信できるように設定済みであった。
懸念点としては、ホスト側のポートを10161としている所。だが、snmpdを動作させている関係でホスト側のポート161をバインドできなかったための処置である。
少し怪しい部分が出てきたので、ホスト側でtcpdumpを実行することにした。
ホスト側のインタフェース「docker0」に対してtcpdumpを実行すると、dockerからのsnmpリクエストの通信ログは出ていたが、snmpレスポンスの通信ログは発生していなかった。
このため、「ホストからコンテナへのsnmpレスポンス」の通信が怪しそう。
念の為、snmpd側のログをみる。
すると
Jul 2 14:04:49 snmp-dev snmpd[10333]: Connection from UDP: [172.17.0.3]:34564->[172.17.0.1]:161 REFUSED
となっていた。
REFUSED(拒否)なので、dockerコンテナ(正確には、ホストの仮装ブリッジdocker0に割り当てられた)のIPアドレスからのアクセスが拒否されていると推定。
ただし、snmpdではアクセス制限をかけていなかった。
通信関係なら「 firewalld 」かとも思い確認してみるが、ポート161に対して「172.0.0.0/8」レベルでアクセス許可の設定を投入していた。
他に何か要因があるかと考えていると、snmpdなので「/etc/hosts.allow」や「/etc/hosts.deny」でアクセス制限できることを思い出す。
というわけで、両ファイルの確認。
「 /etc/hosts.deny 」を確認するも記述なし。
次に、「 /etc/hosts.allow 」を確認したところビンゴ。
プライベートIPアドレスのクラスC(192.168.x.x)とクラスA(10.x.x.x)でアクセス制限をかけていた。
ここに、Dockerの仮想ネットワークで利用しているIPアドレスの範囲(今回の場合、172.17.0.0/16)を許可する設定を追記。
無事、アクセスできるようになった。
dockerコンテナを利用していため、コンテナ側やコンテナ-ホスト間の通信に原因があると思い込んでしまった。
しかし、実際にはコンテナは直接は関係しない原因(IPアドレスによるアクセス制限)であった。
思い込みは捨て、一つ一つ原因を絞り込んでいく大切さを改めて思い出した。