Using docker compose to deploy Django and vue.js applications

Time:2020-3-16

Preface

The main content of this paper is to deploy the back-end Django rest framework and the front-end vue.js application by using the docker compose practice. Record some of the pits encountered and the solutions.

Preparing the docker compose environment

System: Ubuntu 16.04 (alicloud)
User name in Code: Test

Install Docker

# install docker
## prepare
echo 'Preparing...'
sudo apt update
sudo apt upgrade -y
sudo apt install -y linux-image-extra-$(uname -r) linux-image-extra-virtual
## docker
echo 'Installing docker...'
sudo apt remove -y docker-ce docker-engine docker.io
wget -qO- http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh
sudo apt autoremove -y

sudo usermod -aG docker ${USER}

## docker Aliyun accelerator
## https://cr.console.aliyun.com/#/accelerator
echo 'Configuring docker registry mirrors...'
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://<your-own>.mirror.aliyuncs.com"]
}
EOF

exists(){
  command -v "$1" >/dev/null 2>&1
}

echo 'Installing docker-compose...'
if ! exists pip; then
    sudo apt install python-pip
fi
sudo python `which pip` install docker-compose

echo 'Restarting docker...'
sudo systemctl daemon-reload
sudo systemctl restart docker

deploy

directory structure

.
├ -. Env // environment variable
├── docker-compose.yml
├ - backend // place the background Django file
├ - Frontend // place the compiled code of the front-end Vue
└ -- nginx // nginx related configuration
    ├── backend.conf
    ├── Dockerfile
    └── frontend.conf

Specific configuration

docker-compose.yml

version: '3'

services:
  web:
    restart: always
    build: ./backend
    expose:
      - "8000"
    volumes:
      - ./backend:/code
    env_file: .env
    links:
      - db
    depends_on:
      - db
    command: ["/code/wait-for-it.sh", "db:3306", "--", "bash","startup.sh"]
  nginx:
    restart: always
    build: ./nginx
    ports:
      - "80:80"
    volumes:
      - ./frontend:/usr/share/nginx/html/frontend:ro
      - ./backend/public:/usr/share/nginx//html/backend/public:ro
    links:
      - web
    depends_on:
      - web
  db:
    restart: always
    image: mysql:latest
    env_file: .env
    volumes:
      - ./data/initsql:/docker-entrypoint-initdb.d
      - ./data/db:/var/lib/mysql
    command: [mysqld, --character-set-server=utf8, --collation-server=utf8_unicode_ci]

For the first time, using docker compose deployment, many examples are referenced from the Internet. However, because the syntax changes of docker compose versions are not small, many pits are encountered:

Data shared by different containers (data on host host)

Some examples usevolumes_from, but version 3 has deleted the setting item to update the changes.
The official recommendation is at the root node (andservicesConfiguration under the same level)volumes, but there is no way to map to the file of host host. There is a plug-inlocal-persistYou can, but you don’t want to rely on third-party plug-ins. Only trouble points can be used: in each servicevolumeDuplicate mapping of host files in settings

web:
  volumes:
    - ./backend:/code
nginx:
  volumes:
    - ./backend/public:/usr/share/nginx//html/backend/public:ro

Different containers communicate with each other

Use links to achieve communication between containers. Configure the container to be accessed under the links configuration item. There is no problem.

Container start sequence

To start the container in order, you need to use thedepends_on

But there is a problem:depends_onOnly the start order is guaranteed, but our actual requirement is that the commands of the web container can only be executed when MySQL is fully started. Because we addedrestart: always, so it will cause the web container to restart until the DB container starts.

My solution is to add the query available to MySQL service to the start command of web container, and use a query script wait for it:

command: ["/code/wait-for-it.sh", "db:3306", "--", "bash","startup.sh"]

environment variable

There will be multiple containers that use the same environment variables, so they are all placed in the.envIn file

DEBUG=false

MYSQL_HOST=db
MYSQL_DATABASE=mydb
MYSQL_ROOT_PASSWORD=mypass

About MySQL official image configuration

  • You can define volume persistence database files:

    volumes:
-If there is initial data to import, you can define volume mapping to '/ docker entrypoint initdb. D':

volumes:

- ./data/initsql:/docker-entrypoint-initdb.d
Note: this configuration will take effect only when the 'MySQL' directory under '/ var / lib / MySQL /' does not exist. That is to say, once the container has been started once, the files in '/ docker entrypoint initdb. D' will not be imported, unless' / var / lib / MySQL / '(or host's'. / data / db' directory) is cleared manually.

About nginx container configuration

Dockerfile

FROM nginx:alpine

RUN rm /etc/nginx/conf.d/default.conf

ADD frontend.conf /etc/nginx/conf.d/
ADD backend.conf /etc/nginx/conf.d/

frontend.conf – vue app build files

server {
    listen 80 deferred;
    server_name new.bylie.cn;

    root /usr/share/nginx/html/frontend;

    location / {
        try_files $uri $uri/ /index.html =404;
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

backend.confdjango app

server {
    # use 'listen 80 deferred;' for Linux
    # use 'listen 80 accept_filter=httpready;' for FreeBSD
    listen 80 deferred;
    client_max_body_size 5M;

    # set the correct host(s) for your site
    server_name service.bylie.cn;

    keepalive_timeout 5;

    location /public {
        root /usr/share/nginx/html/backend;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # enable this if and only if you use HTTPS
        # proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host $http_host;
        # we don't want nginx trying to do something clever with
        # redirects, we set the Host: header above already.
        proxy_redirect off;
        proxy_pass http://web:8000;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

Backup database to host host

docker-compose exec db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --databases ${MYSQL_DATABASE}' > ./backup/database.sql

About Django web container configuration

Relatively simple

Dockerfile

FROM python:3

ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt

Startup scriptstartup.sh

#!/usr/bin/env bash
python manage.py collectstatic --noinput &&
python manage.py migrate &&
gunicorn django_web_app.wsgi:application -w 2 -b :8000

After the container is running, you may need to import some initial data or fixtures. I wrote an init Django custom command, and executed the command manually:

docker-compose exec web python manage.py init

Recommended Today

2020, I decide to take you to webpack

As the front-end engineering becomes more and more crazy, the front-end that doesn’t order webback really can’t eat or sleep. so-calledwebpackIt’s a static module wrapper for modern JavaScript applications. appetizer Have an appetizer before dinner. What will you learn after reading this article? Learn what a web pack is Know how to package static resources […]