DockerコンテナからホストのPostgreSQL DBにアクセスする


迷走した記録(汗

仕事で利用するRedmineをDockerコンテナで立てたのですが、前に職場が同じだった方から、
非常識である旨、ご指摘を受けて構成を変更するためにいろいろと迷走しました。
何をご指摘受けたのかといいますと、Dockerコンテナ上にDBも内蔵してしまったんですね。
それはコンテナ業界ではあまり取らない手法であると指摘を受けました。

単純に障害が起きてしまった際にデータが飛んでしまうということが理由でして、
試験環境とか特殊な要件がない限り、そのような構成は取らないということでした。

何をしたのか?

まず、私は以下のような構成でRedmineをコンテナで構成したんです。

冒頭に記載しました通り、そうなんです。PostgreSQLをコンテナ内に構築してしまいました…
ではこの記事で何を書こうとしているのかといいますと、PostgreSQLだけコンテナの外に出す形で構成しようと考えて、
結果として、いろいろと迷走したって話なんです。

↑の図のようにPostgreSQLだけ外だしして、そこにコンテナ内のRedmineからアクセスさせようとしたんです。
まぁ、明後日のほうに考えが広がってしまいまして、すごい単純な話でしたので、一応、記事にしておこうと思いました。
自戒の念を込めて、どのような経緯で間違えたのかを記録する意味があります。

まずは結論

必要なことはすごく単純なことだったのですが、以下の2つでいけました。

やったこと
1.Redmineコンテナの設定ファイルにて接続先DBホストをローカルIPアドレスに指定する
2.PostgreSQLのアクセス設定を変更する

上記でいけた訳なのですが、何を考えたのか、コンテナとホスト間でブリッジ接続をさせないと通信できないのではないかと考えたんです。
結局はPostgreSQLのアクセス設定が原因でDockerコンテナ内のプロセスとホストのDBが接続できていないだけでした。

迷走1:通信できない理由がネットワークレベルだと思い込んじゃった

まだ、私もDockerを触り始めたばかりで分かっていないことが多いのですが、
コンテナからホストへの通信ができないんだろうなって勝手に思い込んでいました。

Dockerのプロセス名は以下で確認して、

Dockerプロセス確認コマンド
docker ps

コンテナ内に入るコマンドは以下でいけますよね。

コンテナ内プロセスに潜入するコマンド
docker exec -it <Dockerプロセス名> bash

このプロセスに入って、ホストとの通信ができているのか、できていないのかを判断する方法を結局、見つけられませんでした。
調査する過程でいろいろと見つけたDockerのネットワーク構成についても考察記事をアップしたいと考えています。
探している最中にこのような記事を見かけたりしました!

<Dockerコンテナをブリッジ接続で使う>
https://www.agilegroup.co.jp/technote/docker-network-in-bridge.html

で結局、この記事を書いている時点で、なぜホストとDockerプロセス間で通信できているのか理由は分かっていないです。。

迷走2:iptablesが設定されている?

よく分かっていないのですが、Dockerを入れるとiptablesが設定されるのですね。

# iptables -nvL
Chain INPUT (policy ACCEPT 4546 packets, 1045K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
  202  136K DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0
  652  149K DOCKER     all  --  *      br-7aa7d549b7aa  0.0.0.0/0            0.0.0.0/0
   14   560 ACCEPT     all  --  *      br-7aa7d549b7aa  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
  530  913K ACCEPT     all  --  br-7aa7d549b7aa !br-7aa7d549b7aa  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 3624 packets, 1417K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:11211
    0     0 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:25
    0     0 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:443
  106 28298 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:80
    0     0 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:443
    0     0 ACCEPT     tcp  --  !br-7aa7d549b7aa br-7aa7d549b7aa  0.0.0.0/0            x.x.x.x           tcp dpt:80

Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  br-7aa7d549b7aa docker0  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  docker0 br-7aa7d549b7aa  0.0.0.0/0            0.0.0.0/0
  202  136K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Dockerが用意したインターフェースに対して、ファイアウォールが設定されているのを発見しました。
ホストとコンテナ内とは厳密に通信制御されている印象を受けてしまったことも思い込みを加速させた一因なんでしょうね。
結果としてはホストとコンテナ間の通信は何か制御されているということもなく、そのまま通信することができました。

やったこと、解決策

ご存じの方はご存じだと思いますけど、pg_hba.confというファイルでPostgreSQLのDBへのアクセス制御がされていますよね。
そちらの設定を緩くしてやることでコンテナからホストへのアクセスが出来ました!

/var/lib/pgsql/10/data/pg_hba.confの編集
77 # TYPE  DATABASE        USER            ADDRESS                 METHOD
78
79 # "local" is for Unix domain socket connections only
80 local   all             all                                     trust
81 # IPv4 local connections:
82 host    all             all             127.0.0.1/32            trust
83 # IPv6 local connections:
84 host    all             all             ::1/128                 trust
85 # Allow replication connections from localhost, by a user with the
86 # replication privilege.
87 local   replication     all                                     peer
88 #host    replication     all             127.0.0.1/32            ident
89 #host    replication     all             ::1/128                 ident
90 host    all             all             0.0.0.0/0               trust

88、89行目をコメントして、90行目に0.0.0.0からのアクセスをtrustにするという設定を追加しています。

53 #------------------------------------------------------------------------------
54 # CONNECTIONS AND AUTHENTICATION
55 #------------------------------------------------------------------------------
56
57 # - Connection Settings -
58
59 listen_addresses = '*'          # what IP address(es) to listen on;
60                                         # comma-separated list of addresses;
61                                         # defaults to 'localhost'; use '*' for all
62                                         # (change requires restart)

59行目の""内の値を*に変更することでどこからでもアクセス可能になります。

下記のGithubに上がっていた記事を参考にさせていただきました(ありがとうございます!)

Dockerコンテナのアプリからhost側にあるPostgresqlに接続したい
https://gist.github.com/toenobu/5026188d73b69046248c8792962a7b22

この設定を追加して、PostgreSQLのサービスを再起動し、docker-compose upコマンドを実行したら、
きちんとホストのPostgreSQLに接続した状態でRedmineのコンテナが起動しました。

PostgreSQLの再起動
systemctl restart postgresql-10
systemctl status postgresql-10

これからもDockerの勉強をして気づいたこととか記事をアップしていきますね!