一、构建思路

项目采用了Docker容器化的多服务架构,主要包含以下构建思路:

1. 整体架构设计

- 采用三层架构: Nginx反向代理层 → Django应用层 → MySQL数据库层

- 使用Docker Compose统一管理所有服务容器,实现服务的协同部署

2. 各服务容器配置

Django应用服务

- 基础镜像 :使用 python:3.10-slim 作为基础镜像,保证轻量级

- 依赖管理 :

- 安装系统依赖(gcc、libc-dev等编译工具和数据库驱动)

- 使用 Poetry 管理 Python 依赖,确保依赖版本一致性

- 应用配置 :

- 设置环境变量 PYTHONUNBUFFERED=1 和 DJANGO_SETTINGS_MODULE=work_system.settings

1. PYTHONUNBUFFERED=1

这个环境变量控制Python的输出缓冲行为:

- 默认行为 :Python会对标准输出(stdout)和标准错误(stderr)进行缓冲,只有当缓冲区满了或程序结束时才会一次性输出内容

- 设置为1的作用 :禁用输出缓冲,使Python的打印信息和错误日志能够实时显示在容器日志中

- 容器环境中的重要性 :

- 方便实时查看应用运行状态和调试信息

- 确保Docker日志驱动能捕获到完整的日志

- 避免因为缓冲导致日志丢失或延迟显示

2. DJANGO_SETTINGS_MODULE=work_system.settings

这个环境变量是Django框架的核心配置之一:

- 作用 :指定Django项目使用的配置模块路径

- 路径含义 : work_system.settings 表示使用 work_system 目录下的 settings.py 文件作为配置

在当前项目中,这两个环境变量确保了Django应用在Docker容器中:

- 能够实时输出日志,便于监控和调试

- 能够正确加载项目的配置文件,保证应用正常运行

- 安装 uWSGI 作为 WSGI 服务器

- 复制项目文件并收集静态资源

- 启动方式 :通过 uwsgi.ini 配置文件启动 uWSGI 服务器,监听 Unix socket 文件

MySQL数据库服务

- 基础镜像 :使用官方 mysql:8.0 镜像

- 数据持久化 :挂载 mysql_data 命名卷到 /var/lib/mysql ,保证数据不丢失

- 配置方式 :通过环境变量设置 root 密码、数据库名称、用户名和密码

- 网络暴露 :暴露 3306 端口到主机 3307 端口,方便外部访问

注:容器间访问仍使用3306端口。

Nginx反向代理服务

- 基础镜像 :使用官方 nginx:latest 镜像

- 配置与资源 :挂载配置文件目录和静态文件卷

- 依赖关系 :依赖于 Django 应用启动,确保服务启动顺序正确

- 端口映射 :将 80 端口映射到主机 8080 端口,作为应用的入口点

3. 容器间通信机制

- 共享网络 :所有服务都连接到 app_network 桥接网络

- 服务发现 :容器间通过服务名称直接通信(如 Django 通过 mysql 名称访问数据库)

- 通信协议 :

- Django 应用与 MySQL 通过 TCP/IP 协议通信

- Nginx 与 Django 通过 uWSGI socket 文件进行高效通信

4. 数据与资源管理

- 静态资源 :使用 static_volume 命名卷共享 Django 收集的静态文件到 Nginx

- 代码挂载 :Django 应用代码通过 bind mount 挂载,支持开发时实时更新

- 日志管理 :uWSGI 日志输出到容器内的 /app/uwsgi.log 文件

5. 构建与部署流程

1. 构建 Django 应用镜像(包含所有依赖和配置)

2. 启动 MySQL 数据库容器并初始化数据

3. 启动 Django 应用容器,连接到 MySQL 数据库

4. 启动 Nginx 容器,配置反向代理到 Django 应用

5. 所有服务通过 Docker 网络协同工作

这种构建思路实现了服务的解耦、环境的一致性和部署的便捷性,适合开发和生产环境的快速部署与维护。

二、步骤

1. 创建Django应用镜像的Dockerfile

Dockerfile文件内容如下,此文件存储在项目根目录中,使用uwsgi部署。

# 使用Python 3.10作为基础镜像
FROM python:3.10-slim

# 设置环境变量
ENV PYTHONUNBUFFERED 1
ENV DJANGO_SETTINGS_MODULE work_system.settings

