【docker-compose】CentOS8環境(Django+PostgreSQL)NetworkエラーでDBにアクセス不可解決方法

CentOS8環境において、Django+PostgreSQLの「docker-compose」を実行した際、PostgreSQLへのアクセスエラーが発生し、うまく接続ができない事象の解決方法をまとめます。

Linux系でDockerコンテナを立てて、困っている方は参考にしてください。

※本環境はConoHaVPSを使用しています。

「CentOS8」docker-compose実行時にDjango+PostgreSQLでアクセスエラーが発生する事象の解決方法

CentOS8環境下のDocker-composeの設定内容は以下となります。
「Dockerfile」のproxyはVPSなど外部サーバで実行する場合は必要です。

参考はこちらから

今回は以下のファイル情報をもとに、docker-compose実行時のアクセスエラーの対応方法をまとめます。

  • Dockerfile
  • FROM python:3
    ENV PYTHONUNBUFFERED 1
    RUN mkdir ./code
    WORKDIR /code
    COPY requirements.txt /code/
    RUN pip install --proxy=x.x.x.x:3128 -r requirements.txt
    COPY . /code/
    
  • requirements.txt
  • Django
    psycopg2
    
  • docker-compose.yml
  • version: '3'
    
    services:
      db:
        image: postgres
        ports:
                - 5432:5432
        environment:
                - POSTGRES_PASSWORD=postgres
        volumes:
                - ./db-data:/var/lib/postgresql/data
        container_name: postgres
    
      web:
        restart: always
        build: .
        command: bash -c "python manage.py runserver 0.0.0.0:8000 && python manage.py migrate"
        volumes:
          - .:/code
        ports:
          - 8000:8000
        depends_on:
          - db
        container_name: django
    
    volumes:
        db-data:
    

このファイルの設定で実際にDjangoプロジェクトを作成します。

$ docker-compose run web django-admin startproject webapp .

プロジェクト実行後以下のようにファイルとフォルダが作成されます。

drwx------ 19 systemd-coredump root   4096 Apr 27 14:04 db-data
-rw-r--r--  1 root             root 131072 Apr 27 13:28 db.sqlite3
-rw-r--r--  1 root             root    503 Apr 27 13:58 docker-compose.yml
-rw-r--r--  1 root             root    174 Apr 22 19:53 Dockerfile
-rwxr-xr-x  1 root             root    626 Apr 27 13:26 manage.py
-rw-r--r--  1 root             root     25 Apr 12 16:59 requirements.txt
drwxr-xr-x  3 root             root   4096 Apr 27 13:59 webapp

「docker-compose up」における「TCP/IP connections on port 5432?」エラーの解決方法

Djangoプロジェクト作成を以下コマンドで「docker-compose up」コマンドを実行したところ「TCP/IP」のコネクションエラーが発生しました。

$ docker-compose up
Creating network "django_default" with the default driver
Recreating postgres ... done
Creating django     ... done
Attaching to postgres, django

------中略------

django | django.db.utils.OperationalError: could not connect to server: No route to host
django | 	Is the server running on host "db" (192.168.192.2) and accepting
django | 	TCP/IP connections on port 5432?
django | 

ホスト「db」へのアクセス時にポート5432へアクセスができないというようなエラーみたいです。
Firewallではポート5432は許可をしていますが、いったん切り分けのためにFirewallを停止して確認します。

「切り分け」firewallを落として確認

原因切り分けのためにいったん以下コマンドでFirewallを停止します。
実行後、Firewallの状態で停止していることを確認します。

$ systemctl stop firewalld
$  
$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Sun 2020-04-26 18:52:47 JST; 6s ago
     Docs: man:firewalld(1)
  Process: 2513 ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS (code=exited, status=0/SUCCESS)
 Main PID: 2513 (code=exited, status=0/SUCCESS)

