【问题标题】:My Dockerized Flask Web App Won't Connect with Local Postgres我的 Dockerized Flask Web 应用程序无法与本地 Postgres 连接
【发布时间】:2021-09-01 17:00:31
【问题描述】:

我使用 Flask 编写了一个简单的 Newsletter Web 应用程序,该应用程序与我的本地 Postgres 数据库有连接。当我按原样运行应用程序(不在 Docker 容器内)时,它工作正常,并将提交的用户信息成功发送到我的本地数据库。但是,一旦我尝试 dockerize 这个应用程序(Web 应用程序 + db),无论我尝试什么,我都无法让它工作。

当我运行docker-compose up 时,奇怪的是,当我按照终端上显示的主机 IP 进行操作时,它没有显示任何内容并最终给出“响应时间过长”错误。但是,当我继续 localhost:5000 时,我可以正常看到我的网络应用程序。 话虽如此,它仍然没有连接到 Postgres。当我输入localhost:5000/ready 时,我收到一条消息,指出 Postgres 连接失败,并且每当我提交用户详细信息时,我都会收到“内部服务器错误”。 这是我的终端上的样子:

PS C:\Users\itsno\Desktop\samplewebapp> 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 -

另外,当我登录到我的 pgAdmin4 时,我可以看到名为 mailinglist 的表不存在,它应该是在我运行 docker-compose run app python app.py migrate 之后创建的。

我该如何解决这个问题?

提前谢谢你。

以下是我的文件:

app.py 文件:

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 文件:

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

.env 文件:

POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres

requirements.txt 文件:

Flask
Flask-SQLAlchemy
gunicorn
psycopg2-binary

【问题讨论】:

    标签: postgresql docker flask docker-compose flask-sqlalchemy


    【解决方案1】:

    当您在 Docker 容器中运行 Flask 应用程序时,localhost 表示 Flask 应用程序正在运行的容器。但是您的 Postgres 正在另一个容器上运行,该容器可以使用 db 访问。

    使用 Docker 运行时更改以下行:

    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'
    

    更改您的ready 路由:

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

    更改您的docker-compose.yml 文件:

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

    【讨论】:

    • 感谢您的回复。我已经按照您的建议进行了更改,但是每当我运行 migrate 命令时,我仍然会遇到一个无休止的加载循环
    • 您的/ready 路由现在有效吗?如果是这样,这意味着您的数据库没有正确连接。我不知道您的 migrate 命令,也没有看到任何与之相关的实现。
    • 它仍然给出同样的错误,所以它没有连接到 postgres。此外,当我登录到我的 pgAdmin4 时,我可以看到它没有创建“邮件列表”表,当我运行 docker-compose run app python app.py migrate 时应该这样做
    • 我更新了我的答案,你现在可以检查一下吗?如果这不起作用,您是否也可以使用您的 .env 文件更新您的问题。
    • 它不起作用,所以我更新了我的帖子。另外,我无法通过终端上打印的主机 IP 访问 Web 应用程序是否正常,但是当我手动转到 localhost:5000 时可以访问它?
    【解决方案2】:

    似乎连接错误。 Postgres 服务器默认端口号是5432。我们需要在 docker 上暴露它。

    尝试添加您的docker-compose.yaml 文件:

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

    然后再次运行。

    推荐添加你的 Dockerfile:

    EXPOSE 5432
    

    【讨论】:

    • 如果您阅读documentation about EXPOSE,您会发现它是无操作的。只是为了让开发者看到和理解端口暴露在5432中,但是并没有进行任何操作。但是您认为这是正确的,因为我看到docker-compose.yml 没有为数据库公开端口。 :-)
    • 希望提问者看到并理解我的回答:-)
    猜你喜欢
    • 2019-11-17
    • 1970-01-01
    • 2019-11-06
    • 2021-11-09
    • 2019-05-26
    • 1970-01-01
    • 2017-12-29
    • 2022-06-19
    • 2019-12-15
    相关资源
    最近更新 更多