简体   繁体   中英

How to connect a Docker container to PostgreSQL running on the localhost using a DATABASE_URL?

I'm following the Aptible Django Quickstart Tutorial which described how to create and deploy an app Aptible's PaaS. I would also like to be able to run the Docker container with the Django app locally and connect to a local PostgreSQL database, however, and it is unclear to me how to do this.

The Dockerfile for the Django app is:

FROM python:3.6

# System prerequisites
RUN apt-get update \
 && apt-get -y install build-essential libpq-dev \
 && rm -rf /var/lib/apt/lists/*

# If you require additional OS dependencies, install them here:
# RUN apt-get update \
#  && apt-get -y install imagemagick nodejs \
#  && rm -rf /var/lib/apt/lists/*

# Install Gunicorn. If Gunicorn is already present in your requirements.txt,
# you don't need that (but if won't hurt).
RUN pip install gunicorn

ADD requirements.txt /app/
WORKDIR /app
RUN pip install -r requirements.txt

ADD . /app

EXPOSE 8000

CMD ["gunicorn", "--access-logfile=-", "--error-logfile=-", "--bind=0.0.0.0:8000", "--workers=3", "mysite.wsgi"]

where mysite is the name of the Django app. Its settings.py uses dj-database-url as follows:

import dj_database_url
DATABASES = {'default': dj_database_url.config()}

In order to connect to a local instance of PostgreSQL, it would seem I should follow the Docker for Mac Solution on Allow docker container to connect to a local/host postgres database :

docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal

However, if I try this I still get an error ending with

  File "/usr/local/lib/python3.6/site-packages/psycopg2/__init__.py", line 130, in connect
    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
django.db.utils.OperationalError: could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?
could not connect to server: Cannot assign requested address
    Is the server running on host "localhost" (::1) and accepting
    TCP/IP connections on port 5432?

It would seem to me that the app as currently configured is not 'doing anything' with the DB_PORT and DB_HOST environment variables, because it is reading these in one go from the DATABASE_URL . Is this the problem? If so, how could I fix this while still using DATABASE_URL as this appears to be the 'interface' to Aptible?

I managed to fix the problem by changing the DATABASE_URL in the .env file from

DATABASE_URL=postgres://my_app:my_password@localhost/my_database

to

DATABASE_URL=postgres://my_app:my_password@docker.for.mac.host.internal/my_database

and running the container, which I tagged lucy_web , like so:

docker run -p 8000:8000 --env-file .env lucy_web

It was not necessary to change listen_addresses to '*' in my postgresql.conf ; this was still at its default, localhost . (I believe this is because the -p 8000:8000 argument maps port 8000 on localhost to the container).

As I understand, postgres is not running on a container but as a service on your host os, right?

Please theck below:

1. Check your postgres accepts connections on all ip addresses

Usually postgres listens to localhost only, that means, connections to other than localhost are refused. Each docker container is attached to a virtual network and communication from container to host happens through that virtual network.

Update your postgresql.conf file and add:

listen_addresses = '*'          # what IP address(es) to listen on;
                                    # comma-separated list of addresses;
                                    # defaults to 'localhost'; use '*' for all
                                    # (change requires restart)

2. Use correct ip address/hostname

As stated before, container communicates to host through this virtual network. Make sure your are using the correct hostname or ip address.

  • localhost

localhost is not going to work because from within the container context, localhost refers to the container

  • docker.for.mac.host.internal

At least for me it doesn't work (docker-ce on a mac), see that host resolution is not working

docker run --rm -it postgres:10 ping docker.for.mac.host.internal
ping: unknown host
  • use your ip address

I'm using my the ip address given by my dhcp server, ping works

docker run --rm -it postgres:10 ping 192.168.0.* -c 1
PING 192.168.0.* (192.168.0.*): 56 data bytes
64 bytes from 192.168.0.*: icmp_seq=0 ttl=37 time=0.455 ms

So try using a valid ip address, either the ip of the docker device or the ip from your physical network interface.

3. Use a docker compose file

Use a docker compose file to run with either compose or swarm, see sample application here: https://docs.docker.com/engine/swarm/stack-deploy/#create-the-example-application

Windows 用户配置他们的 env 以使用:

DATABASE_URL=postgres://my_app:my_password@docker.host.internal/my_database

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM