発端

Dockerで、Djangoコンテナ+uWSGI(Emperorモード)コンテナ+Postgresコンテナ、という構成にしてて、direnvで管理していたPostgresの接続情報でアプリ側から繋がらない現象にハマった

1
2
3
psycopg2.OperationalError: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

環境

1
2
3
4
Django==2.0.5
psycopg2==2.7.4
psycopg2-binary==2.7.4
python-dotenv==0.8.2

原因

結論から言うと、.envrcで管理している環境変数が、uWSGIコンテナだけ反映されていなかった

調べていく過程で「そらそうやわ」ってなったんだけど、当時切り分けのために実施した内容をまとめると

  • manage.py migrateは問題ない(※実際にスキーマが出来てる)
  • ブラウザからのアクセスでエラーになる

なんていうややこしい状態になった

これは、wsgi.pyを動かしているuWSGIコンテナ側には、direnvの.envrcに記述した以下の内容が反映されていないために出ている事が分かった

1
2
3
4
$ cat .envrc
export DB_HOST = [Postgresコンテナ]
export DB_USER = username
(以下略)

考えた

解決方法としてどんな方法があるのか考えてみた

  • uWSGIコンテナ側で環境変数を管理し、起動コマンドで環境変数を渡す
  • Djangoコンテナ側で、環境変数の管理方法を変える

1つ目の方法は、たとえdocker-compose.yml側に書いて管理したとしても、アプリ数が増えていくと、どんどん肥大化していってしまうので、やっぱりDjangoコンテナ側でなんとかするのがいいのかなぁという結論になりました

direnvは特性上、コマンドライン上でpython manage.pyする時だけは環境変数が問題なくセットされるが、uWSGIコンテナ側では当然反映されないので、じゃあDjangoコンテナ側で環境変数ロード出来る仕組みを作ればいいのか、そういえば、dotenvとかあったなー、というところに帰結し、乗り換えました

dotenv: インストール

1
$ pip install python-dotenv

dotenv: .envを作成

1
$ vim .env
1
2
3
DB_HOST=[Postgresコンテナ]
DB_USER=username
(以下略)

dotenv: .envの読み込み

修正箇所は、setting.pyのみです

1
$ vim settings.py
1
2
3
4
5
6
7
8
import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) /* ※この行より下に書く */

# 以下2行を追記(verbose=Trueはデバッグ出力用)
from dotenv import load_dotenv
load_dotenv(dotenv_path=BASE_DIR+'/../.env', verbose=True)

おわりに

今思えば、Python3+Django1.10+Nginx+uWSGIでMySQLに接続するまでのメモで似たような事をしているので、wsgi.py使う勢は覚えといたほうがよいのかもしれない