docker 部署 flask 项目
docker 部署 flask 项目
项目结构说明
nginx 做反向代理,gunicorn 启动 flask,flask 连接 mysql
镜像
- nginx:1.21.3
- mysql:8
- flask_app(以 python 镜像为基础构建的项目镜像)
docker 版本:
- Docker version 20.10.9
- Docker Compose version v2.0.1
镜像说明
nginx
-
处理前端页面及静态文件请求;
-
代理 flask 的后端服务;
-
nginx 配置
#user nobody; worker_processes 4; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr [$request_time $upstream_response_time] [$time_local -$msec] [$request] [$request_body] ' '$status $body_bytes_sent ' '"$http_user_agent"' '$scheme $server_addr $request_uri'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 600; #gzip on; upstream flask_app { server 172.16.238.10:5000; } server { listen 8080; server_name localhost; server_tokens off; # 前端页面 location /index.html { root /usr/share/nginx/html/web; index index.html index.htm; } location /logo.png { root /usr/share/nginx/html/web; index index.html index.htm; } location /css { root /usr/share/nginx/html/web; index index.html index.htm; } location /js { root /usr/share/nginx/html/web; index index.html index.htm; } location /img { root /usr/share/nginx/html/web; index index.html index.htm; } location /fonts { root /usr/share/nginx/html/web; index index.html index.htm; } # 后端接口 proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; location / { proxy_pass http://flask_app; proxy_redirect off; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 1024m; } } }
mysql
-
将数据库结构和初始数据导出为 sql 脚本,启动 mysql 容器时指定执行 mysql 初始化脚本
-
mysql 初始化脚本
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; CREATE flask_app; USE flask_app; -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(0) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `phone_num` varchar(13) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES (1, 'tom', '13549872211'); INSERT INTO `student` VALUES (2, 'Jerry', '13549872212'); SET FOREIGN_KEY_CHECKS = 1; -
mysql 配置
[mysqld] user=mysql character-set-server=utf8 default_authentication_plugin=mysql_native_password lower_case_table_names=1 secure_file_priv=/var/lib/mysql table_definition_cache=400 [client] default-character-set=utf8 [mysql] default-character-set=utf8
flask_app
镜像构建方式
构建 flask app 的镜像一般有两种方式:
- 直接以 python 镜像为基础,创建容器,再在容器中部署完成,最后导出为镜像;
- 使用Dockerfile构建镜像;
第一种比较麻烦,并且每次更新代码都需要重新手动构建镜像,因此使用Dockerfile
方式
gunicorn 配置
import multiprocessing # 监听的端口 bind = "0.0.0.0:5000" # 防止在服务器上 work 启动过多,限制 work 数量 workers = multiprocessing.cpu_count() * 2 + 1 if multiprocessing.cpu_count() * 2 + 1 <= 6 else 6 backlog = 20480 debug = False timeout = 500 errorlog = './log/gunicorn_error.log'
启动脚本
start.sh
在容器启动时运行,使用gunicorn
启动 flask_app
- 由于在
Dockerfile
中配置了WORKDIR
,因此start.sh
的执行环境默认就在WORKDIR
下 - 需要注意
start.sh
的换行符,需要设置为LF
#!/bin/bash mkdir log gunicorn -c gun.conf app:app --daemon # 保留一个 bash /bin/bash
Dockerfile 配置
# python 基础镜像版本 FROM python:3.8.12-slim # 将代码复制到镜像中的目录下 COPY ./ /usr/local/flask_app/ # 设置工作目录,容器运行时,命令行默认就在这个目录 WORKDIR /usr/local/flask_app/ # apt-get 更换国内源 RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \ sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list && \ apt-get update # 安装环境 RUN chmod +x start.sh \ && apt-get install -y -q -o Acquire::http::Pipeline-Depth=0 gcc \ && apt-get clean \ && pip3 install -r requirements.txt -i https://pypi.douban.com/simple # 启动容器时,执行脚本 ENTRYPOINT ["./start.sh"]
构建镜像
- 执行构建命令时,将项目文件放入
flask_app
目录下,目录结构如下:--- flask_app --- Dockerfile --- start.sh --- app.py --- gun.py --- requirements.txt --- ... 其他项目文件 - 在
flask_app
目录下执行docker build -t flask_app .
命令创建镜像
使用 docker-compose
单独去启动容器比较麻烦,使用 docker-compose 来管理容器更加方便,需要创建docker-compose.yml
文件
docker-compose 配置文件
version: '3.3' services: mysql: image: mysql:8 container_name: mysql_container restart: always command: bash -c "chmod 644 /etc/mysql/my.cnf && /entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password" volumes: # 挂载 my.cnf 配置文件 - ./docker_volumes/mysql/my.cnf:/etc/mysql/my.cnf # 初始化数据库,创建容器时会执行 init 下的 sql 语句 - ./docker_volumes/mysql/init:/docker-entrypoint-initdb.d/ environment: # 设置密码 - 'MYSQL_ROOT_PASSWORD=1234' # 设置时区 - 'TZ=Asia/Shanghai' ports: # 映射端口,如果不用外部访问可以不配置 - 3306:3306 logging: driver: 'json-file' options: max-size: '100m' networks: flask_app_net: ipv4_address: 172.16.238.3 nginx: image: nginx:1.21.3 container_name: nginx_container restart: always volumes: - ./docker_volumes/nginx/cert:/etc/nginx/cert - ./docker_volumes/nginx/conf/nginx.conf:/etc/nginx/nginx.conf ports: - '8080:8080' environment: - 'TZ=Asia/Shanghai' logging: driver: 'json-file' options: max-size: '100m' networks: flask_app_net: ipv4_address: 172.16.238.7 flask_app: image: flask_app container_name: flask_app restart: always tty: true environment: - 'TZ=Asia/Shanghai' volumes: # 挂载目录 logging: driver: 'json-file' options: max-size: '100m' depends_on: - mysql networks: flask_app_net: ipv4_address: 172.16.238.10 # 创建一个虚拟网络,固定每个容器的 ip networks: flask-app-net: name: flask_app_net ipam: driver: default config: - subnet: '172.16.238.0/24'
启动
目录结构
- 目录结构
--- docker_demo --- docker-compose.yml --- docker_volumes --- mysql --- init --- init.sql # 数据库初始化 --- my.cnf # mysql 配置 --- nginx --- cert # nginx 证书 --- conf --- nginx.conf # nginx 配置文件 - 在
docker-compose.yml
同级目录下执行docker-compose up -d
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!