返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Django

Django Application Deployment: Docker Containerization Practice

Before this, I had always deployed applications using uwsgi+virtualenv+nginx, which was rather cumbersome to operate and depended on the Python version on the server. For service management, plain uwsgi + pid wasn't particularly troublesome, but it was never as convenient as docker compose. Unfortunately the original server was a 32-bit system so I couldn't use docker. Now I've added a new server, so I quickly got docker set up~ I have to say it's really too simple and convenient, completely foolproof, and I basically didn't like the previous u

曦远 (DealiAxy)约 18 分钟
目录10 个章节

Before this, I had always deployed applications using uwsgi+virtualenv+nginx, which was rather cumbersome to operate and depended on the Python version on the server. For service management, plain uwsgi + pid wasn't particularly troublesome, but it was never as convenient as docker compose. Unfortunately the original server was a 32-bit system so I couldn't use docker. Now I've added a new server, so I quickly got docker set up~ I have to say it's really too simple and convenient, completely foolproof, and I basically didn't run into the kinds of pitfalls I had with the previous uwsgi deployment. Awesome!

Installation

It's best to install docker and compose on your development machine for local testing. For installation methods, just refer to the official site; this article won't go into details.

Reference: https://docs.docker.com/

Writing the Dockerfile

First, you need to write a Dockerfile for the Django application to build the service image.

My Dockerfile is as follows, with comments on every line for your reference:

FROM python:3.7

# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1

# 创建 code 文件夹并将其设置为工作目录
RUN mkdir /code
WORKDIR /code

# 更新 pip
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U
# 设置清华源
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

# 将 requirements.txt 复制到容器的 code 目录
ADD requirements.txt /code/

# 安装库
RUN pip install -r requirements.txt

# 将当前目录复制到容器的 code 目录
ADD . /code/

After writing it, you can directly run docker run to build the image, then enter the container's command line and execute python manage.py runserver 0.0.0.0 8000 to test whether the server starts normally (of course you won't be able to access it before exposing the port)

Orchestrating Services with Compose

Docker Compose is a Docker tool for defining and running complex applications. An application that uses Docker containers typically consists of multiple containers. With Docker Compose, you no longer need to use shell scripts to start containers. Compose manages multiple Docker containers through a configuration file. In the configuration file, all containers are defined via services, then you use the docker-compose script to start, stop, and restart the application, as well as the services in the application and all dependent service containers. It is very suitable for development scenarios that combine multiple containers.

Official docs: https://docs.docker.com/compose/overview/

Note that the compose version needs to correctly correspond to the docker version to run properly. Docker updates quickly, so it's best to install from the latest version on the official site~

Below is my docker-compose.yml file; I'll introduce the configuration items afterward

version: "3"
services:

  mongo:
    image: mongo
    expose:
      - 27017
    restart: on-failure # 退出代码指示出现故障错误时重启

  postgres:
    image: postgres
    expose:
      - 5432
    restart: on-failure
    environment:
      - POSTGRES_PASSWORD=password

  web:
    restart: always # 除正常工作外,容器会在任何时候重启,比如遭遇 bug、进程崩溃、docker 重启等情况。
    build: .
    environment:
      - ENVIRONMENT=docker
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "9000:8000"
    depends_on:
      - postgres
      - mongo

As you can see, this project uses PostgreSQL and MongoDB. I use compose to integrate them together and expose ports for web (that is, the Django application) to use.

After writing the docker-compose.yml file, run docker-compose up and it will automatically build each image and run the services—very convenient.

If you need to run in the background, use: docker-compose up -d

To rebuild images, use: docker-compose up --build

To delete, use: docker-compose down

Start and stop: docker-compose start, docker-compose stop

Compose Configuration

The official site has very detailed configuration documentation. In this article I'll only introduce a few configuration items I commonly use.

build

build can specify the path containing the build context, for example in the docker-compose.yml above:

web:
  build: .

volumes Configuration

Note that under the web node there is a volumes configuration.

As you can see from the Dockerfile earlier, the Django application code is statically copied into the container at build time, i.e., via the ADD . /code/ command in the Dockerfile, which copies the source code from the physical host into the container, so subsequent code changes in the src directory on the physical host will not be reflected in the container. You can use the volumes keyword to mount a physical host directory into the container (at this point you can delete the ADD . /code/ command in the Dockerfile; there's no need to pack the code into the image when creating it, but instead dynamically mount via volumes, so the container and the physical host share a data volume, which still enables hot-reloading of the program)

These two are actually pretty similar, but the official docs say the former is no longer recommended, so just use depends_on. Its purpose is to link containers across multiple services. For example in this article, my Django application needs to use a postgresql database and MongoDB, so I link them together and expose ports (but note that in docker, each image is a separate host, so these three services are equivalent to three different VMs and cannot be accessed via localhost:port). Thus in the Django service you need to use a form like postgres:5432.

Here postgres is the service name we wrote in depends_on. Of course you can set an alias, for example postgres:db, then you'd access it via db:5432~

The principle of accessing the server via this name is equivalent to local DNS, or rather the hosts file~

Database Migration

After the Django application is deployed on the server, there's still the issue of database migration. It's actually easy to solve—either go directly into the docker environment to run commands, or use docker-compose run to execute them, as follows:

docker-compose run web python3 manage.py makemigrations
docker-compose run web python3 manage.py migrate

Other commands you need to run work the same way~

command

This command is the command to execute after a service's image has been built and started. Generally you can only execute one, though you can also execute multiple (not recommended)

I glanced at Stack Overflow; there are roughly two methods:

The first:

web:
  command: python a.py && python b.py

The second, using a pipe:

web:
  command:
    - /bin/sh
    - -c
    - |
      python a.py
      python b.py

That's about all I'll cover, because it's really just that simple. For more operations, refer to the official docs~

References

_EOF_

Django Application Deployment: Docker Containerization Practice

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…