使用Docker Compose部署Django和Vue.js應用

前言

本文主要內容關於使用docker-compose實踐部署後端django-rest-framework和前端vue.js應用。記錄其中遇到的一些坑以及解決辦法。html

準備Docker-compose環境

系統:Ubuntu 16.04(阿里雲)
代碼中用戶名:test前端

安裝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

部署

目錄結構

.
├── .env // 環境變量
├── docker-compose.yml
├── backend // 放置後臺django文件
├── frontend // 放置前端vue編譯後代碼
└── nginx // nginx相關配置
    ├── backend.conf
    ├── Dockerfile
    └── frontend.conf

具體配置

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]

第一次使用docker-compose部署,從網上參考了許多例子。可是因爲docker-compose個版本的語法改動不小,遇到不少坑:vue

不一樣容器共享數據(host主機上的數據)

有些例子使用volumes_from,可是version 3已經刪除該設置項更新變化
官方推薦在根節點(與services同級)下配置volumes,可是無法映射到host主機的文件,有個插件local-persist能夠作到,可是不想依賴第三方插件。只能使用麻煩點的寫法:在每一個service的volume設置項裏重複映射host主機的文件python

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

不一樣容器互相通訊

使用links實現容器間通訊。配置須要訪問的容器於links配置項下,沒什麼毛病。

容器啓動順序

實現容器按順序啓動,須要用到depends_onmysql

可是會有一個問題:depends_on只保證啓動順序,而咱們的實際需求是:web容器啓動的commands必須等到mysql徹底啓動,web容器的command才能夠執行。由於咱們加了restart: always,因此會致使web容器不斷重啓直到db容器啓動完成。linux

個人解決辦法是:給web容器的啓動命令加上對mysql服務可用的查詢,使用了一個查詢腳本wait-for-it:nginx

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

環境變量

會有多個容器使用相同環境變量的狀況,因此都放在.env文件裏git

DEBUG=false

MYSQL_HOST=db
MYSQL_DATABASE=mydb
MYSQL_ROOT_PASSWORD=mypass

關於Mysql官方鏡像配置

  • 能夠定義volume持久化數據庫文件:github

    volumes:
- 若是有初始數據須要導入,能夠定義volume映射到`/docker-entrypoint-initdb.d`:

volumes:web

- ./data/initsql:/docker-entrypoint-initdb.d
注意: 該配置只有在`/var/lib/mysql/`下的`mysql`目錄不存在時纔會生效。也就是說,一旦容器啓動過一次,以後就在也不會導入`/docker-entrypoint-initdb.d`裏的文件,除非手動清空`/var/lib/mysql/`(或host主機的`./data/db`目錄)。

關於Nginx容器配置

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.conf - django 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;
    }
}

備份數據庫到host主機

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

關於django web容器配置

比較簡單

Dockerfile

FROM python:3

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

啓動腳本startup.sh

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

當容器運行起來以後,可能須要導入一些初始數據或者fixtures,我寫了一個init的django custom command,手動執行該command:

docker-compose exec web python manage.py init
相關文章
相關標籤/搜索