skip to Main Content

I’ve written a simple Newsletter web app using Flask that has a connection with my local Postgres database. When I run the app as-is (not inside a Docker container) it works perfectly normal and sends the submitted user info to my local DB successfully. However, once I try to dockerize this application (web app + db) I cannnot get it to work no matter what I try.

When I run docker-compose up, weirdly, when I follow the host IP that’s displayed on my terminal it does not show anything and eventually gives a "took too long to respond" error. However, when I go on localhost:5000 I can see my web app normally.
With that said, it still does not connect to Postgres. When I type localhost:5000/ready I get a message that the Postgres connection has failed, and whenever I submit the user details I get an "Internal Server Error".
Here’s what that looks like on my terminal:

PS C:UsersitsnoDesktopsamplewebapp> docker-compose up
Creating samplewebapp_db_1 ... done
Creating samplewebapp_app_1 ... done
Attaching to samplewebapp_db_1, samplewebapp_app_1
db_1   | The files belonging to this database system will be owned by user "postgres".
db_1   | This user must also own the server process.
db_1   |
db_1   | The database cluster will be initialized with locale "en_US.utf8".
db_1   | The default database encoding has accordingly been set to "UTF8".
db_1   | The default text search configuration will be set to "english".
db_1   |
db_1   | Data page checksums are disabled.
db_1   |
db_1   | fixing permissions on existing directory /var/lib/postgresql/data ... ok
db_1   | creating subdirectories ... ok
db_1   | selecting dynamic shared memory implementation ... posix
db_1   | selecting default max_connections ... 100
db_1   | selecting default shared_buffers ... 128MB
db_1   | selecting default time zone ... Etc/UTC
db_1   | creating configuration files ... ok
db_1   | running bootstrap script ... ok
db_1   | performing post-bootstrap initialization ... ok
db_1   | syncing data to disk ... ok
db_1   |
db_1   |
db_1   | Success. You can now start the database server using:
db_1   |
db_1   |     pg_ctl -D /var/lib/postgresql/data -l logfile start
db_1   |
db_1   | initdb: warning: enabling "trust" authentication for local connections
db_1   | You can change this by editing pg_hba.conf or using the option -A, or
db_1   | --auth-local and --auth-host, the next time you run initdb.
db_1   | waiting for server to start....2021-09-01 18:31:49.450 UTC [48] LOG:  starting PostgreSQL 13.4 (Debian 13.4-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
db_1   | 2021-09-01 18:31:49.457 UTC [48] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1   | 2021-09-01 18:31:49.475 UTC [49] LOG:  database system was shut down at 2021-09-01 18:31:49 UTC
db_1   | 2021-09-01 18:31:49.485 UTC [48] LOG:  database system is ready to accept connections
db_1   |  done
db_1   | server started
db_1   |
db_1   | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
db_1   |
db_1   | 2021-09-01 18:31:49.565 UTC [48] LOG:  received fast shutdown request
db_1   | waiting for server to shut down....2021-09-01 18:31:49.573 UTC [48] LOG:  aborting any active transactions
db_1   | 2021-09-01 18:31:49.574 UTC [48] LOG:  background worker "logical replication launcher" (PID 55) exited with exit code 1
db_1   | 2021-09-01 18:31:49.574 UTC [50] LOG:  shutting down
db_1   | 2021-09-01 18:31:49.623 UTC [48] LOG:  database system is shut down
db_1   |  done
db_1   | server stopped
db_1   |
db_1   | PostgreSQL init process complete; ready for start up.
db_1   |
db_1   | 2021-09-01 18:31:49.698 UTC [1] LOG:  starting PostgreSQL 13.4 (Debian 13.4-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
db_1   | 2021-09-01 18:31:49.698 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
db_1   | 2021-09-01 18:31:49.698 UTC [1] LOG:  listening on IPv6 address "::", port 5432
db_1   | 2021-09-01 18:31:49.713 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1   | 2021-09-01 18:31:49.728 UTC [67] LOG:  database system was shut down at 2021-09-01 18:31:49 UTC
db_1   | 2021-09-01 18:31:49.738 UTC [1] LOG:  database system is ready to accept connections
app_1  |  * Serving Flask app 'app.py' (lazy loading)
app_1  |  * Environment: production
app_1  |    WARNING: This is a development server. Do not use it in a production deployment.
app_1  |    Use a production WSGI server instead.
app_1  |  * Debug mode: off
app_1  |  * Running on all addresses.
app_1  |    WARNING: This is a development server. Do not use it in a production deployment.
app_1  |  * Running on http://172.18.0.3:5000/ (Press CTRL+C to quit)
app_1  | 172.18.0.1 - - [01/Sep/2021 18:32:48] "GET / HTTP/1.1" 200 -
app_1  | 172.18.0.1 - - [01/Sep/2021 18:32:48] "GET /static/style.css HTTP/1.1" 304 -     
app_1  | 172.18.0.1 - - [01/Sep/2021 18:32:48] "GET /static/newsletter.jpg HTTP/1.1" 304 -
app_1  | [2021-09-01 18:32:57,708] ERROR in app: Exception on /submit [POST]
app_1  | Traceback (most recent call last):
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 3212, in _wrap_pool_connect
app_1  |     return fn()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 307, in connect
app_1  |     return _ConnectionFairy._checkout(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 767, in _checkout
app_1  |     fairy = _ConnectionRecord.checkout(pool)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 425, in checkout
app_1  |     rec = pool._do_get()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/impl.py", line 146, in _do_get
app_1  |     self._dec_overflow()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__       
app_1  |     compat.raise_(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
app_1  |     raise exception
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/impl.py", line 143, in _do_get
app_1  |     return self._create_connection()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 253, in _create_connection   
app_1  |     return _ConnectionRecord(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 368, in __init__
app_1  |     self.__connect()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 611, in __connect
app_1  |     pool.logger.debug("Error on connect(): %s", e)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__       
app_1  |     compat.raise_(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
app_1  |     raise exception
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 605, in __connect
app_1  |     connection = pool._invoke_creator(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/create.py", line 578, in connect
app_1  |     return dialect.connect(*cargs, **cparams)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 584, in connect
app_1  |     return self.dbapi.connect(*cargs, **cparams)
app_1  |   File "/usr/local/lib/python3.9/site-packages/psycopg2/__init__.py", line 122, in connect
app_1  |     conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
app_1  | psycopg2.OperationalError: could not connect to server: Connection refused
app_1  |        Is the server running on host "localhost" (127.0.0.1) and accepting
app_1  |        TCP/IP connections on port 5432?
app_1  | could not connect to server: Cannot assign requested address
app_1  |        Is the server running on host "localhost" (::1) and accepting
app_1  |        TCP/IP connections on port 5432?
app_1  |
app_1  |
app_1  | The above exception was the direct cause of the following exception:
app_1  |
app_1  | Traceback (most recent call last):
app_1  |   File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app
app_1  |     response = self.full_dispatch_request()
app_1  |   File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request
app_1  |     rv = self.handle_user_exception(e)
app_1  |   File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request
app_1  |     rv = self.dispatch_request()
app_1  |   File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request
app_1  |     return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
app_1  |   File "/code/app.py", line 60, in submit
app_1  |     if db.session.query(mailinglist).filter(mailinglist.customer == customer).count() == 0:
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 3090, in count
app_1  |     return self._from_self(col).enable_eagerloads(False).scalar()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 2831, in scalar
app_1  |     ret = self.one()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 2808, in one
app_1  |     return self._iter().one()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 2846, in _iter
app_1  |     result = self.session.execute(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1688, in execute
app_1  |     conn = self._connection_for_bind(bind)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1529, in _connection_for_bind
app_1  |     return self._transaction._connection_for_bind(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 747, in _connection_for_bind
app_1  |     conn = bind.connect()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 3166, in connect
app_1  |     return self._connection_cls(self, close_with_result=close_with_result)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 96, in __init__
app_1  |     else engine.raw_connection()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 3245, in raw_connection
app_1  |     return self._wrap_pool_connect(self.pool.connect, _connection)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 3215, in _wrap_pool_connect
app_1  |     Connection._handle_dbapi_exception_noconnection(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 2069, in _handle_dbapi_exception_noconnection
app_1  |     util.raise_(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
app_1  |     raise exception
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 3212, in _wrap_pool_connect
app_1  |     return fn()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 307, in connect
app_1  |     return _ConnectionFairy._checkout(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 767, in _checkout
app_1  |     fairy = _ConnectionRecord.checkout(pool)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 425, in checkout
app_1  |     rec = pool._do_get()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/impl.py", line 146, in _do_get
app_1  |     self._dec_overflow()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
app_1  |     compat.raise_(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
app_1  |     raise exception
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/impl.py", line 143, in _do_get
app_1  |     return self._create_connection()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 253, in _create_connection
app_1  |     return _ConnectionRecord(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 368, in __init__
app_1  |     self.__connect()
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 611, in __connect
app_1  |     pool.logger.debug("Error on connect(): %s", e)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
app_1  |     compat.raise_(
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
app_1  |     raise exception
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/pool/base.py", line 605, in __connect
app_1  |     connection = pool._invoke_creator(self)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/create.py", line 578, in connect
app_1  |     return dialect.connect(*cargs, **cparams)
app_1  |   File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 584, in connect
app_1  |     return self.dbapi.connect(*cargs, **cparams)
app_1  |   File "/usr/local/lib/python3.9/site-packages/psycopg2/__init__.py", line 122, in connect
app_1  |     conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
app_1  | sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not connect to server: Connection refused
app_1  |        Is the server running on host "localhost" (127.0.0.1) and accepting
app_1  |        TCP/IP connections on port 5432?
app_1  | could not connect to server: Cannot assign requested address
app_1  |        Is the server running on host "localhost" (::1) and accepting
app_1  |        TCP/IP connections on port 5432?
app_1  |
app_1  | (Background on this error at: https://sqlalche.me/e/14/e3q8)
app_1  | 172.18.0.1 - - [01/Sep/2021 18:32:57] "POST /submit HTTP/1.1" 500 -

Also when I log in to my pgAdmin4, I can see that the table called mailinglist does not exist, which was supposed to be created after I ran docker-compose run app python app.py migrate.

How can I go about fixing this?

Thank you in advance.

Below are my files:

app.py file:

import time
import psycopg2
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# Enable/disable debugging features 
ENV = 'dev'

# Enter your DB URI
if ENV == 'dev':
    app.debug = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost/postgres'
else:
    app.debug = False
    app.config['SQLALCHEMY_DATABASE_URI'] = ''

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

class mailinglist(db.Model):
    __tablename__ = 'mailinglist'
    id = db.Column(db.Integer, primary_key=True)
    customer = db.Column(db.String(200), unique=True)
    email = db.Column(db.String(200), unique=True)
    source = db.Column(db.String(200))

    def __init__(self, customer, email, source):
        self.customer = customer
        self.email = email
        self.source = source

@app.route('/')
def index():
    return render_template('index.html')

@app.route("/health")
def health():
    return render_template('code200.html')

@app.route("/ready")
def test():
    try:
        conn = psycopg2.connect("dbname='postgres' user='postgres' host='localhost' password='postgres' connect_timeout=1")
        conn.close()
        return render_template('code200.html')
    except:
        return render_template('code503.html')

@app.route('/submit', methods=['POST'])
def submit():
    if request.method == 'POST':
        customer = request.form['customer']
        email = request.form['email']
        source = request.form['source']
        if customer == '' or email == '':
            return render_template('index.html', message='Please enter required fields')
        if db.session.query(mailinglist).filter(mailinglist.customer == customer).count() == 0:
            data = mailinglist(customer, email, source)
            db.session.add(data)
            db.session.commit()
            return render_template('success.html')
        return render_template('index.html', message='You have already signed up to our newsletter.')

if __name__ == '__main__':
    dbstatus = False
    while dbstatus == False:
        try:
            db.create_all()
        except:
            time.sleep(2)
        else:
            dbstatus = True

Dockerfile:

FROM python:3.9

RUN mkdir /code

WORKDIR /code

COPY . .

ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN pip install -r requirements.txt

EXPOSE 5000

CMD ["flask", "run"]

docker-compose.yml file:

version: "3.9"
services:
  app:
    build: .
    ports:
      - "5000:5000"
    depends_on: 
      - db
  db:
    image: postgres
    env_file: .env

.env file:

POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres

requirements.txt file:

Flask
Flask-SQLAlchemy
gunicorn
psycopg2-binary

2

Answers


  1. When you run the Flask app inside a Docker container, localhost means the container the Flask app is running. But your Postgres is running on another container that is accessible using db.

    When running using Docker change the following line:

    if ENV == 'dev':
        app.debug = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost/postgres'
    else:
        app.debug = False
        app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost/postgres'
    

    Change your ready route:

    @app.route("/ready")
    def test():
        try:
            conn = psycopg2.connect("dbname='postgres' user='postgres' host='db' port='5432' password='postgres' connect_timeout=1")
    

    Change your docker-compose.yml file:

    version: "3.9"
    services:
      app:
        build: .
        ports:
          - "5000:5000"
        depends_on: 
          - db
      db:
        image: postgres
        env_file: .env
        ports:
          - "5432:5432"
    
    Login or Signup to reply.
  2. It seems like connection error. Postgres server default port number is 5432. We need to expose it on docker.

    Try add your docker-compose.yaml file:

    service:
      db:
        ports:
          - "5432:5432"
    

    and run again.

    Recommended add your Dockerfile:

    EXPOSE 5432
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search