Search code examples
dockerflaskcontainerslocalhost

Container on custom network - can't reach from host machine


I created two Docker images and ran them. One is a simple Flask application (for testing purposes only) and the other is a PostgreSQL.
I attached the code, Dockerfiles, and commands I use to run them below.
I have tested simple commands like curl from the Flask container interactive mode, it communicates with the DB container successfully and does what it needs to do.
But here's the problem - whenever I try to reach it using the host machine (and I tried this on both MacOS and Ubuntu machines), by using localhost:8080 or 127.0.0.1:8080 or even the network's IP (the network I created, command is below), it simply won't reach the Flask container. Meaning I can't even check the container's logs to see what is happening because it doesn't get there.
I checked the firewall to make sure nothing is blocked and I have tried mapping the container to a different port on my machines... didn't work.
Would love some help trying to understand why is that happening.

app.py:

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@my-postgres-container:5432/db'

db = SQLAlchemy(app)

migrate = Migrate(app, db)

class MyUser(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), unique=True, nullable=False)

@app.route('/users', methods=['POST'])
def create_user():
    data = request.get_json()
    new_user = MyUser(name=data['name'])
    db.session.add(new_user)
    db.session.commit()
    return jsonify({'message': 'New user created!'})

@app.route('/users', methods=['GET'])
def get_all_users():
    users = MyUser.query.all()
    output = []
    for user in users:
        user_data = {'id': user.id, 'name': user.name}
        output.append(user_data)
    return jsonify({'users': output})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Dockerfile-app:

FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

ENTRYPOINT ["bash", "-c"]
CMD ["flask db init && flask db migrate && flask db upgrade && flask run"]

Dockerfile-db:

FROM postgres:latest

ENV POSTGRES_USER postgres
ENV POSTGRES_PASSWORD postgres
ENV POSTGRES_DB db

EXPOSE 5432

CMD ["postgres"]

requirements.txt:

alembic==1.13.1
blinker==1.7.0
click==8.1.7
Flask==3.0.2
Flask-Migrate==4.0.7
Flask-SQLAlchemy==3.1.1
itsdangerous==2.1.2
Jinja2==3.1.3
Mako==1.3.2
MarkupSafe==2.1.5
psycopg2-binary==2.9.9
SQLAlchemy==2.0.29
typing_extensions==4.10.0
Werkzeug==3.0.1

Commands I use to run them:

docker network create my-network
docker volume create my-volume
docker build -t my-postgres -f Dockerfile-db .
docker run -d -p 5432:5432 --name my-postgres-container --network my-network -v my-volume:/var/lib/postgresql/data my-postgres
docker build -t my-app -f Dockerfile-app .
docker run -d -p 8080:5000 --name my-app-container --network my-network my-app

Thank you.


Solution

  • Your app binds to 127.0.0.1, so it'll only accept connections from inside the container. To get it to bind to 0.0.0.0 so it'll accept connections from outside, you need to have the --host=0.0.0.0 option on your flask run command.

    Change the last line in your Dockerfile-app from

    CMD ["flask db init && flask db migrate && flask db upgrade && flask run"]
    

    to

    CMD ["flask db init && flask db migrate && flask db upgrade && flask run --host=0.0.0.0"]
    

    and it'll work.

    I can see in your app.py file that you try to bind to 0.0.0.0. For some reason that doesn't work. I'm not a Python expert, so I don't know why.