docker-compose部署下Fastapi中使用sqlalchemy和Alembic

news/2025/1/8 17:37:39/文章来源:https://www.cnblogs.com/goldsunshine/p/18660250

本篇介绍使用Fastapi + sqlalchemy + alembic 来完成后端服务的数据库管理,并且通过docker-compose来部署后端服务和数据库Mysql。包括:

  1. 数据库创建,数据库用户创建
  2. 数据库服务发现
  3. Fastapi 连接数据库
  4. Alembic 连接数据库
  5. 服务健康检查

部署数据库

version: '3'
services:db:image: mysqlcontainer_name: dbenvironment:- MYSQL_ROOT_PASSWORD=tv_2024 # root用户密码- MYSQL_DATABASE=tileView- MYSQL_USER=tile_viewer- MYSQL_PASSWORD=tv_2024- TZ=Asia/Shanghaivolumes:- ./mysql:/var/lib/mysql- /etc/localtime:/etc/localtime:roports:- 3306:3306restart: always

部署数据库有三个注意点:

  1. 将数据库文件映射出来,避免丢失数据

数据库中存储的数据都容器里在/var/lib/mysql目录下,将该目录映射出来,避免重启容器丢失数据

二、自动创建数据库DB

很多情况下需要在启动数据库容器是自动创建数据库,在environment中设置 MYSQL_DATABASE=tileView即可在容器启动是创建数据库

三、创建可读写可远程用户

默认情况下非root用户不支持远程连接读写权限,在environment中设置

  1. MYSQL_USER=tile_viewer
  2. MYSQL_PASSWORD=tv_2024

将会获得一个可远程可读写MYSQL_DATABASE库的用户

Fastapi 连接数据库

非docker部署情况下使用IP和端口连接数据库,使用docker-compose部署时服务都是自动化启动,事先不知道数据库的IP,这是就可以使用docker-compose提供的能力:使用服务名来请求服务。

docker-compose中可以使用服务的名称来通信,在通信请求中将服务名替换成容器IP。

首先将数据库连接的URL映射到服务的容器中

version: '3'
services:db:image: mysqlcontainer_name: dbenvironment:- MYSQL_ROOT_PASSWORD=tv_2024 # root用户密码- MYSQL_DATABASE=tileView- MYSQL_USER=tile_viewer- MYSQL_PASSWORD=tv_2024- TZ=Asia/Shanghaivolumes:- ./mysql:/var/lib/mysql- /etc/localtime:/etc/localtime:roports:- 3306:3306restart: alwayshealthcheck:test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]interval: 10stimeout: 5sretries: 3server:image: tileview:1.0restart: alwayscontainer_name: tileview_serverports:- "9100:9100"volumes:- ./tiles_store:/app/server/tiles_store- ./log:/app/server/log- ./upload:/app/server/uploaddepends_on:db:condition: service_healthyenvironment:- DATABASE_URI=mysql+pymysql://tile_viewer:tv_2024@db/tileView

depends_on: 表示该服务依赖db服务,db服务要先启动。condition: service_healthy

DATABASE_URI:表示将数据库连接信息注入到该容器中,其中@db表示数据库IP:端口号 使用数据库服务名称db来替换,在容器中请求该url时,docker-compose会自动将db转换成对应的数据库的IP和端口号。

depends_on:- dbenvironment:- DATABASE_URI=mysql+pymysql://tile_viewer:tv_2024@db/tileView

修改sqlalchemy中数据库的连接

sqlalchemy 连接数据库时,数据库的url配置从环境变量中获取

sqlalchemy/database.py

import osfrom sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmakerSQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URI")
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)Base = declarative_base()

使用环境变量获取数据库

SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URI")

在Fastapi 服务 调用数据库的方法。

DATABASE_URI=mysql+pymysql://tile_viewer:tv_2024@db/tileView

使用数据库服务名db来找到服务地址,在docker-compose中会将服务名解析成服务的IP。在使用时会将db解析成172.10.0.2,找到服务的IP。

