本文使用环境:
搭建 Linux 环境可参考:
项目结构如下:
flask_project/
├── docker-compose.yml
├── flaskapp
│ ├── Dockerfile
│ ├── app.py
│ ├── gunicorn.config.py
│ └── requirements.txt
└── nginx
├── Dockerfile
└── nginx.conf
./flaskapp/app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
项目依赖文件:./flaskapp/requirements.txt
Flask==2.0.2
gunicorn==20.1.0
gunicorn[gevent]
gunicorn 配置文件:./flaskapp/gunicorn.config.py
import multiprocessing
# 默认'127.0.0.1:8000',防火墙需开启对应端口
bind = '0.0.0.0:8000'
# 并发进程数,默认1
workers = multiprocessing.cpu_count() * 2 + 1
# 允许挂起的连接数最大值,默认2048
backlog = 2048
# 进程的工作方式,默认'sync'
worker_class = 'gevent'
# 最大客户客户端并发数量,对使用线程和协程的worker的工作有影响
#worker_connections = 1200
# 调试模式,默认False
#Debugging = True
# 进程名
proc_name = 'gunicorn.proc'
# pid文件,如果不设置将不会创建
pidfile = '/tmp/gunicorn.pid'
# 访问记录
accesslog = '-'
# 访问记录格式
# access_log_format = '%(h)s %(t)s %(U)s %(q)s'
# 日志文件
errorlog = '-'
# 错误日志输出等级,默认'info'
#loglevel = 'debug'
注:容器写入
stdout
或stderr
的任何内容都将被捕获并存储为容器的日志。 出于这个原因,accesslog
和errorlog
都配置为-
,容器部署时把日志发送到标准输出,以便由 Docker 作为日志存储。
创建 flask 和 nginx 通信使用的网络
// 创建网桥,连接方式是 bridge
$ docker network create -d bridge flask-nginx
// 显示所有 bridge
$ docker network ls
# NETWORK ID NAME DRIVER SCOPE
# ddeb87894904 flask-nginx bridge local
以 python:3.7.9-slim 为基础镜像,Dockerfile 如下:
FROM python:3.7.9-slim
WORKDIR /ubuntu/flaskapp
COPY ./requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY . .
CMD ["gunicorn", "-c", "./gunicorn.config.py", "app:app"]
构建镜像并启动
# 当前工作目录:flaskapp
# 构建镜像
$ docker build -t="my_flaskapp:0.1" .
# 后台启动flask容器,加入网桥flask-nginx
$ docker run -itd \
--name flask \
--network flask-nginx \
-p 8000:8000 \
-e APP_NAME=flask_0.1 \
my_flaskapp:0.1
# 查看容器ip
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' flask
# 172.20.0.2
nginx 配置文件 nginx.conf,具体可参考 Nginx 配置详解。
user nginx; # 配置用户名为nginx
worker_processes auto; # 允许生成的进程数,默认为1,auto表示和CPU内核有关,有几个内核,就会开启几个进程
error_log /var/log/nginx/error.log; # 指定日志路径,级别,这个设置可以放入全局块,http块,server块,级别依次为:debug|info|notice|warn|error|crit|alert|emerg
pid /run/nginx.pid; # 指定nginx进程运行文件存放地址
include /usr/share/nginx/modules/*.conf; # include 指定包含其他扩展配置文件
events {
worker_connections 1024; # 最大连接数,默认为512
}
http {
# 设置日志格式,默认为 conbined
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main; # nginx 访问日志存放位置
sendfile on; # 允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
tcp_nopush on; # 减少网络报文段的数量
tcp_nodelay on;
keepalive_timeout 65; # 连接超时时间,默认为75s,可以在http块,server块,location块。
types_hash_max_size 2048;
include /etc/nginx/mime.types; # 文件扩展名与文件类型映射表
default_type application/octet-stream; # 默认文件类型,默认为 text/plain
include /etc/nginx/conf.d/*.conf; # 包含的子配置项位置及文件
server {
listen 80 default_server; # 监听 80 端口,default_server 表示默认服务器
listen [::]:80 default_server; # 为 IPv6 设置
server_name _; # 配置域名
access_log /var/log/nginx/flaskapp_access.log;
error_log /var/log/nginx/flaskapp_error.log;
root /usr/share/nginx/html; # 服务器默认启动目录
include /etc/nginx/default.d/*.conf;
location / { # 用于做URL匹配
proxy_pass http://flask:8000; # 将固定的请求路由到新的uri
proxy_redirect off; # 关闭重定向
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
proxy_pass http://flask:8000;
expires 30d; # 静态文件30天后在客户端浏览器的缓存到期
}
location ~ .*\.(js|css)?$ {
proxy_pass http://flask:8000;
expires 15d;
}
error_page 404 /404.html; # 配置404页面
location = /40x.html {
}
error_page 500 502 503 504 /50x.html; # 错误状态码的显示页面,配置后需要重启
location = /50x.html {
}
}
}
nginx 容器通过 --network
连接 flask 容器,因此配置文件中 location
的代理地址为 flask:8000
。
注:docker 官方已不推荐使用
docker run --link
来链接 2 个容器互相通信,随后的版本会删除--link
。
以 nginx:1.21.4 为基础镜像,Dockerfile 如下:
FROM nginx:1.21.4
RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx
构建镜像并启动
# 当前工作目录:nginx
$ docker build -t "my_nginx:1.0" .
# 后台启动nginx容器,加入网桥flask-nginx
$ docker run -itd --name nginx -p 80:80 --network flask-nginx my_nginx:1.0
# 查看容器ip
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx
# 172.20.0.3
现在浏览器可以通过 http://主机地址
访问 flask 项目。主机地址可以通过 ifconfig
命令查看。
# 访问项目地址
$ curl http://172.17.29.117
Hello World
需要安装 Docker Compose
docker-compose.yml
version: '3'
networks:
flask-nginx:
services:
flaskapp:
image: my_flaskapp:0.1
build: ./flaskapp
container_name: flask
volumes:
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
networks:
- flask-nginx
ports:
- "8000"
environment:
- APP_NAME=flask_0.2
nginx:
image: my_nginx:1.0
build: ./nginx
container_name: nginx
volumes:
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
networks:
- flask-nginx
ports:
- "80:80"
depends_on:
- flaskapp
depends_on
设置依赖关系
docker-compose up
:以依赖性顺序启动服务。在上面示例中,先启动 flaskapp ,才会启动 nginx。docker-compose up SERVICE
:自动包含 SERVICE 的依赖项。在上面示例中,docker-compose up nginx
还将创建并启动 flaskapp。docker-compose stop
:按依赖关系顺序停止服务。在上面示例中,nginx 在 flaskapp 之前停止。运行项目
# 后台运行
docker-compose up -d
# 查看运行状态
docker-compose ps