WsgiDAV Docker 与 WSGI 服务器部署指南
用 Docker 与主流 WSGI 服务器(gunicorn/uvicorn)编排部署 WsgiDAV 4.3.5 WebDAV 服务器,覆盖镜像选择、WSGI 应用工厂、docker-compose 编排、数据卷持久化与验证。
WsgiDAV Docker 与 WSGI 服务器部署指南
目标:用 Docker 容器化部署 WsgiDAV 4.3.5 WebDAV 服务器,并演示如何把 WsgiDAV 作为 WSGI 应用挂载到 gunicorn(同步/多进程)与 uvicorn(ASGI)之上,实现端口映射、数据卷持久化与多用户认证。
WsgiDAV 本质是一个 WSGI 应用(wsgidav.wsgidav_app.WsgiDAVApp),既可作为独立服务器运行(默认 cheroot),也完全可以交给 gunicorn、uvicorn 等生产级 WSGI/ASGI 服务器托管。Docker 场景下,常见两种方式:
- 直接在容器内跑
wsgidav -c(cheroot 兜底); - 用 gunicorn / uvicorn 加载
wsgidav_app:WsgiDAVApp(或自建application工厂),便于多 worker、优雅重启与负载。
本文以 Ubuntu 22.04 + Python 3.10 镜像演示。
1. 镜像选型
WsgiDAV 官方没有单一官方 Docker 镜像仓库,最稳妥的方式是 python:3.10-slim(或 python:3.11-slim)系统镜像上 pip install wsgidav。本文使用 python:3.10-slim。
docker pull python:3.10-slim
也可用
python:3.11、python:3.10-alpine(注意 alpine 需额外编译依赖,生产建议-slim)。
2. 目录规划
宿主机编排目录 /opt/data/wsgidav/:
mkdir -p /opt/data/wsgidav/data
cd /opt/data/wsgidav
./data:WebDAV 共享根,容器内挂载/data./config.yml、./Dockerfile、./docker-compose.yml:编排文件
3. WSGI 应用工厂(方式一:gunicorn 读取 application)
编写应用工厂 /opt/data/wsgidav/app.py,供 gunicorn 加载(wsgidav.wsgidav_app.WsgiDAVApp 实例即 WSGI 可调用对象):
# /opt/data/wsgidav/app.py
from wsgidav.wsgidav_app import WsgiDAVApp
_config = {
"host": "0.0.0.0",
"port": 8080,
"provider_mapping": {"/": {"root": "/data"}},
"simple_dc": {
"user_mapping": {
"/": {"admin": {"password": "admin123", "roles": ["admin"]}}
}
},
}
application = WsgiDAVApp(_config)
结构要点:
application是模块级变量,gunicorn 用app:application引用。provider_mapping的/挂到容器内/data(与 compose 的 volume 挂载点一致)。simple_dc.user_mapping键为 realm/。
4. Dockerfile
# /opt/data/wsgidav/Dockerfile
FROM python:3.10-slim
RUN pip install --no-cache-dir wsgidav cheroot gunicorn lxml
WORKDIR /opt/app
COPY app.py /opt/app/app.py
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "app:application"]
--workers 2起两个 worker;若用方式二(wsgidav 直接跑)则不需要 gunicorn/lxml,CMD ["wsgidav","-c","/etc/wsgidav.yaml"]。
构建:
docker build -t wsgidav:4.3.5 .
5. docker-compose.yml(gunicorn)
# /opt/data/wsgidav/docker-compose.yml
services:
wsgidav:
build: .
image: wsgidav:4.3.5
container_name: wsgidav
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./data:/data
command: ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "app:application"]
ports: "8080:8080":宿主 8080 映射容器 8080volumes: ./data:/data:共享根持久化到宿主./datacommand:覆盖Dockerfile默认 CMD 的 worker 数量等
启动:
docker compose up -d
docker compose ps
# NAME IMAGE STATUS PORTS
# wsgidav wsgidav:4.3.5 Up 5 sec 0.0.0.0:8080->8080/tcp
查看日志:
docker compose logs -f wsgidav
验证:
# 未认证 → 401
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/
# 401
# OPTIONS → DAV 头
curl -s -u admin:admin123 -X OPTIONS -i http://127.0.0.1:8080/
# HTTP/1.1 200 OK
# DAV: 1,2
# Allow: OPTIONS, HEAD, GET, PROPFIND, DELETE, COPY, MOVE, PROPPATCH, LOCK, UNLOCK
# PROPFIND 列目录(先在 data 放个文件)
echo test > data/hello.txt
curl -s -u admin:admin123 -X PROPFIND -H "Depth: 1" http://127.0.0.1:8080/ | grep -o "<D:href>[^<]*</D:href>"
# <D:href>/</D:href>
# <D:href>/hello.txt</D:href>
# PUT / GET / DELETE
curl -s -u admin:admin123 -o /dev/null -w "PUT -> %{http_code}\n" -T /etc/hostname http://127.0.0.1:8080/u.txt
# PUT -> 201
curl -s -u admin:admin123 http://127.0.0.1:8080/u.txt
# <你的主机名>
curl -s -u admin:admin123 -o /dev/null -w "DELETE -> %{http_code}\n" -X DELETE http://127.0.0.1:8080/u.txt
# DELETE -> 204
6. 方式二:直接跑 wsgidav(无 app.py)
不写 app.py,用 wsgidav 自带的命令行 + 配置文件 + cheroot,Docker 内即可:
# docker-compose.yml(方式二)
services:
wsgidav:
image: python:3.10-slim
container_name: wsgidav
restart: unless-stopped
command: sh -c "pip install --no-cache-dir wsgidav cheroot lxml && wsgidav -c /etc/wsgidav.yaml"
ports:
- "8080:8080"
volumes:
- ./wsgidav.yaml:/etc/wsgidav.yaml:ro
- ./data:/data
wsgidav.yaml 指向容器内 /data:
host: 0.0.0.0
port: 8080
provider_mapping:
"/":
root: /data
simple_dc:
user_mapping:
"/":
admin:
password: admin123
roles: ["admin"]
方式二每次启动都会
pip install(把镜像当一次性的话需先 commit 或写 Dockerfile)。生产建议把安装固化进 Dockerfile(见第 4 节)。
7. 方式三:uvicorn 托管(ASGI)
WsgiDAV 4.3.5 也提供 ASGI 网关接口。安装 uvicorn 后,用相关网关适配器:
pip install uvicorn
将 app.py 顶层替换为 ASGI 适配(示例,需安装对应 worker/adapter):
from wsgidav.fs_dav_provider import FilesystemProvider
from wsgidav.wsgidav_app import WsgiDAVApp
_config = {
"provider_mapping": {"/": FilesystemProvider("/data")},
"simple_dc": {
"user_mapping": {"/": {"admin": {"password": "admin123", "roles": ["admin"]}}}
},
"http_authenticator": {"domain_controller": None},
}
app_wsgi = WsgiDAVApp(_config)
# 通过 uvicorn 的 WSGIMiddleware 桥接
from uvicorn.middleware.wsgi import WSGIMiddleware
application = WSGIMiddleware(app_wsgi)
启动:
uvicorn --host 0.0.0.0 --port 8080 --app-dir /opt "app:application"
ASGI/WSGI 桥接会引入中间件开销;若仅需同步 WebDAV,gunicorn(第 5 节)更直接、性能更好。uvicorn 适合已采用 ASGI 技术栈、希望与其他 ASGI 服务共存的场景。
8. 数据持久化与重启验证
# 写入容器共享根
echo hi > data/persist.txt
docker compose down
docker compose up -d
# 数据仍在
cat data/persist.txt
# hi
./data:/data 保证容器销毁/重建不丢数据。
9. 日常运维
docker compose ps
docker compose logs -f wsgidav
docker compose restart wsgidav # 改配置后
docker compose stop wsgidav
docker compose down # 停止并移除容器(数据保留)
docker exec wsgidav ls -la /data # 进容器查共享目录
10. 常见问题
Q1:gunicorn 报 Worker failed to boot?
多半是 app.py 里有语法/导入错误,或 --chdir/--app-dir 指向不对。docker compose logs 看 Traceback。
Q2:simple_dc.user_mapping 键?
必须等于 provider realm(容器内挂 /data 时 realm 仍是 /,键写 "/")。
Q3:容器内端口连不上?
确认 ports 映射、容器内 host: 0.0.0.0 且 port 一致;docker compose ps 看 PORTS。
Q4:想固定 Python 版本? 用 python:3.11-slim 或在 Dockerfile FROM python:3.11-slim。
Q5:多 worker 下锁/属性状态? gunicorn 多进程时内存态 LockStorageDict/属性不去共享,多 worker 场景建议使用数据库类 lock/property store 或单 worker,详见配置篇。
11. 参考链接
- WsgiDAV 仓库:
https://github.com/mar10/wsgidav - Gunicorn 文档:
https://docs.gunicorn.org - Uvicorn 文档:
https://www.uvicorn.org - WsgiDAV 配置:
https://wsgidav.readthedocs.io/en/latest/run-configure.html