欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn云端部署

程序员文章站 2024-03-12 09:17:26
...

上一章我们实现了在 Docker 中添加了 MySQL 数据库,但采用的开发服务器虽然使用便捷,但性能差、可靠性低,无法应用在生产环境中。

因此本章将实现 Docker + Django + MySQL + Nginx + Gunicorn 容器项目,完成最终的服务器部署。

直接进入本章的 Docker 入门读者,建议回到教程第一章开始阅读,否则某些内容不好理解。对 Django 项目部署都没有概念的读者,还可以先阅读我的博文:将 Django 项目部署到服务器

Docker-compose

在部署到服务器之前,先来尝试本地部署。

在上一章的基础上,继续修改 docker-compose.yml 配置:

version: "3"

services:
  app:
    restart: always
    build: .
    command: bash -c "python3 manage.py collectstatic --no-input && python3 manage.py migrate && gunicorn --timeout=30 --workers=4 --bind :8000 django_app.wsgi:application"
    volumes:
      - .:/code
      - static-volume:/code/collected_static
    expose:
      - "8000"
    depends_on:
      - db
    networks:
      - web_network
      - db_network
  db:
    image: mysql:5.7
    volumes:
      - "./mysql:/var/lib/mysql"
    ports:
      - "3306:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
      - MYSQL_DATABASE=django_app
    networks:
      - db_network
  nginx:
    restart: always
    image: nginx:latest
    ports:
      - "8000:8000"
    volumes:
      - static-volume:/code/collected_static
      - ./config/nginx:/etc/nginx/conf.d
    depends_on:
      - app
    networks:
      - web_network
      
networks:
  web_network:
    driver: bridge
  db_network:
    driver: bridge
    
volumes:
  static-volume:

有点复杂。来看看大体思路:

  • 定义了 3 个容器,分别是 appdbnginx 。容器之间通过定义的端口进行通讯。
  • 定义了 2 个网络,分别是 web_networkdb_network 。只有处在相同网络的容器才能互相通讯。不同网络之间是隔离的,即便采用同样的端口,也无法通讯。
  • 定义了 1 个数据卷static-volume 。数据卷非常适合多个容器共享使用同一数据,你可以看到 appnginx 都用到了它。
  • exposeports 都可以暴露容器的端口,区别是 expose 仅暴露给其他容器,而 ports 会暴露给其他容器和宿主机。

这么讲可能还是很难理解,让我们继续分解。

网络 network

Docker 允许用户给每个容器定义其工作的网络,只有在相同的网络之中才能进行通讯。你可以看到 nginx 容器处于 web_network 网络,而 db 容器处于 db_network 网络,因此它两是无法通讯的,实际上确实也不需要通讯。而 app 容器同时处于 web_networkdb_network 网络,相当于是桥梁,连通了3个容器。

定义网络可以隔离容器的网络环境,也方便运维人员一眼看出网络的逻辑关系。

数据卷

之前我们见识过的用于映射宿主机和容器目录的卷了,实际上称为挂载;现在新出现的 static-volume 才叫。它的使用方式像这样:static-volume:/code/collected_static ,冒号后面还是容器内的目录,但冒号前的却不是宿主机目录、仅仅是卷的名称而已。从本质上讲,数据卷也是实现了宿主机和容器的目录映射,但是数据卷是由 Docker 进行管理的,你甚至都不需要知道数据卷保存在宿主机的具体位置。

相比挂载,数据卷的优点是由于是 Docker 统一管理的,不存在由于权限不够引发的挂载问题,也不需要在不同服务器指定不同的路径;缺点是它不太适合单配置文件的映射。

和挂载一样,数据卷的生命周期脱离了容器,删除容器之后卷还是存在的。下次构建镜像时,指定卷的名称就可以继续使用了。

既然 Docker 能够管理卷,所以要想删除卷也是非常容易的。指令嘛,我不告诉你,生产环境千万不要手贱。定期备份数据是个好习惯。

