作者: Ju4t
架构 Django + uWSGI (http方式),如使用socket方式需要Nginx转发;
注释掉了 nginx 和 uwsgi 部署在同一容器内的配置;
docker-compose 为推荐架构,如果您了解 Nginx+ 更推荐 ^_^;
django静态文件、数据库等操作,建议单独处理;
├── Dockerfile
├── README.md
├── db.sqlite3
├── djangoProject
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── docker-compose.yml
├── docker-entrypoint.sh
├── manage.py
├── nginx.conf
├── requirements.txt
├── templates
├── uwsgi.ini
FROM python:3.9-alpine
LABEL maintainer="ju4t@qq.com"
LABEL org.opencontainers.image.title="labdoc"
LABEL org.opencontainers.image.authors="ju4t@qq.com"
ENV PYTHONUNBUFFERED 1
ENV MIRRORS https://mirrors.aliyun.com
ENV WORKDIR /app
ENV PRODUCT 1
ENV DEBUG 0
ENV ALLOWED_HOSTS labdoc.cc
ENV SECRET_KEY ''
ENV DB_HOST ''
ENV DB_NAME ''
ENV DB_USER ''
ENV DB_PASS ''
ENV KV_HOST ''
ENV KV_USER ''
ENV KV_PASS ''
# Alpine Linux 源 指向最新的稳定版本
RUN echo $MIRRORS/alpine/latest-stable/main > /etc/apk/repositories; \
echo $MIRRORS/alpine/latest-stable/community >> /etc/apk/repositories
RUN apk --no-cache add \
# 基础依赖
gcc libgcc musl-dev \
# mysqlclient 依赖
mariadb-connector-c-dev \
# Pillow 自测依赖,官方推荐依赖 > https://pillow.readthedocs.io/en/latest/installation.html#external-libraries
libxml2-dev libxslt-dev libffi-dev jpeg-dev zlib-dev
# Nginx
#RUN apk --update add nginx
#ADD deployment/nginx.conf /etc/nginx/http.d/default.conf
# 根据结构自行调整,包含 requirements.txt
WORKDIR $WORKDIR
COPY ./ $WORKDIR
# 安装包
RUN pip install --upgrade pip -i $MIRRORS/pypi/simple && \
pip install --no-cache-dir -r requirements.txt -i $MIRRORS/pypi/simple && \
# uWSGI 部署
pip install --no-cache-dir uWSGI -i $MIRRORS/pypi/simple
# apk del gcc
# 如果 nginx 和 uwsgi 部署在同一docker里,不能使用 uwsgi账号,而是通过root 启动 nginx 和 uwsgi
RUN adduser --disabled-password --no-create-home uwsgi && \
chown -R uwsgi:uwsgi $WORKDIR
USER uwsgi
# 调试
#ENTRYPOINT ["python manage.py runserver 0.0.0.0:8000"]
# entrypoint 文件启动
ENTRYPOINT ["sh", "./docker-entrypoint.sh"]
EXPOSE 80 443 3031 8000
#!/bin/sh
echo "*** 启动 uWSGI 服务 ***"
# 1、nginx + socket 2、http-socket
# http-socket > http
#nohup uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8000 --socket :3031
nohup uwsgi --ini /app/uwsgi.ini
#echo "*** 启动 Nginx 服务 ***"
#nginx -g "daemon off;"
exec "$@"
Django>=3.0,<4.0
mysqlclient # 官方推荐 https://pypi.org/project/mysqlclient/
djangorestframework
djangorestframework-jwt
drf-extensions
django-filter
django-redis
django-mditor # 编辑器
Markdown # 前端渲染
pygments # 脚本高亮css生成
# oss
# 默认使用阿里云镜像无法安装,用 清华的可以 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple oss2
oss2 # https://help.aliyun.com/document_detail/85288.html
django_oss_storage
Pillow # 图片
[uwsgi]
chdir = /app
module = djangoProject.wsgi
# 根据cpu核心自动计算 processes、threads
master = true
enable-threads = true
processes = %(%k * 2)
threads = %(%k * 20)
# 使用 nginx 服务中的用户,uwsgi.sock
gid = uwsgi
uid = uwsgi
lazy-apps = true
chmod-socket = 777
# http 暴露端口,直接访问
http-socket = :8000
# socket文件,配合nginx时候使用
socket = :3031
;socket = uwsgi.sock
# status文件,可以查看uwsgi的运行状态,uwsgitop uwsgi.status
;stats = uwsgi.status
# pid文件,通过该文件可以控制uwsgi的重启和停止
pidfile = uwsgi.pid
# 日志文件存放位置
# daemonize = uwsgi.log
# 退出uwsgi是否清理中间文件,包含pid、sock和status文件
vacuum = true
# 调优wsgi-file
# 处理过多少个请求后重启进程,目的是防止内存泄露
max-requests = 5000
# 每个进程排队的请求数量,默认:100 并发数 = procsses * threads * listen
# 使用时需要修改系统
# listen = 65535
# header 的 buffer 大小 默认:4k
buffer-size = 65536
# 所有进程在 30s 没有响应后傻屌
harakiri = 30
# 记录慢于 3000 毫秒的请求
log-slow = 3000
# 关闭log,提升性能
disable-logging = true
# 单独开一个线程进行 log 写入工作,这样有更好的性能
threaded-log = true
# uWSGI 配置参数 https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/ThingsToKnow.html
upstream django {
# server unix:///app/uwsgi.sock; # for a file socket
server djangoproject-app-1:3031 weight=100;
server djangoproject-app-2:3031 weight=100;
}
server {
listen 80;
listen [::]:80;
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
server_name localhost;
# charset utf-8;
gzip on;
# ssl_certificate /app/blog/ssl/server.pem;
# ssl_certificate_key /app/blog/ssl/server.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
client_max_body_size 75M;
location /media {
alias /app/media;
}
location /static {
alias /app/static;
}
# Finally, send all non-media requests to the Django server.
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass django; # 127.0.0.1:3031; unix:///app/uwsgi.sock;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
}
}
version: "3.8"
services:
app:
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
resources:
limits:
cpus: '0.50'
memory: '512M'
reservations:
cpus: '0.25'
memory: '128M'
build:
context: .
dockerfile: Dockerfile
# command: python manage.py runserver 0.0.0.0:8000
# ports:
# - 80:80 # NGINX
# - 8000:8000 # HTTP
# - 8080:8080 # socket
# networks:
# - vlan100
volumes:
- ./:/app
# env_file: .env
restart: always
nginx:
deploy:
resources:
limits:
cpus: '0.50'
memory: '512M'
reservations:
cpus: '0.25'
memory: '128M'
image: nginx
ports:
- 80:80
- 443:443
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
restart: always
#networks:
# vlan100:
# driver: bridge
$ docker build -t djangoproject ./
# 拉起日志
(djangoProject) ju4t@Mac djangoProject % docker compose up
[+] Building 53.8s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.54kB 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.9-alpine 0.0s
=> [1/7] FROM docker.io/library/python:3.9-alpine 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 12.84kB 0.0s
=> CACHED [2/7] RUN echo https://mirrors.aliyun.com/alpine/latest-stable/main > /etc/apk/repositories; echo https://mirrors.aliyun.com/alpine/latest-stable/community >> /etc/apk/repositories 0.0s
=> CACHED [3/7] RUN apk update && apk --update add gcc libgcc musl-dev libxml2-dev libxslt-dev libffi-dev jpeg-dev zlib-dev 0.0s
=> CACHED [4/7] WORKDIR /app 0.0s
=> [5/7] COPY ./ /app 0.0s
=> [6/7] RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple && pip install --no-cache-dir uWSGI -i https://mirrors.aliyun.com/pypi/simple && pip install --no-cache-dir - 52.1s
=> [7/7] RUN adduser --disabled-password --no-create-home uwsgi 0.3s
=> exporting to image 1.3s
=> => exporting layers 1.3s
=> => writing image sha256:4ece610667ea966a17002442a53ac24e7f33e777b4e7a606e7e672410ce72825 0.0s
=> => naming to docker.io/library/djangoproject_app 0.0s
[+] Running 4/4
⠿ Network djangoproject_default Created 0.1s
⠿ Container djangoproject-app-2 Created 0.1s
⠿ Container djangoproject-app-1 Created 0.1s
⠿ Container djangoproject-nginx-1 Created 0.2s
Attaching to djangoproject-app-1, djangoproject-app-2, djangoproject-nginx-1
djangoproject-app-1 | *** 启动 uWSGI 服务 ***
djangoproject-app-1 | [uWSGI] getting INI configuration from /app/uwsgi.ini
djangoproject-app-1 | *** Starting uWSGI 2.0.20 (64bit) on [Tue Oct 25 03:42:19 2022] ***
djangoproject-app-1 | compiled with version: 11.2.1 20220219 on 25 October 2022 03:41:40
djangoproject-app-1 | os: Linux-5.10.76-linuxkit #1 SMP Mon Nov 8 10:21:19 UTC 2021
djangoproject-app-1 | nodename: a030e669cce6
djangoproject-app-1 | machine: x86_64
djangoproject-app-1 | clock source: unix
djangoproject-app-1 | detected number of CPU cores: 4
djangoproject-app-1 | current working directory: /app
djangoproject-app-1 | writing pidfile to uwsgi.pid
djangoproject-app-1 | detected binary path: /usr/local/bin/uwsgi
djangoproject-app-1 | !!! no internal routing support, rebuild with pcre support !!!
djangoproject-app-1 | chdir() to /app
djangoproject-app-1 | your memory page size is 4096 bytes
djangoproject-app-1 | *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
djangoproject-app-1 | detected max file descriptor number: 1048576
djangoproject-app-1 | lock engine: pthread robust mutexes
djangoproject-app-1 | thunder lock: disabled (you can enable it with --thunder-lock)
djangoproject-app-1 | uwsgi socket 0 bound to TCP address :8000 fd 3
djangoproject-app-1 | uwsgi socket 1 bound to TCP address :3031 fd 4
djangoproject-app-1 | Python version: 3.9.9 (main, Nov 30 2021, 03:30:22) [GCC 10.3.1 20211027]
djangoproject-app-1 | Python main interpreter initialized at 0x7fceadc66ac0
djangoproject-app-1 | python threads support enabled
djangoproject-app-1 | your server socket listen backlog is limited to 100 connections
djangoproject-app-1 | your mercy for graceful operations on workers is 60 seconds
djangoproject-app-1 | mapped 52315056 bytes (51088 KB) for 640 cores
djangoproject-app-1 | *** Operational MODE: preforking+threaded ***
djangoproject-app-2 | *** 启动 uWSGI 服务 ***
djangoproject-app-2 | [uWSGI] getting INI configuration from /app/uwsgi.ini
djangoproject-app-2 | *** Starting uWSGI 2.0.20 (64bit) on [Tue Oct 25 03:42:19 2022] ***
djangoproject-app-2 | compiled with version: 11.2.1 20220219 on 25 October 2022 03:41:40
djangoproject-app-2 | os: Linux-5.10.76-linuxkit #1 SMP Mon Nov 8 10:21:19 UTC 2021
djangoproject-app-2 | nodename: 928321472d8a
djangoproject-app-2 | machine: x86_64
djangoproject-app-2 | clock source: unix
djangoproject-app-2 | detected number of CPU cores: 4
djangoproject-app-2 | current working directory: /app
djangoproject-app-2 | writing pidfile to uwsgi.pid
djangoproject-app-1 | *** uWSGI is running in multiple interpreter mode ***
djangoproject-app-1 | spawned uWSGI master process (pid: 8)
djangoproject-app-1 | spawned uWSGI worker 1 (pid: 9, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 2 (pid: 10, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 3 (pid: 11, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 4 (pid: 12, cores: 80)
djangoproject-app-2 | detected binary path: /usr/local/bin/uwsgi
djangoproject-app-2 | !!! no internal routing support, rebuild with pcre support !!!
djangoproject-app-2 | chdir() to /app
djangoproject-app-2 | your memory page size is 4096 bytes
djangoproject-app-2 | *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***
djangoproject-app-2 | detected max file descriptor number: 1048576
djangoproject-app-2 | lock engine: pthread robust mutexes
djangoproject-app-2 | thunder lock: disabled (you can enable it with --thunder-lock)
djangoproject-app-2 | uwsgi socket 0 bound to TCP address :8000 fd 3
djangoproject-app-2 | uwsgi socket 1 bound to TCP address :3031 fd 4
djangoproject-app-2 | Python version: 3.9.9 (main, Nov 30 2021, 03:30:22) [GCC 10.3.1 20211027]
djangoproject-app-1 | spawned uWSGI worker 5 (pid: 13, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 6 (pid: 14, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 7 (pid: 15, cores: 80)
djangoproject-app-1 | spawned uWSGI worker 8 (pid: 16, cores: 80)
djangoproject-app-2 | Python main interpreter initialized at 0x7f31087cdac0
djangoproject-app-2 | python threads support enabled
djangoproject-app-2 | your server socket listen backlog is limited to 100 connections
djangoproject-app-2 | your mercy for graceful operations on workers is 60 seconds
djangoproject-app-2 | mapped 52315056 bytes (51088 KB) for 640 cores
djangoproject-app-2 | *** Operational MODE: preforking+threaded ***
djangoproject-app-2 | *** uWSGI is running in multiple interpreter mode ***
djangoproject-app-2 | spawned uWSGI master process (pid: 9)
djangoproject-app-2 | spawned uWSGI worker 1 (pid: 10, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 2 (pid: 11, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 3 (pid: 12, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 4 (pid: 13, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 5 (pid: 14, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 6 (pid: 15, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 7 (pid: 16, cores: 80)
djangoproject-app-2 | spawned uWSGI worker 8 (pid: 17, cores: 80)
djangoproject-nginx-1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
djangoproject-nginx-1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
djangoproject-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
djangoproject-nginx-1 | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
djangoproject-nginx-1 | 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
djangoproject-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
djangoproject-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
djangoproject-nginx-1 | /docker-entrypoint.sh: Configuration complete; ready for start up
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: using the "epoll" event method
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: nginx/1.21.5
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: OS: Linux 5.10.76-linuxkit
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: start worker processes
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: start worker process 31
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: start worker process 32
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: start worker process 33
djangoproject-nginx-1 | 2022/10/25 03:42:21 [notice] 1#1: start worker process 34
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7fceadc66ac0 pid: 9 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7f31087cdac0 pid: 12 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7fceadc66ac0 pid: 10 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7f31087cdac0 pid: 14 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7f31087cdac0 pid: 13 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7fceadc66ac0 pid: 11 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7fceadc66ac0 pid: 15 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7fceadc66ac0 pid: 13 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7fceadc66ac0 pid: 14 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f31087cdac0 pid: 11 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 3 seconds on interpreter 0x7fceadc66ac0 pid: 12 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f31087cdac0 pid: 10 (default app)
djangoproject-app-1 | WSGI app 0 (mountpoint='') ready in 3 seconds on interpreter 0x7fceadc66ac0 pid: 16 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f31087cdac0 pid: 16 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f31087cdac0 pid: 15 (default app)
djangoproject-app-2 | WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0x7f31087cdac0 pid: 17 (default app)
(djangoProject) ju4t@Mac djangoProject % docker images | grep django
djangoproject_app latest 4ece610667ea 3 minutes ago 228MB
不使用 nginx 代理,http-stock 暴露服务
http 和 nginx/apache同级别,前端不支持uwsgi时使用http-stock
一般地,使用 http-stock
同一台服务器上使用UNIX Socket uwsgi.sock,多台服务器上Nginx转发 使用 TCP/IP Socket :3031
如果 nginx 和 uwsgi 部署在同一docker里,不能在dockerfile中 USER uwsgi 账号,而是通过 root 启动 nginx 和 uwsgi
uwsgi启动时指定gid/uid
# nginx + uwsgi 在同一docker
/app # ps
PID USER TIME COMMAND
1 root 0:00 sh ./docker-entrypoint.sh
8 uwsgi 0:00 uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8080 --socket :3031
9 root 0:00 nginx: master process nginx -g daemon off;
10 nginx 0:00 nginx: worker process
11 nginx 0:00 nginx: worker process
12 nginx 0:00 nginx: worker process
13 nginx 0:00 nginx: worker process
14 uwsgi 0:00 uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8080 --socket :3031
16 uwsgi 0:00 uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8080 --socket :3031
17 uwsgi 0:00 uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8080 --socket :3031
20 uwsgi 0:00 uwsgi --master --enable-threads --processes 4 --threads 2 --gid uwsgi --uid uwsgi --module djangoProject.wsgi --http-socket :8080 --socket :3031
22 root 0:00 /bin/sh
30 root 0:00 ps
/app #
# 独立部署
/app $ ps
PID USER TIME COMMAND
1 uwsgi 0:00 sh ./docker-entrypoint.sh
8 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
9 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
10 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
11 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
12 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
13 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
14 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
15 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
16 uwsgi 0:00 uwsgi --ini /app/uwsgi.ini
649 uwsgi 0:00 /bin/sh
655 uwsgi 0:00 ps