0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NextCloudを使いたかった。―Docker内のコンテナからインターネットにアクセスできない―

Posted at

結論

(ネットワークモードにhostを使用する以外は)無理!!!!!!!!!! だった。

前提条件

自宅サーバを動かしてる。OSはArchLinuxで試験的かつ個人利用のみでWebサーバとVPNサーバを動かしてる。

やりたかったこと

一番最初の目的はNextCloud(ストレージサーバ)の構築だった。異なるサーバソフトウェアを一つのサーバ機上に展開するのはヤバイとそろそろ気付き始めたので、勉強ついでにDockerを使って導入しよう、可能ならWebServerとVPNServerもコンテナとして移行させよう、なんてこと考えてた。

Docker composeの利用

調べ始め、よくわからないけどdocker-composeとか言うものを使えば良いらしいと聞き、ネットに散見しているNextCloudのdocker-compose.yamlを拾ってきて実行した。

参考にしたサイト:

だが、どう試してもアクセスができない。ブラウザからのアクセスもcurlからのアクセスも、Timeoutによって何も表示されない。真っ白な画面が表示されるだけ。信頼できるドメインに自分のドメインが登録できていないからかとそちらも試したが変わず。docker-composeのポートマッピングは80番ポートから変更しており、nftablesなどは一時的に無効化している。

参考にしたサイト:

サーバ内からcurlをしてみるとデータが取ってこれると気づいた。ということは、インターネットとの接続がうまく行ってない?と考え、Webサーバ用に動いているNginxに協力してもらい、サブドメインを見分けてNextCloudに転送してもらうよう設定した。

# こんなイメージ
server {
        listen       80;
        server_name  nextcloud.example.com;

        location / {
        proxy_pass http://localhost:60000/;
        }
    }

Nginxの転送技を使うことで外部からのアクセスが可能になり、ログイン画面に到達できた。
image.png

NextCloudとDBサーバ間の通信

すんなり進んでほしい思いとは裏腹に、すぐに次の問題に直面した。NextCloudの管理用アカウントを入力しインストールボタンを押すと、次のエラーが表示された。
Error while trying to create admin account: An exception occurred in the driver: SQLSTATE[HY000] [2002] Connection refused
image.png
原因はNextCloudサーバとDBサーバとの間で正常な通信ができていないことと読み取った。DBサーバのユーザ名とパスワードをすべて同じ文字列にしてみたり、DBサーバの指定方法を"localhost"や"127.0.0.1"などに変えてみたり、DBサーバそのものをMariaDBからPostgreSQLに変更したりしたが結果は変わらなかった。そもそも公式に当たっていないのは論外ということか?と思い始めDockerHubやGitHubの公式リポジトリに当たって説明されているExamplesにそのまましたがって構築したが、同様のエラーが発生した。ちなみに、GitHubにある公式リポジトリにはmariadbの10.6が指定されていたが、これはそのままだと実行エラーが発生するため最新版にする必要がある。

参考にしたサイト:

公式から別途提供されているall-in-oneパッケージを見つけ、docker-composeを捨てることにした🥺。すると、次のエラーが発生した。

$ sudo docker run --init --sig-proxy=false --name nextcloud-aio-mastercontainer --restart always --publish 80:80 --publish 8080:8080 --publish 8443:8443 --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config --volume /var/run/docker.sock:/var/run/docker.sock:ro nextcloud/all-in-one:latest
Trying to fix docker.sock permissions internally...
Creating docker group internally with id 974
**Could not resolve the host nextcloud.com.**
Most likely the DNS resolving does not work.
You should be able to fix this by following https://dockerlabs.collabnix.com/intermediate/networking/Configuring_DNS.html
Apart from that, there has been this: https://github.com/nextcloud/all-in-one/discussions/2065

つまるところ、nextcloud.comのドメイン解決ができない。docker内のコンテナからnextcloud.comへの接続ができないということだった。

コンテナからのpingが帰ってこない

問題の切り分け

どうも、コンテナから外へ通信がうまく行っていないようである。少なくともドメイン解決ができていない。とりあえずこれを分離させるため、これまた見様見真似で新規のdockerコンテナを作成し、ここから8.8.8.8にpingを打ってみた。

