基于 Docker 和 Gunicorn 如何部署 Python Sanic 项目

基于 docker+gunicorn 部署 sanic 项目

源代码: https://github.com/ltoddy/Python-useful/tree/master/sanic-app

最近云服务提供商在打价格战,我在滴滴云上花了很少的钱租了一个月的云服务器: 公网 ip 是:116.85.42.182, 以下我以 116.85.42.182 这个 ip 为演示,当你自己在部署的时候请换乘自己的 ip 地址.

买完服务器之后,你会得到一个公网 ip,你可以通过 ssh 命令连接上你的服务器.

ssh [email protected]

顺便提一句,滴滴云给你创建的账户叫"dc2-user",你需要自己设置 root 的密码.

然后安装 docker:

sudo apt-get install docker.io

演示一个最小的 sanic-app,来部署一下.

这是项目树(目录).

.
├── app.py
├── Dockerfile
└── templates
    └── index.html

1 directory, 3 files

app.py

import os

from sanic import Sanic from sanic.response import html from sanic.response import HTTPResponse from jinja2 import Environment, FileSystemLoader

app = Sanic(name) base_dir = os.path.abspath(os.path.dirname(file)) templates_dir = os.path.join(base_dir, ‘templates’) jinja_env = Environment(loader=FileSystemLoader(templates_dir), autoescape=True)

def render_template(template_name: str, **context) -> str: template = jinja_env.get_template(template_name) return template.render(**context)

@app.route(’/’) async def index(request) -> HTTPResponse: return html(render_template(‘index.html’))

这里的 python 代码,用到了 sanic 框架和 jinja2 木板引擎,所以带会需要安装这两个依赖.

Dockerfile

FROM taoliu/gunicorn3

WORKDIR /code

ADD . /code

RUN pip install sanic
&& pip install jinja2

EXPOSE 8080

CMD gunicorn app:app --bind 0.0.0.0:8080 --worker-class sanic.worker.GunicornWorker

第一行那里"FROM taoliu/gunicorn3",由于没找到合适的 Python3 的 gunicorn 的基础镜像,所以我自己做了一个,方便所有人使用.

RUN pip install sanic \ && pip install jinja2 这里,来安装那两个依赖.

CMD gunicorn app:app --bind 0.0.0.0:8080 --worker-class sanic.worker.GunicornWorker 这行,是镜像运行他所以执行的命令.

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ltoddy's home</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.css">
</head>
<body>
<div class="container">
    <div class="page-header">
        <h1>Welcome</h1>
    </div>
</div>
</body>
</html>

然后把这些文件传到服务器上:

scp -r * [email protected]:~

然后 ssh 连上我们的服务器,去构建我们的 docker 镜像(这个过程有些漫长,具体看网速.)

docker build -t sanic-demo .

docker images

来查看一下当前拥有的镜像

然后后台运行 docker 镜像:

docker run -d --restart=always -p 5000:8080 sanic-demo:latest

这时候打开浏览器输入: 116.85.42.182:5000 来看看效果吧.

最后说明一点,去滴滴云那里的防火墙规则那里,添加 5000 端口的规则.

https://img.vim-cn.com/00/b211cca5695de1c1c71ddf48faa4916cf441c6.png


基于 Docker 和 Gunicorn 如何部署 Python Sanic 项目

4 回复

感谢分享!
1. sanic 中加载 jinja2 模板不用函数速度可以更快。毕竟启动的时候就加载好了
2. Dockfile 中,能用 COPY 就不要用 ADD。再者因为分层,RUN 命令可以前置于第二行


好的,这是一个很实际的问题。用Docker和Gunicorn部署Sanic项目,关键在于理解Sanic的异步特性,并正确配置Gunicorn的工作进程。

Sanic是一个异步框架,所以Gunicorn的默认同步工作器(sync)无法直接运行它。我们需要使用支持异步的工作器,比如uvicorn.workers.UvicornWorker(通过uvloophttptools)或者sanic.worker.GunicornWorker。这里我推荐使用uvicorn的方案,因为它性能优秀且是ASGI标准实现。

下面是一个完整的、可直接使用的部署方案,包含Dockerfiledocker-compose.ymlgunicorn配置文件。

1. 项目结构与核心文件

假设你的项目结构如下:

your_sanic_app/
├── app.py              # 你的Sanic应用主文件
├── requirements.txt    # 项目依赖
├── Dockerfile
├── docker-compose.yml
└── gunicorn.conf.py    # Gunicorn配置文件

2. 应用文件示例 (app.py)

from sanic import Sanic
from sanic.response import text

app = Sanic("MyApp")

@app.get("/")
async def hello(request):
    return text("Hello from Sanic in Docker with Gunicorn!")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=False)

3. 依赖文件 (requirements.txt)

sanic>=21.12
gunicorn>=20.1
uvicorn[standard]>=0.18  # 关键:提供UvicornWorker

4. Gunicorn 配置文件 (gunicorn_conf.py)

# 绑定地址和端口
bind = "0.0.0.0:8000"
# 使用Uvicorn的异步工作器来运行Sanic应用
worker_class = "uvicorn.workers.UvicornWorker"
# 工作进程数,通常建议设置为 (2 * CPU核心数) + 1
workers = 2
# 每个工作进程处理的线程数,对于异步应用,通常为1
threads = 1
# 工作进程最大请求数,达到后重启,有助于防止内存泄漏
max_requests = 1000
max_requests_jitter = 50
# 超时时间
timeout = 120
keepalive = 5
# 日志配置
accesslog = "-"  # 输出到stdout
errorlog = "-"   # 输出到stderr
# 防止Gunicorn在接收到SIGTERM时立即杀死工作进程,允许优雅关闭
graceful_timeout = 30

5. Dockerfile

# 使用官方Python轻量级镜像
FROM python:3.10-slim

# 设置工作目录
WORKDIR /app

# 设置环境变量,确保Python输出直接显示在容器日志中,而不被缓冲
ENV PYTHONUNBUFFERED=1

# 安装系统依赖(如果需要编译某些Python包)
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip \
    && pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口(与gunicorn配置中的bind端口一致)
EXPOSE 8000

# 启动命令:使用gunicorn加载配置文件运行应用
# `app:app` 指从 `app.py` 模块中导入 `app` 实例
CMD ["gunicorn", "-c", "gunicorn.conf.py", "app:app"]

6. Docker Compose 文件 (docker-compose.yml) (可选,用于简化运行)

version: '3.8'
services:
  sanic-app:
    build: .
    container_name: my-sanic-app
    ports:
      - "8000:8000"  # 主机端口:容器端口
    restart: unless-stopped
    # 如果需要,可以在这里设置环境变量或挂载卷
    # environment:
    #   - MY_ENV=value
    # volumes:
    #   - ./logs:/app/logs

部署与运行

  1. 构建镜像:在项目根目录执行 docker build -t my-sanic-app .
  2. 运行容器
    • 直接运行:docker run -d -p 8000:8000 --name sanic-container my-sanic-app
    • 或使用Docker Compose:docker-compose up -d

现在你的Sanic应用就在Docker容器中,通过Gunicorn(使用Uvicorn工作器)提供服务了。访问 http://localhost:8000 即可看到结果。

核心要点总结:用 uvicorn.workers.UvicornWorker 作为Gunicorn的worker来跑异步的Sanic应用。

你说的第二条我清楚,第一条不是很清楚。

把你自行构建的镜像 taoliu/gunicorn3 相关 Dockerfile 也放到 github 上给人看看吧

回到顶部