【问题标题】:Accessing MySQL docker container from Flask APP从 Flask APP 访问 MySQL docker 容器
【发布时间】:2022-11-18 16:47:56
【问题描述】:

我整天都在尝试从我的 SQLALCHEMY flask 应用程序连接到 MySQL 运行容器,但没有成功。不知道我做错了什么,也许我遗漏了一些您可能会引起我注意以解决我的问题的东西。

仅供参考。

我有以下文件:

带有 MySQL 和 Adminer 的 docker-compose.yml 文件:

version: '3.1'
services:
  db:
    image: mysql:5.7
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: mysqldb
      MYSQL_ROOT_PASSWORD: master
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    networks:
      - mysqlcomposenetwork
    volumes:
      - ./data:/data
    ports:
      - 100:100
  adminer:
    image: adminer
    restart: unless-stopped
    ports:
      - 8080:8080
    networks:
      - mysqlcomposenetwork

networks: 
  mysqlcomposenetwork:
    driver: bridge

db.yml 文件来存储与应用程序隔离的连接字符串信息。

mysql_host: 'localhost:100'
mysql_user: 'user'
# Enter your password in field below
mysql_password: 'password'
mysql_db: 'mysqldb'

最后是我的 app.py,这是一个通过 flask_sqlalchemy 模块利用 ORM 的基本 Flask 应用程序。请注意,在运行 app.py 之前,mysql 和 adminer 容器都在运行,并且 db.yml 文件位于 app.py 的同一目录中;因此,可访问。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import pymysql
import datetime
import yaml


app = Flask(__name__)
db = yaml.full_load(open('db.yml'))

#mysql://username:password@host:port/database_name
connection_str='mysql+pymysql://'+db['mysql_user']+':'+db['mysql_password']+'@'+db['mysql_host']+'/'+db['mysql_db']
app.config['SQLALCHEMY_DATABASE_URI']=connection_str
print(connection_str)


db = SQLAlchemy(app)


class Visitor(db.Model):
    accessed_at=db.Column(db.Float,primary_key=True)
    user_id=db.Column(db.Integer)
    page_id=db.Column(db.Integer)

    def __init__(self,accessed_at,user_id,page_id):
        self.accessed_at=accessed_at
        self.user_id=user_id
        self.page_id=page_id




if __name__ == '__main__':
    with app.app_context():
        db.create_all()
        visitor=Visitor(datetime.datetime.now().timestamp(),1000,5)
        db.session.add(visitor)
        db.session.commit()
        print(Visitor.query.all())


运行app..py后提示如下错误:sqlalchemy.exc.OperationalError:(pymysql.err.OperationalError)(2003,“无法连接到‘localhost’上的 MySQL 服务器([WinError 10061]

已经尝试将 mysql_host: 'localhost:100' 更改为 mysql_host: 'db:100' 和 mysql_host: 'db'。他们都没有工作...

感谢您的关注和可能的反馈,以帮助我克服程序中的这个严重问题。

我无法从外部连接到 MySQL 容器数据库。具体来说,来自烧瓶应用程序。

【问题讨论】:

    标签: python flask docker-compose flask-sqlalchemy mysql-python


    【解决方案1】:

    我已经在这个 github repo 中解决了你的问题:

    https://github.com/jcroyoaun/stackoverflow-flask-question

    如果你能克隆我的仓库并尝试,我将不胜感激

    docker-compose up --build
    

    第一的。

    之后,如果它对你有用,请阅读错误的解释。 (我在我的 Mac 上运行它后修改了一些东西,因为我必须指定平台:“linux/amd64”,因为我使用带有 arm architectore 的 M1 芯片和 mysql 图像的容器不会在我的本地运行,所以如果你有运行时出现任何问题,请在此处发布)

    注意:为简单起见,我只添加了我从您共享的代码中更改的代码行。

    有关代码库的完整视图,请参阅上面共享的存储库。

    我从你的代码中改变了什么

    1. 在 main.py 上更改
      connection_str='mysql://'+db['mysql_user']+':'+db['mysql_password']+'@'+db['mysql_host']+'/'+db['mysql_db']
      app.config['SQLALCHEMY_DATABASE_URI']=connection_str
      print(connection_str)
      

      解释 : -> 我不需要 pymysql 你的特殊情况,所以我把它从连接字符串中删除了

      1. 然后在你的 db.yml 文件上,我从
      mysql_host: 'localhost:100'
      

      mysql_host: 'db:3306'
      

      解释 : -> 当您在 Docker compose 中使用网络时,服务名称的值可以解析为主机名。在网络方面,你的“管理员”Flask 应用程序位于不同的容器中,无法将“localhost”解析为自身之外的东西,因此,你可以使用主机名,因为它依赖于 DNS 解析,以便它可以从管理员容器之外的外部世界。

      我还更改了端口,因为默认情况下,mysql 侦听端口 3306,因此内部映射端口 100 没有意义,除非您修改基本 docker 映像的配置 (source)

      1. 我也更改了在 docker-compose.yml 上声明的 db 服务上的端口,这样我们通过匹配从我们之前更改的 db.yml 端口读取的连接字符串来允许连接通过。变化来自
            ports:
              - 100:100
        

            ports:
              - 3306:3306
        

        到目前为止,连接工作正常,但是我在您的代码中发现了一些错误,我也需要修改这些错误。

        我做的额外调整

        首先,我必须重新创建您的架构并添加一个更改了几个参数的表。您将 accessed_at 定义为

        CREATE TABLE `visitor` (
          `accessed_at` float(10,7),
        

        但是你传递的数字就像 1668759725.166818

        本质上 10,7 的意思是你想要:

        • 10 个总精度单位
        • 小数点后 7 个单位,因此
        • 小数点前只有3个单位

        因此我补充道:

        CREATE TABLE `visitor` (
          `accessed_at` float(18,6),
        

        正如我发现它更适合您作为主键传递的纪元时间戳。

        我简要更改了一些其他内容(您可以在 GitHub 存储库上看到)

        a) 我认为将 schema.sql 复制到 docker-entrypoint-initdb.d/ 以预加载表并让它们为您首次运行应用程序+数据库做好准备是一个好习惯,否则您将拥有第一次手动插入架构名称和表。我在项目的 ./mysqldockerfile/Dockerfile 目录下为此创建了一个 Dockerfile。

        b) 我还修改了您在 docker-compose.yml 上第 14 行安装的卷,/var/lib/mysql 通常是可以为数据库存储/检索数据的地方,因此,从本地安装卷 (@ 987654331@) 将允许插入的数据在重启后持续存在(因为它现在存储在您的本地硬盘上)。

        注意:还有其他错误/异常被抛出,但连接问题现在工作正常。

    【讨论】:

      猜你喜欢
      • 2021-03-04
      • 1970-01-01
      • 2017-07-24
      • 2017-10-12
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 2019-01-19
      相关资源
      最近更新 更多