前言

部署和开发是两个完全不同的工作。得益于 docker 等虚拟化技术,现在的部署已经简单许多了。尽管作者是用原生 linux 环境做示范,但是我选用 docker 作为部署工具。主要以查找博客和问 chatgpt 来学习,中间由于对 nginx 不了解,还看了相关的视频教程。大概花了三四天时间,从本地 win 环境,到最终的云主机。现在,我终于可以说,自己是一个全栈工程师了,真正从应用的开发到落地都有了粗浅的涉及。

总体流程图

这是两容器之间的配合示意图。外部的请求从宿主机的 8000 端口进来,然后被 docker 投射到容器 1,交给 nginx 处理。nginx 根据请求的 url,判断是动态还是静态请求。如果是静态,则去找 vue 项目打包来的文件夹 dist 内的资源并返回;如果是动态资源,通过 http 方式转发给容器 2 的端口 8000。uwsgi 处理完逻辑后,将可能有的响应转回给 nginx,再返回给用户。

项目结构

wey
 ├── docker-compose.yml
 ├── wey-frontend
 │   ├── dist
 │   ├── Dockerfile
 │   ├── index.html
 │   ├── nginx.conf
 │   ├── node_modules
 │   ├── package-lock.json
 │   ├── package.json
 │   ├── postcss.config.js
 │   ├── public
 │   ├── README.md
 │   ├── src
 │   ├── tailwind.config.js
 │   └── vite.config.js
 └── wey_backend
     ├── account
     ├── chat
     ├── db.sqlite3
     ├── Dockerfile
     ├── manage.py
     ├── media
     ├── notification
     ├── pip.conf ## 给容器2的pip换源
     ├── post
     ├── requirements.txt
     ├── scripts
     ├── search
     ├── uwsgi.ini
     └── wey_backend

容器 1 配置

# nginx.conf

server {
    listen 80;
    server_name 127.0.0.1;

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://django:8000;
    }

    location /static {
        alias '/var/www/mysite/assets/static';
    }

    location /media {
        alias '/var/www/mysite/assets/media';
    }

    location /admin/ {
        proxy_pass http://django:8000;
    }

}

对应的 dockerfile:

# 使用一个基础的 Node.js 镜像作为构建环境
FROM node:14 as builder

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json 文件到容器中
COPY package*.json ./

# 安装依赖
RUN npm install

# 复制前端应用源代码到容器中
COPY . .

# 执行构建命令
RUN npm run build

# 创建一个新的容器镜像
FROM nginx:latest

# 复制构建产物到 Nginx 的默认静态文件目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 将自定义的 nginx.conf 文件复制到容器中,覆盖默认配置
# remove the default conf
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露容器的 80 端口
EXPOSE 80

容器 2 配置

[uwsgi]

module = wey_backend.wsgi
py-autoreload=1
http-timeout = 86400

http=0.0.0.0:8000

master=true
processes = 4
threads=2

chmod-socket=666

vaccum=true
die-on-term=true

对应的 dockerfile 配置:

FROM python:3.11
RUN mkdir /code
WORKDIR /code
COPY . /code

COPY pip.conf /root/.pip/pip.conf

# uwsgi setup
RUN pip install uwsgi
RUN pip install -r requirements.txt

EXPOSE 8000

CMD ["uwsgi", "--ini", "uwsgi.ini"]

docker-compose

docker compose 是在有多个容器且容器之间存在依赖关系时适用。它取代的是命令行构建镜像和创建容器的方式,使得部署更简洁。比如在 nginx 中,ports:”8000:80”,是在建立端口映射。volumes:是在把特定的目录在整个 docker 应用进程内建立一个索引,实现文件共享。

version: "3.9"
services:
  nginx:
    build: ./wey-frontend/
    restart: always
    ports:
      - "8000:80"
    volumes:
      - web_static:/var/www/mysite/assets/static
      - web_media:/var/www/mysite/assets/media
    depends_on:
      - django


  django:
    build: ./wey_backend/
    restart: always
    expose:
      - 8000
    command: >
      sh -c "python manage.py collectstatic --noinput
      && uwsgi --ini uwsgi.ini"
    volumes:
      - web_static:/var/www/mysite/assets/static
      - web_media:/var/www/mysite/assets/media

volumes:
  web_static:
  web_media:

总结

这篇文章实现了用 docker 来部署 django+vue 的前后端分离网站,并用 docker-compose 来简化了部署。

为什么中间遭遇了较大的挫折并且一度想放弃呢?反思的结果是,自己一开始就把多个容器放在一起考虑,导致头绪纷乱无章。后面在尝试了测试两个容器是否能独立运行,然后联合运行,才成功。