# 创建工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    g++ \
    libc-dev \
    libpq-dev \
    libmariadb-dev-compat \
    libmariadb-dev \
    pkg-config \
    && rm -rf /var/lib/apt/lists/*

# 安装Python依赖
COPY pyproject.toml /app/
ENV MYSQLCLIENT_CFLAGS="-I/usr/include/mariadb"
ENV MYSQLCLIENT_LDFLAGS="-L/usr/lib/mariadb -lmariadb"
RUN pip install --upgrade pip \
    && pip install poetry \
    && poetry config virtualenvs.create false \
    && poetry install --only main --no-root

# 安装uWSGI
RUN pip install uwsgi

# 复制项目文件
COPY . /app/

# 收集静态文件
RUN python manage.py collectstatic --noinput

# 暴露端口
EXPOSE 8000

# 启动uWSGI
CMD ["uwsgi", "--ini", "uwsgi.ini"]

2.创建uwsgi.ini文件

此文件在项目根目录下

[uwsgi]
# 项目目录
chdir = /app

# Django的wsgi文件
module = work_system.wsgi:application

# 进程相关设置
master = true
processes = 4
threads = 2

# 监听的套接字文件(将与Nginx通信)
socket = /app/uwsgi.sock
chmod-socket = 666
vacuum = true

# 日志设置
logto = /app/uwsgi.log
log-reopen = true

# 进程pid文件
pidfile = /app/uwsgi.pid

# 退出时清理环境
die-on-term = true

# Python相关设置
gharbage-collect = 1
memory-report = true

3.创建nginx的.conf文件

在项目根目录下创建新的目录nginx/conf.d,在此目录中创建django.conf文件

upstream django {
    server unix:///app/uwsgi.sock; # uWSGI的套接字文件, 与uwsgi.ini中的socket对应
}
# upstream 是Nginx的负载均衡模块,用于定义一组后端服务器
# django 是这个服务器组的名称,可以在后续配置中通过这个名称引用
# 协议类型: unix:// 表示使用Unix域套接字(Unix Domain Socket,UDS)进行通信,而不是TCP/IP套接字
# 套接字路径: /app/uwsgi.sock 是UWSGI服务器监听的套接字文件路径
# 通信方式:Nginx通过这个套接字文件与UWSGI服务器进行通信,转发客户端请求
# 与传统的TCP/IP套接字相比,Unix域套接字:
# - 只能在同一台机器上的进程间通信(适合容器内部通信)
# - 通信效率更高(避免网络协议栈的开销)
# - 安全性更好(基于文件系统权限控制访问)
#  在整个架构中的作用
# - UWSGI服务器启动时会在指定路径创建这个 sock 文件
# - Nginx通过 uwsgi_pass django; 指令将请求转发到这个upstream组
# - include uwsgi_params; 和其他 uwsgi_param 指令确保正确传递请求参数到UWSGI
# - UWSGI再将请求传递给Django应用处理
# 这种配置实现了Nginx作为反向代理,通过高效的Unix套接字与UWSGI服务器通信,为Django应用提供请求转发和负载均衡功能。

server {
    listen 80;  # 监听容器的80端口,是客户端请求的入口
    server_name localhost; # 匹配发往localhost域名的请求,通常用于本地开发

    # 静态文件处理
    location /static/ {
        alias /app/static_collect/;
        expires 30d;
    }
# - location /static/ :匹配所有以 /static/ 开头的URL请求
# - alias /app/static_collect/ :将请求映射到容器内的 /app/static_collect/ 目录(Django收集静态文件的目录)
# - expires 30d :设置静态文件的浏览器缓存时间为30天,减少重复请求,提高性能


    # 媒体文件处理(如果有)
    location /media/ {
        alias /app/media/;
    }

# - location /media/ :匹配所有以 /media/ 开头的URL请求
# - alias /app/media/ :将请求映射到容器内的 /app/media/ 目录(Django上传媒体文件的目录)


    # 将所有非静态请求转发到uWSGI
    location / {
        uwsgi_pass django;    # 通过uwsgi_pass 发送至开头的upstream django组
        include uwsgi_params;

        # uWSGI参数
        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 $scheme;
    }

    # 错误页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

4.创建docker-compose.yml文件

此文件在项目根目录中

services:
  # Django应用服务
  django:
    build: .
    container_name: django_app
    volumes:
      - .:/app
      - static_volume:/app/static_collect
    depends_on:
      - mysql
    environment:
      - MYSQL_HOST=mysql
      - MYSQL_USER=django
      - MYSQL_PASSWORD=django_password
      - MYSQL_DB=django_db
      - DJANGO_SETTINGS_MODULE=work_system.settings
    networks:
      - app_network

  # MySQL数据库服务
  mysql:
    image: mysql:8.0
    container_name: mysql_db
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=django_db
      - MYSQL_USER=django
      - MYSQL_PASSWORD=django_password
    networks:
      - app_network
    ports:
      - "3307:3306"

  # Nginx反向代理服务
  nginx:
    image: nginx:latest
    container_name: nginx_server
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - static_volume:/app/static_collect
      - .:/app
    depends_on:
      - django
    networks:
      - app_network
    ports:
      - "8080:80"

# 定义网络
networks:
  app_network:
    driver: bridge

# 定义数据卷
volumes:
  mysql_data:
  static_volume:

通信机制

  1. 通信基础:django, mysql, nginx三个容器都连接到一个桥接网络app_network(在yml文件中定义的)

  2. Django和MySQL的通信:django通过环境变量指定MySql的连接信息。

    environment:
      - MYSQL_HOST=mysql
      - MYSQL_USER=django
      - MYSQL_PASSWORD=django_password
      - MYSQL_DB=django_db
      - DJANGO_SETTINGS_MODULE=work_system.settings

3.Nginx和Django的通信:通过uWSGI协议,uWSGI服务器在/app/uwsgi.sock创建套接字文件(在uwsgi.ini中配置的),nginx通过uwsgi_pass指令连接到该套接字。

三、资源共享机制

1、静态资源共享

django在容器中创建了容器目录/app/static_collect,然后进行了卷static_volume:与容器目录/app/static_collect的挂载:

static_volume:/app/static_collect

nginx容器中同样创建了同名的容器目录/app/static_collect,然后进行了同样的挂在。

这样:

django通过python manage.py clollectstatic收集静态文件到/app/static_collect/目录中,

也就保存到了卷static_volume中,

也就同时存在于nginx的/app/static_collect目录中。

2、代码挂载

- Django代码通过bind mount挂载到容器: - . :/app (挂载本地目录)

- 实现开发时代码修改的实时生效

3、详细解释:

(1) 共享卷配置

在 docker-compose.yml 中, Django和Nginx容器都挂载了相同的主机目录 到容器内的 /app 路径:

# Django服务配置
django:
  volumes:
    - .:/app  # 主机当前目录映射到容器的/app目录
    ...
# Nginx服务配置
nginx:
  volumes:
    - .:/app  # 同一主机目录映射到Nginx容器的/app目录

(2)uWSGI套接字创建

uWSGI服务器在Django容器内的 /app 目录创建套接字文件:

# uwsgi.ini配置
socket = /app/uwsgi.sock  # 套接字文件位置
chmod-socket = 666        # 设置可读写权限

(3)套接字文件共享机制

- Django容器创建的 /app/uwsgi.sock 文件通过绑定挂载同步到 主机 的当前目录

- Nginx容器通过相同的绑定挂载,从 主机 同步获取到这个 uwsgi.sock 文件

- 最终,Nginx容器内也能看到 /app/uwsgi.sock 文件 4. Nginx使用套接字通信

在Nginx配置中,直接使用这个共享的套接字文件与uWSGI通信:


upstream django {
    server unix:///app/uwsgi.sock;  # 使用共享的套接字文件
}

(4)关键技术点

- 绑定挂载(Bind Mount) :实现主机与多个容器之间的文件实时同步

- 套接字权限 : chmod-socket = 666 确保Nginx可以读写这个套接字文件

- 同一网络 :虽然两个容器在同一Docker网络( app_network )中,但这里主要通过共享卷通信

这种配置方式高效且安全,避免了通过网络TCP连接带来的额外开销,是Docker环境中uWSGI与Nginx通信的常见最佳实践。

4、总结通信流程

1. 客户端请求 → Nginx容器(80端口)

2. 静态请求 → Nginx直接从 /app/static_collect/ 返回

3. 动态请求 → Nginx通过 /app/uwsgi.sock 转发到Django的uWSGI服务器

4. Django处理 → 需要数据库时通过TCP/IP连接到MySQL容器( mysql:3306 )

5. 响应返回 → Django → Nginx → 客户端

这种架构充分利用了Docker的网络和卷特性,实现了三个容器之间的高效、可靠通信。