迁移工具alembic中数据库连接

在数据库迁移工具中需要配置数据库的连接信息,该信息是配置在alembic.ini中,如果要使用环境变量中动态获取的方法,需要改变两点:

  1. alembic.ini中不配置数据库连接信息
  2. 在alembic/env.py动态获取连接url,并设置到alembic.ini中

alembic.ini中不配置数据库连接信息

在alembic/env.py动态获取连接url,并设置到alembic.ini中

alembic/env.py

from logging.config import fileConfigfrom alembic import context
from sqlalchemy import engine_from_config, pool# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:fileConfig(config.config_file_name)# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.import os  # noqa
import sys  # noqafrom server.db.base import Base  # noqabasedir = os.path.split(os.getcwd())[0]
sys.path.append(basedir)target_metadata = Base.metadatadef get_url() -> str:return os.getenv("DATABASE_URI", "sqlite:///app.db")def run_migrations_offline() -> None:"""Run migrations in 'offline' mode.This configures the context with just a URLand not an Engine, though an Engine is acceptablehere as well.  By skipping the Engine creationwe don't even need a DBAPI to be available.Calls to context.execute() here emit the given string to thescript output."""# url = config.get_main_option("sqlalchemy.url")url = get_url()context.configure(url=url,target_metadata=target_metadata,literal_binds=True,dialect_opts={"paramstyle": "named"},)with context.begin_transaction():context.run_migrations()def run_migrations_online() -> None:"""Run migrations in 'online' mode.In this scenario we need to create an Engineand associate a connection with the context."""configuration = config.get_section(config.config_ini_section)configuration["sqlalchemy.url"] = get_url()connectable = engine_from_config(configuration,prefix="sqlalchemy.",poolclass=pool.NullPool,)with connectable.connect() as connection:context.configure(connection=connection, target_metadata=target_metadata)with context.begin_transaction():context.run_migrations()if context.is_offline_mode():run_migrations_offline()
else:run_migrations_online()

在 run_migrations_offline 中将url获取从配置文件中改成从环境变量中

# url = config.get_main_option("sqlalchemy.url")
url = get_url()

在 run_migrations_online 中修改配置文件的数据库连接信息

configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = get_url()
connectable = engine_from_config(configuration,prefix="sqlalchemy.",poolclass=pool.NullPool,
)

以上操作之后就能通过服务发现的方式动态使用数据库

数据库健康检查

在前面的配置中虽然让服务依赖db,db会先启动然后服务后启动,但是这种情况还会出现数据库连不上的情况,因为db启动不代表服务就绪,未就绪的时候连接会导致connect refuse。解决这个问题的方法是给db增加一个健康检查 healthcheck。

services:db:image: mysqlcontainer_name: dbenvironment:- MYSQL_ROOT_PASSWORD=tv_2024 # root用户密码- MYSQL_DATABASE=tileView- MYSQL_USER=tile_viewer- MYSQL_PASSWORD=tv_2024- TZ=Asia/Shanghaivolumes:- ./mysql:/var/lib/mysql- /etc/localtime:/etc/localtime:roports:- 3306:3306restart: alwayshealthcheck:test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]interval: 10stimeout: 5sretries: 3

当健康检查完成才代表数据库启动成功,服务才会启动。服务中也需要依赖数据库健康检查完成,写法如下:

depends_on:db:condition: service_healthy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865973.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

误删除了表?PolarDB MySQL帮你恢复!完成就送2025蛇年春联!

由于DDL语句无法回滚,如果误删除了表(例如DROP TABLE),可能会导致数据丢失。PolarDB MySQL提供表回收站的功能,删除的表会被临时转移到表回收站。 通过本次操作,带您体验如何使用PolarDB MySQL提供表回收站的功能,从表回收站恢复误删的表。 完成任务赢奖励,活动火热进行…

《墨香古韵:传统与现代的完美融合》——传世经典的美,划破时空的风格和型

