Docker 컨테이너에서 로컬 PostgreSQL 접속

Thu Sep 19, 2024
3 minutes to read

본래 PostgreSQL을 Docker 컨테이너로 돌리다가 굳이 Docker로 돌릴 필요가 있나 싶어 로컬 서비스로 옮기기로 했다.

다만 그냥 옮겨서 바로 포트에 연결해 사용할 수는 없고 추가적인 설정이 필요하다.

PostgreSQL 설정 #

연결 설정 #

Docker 컨테이너는 docker0 인터페이스를 통해 외부와 통신한다.
이는 컨테이너 내에서 포트에 연결을 요청하면 로컬에서는 docker0로부터의 요청으로 해석된다는 것이다.

PostgreSQL이 기본적으로 localhost만 LISTEN 하기 때문에 이를 docker0도 LISTEN 하도록 수정해 줄 필요가 있다.

postgresql.conf를 열어 listen_addresses 항목을 수정한다.

ip route show dev docker0
1# ip route show dev docker0
2172.17.0.0/16 proto kernel scope link src 172.17.0.1 linkdown
/var/lib/postgres/data/postgresql.conf
 1#------------------------------------------------------------------------------
 2# CONNECTIONS AND AUTHENTICATION
 3#------------------------------------------------------------------------------
 4
 5# - Connection Settings -
 6
 7listen_addresses = 'localhost,172.17.0.1'
 8                    # what IP address(es) to listen on;
 9                    # comma-separated list of addresses;
10                    # defaults to 'localhost'; use '*' for all
11                    # (change requires restart)
12#port = 5432                # (change requires restart)
13max_connections = 100           # (change requires restart)
14#reserved_connections = 0       # (change requires restart)

IP 필터링을 사용할 이유가 없다면 *로 설정해 모든 IP를 허용해도 상관없다.

인증 설정 #

PostgreSQL은 pg_hba.conf 파일에 선언된 IP가 아니면 연결을 거부한다.
필요에 따라 IP 범위와 인증 방식을 지정해주면 된다.

아래 예시에서는 마지막 줄이 Docker를 위한 설정이다.

/var/lib/postgres/data/postgresql.conf
 1# TYPE  DATABASE        USER            ADDRESS                 METHOD
 2
 3# "local" is for Unix domain socket connections only
 4local   all             all                                    scram-sha-256
 5# IPv4 local connections:
 6host    all             all             127.0.0.1/32           scram-sha-256
 7# IPv6 local connections:
 8host    all             all             ::1/128                scram-sha-256
 9# Allow replication connections from localhost, by a user with scram-sha-256
10# replication privilege.
11local   replication     all                                    scram-sha-256
12host    replication     all             127.0.0.1/32           scram-sha-256
13host    replication     all             ::1/128                scram-sha-256
14
15host    all             all             192.168.0.0/24         scram-sha-256
16host    all             all             172.0.0.0/8            scram-sha-256

서비스 시작 순서 변경 #

위에서 PostgreSQL이 docker0의 IP를 LISTEN 하도록 설정했다.
문제는 PostgreSQL 서비스가 Docker 서비스보다 먼저 시작될 수 있다는 것이다. 이 경우 IP가 사용 상태가 아니므로 해당 IP에 bind할 수 없다.

1LOG:  could not bind IPv4 address "172.17.0.1": Cannot assign requested address
2WARNING:  could not create listen socket for "172.17.0.1"

해결책은 서비스의 drop-in 디렉터리를 만들어 순서에 대한 설정을 추가하는 것이다.
아래 설정은 docker 서비스 시작 이후에 postgresql 서비스가 시작되도록 한다.

/lib/systemd/system/postgresql.service.d/docker.conf
1[Unit]
2Wants=docker.service
3After=docker.service

서비스 재시작 #

모든 수정이 끝났다면 systemctl daemon-reload 명령으로 서비스를 다시 불러오고, PostgreSQL 서비스를 재시작해 변경사항을 적용한다.

Docker 컨테이너 설정 #

두 번째 문제는 어느 IP를 통해 컨테이너 내부에서 로컬에 연결할 수 있느냐이다.

localhost는 컨테이너 내부의 localhost이므로 사용할 수 없다.
외부로 연결하려면 위에서 언급한 것처럼 docker0의 IP를 사용해야 한다.

Host 매핑 #

docker run 명령의 경우 --add-host "(host):host-gateway" 파라미터를 사용해 docker0의 IP를 원하는 host에 매핑해줄 수 있다.

Docker Compose의 경우 아래처럼 설정해 같은 결과를 얻을 수 있다.

1extra_hosts:
2    - "(host):host-gateway"

이후 설정한 host를 통해 포트에 접근할 수 있다. 아래는 host를 host.docker.internal로 설정해 사용하는 예시이다.

1DATABASE_URL: postgresql://host.docker.internal/service