Apr 26 16:24:32 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-24f954cda79b -o br->
Apr 26 16:31:12 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-9b06ad455975 -o br->
Apr 26 16:32:26 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-fb2025b06515 -o br->
Apr 26 16:35:37 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-b338f46a6314 -o br->
Apr 26 16:48:47 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-86190d7798ac -o br->
Apr 26 16:50:35 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-cec9a093e241 -o br->
Apr 26 16:59:14 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-4141be596031 -o br->
Apr 26 18:45:13 118-27-15-211 firewalld[2513]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i br-29629961a169 -o br->
Apr 26 18:52:46 118-27-15-211 systemd[1]: Stopping firewalld - dynamic firewall daemon...
Apr 26 18:52:47 118-27-15-211 systemd[1]: Stopped firewalld - dynamic firewall daemon.
$ 

FWを停止後、再度「docker-compose up」実行

FW停止後再度「docker-compose up」を実行すると以下のエラーが発生します。
うまくDNATが効いていないような感じです。

$ docker-compose up
Recreating postgres ... 
Recreating postgres ... error

ERROR: for postgres  Cannot start service db: driver failed programming external connectivity on endpoint postgres (c704035d23abbcc3aa3c1c8312413426ea24dae1cb9e55a3f4264dd0973b224e):  (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 5432 -j DNAT --to-destination 192.168.192.2:5432 ! -i br-29629961a169: iptables: No chain/target/match by that name.
 (exit status 1))

ERROR: for db  Cannot start service db: driver failed programming external connectivity on endpoint postgres (c704035d23abbcc3aa3c1c8312413426ea24dae1cb9e55a3f4264dd0973b224e):  (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 5432 -j DNAT --to-destination 192.168.192.2:5432 ! -i br-29629961a169: iptables: No chain/target/match by that name.
 (exit status 1))
ERROR: Encountered errors while bringing up the project.

原因はiptable上のNATルールで失敗しているようです。

Creating network "django_default" with the default driver
ERROR: Failed to Setup IP tables: Unable to enable SKIP DNAT rule:  (iptables failed: iptables --wait -t nat -I DOCKER -i br-d8e6d6e46e1a -j RETURN: iptables: Index of insertion too big.
 (exit status 1))

「docker-compose up」アクセスエラーの解決方法

エラーの解決方法は、NAPT(IPマスカレード)の設定をFWに追加します。

NAPT(Network Address Port Translation)は、IPアドレスの変換と同時にポート番号も変換する機能です。

まずは、Docker 管理のネットワークファイルの再構成をします。
※再構築は特にしなくてもいいかもしれないです。

$ mv /var/lib/docker/network/files /tmp/docker-iptables-err
$ systemctl restart docker

次に、FWにNAPTの許可設定をしますが、firewallをあげた後に、dockeerを上げる手順にします。

$ firewall-cmd --add-masquerade --permanent
success
$ firewall-cmd --reload

この後にDockerを再起動すると事象は解消されます。
実行の流れは以下でまとめています。

実行結果

Docker停止

$ systemctl stop docker

NAPTをFWで許可・再起動

$ firewall-cmd --add-masquerade --permanent
success
$ firewall-cmd --reload
success

Docker起動

$ systemctl start docker

「docker-compose」コマンド実行

$ docker-compose up -d
Starting postgres ... done
Starting django   ... done
$

上記実行後、正常にDockerにアクセスすることができます。

Django起動後、データベースにアクセスするとエラーになる場合

Djangoが起動できても、管理画面へのアクセス時に以下のエラーが発生することがあります。

この事象が発生した場合は「migrate」コマンドでデータベースと同期することで解消されます。

$ docker-compose run web python manage.py migrate

※このコマンドは必ず「docker-compose run」で実行します。「web」はdocker-compose.ymlで書いているサービス名でDjangoコンテナへのアクセスとなります。
通常のmigrateコマンドはホスト自身に実施するためコンテナ上には反映されません。

データベースとの同期がとれると以下ように管理画面が正常に表示されます。

dockerコンテナでのユーザー作成(管理画面アクセス)

次にDockerコンテナ上のDjango管理画面にアクセスするユーザーの作成をします。
こちらも「docker-compose run」を実行します。