《墨香古韵:传统与现代的完美融合》 由“解锁AI超能”的邦林AIGC出品 一直叹服古人用那样少的笔墨,就可以塑造一个让人无限联想、余味无穷的作品。 而上帝造人,诸多完美,唯独留下一个大大的Bug, 那就是人想象不出自己没见闻过的东西,而有大师也曾说过,人的想象力总是先于…

学习 - Linux - Centos安装jdk8

Centos安装jdk8 安装包下载地址: 通过网盘分享的文件:jdk 链接: https://pan.baidu.com/s/1dQTMZk7foPZhOcw55QM_lQ?pwd=sky1 提取码: sky1 二、上传至Centos系统解压文件并移动到usr/local目录下 解压 tar zxvf jdk-8u181-linux-x64.tar.gz 移动 mv jdk1.8.0_181 /usr/loca…

CICD Day7、Jenkins Pipeline 常用指令及Pipeline快捷生成方式(片段生成器)

1、常用指令 在编写Pipeline脚本时,会涉及各种指令,这些指令用于实现构建过程中的不同功能。熟悉这些指令后,编写一个完整的Pipeline脚本将变得十分简单 1.1 shsh指令用于执行shell命令,配置示例如下stage(Build) {stage {sh hostname} }在上述配置中,在构建的过程中,执行…

DC-6 靶场通关小记

wordpress用户枚举、暴力破解得密码、CVE-2018-15877 plainview_activity_monitor RCE漏洞、水平权限提示、nmap --interative失效时 提权地址 https://www.vulnhub.com/entry/dc-6,315/环境配置 略,有问题可参考 https://www.cnblogs.com/lrui1/p/18655388 需要向hosts文件添…

【Java编程】一个高性能、支持百万级多任务重试框架:Fast-Retry

前言 假设你的系统里有100万个用户,然后你要轮询重试的获取每个用户的身份信息, 如果你还在使用SpringRetry和GuavaRetry 之类的这种单任务的同步重试框架,那你可能到猴年马月也处理不完,即使加再多的机器和线程也是杯水车薪,而Fast-Retry正是为这种场景而生。 Fast-Retry …

mac m1 安装ffmpeg,配置环境变量

1 首先要安装brew 2 git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg 3 cd ffmpeg 4 执行脚本 ./configure --prefix=/opt/local 5 编译 sudo make ,需要提权,要不系统目录无法创建文件夹 6 安装 make install 7 安装成功,查看 ffmpeg版本 /opt/local/bin/ffmpeg -ve…

如何在 LobeChat 中使用 Ollama

本文介绍了如何在LobeChat中使用Ollama框架运行本地大型语言模型。文章详细说明了在macOS、Windows和Linux操作系统下安装和配置Ollama的步骤,并指导用户如何通过Docker容器部署Ollama。此外,文章还介绍了如何在LobeChat中安装和选择Ollama模型进行对话。Ollama 是一款强大的…

密码综合实战

这种加密本质上是换汤不换药的,我们需要有所创新,下面是我的想法(key{A}和key{B}表示的是A和B独有的秘钥): 假设现在有服务器192.168.1.1,本机扮演角色A,服务器扮演角色B,进行如下逻辑:A拥有A的专属秘钥(汉字秘钥)进行一次加密发送给B,B接受到后再用B的专属秘钥再次加…

FrontEnd性能优化.md

性能优化 性能优化\浏览器渲染原理 Get Started有这样几个问题,我们来思考下:1.我们平常浏览的网页是否是应用?2.在操作系统中的应用是如何运行的3.浏览器究竟是什么4.webkit和浏览器的关系5.浏览器是如何呈现网页的6.经典问题:从浏览器的地址栏输入一个网址直到网页内容呈…

Tita OKR 应用技巧:OKR 评分

OKR 评分价值 OKR(目标与关键成果)评分主要有以下几方面价值: 一、目标管理方面明确目标完成程度OKR评分可以直观地展现目标的达成情况。例如,一个产品团队设定了提升用户满意度的目标,通过OKR评分,可以清楚地看到用户满意度指标从初始的60%提升到了75%还是80%等具体数值…