前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker-compose部署Django项目笔记

Docker-compose部署Django项目笔记

作者头像
Hsinyan
发布2022-06-19 17:56:31
1.1K0
发布2022-06-19 17:56:31
举报
文章被收录于专栏:Hsinyan写字的地方

准备好以下的内容

  1. 项目文件
  2. 使用pip freeze > requirements.txt命令打包好项目的依赖包列表
  3. 安装好Docker和Docker-compose,可以分别用docker -vdocker-vompose -v命令查看是否安装成功。

编写Dockerfile文件

Docker 允许通过文本格式的配置文件来构建镜像,默认名称为 Dockerfile

代码语言:javascript
复制
# 从Docker仓库中拉去带有Python3.7的Linux环境
FROM python:3.7

# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1

# 这两行是在系统钟安装了MySQL的连接器
RUN apt-get update
RUN apt-get install python3-dev default-libmysqlclient-dev -y

# 创建 code 文件夹并将其设置为工作目录
RUN mkdir /code
WORKDIR /code
# 更新 pip
RUN pip install pip -U
# 将 requirements.txt 复制到容器的 code 目录
ADD requirements.txt /code/
# 安装库
RUN pip install -r requirements.txt
# 将当前目录复制到容器的 code 目录
ADD . /code/

理解这些Docker指令的关键,在于牢记容器内的环境和宿主机是隔离的,核心问题是搞清楚那些操作是针对宿主机,哪些操作是针对容器

FROM python:3.7 指令从仓库拉取一个包含 python 3.7 的 Linux 操作系统环境(Linux 版本为 Debian)。

RUNWORKDIR 指令都是针对容器的,功能是在容器里创建目录、并将其设置为工作目录。注意宿主机是没有这个目录的。

ADD 指令出现了两次。ADD requirements.txt /code/ 意思是将宿主机当前目录(即 Dockerfile 所在目录)的 requirements.txt 文件复制到容器的 /code 目录中。ADD . /code/ 意思是把当前目录所有内容复制到容器 /code/ 目录,注意中间那个

编写docker-compose.yml文件

代码语言:javascript
复制
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:
      - "3307:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
      - MYSQL_DATABASE=django_app
    networks:
      - db_network
  nginx:
    restart: always
    image: nginx:latest
    ports:
      - "8001: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:

version 代表 docker-compose.yml 的版本,目前最新版为 3,不需要改动它。

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

下面具体分析一下:

定义了一个名叫 app 的容器。后面的内容都是 app 容器的相关配置:

  • restart :除正常工作外,容器会在任何时候重启,比如遭遇 bug、进程崩溃、docker 重启等情况。
  • build :指定一个包含 Dockerfile 的路径,并通过此 Dockerfile 来构建容器镜像。注意那个 "." ,代表当前目录。
  • command :容器运行时需要执行的命令。这里就是我们很熟悉的运行开发服务器了。
  • volumes卷,这是个很重要的概念。前面说过容器是和宿主机完全隔离的,但是有些时候又需要将其连通;比如我们开发的 Django 项目代码常常会更新,并且更新时还依赖如 Git 之类的程序,在容器里操作就显得不太方便。所以就有,它定义了宿主机和容器之间的映射:"." 表示宿主机的当前目录,":" 为分隔符,"/code" 表示容器中的目录。即宿主机当前目录和容器的 /code 目录是连通的,宿主机当前目录的 Django 代码更新时,容器中的 /code 目录中的代码也相应的更新了。这有点儿像是在容器上打了一个洞,某种程度上也是实用性隔离性的一种妥协。

严格意义上讲,这里用到的 .:/code 并不是,而是叫挂载,它两是有区别的,只不过 docker-compose 允许将挂载写到卷的配置中。

  • expose:暴露容器的8000端口供其他容器访问,宿主机和外界无法访问
  • networks:能够访问web_networkdb_network
  • depends_on ,意思是此容器需要等待 db 容器启动完毕才能够启动。

分析一下 db 容器:

  • image :从仓库拉取 MySQL 5.7 。
  • volumes :这里出现的 static-volume。它的使用方式像这样:static-volume:/code/collected_static ,冒号后面还是容器内的目录,但冒号前的却不是宿主机目录、仅仅是卷的名称而已。从本质上讲,数据卷也是实现了宿主机和容器的目录映射,但是数据卷是由 Docker 进行管理的,你甚至都不需要知道数据卷保存在宿主机的具体位置。

相比挂载,数据卷的优点是由于是 Docker 统一管理的,不存在由于权限不够引发的挂载问题,也不需要在不同服务器指定不同的路径;缺点是它不太适合单配置文件的映射。和挂载一样,数据卷的生命周期脱离了容器,删除容器之后卷还是存在的。下次构建镜像时,指定卷的名称就可以继续使用了。

  • ports :MySQL 默认通信端口为 3306 。由于我的机子上已经跑了一个MySQL服务,所以我将容器内的3306端口映射为本机的3307端口。
  • environment :定义容器的环境变量,设置了 MySQL 的 root 用户的密码、数据库的名称。
  • network:只能够访问db_network

添加db容器后记得的修改Django里的数据库设置。

代码语言:javascript
复制
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_app',
        'USER': 'root',
        'PASSWORD': 'mypassword',
        'HOST': 'db',
        'PORT': '3306',
        'OPTIONS': {'charset': 'utf8mb4'},
    }
}

最后分析一下nginx容器,其他配置与上述两个大致一样,值得说一说的是ports设置,由于我的服务器上部署了其他服务,所以我将nginx端口映射为8001。

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

Nginx配置

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

代码语言:javascript
复制
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文件的最后两行增加mysqlclient库和gunicorn库。

代码语言:javascript
复制
mysqlclient==2.0.1
gunicorn==19.9.0

再修改Django项目的配置文件

代码语言:javascript
复制
ALLOWED_HOSTS = ['*']

...

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

部署

运行命令docker-compose build构造镜像,再使用docker-compose up即可启用服务。

下面附上一下经常用到的命令:

  • 停止容器,docker-compose down
  • 后台运行docker容器:docker-compose up -d
  • 只想启动其中的一个容器:docker-compose up -d db或者docker-compose up -d app即可启动db容器或app容器。
  • 进入容器:docker exec -it container_id /bin/bash
  • 上面的container_id如果不知道如何获取可以通过docker ps命令查看。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 准备好以下的内容
  • 编写Dockerfile文件
  • 编写docker-compose.yml文件
  • Nginx配置
  • 部署
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档