$ docker run -itd --name alp alpine
6f6db48a1db25d04fbd175fbf263476634967c50f3d52710c1556234bea253a1
$ docker attach alp
/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss

このように、ドメイン解決とは関係なく通信ができていないことがわかる。
(現状わかっている)唯一の解決策は、上記のdocker runコマンドに--net=hostを付けることだった。これについて説明する。

Dockerと3種類のネットワーク

Dockerには3種類のネットワークモードが存在する。noneとhost、bridgeの3つである。なお、Dockerそのものに触り始めたばっかりであるとともに、解説そのものがメインの記事ではないため説明が適当であっても勘弁してほしい。
「none」はコンテナが全く通信をしない場合に設定する。コンテナ間の通信はできず、もちろん外部のネットワークとも通信ができない。
「host」はコンテナがDockerを実行するホストのネットワークインターフェースをそのまま利用する設定である。一つのインターフェースを共有する形であるため、ホストが接続するネットワークに対してコンテナからそのままアクセスすることが可能である。ポートマッピングをする必要は当然無く、コンテナとしてサーバを立てれば外からそのままアクセスが可能となる。コンテナ間の通信も可能である。
「bridge」はソフトウェアブリッジを構築し、NAT/NAPTを経由してホスト含め外部のネットワークと通信を行う。コンテナにはそれぞれプライベートIPアドレスが割り振られ、IPを用いることでコンテナ間の通信が可能となる。Dockerではこれがデフォルトとなっている。
Docker内にネットワークを新規作成することも可能である。Dockerからデフォルトで提供されているものをそのまま利用するにはセキュリティ的なリスクが存在するため、各自で作成することが推奨されている。

参考にしたサイト:

ネットワークモードにhostを使うと

Dockerがつながらない事象について調べる中で、hostを設定するとうまく行くという事例がいくつかヒットした。つまるところ、Dockerのブリッジを使わなければうまく行くということである。しかしながら、これには大きな欠点がある。それはポートがそのまま適用されてしまう点である。現時点でNginxを使用しWebサーバを立てている。一方NextCloudは内部でApacheを使用しており、アクセスはブラウザがメインであるためNginxと競合してしまうのである。これではDockerを使わず直接デプロイするのと変わらないのだ。docker-composeを使った場合でもネットワークモードをhostにするとうまく行ったが、これでは意味がない。
ついでに、不具合があるならその原因を追求するのが条理である。なんとかして問題解決できるよう頑張ってみる。

参考にしたサイト

【本編】インターネットにつながらない原因究明

さて、どう調べてみても上記で例示したような、コンテナからサクッとgoogleへpingが届かないような状況は正常でないらしい。これを解消するためにまる一日費やしたが解決しなかったので、試したこととその意味を箇条書きに羅列する。誰か助けてほしい。

1. systemctl restart docker

Dockerがうまく働かないなら、Dockerそのものを再起動させるのが良いと考えた。効果はなかった。

2. systemctl restart docker.socket

Dockerは簡単にいえば通信部に別途ソケットファイルを用いている。Docker.serviceのトリガーにもこのソケットが設定されている。とりあえずこちらも再起動させた。効果はなかった。

3. reboot

とりあえず、なにかうまく行かない場合はPCを再起動させるのが定番である。効果はなかった。

4. systemctl stop iptables, systemctl stop nftables

通信できないとなれば、やっぱり疑うべきはフィルタ部分である。もともとサーバではiptablesを動かしていたが途中からnftablesに移行した。どちらが影響しているかわからないため、両方とも動作を停止させ無効化させた。効果はなかった。

5. iptables -t nat -F

iptablesは-Fオプションによってフラッシュ(初期化)することができる。iptables内にはテーブルという枠組みが存在しており、パケットは全ていずれかのテーブルに割り振られる。そのうちNATに関するテーブルがnatテーブルであり、このコマンドではnatテーブル上のルールをリセットする。効果はなかった。

6. iptables -P FORWARD ACCEPT

iptables中のチェイン、FORWARDはパケットがマシンを中継する場合に適応される。Dockerのブリッジとマシン上のネットワークインターフェース(ここではeth0とする)は別物であるため、外から入ってきたパケットはeth0を経由してDockerへと入る。本来ならDockerがうまくiptablesを調整するが、これがうまく行っていない場合はFORWARDで止まるはずである。よってこのコマンドによってFORWARDに来るパケットを際限なく通過できるようにする。効果はなかった。