数据卷有个很重要的特性:启动时如果卷是空的,则会将容器映射目录的所有内容复制到卷里去。换句话说就是,只要卷初始化完成后,容器原始的 collected_static 目录就不会再使用了,新增的文件也只存在于卷中,容器中是没有的。

实际上 static 静态文件(以及 media 媒体文件)的持久存储,通过挂载或者数据卷都可以实现;具体用哪种,这个就见仁见智了,你自己选择。

篇幅有限,教程没有讲到 media 媒体文件,但它的设置和 static 是完全相同的。

其他配置

首先修改 Nginx 的配置文件,即映射到 nginx 容器的 config/nginx/django_app.conf

upstream app {
  ip_hash;
  server app:8000;
}

server {
  listen 8000;
  server_name localhost;
  
  location /static/ {
    autoindex on;
    alias /code/collected_static/;
  }
  
  location / {
    proxy_pass http://app/;
  }
}

此配置下 Nginx 会监听容器的 8000 端口,并将受到的请求发送到 app 容器(静态文件请求除外)。

requirements.txt 文件中增加 gunicorn 库:

django==2.2
mysqlclient==1.3.14
gunicorn==19.9.0

最后修改 django_app/settings.py和静态文件存放目录的配置:

...

ALLOWED_HOSTS = ['*']

...

STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
STATIC_URL = '/static/'

所有配置就完成了。

教程使用空的 Django 项目,为演示效果,就没有修改 DEBUG=False 了。若你用的自己的项目测试,记得把它为 False。

测试

测试指令就一条:

$ docker-compose up

浏览器访问 127.0.0.1:8000 又看到熟悉的 Django 小火箭了。

和上一章类似,第一次启动容器时可能会出现无法连接 MySQL 的错误,这是由于虽然 db 容器已经启动,但初始化并未完成;重新启动容器之后就可以正常工作了。若多次启动都无法正常工作,那就是别的原因了,好好检查吧。

本地部署成功,下一步服务器部署。

服务器部署

有了本地部署的经验,服务器部署就非常非常简单了。

还是类似的,部署前将 Docker 、 Docker-compose 、 Python3 等工具在服务器上安装好;将项目用 Git 克隆到服务器本地。

接下来把 settings.pyconfig/nginx/django_app.confrequirements.txt 相关位置都按教程流程改好;将 docker-compose.ymlDockerfile 复制到服务器。

由于 http 请求默认为 80 端口,所以为了接收公网请求,还需要做一点点修改 docker-compose.yml 的工作:

version: "3"

services:
  app:
    ...
    command: bash -c "... your_project_name.wsgi:application"  # 改为你的项目名称
    ...
  db:
    ...
  nginx:
    ...
    ports:
      - "80:8000"  # 监听 80 端口
    ...
      
networks:
  ...
    
volumes:
  ...

修改 Gunicorn 绑定的项目名称,以及让宿主机监听公网 http 默认的 80 端口。

此外还要修改 config/nginx/django_app.conf

upstream your_domain_name {
  ip_hash;
  server app:8000;
}

server {
  ...
  
  location / {
    proxy_pass http://your_domain_name/;
  }
}

这个改动主要是为了照顾各种第三方登录的回调地址(不改这里, GitHub、Weibo 三方登录都会失败)。如果你没有类似的需求,不改也是可以的。比如博主的个人网站www.dusaiphoto.com,所以这里的 your_domain_name 就修改为 www.dusaiphoto.com

最后,记得将 settings.py 中的 DEBUG 配置修改好:

# DEBUG=True 注释掉
DEBUG=False

这样就可以了!构建镜像并启动容器:

 docker-compose up

在浏览器中就可以正常访问你的网站了。

总结

现在你已经可以部署一个线上的容器化 Django 项目了,恭喜!

若本教程对你有帮助,请到GitHub给个 Star 哟,也欢迎阅读我的Django 搭建博客教程

老朋友们,下个教程见!