docker单台服务器部署django

容器

  • uwsgi
  • daphne
  • celery-worker
  • celery-beat
  • redis
  • mysql
  • nginx

目录结构

- project
	docker-compose.yml
	- backend
		- Dockerfile
	- nginx
		- www
			- dist
		- conf
			- nginx.conf
		- log
	- mysql
		- data

Dockerfile

构建python容器

FROM python:3.9.6
ENV PYTHONUNBUFFERED 1
ENV CLOSE_LOGGING False

RUN groupadd -r work && useradd -r -g work work && \
    mkdir workspace && chown -R work:work /workspace

WORKDIR /workspace
COPY ./ /workspace

RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.douban.com/simple \
    && rm requirements.txt
USER work

docker-compose

编排容器

version: "3"

# 手动创建 docker network 或者 设置自动创建network
networks:
  my-network:
    external: true

services:

  db:
    image: mysql:5.7.37
    container_name: mysql
    command:
      [
          '--character-set-server=utf8mb4',
          '--collation-server=utf8mb4_general_ci'
      ]
    environment:
      MYSQL_ROOT_PASSWORD: hello
      MYSQL_USER: hello
      MYSQL_PASSWORD: hello@2023
      MYSQL_DATABASE: hello
    volumes:
    	# 将 mysql 数据挂载到宿主机
      - ./mysql/data:/var/lib/mysql
    networks:
      - my-network
    # 宿主机重启自动重启容器
    restart: always

  redis:
    image: redis:6.2.5
    container_name: redis
    command: redis-server --requirepass hello
    networks:
      - my-network
    restart: always
    
  dj-uwsgi:
  	# 指定 Dockerfile路径
    build: ./backend
    # 指定镜像名称
    image: web
    container_name: uwsgi
    # 启动服务。保证 web容器在 db redis 启动后启动
    command: /bin/sh -c "sleep 6 && python manage.py migrate && uwsgi --ini uwsgi.ini"
    # 设置环境变量
    environment:
      - DEBUG=0
      # mysql 指定 db 容器名称
      - DATABASE_HOST=mysql
      # 容器中使用的端口是3306
      - DATABASE_PORT=3306
      - DATABASE_NAME=hello
      - DATABASE_USER=hello
      - DATABASE_PASSWORD=hello@2023
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=hello
    volumes:
      - ./backend:/workspace
    networks:
      - my-network
    restart: always
    # 设置容器启动的先后顺序
    depends_on:
      - db
      - redis

  dj-daphne:
    build: ./backend
    image: web
    container_name: daphne
    command: daphne -b 0.0.0.0 -p 8000 --access-log - --proxy-headers core.asgi:application
    environment:
      - DEBUG=0
      - DATABASE_HOST=mysql
      - DATABASE_PORT=3306
      - DATABASE_NAME=hello
      - DATABASE_USER=hello
      - DATABASE_PASSWORD=hello@2023
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=hello
    volumes:
      - ./backend:/workspace
    networks:
      - my-network
    restart: always
    depends_on:
      - dj-uwsgi

  celery-worker:
    build: ./backend
    image: web
    container_name: celery-worker
    command: /bin/sh -c "sleep 6 && celery -A async_tasks worker -l info"
    environment:
      - DEBUG=0
      - DATABASE_HOST=mysql
      - DATABASE_PORT=3306
      - DATABASE_NAME=hello
      - DATABASE_USER=hello
      - DATABASE_PASSWORD=hello@2023
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=hello
    volumes:
      - ./backend:/workspace
    networks:
      - my-network
    restart: always
    depends_on:
      - dj-uwsgi

  nginx:
    image: nginx:1.19
    container_name: nginx
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./nginx/log:/var/log/nginx
      - ./nginx/www:/usr/share/nginx/html
    ports:
    	# 映射端口
      - "80:8000"
    networks:
      - my-network
    restart: always
    depends_on:
      - dj-daphne
      - celery-worker

nginx

nginx.conf 配置

# namespace docker-compose 可以直接使用
upstream  django {
    # uwsgi socket 对应
    server dj-uwsgi:8000;
}

server {
    # 配置gzip
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types application/octet-stream model/gltf-binary text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    listen 80;
    server_name 127.0.0.1;
  	# 前端打包后是一个dist文件夹
    root /usr/share/nginx/html/dist;
    if ($request_method !~ ^(GET|HEAD|POST|OPTIONS)$ ) {
        return 403;
    }
    index index.html index.htm;

    # 前端页面转发
    location / {
        try_files $uri /index.html;
    }

    location /api {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass django;
    		# uwsgi 转发
        rewrite "^/api/(.*)$" /$1 break;
    }

    location /beat {
        proxy_pass http://dj-daphne:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_redirect off;
        proxy_set_header Host $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-Host $server_name;

        proxy_connect_timeout 600;
        proxy_send_timeout 600;
        proxy_read_timeout 600;
        send_timeout 600;
        client_max_body_size 50M;
    		# daphne 转发
        rewrite "^/beat/(.*)$" /$1 break;
    }
}

uwsgi

注意只能前台运行,类似supervisor

[uwsgi]
chdir = /workspace
socket = :8000
uid = root
gid = root
module = core.wsgi:application
master = True
processes = 2
max-requests = 5000
pidfile  = /tmp/uwsgi.pid
vacuum = true
enable-threads = true
harakiri = 30
buffer-size = 65536

docker-compose命令

docker-compose up --build -d # 构建后台运行