7. /etc/docker/daemon.jsonをいじる

今回は関係ない話となるが、念の為DNSの設定をしてみた。例として次のように書き込む。

{
    "dns": ["8.8.8.8", "8.8.4.4"]
}

その後、Dockerのサービスをリスタートさせる。こうすると、コンテナ内のetc/resolv.confにDNSの解決先として8.8.8.8、8.8.4.4が設定される。aptのアップデートなどドメイン解決の点でエラーが発生している場合はこれが有効となる。効果はなかった。

8. コンテナ内の/etc/resolv.confに8.8.8.8などを設定する

コンテナ内にexecやattachなどで直接入り込み、nameserverとして8.8.8.8などを設定する。ひとつ上の方法を自分の手で行う形である。効果はなかった。

9. サーバ機の/etc/resolv.confに8.8.8.8などを設定する

コンテナの/etc/resolv.confはサーバ機、つまりホストマシンのresolv.confが引き継がれるらしい。元々8.8.8.8が設定されていたが、試しに8.8.4.4も追記してみた。効果はなかった。

10. runコマンドのオプションとして--dns=8.8.8.8などを指定する

ふたつ上とほぼ同じである。効果はなかった。

11. docker system prune

参考にしたサイトではaptやapt-getのupdateの失敗対応方法として、容量不足を挙げられていた。サーバの空き容量に不安はなかったが、もしかするとDockerに割り当てられている容量が不足している?可能性も踏まえてDockerのキャッシュを消去した。効果はなかった。

12. brctl delbr docker0

Dockerが作成する仮想ブリッジはLinuxと深く結びついており、brctl(bridge-utils)からコントロールすることが可能である。docker0が仮想ブリッジの名前であるが、このコマンドで試しに消去している。その後Dockerのサービスを再起動させ、改めて構築させた。効果はなかった。

13. ip link delete docker0

ひとつ上とほぼ同じである。ここではip(iproute2)より仮想ブリッジであるdocker0を削除した。効果はなかった。

14. sysctl -w net.bridge.bridge-nf-call-iptables=0

Dockerのネットワークがbridgeモードで動作するとき、Linuxのカーネル機能を用いて仮想的なブリッジを作成している。このとき、カーネル部でパケット全体の処理を制御しているのがNetfilterである。よくフィルタとしてiptablesやnftablesを利用するが、これはユーザ向けのインターフェースであり内部ではNetfilterが制御されている。上のコマンドではブリッジに関するNetfilterを無効化するものである。この場合再起動後に無効化されるため、即時無効化する場合はproc/sys/net/bridge/bridge-nf-call-iptablesに0を格納するらしい。これにより制御を無効化するため、変なフィルタが掛かっていたとしてもスルーされて繋がるはずである。効果はなかった。

15. sysctl -w net.ipv4.ip_forward=1

6番の前提となる、IPフォワードを有効化する設定である。IPフォワードは異なるネットワークインターフェース間での通信を転送することである。何故かiptablesでの設定を先にしていたが、ここで改めて有効化させてみた。効果はなかった。

16. Dockerを再インストールする

何をどうやってもDockerがうまく動かないなら、最終的には再インストールしか無い。pacmanから-Rと-Sによって再インストールした。効果はなかった。

17. /ver/lib/dockerを削除する

Dockerのイメージやコンテナ等は全て/var/lib/docker内に保存されている。Dockerをpacmanより削除するのみではこれらが削除されないため、Dockerを完全に削除するにはここまで消去する必要がある。効果はなかった。

18. Dockerをダウングレードする

最新のDockerのパッケージに未知のバグが含まれていて、奇跡的にエラーがおきているに違いない。古いパッケージを使えばもしかしたらうまく動くかもしれない!効果はなかった。

参考にしたサイト

最後に

途中、こんなこと言いました。

**不具合があるならその原因を追求するのが条理**である。なんとかして問題解決できるよう頑張ってみる。

駄目でした。どうもすみませんでした。
この後サーバ決まるごと構築し直してくる。
もし他の方法をご存知の方がいらっしゃいましたらご教授いただけますと幸いです。
駄文をお読みいただきありがとうございました。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?