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/
Django psycopg2
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)のアクセスエラー解決方法となります。
Dockerを構築するならVPSがおすすめです。
エンジニアのオンライン学習
ITエンジニアにおすすめの教材、オンラインスクールです。
無料からエンジニアの学習ができる教材などまとめているので参考にしてください。
おすすめオンライン教材 | |
自宅で学習ができるオンラインスクール | |
ITエンジニアの開発・検証・学習としてインターネット上で専用のサーバ(VPS)を利用しましょう!
実務経験はVPSで学べます。
コメントを残す