$ docker-compose run web python manage.py createsuperuser
Starting postgres ... done
Username (leave blank to use 'root'): root
Email address: 
Password:
Password (again):
Superuser created successfully.
$

上記でユーザー作成後、再度管理画面にアクセスをし、ログインできることを確認します。

ログインが正常にできると以下の画面に切り替わります。

不要な「ゴミコンテナ」の削除

上記「docker-compose run」コマンドを実行すると、不要なコンテナが作成されているので削除をします。

今回、作成されるコンテナ名は「django」と「postgres」となりますので、そのほかのコンテナは、「docker-compose run」で実行された不要なコンテナとなります。
ステータスも「Exited」となっているので削除しても問題ないです。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                          PORTS                    NAMES
9db2f7d399cf        django_web          "python manage.py cr…"   About a minute ago   Exited (0) 51 seconds ago                                django_web_run_3c85e797b463
2384f76a0327        django_web          "python manage.py su…"   About a minute ago   Exited (1) About a minute ago                            django_web_run_ff0599e6dd00
b5c954794171        django_web          "python manage.py mi…"   2 minutes ago        Exited (0) 2 minutes ago                                 django_web_run_1b1c595e1631
33c2f1d63efb        django_web          "bash -c 'python man…"   2 minutes ago        Up 2 minutes                    0.0.0.0:8000->8000/tcp   django
47124a91007c        postgres            "docker-entrypoint.s…"   2 minutes ago        Up 2 minutes                    0.0.0.0:5432->5432/tcp   postgres
$

不要なコンテナを一気に削除する場合はスペースを入れると便利です。

$ docker rm django_web_run_3c85e797b463 django_web_run_ff0599e6dd00 django_web_run_1b1c595e1631
django_web_run_3c85e797b463
django_web_run_ff0599e6dd00
django_web_run_1b1c595e1631

削除後再度コンテナを確認し、不要なコンテナが削除されていることを確認します。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
33c2f1d63efb        django_web          "bash -c 'python man…"   3 minutes ago       Up 3 minutes        0.0.0.0:8000->8000/tcp   django
47124a91007c        postgres            "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:5432->5432/tcp   postgres
$

「django.db.utils.OperationalError: 」で名前解決エラーが発生した場合

以下のように任意のDockerネットワークを作成し、エラーが出る場合があります。

django | django.db.utils.OperationalError: could not translate host name "djangonet" to address: Name or service not known

こちらは「settings.py」で別途作成した、「djangonet」というネットワークをHOSTに設定した際に起きたエラーとなります。

解決方法

今回は、「docker-compose.yml」で書かれている通り、settings.pyのHOSTを「db」にすることでPostgreSQLへアクセスできます。

別途作成したネットワークではアクセスできないので注意しましょう。
※ここ重要です。

最終的な「settings.py」のデータベース設定は以下となります。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD' : 'postgres',
        'HOST' : 'db',
        'PORT' : 5432,
    }
}

DockerでDjango+PostgreSQLを連携したコンテナを立てる記事は以下を参考にしてください。

以上が、CentOS8環境におけるDockerコンテナ(Django+PostgreSQL)のアクセスエラー解決方法となります。




エンジニアのオンライン学習

ITエンジニアにおすすめの教材、オンラインスクールです。
無料からエンジニアの学習ができる教材などまとめているので参考にしてください。

おすすめオンライン教材
自宅で学習ができるオンラインスクール

ITエンジニアの開発・検証・学習としてインターネット上で専用のサーバ(VPS)を利用しましょう!
実務経験はVPSで学べます。



コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

ABOUT US
げんき☆ひろき
インターネット関連のSEをやっています。 ネットワーク、サーバー、ストレージ、仮想基盤まで幅広く手を出しており、MVNOの構築経験もあります。 現在は、Pythonを使ったプログラミングの開発をしネットワークの自動化ツールを作成しています! Pythonの入門書も作成しているので、ぜひ参考にしてください!