本文主要內容關於使用docker-compose實踐部署後端django-rest-framework和前端vue.js應用。記錄其中遇到的一些坑以及解決辦法。html
系統:Ubuntu 16.04(阿里雲)
代碼中用戶名:test前端
# 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
有些例子使用
volumes_from
,可是version 3已經刪除該設置項更新變化。
官方推薦在根節點(與services
同級)下配置volumes
,可是無法映射到host主機的文件,有個插件local-persist
能夠作到,可是不想依賴第三方插件。只能使用麻煩點的寫法:在每一個service的volume
設置項裏重複映射host主機的文件pythonweb: volumes: - ./backend:/code nginx: volumes: - ./backend/public:/usr/share/nginx//html/backend/public:ro
使用links實現容器間通訊。配置須要訪問的容器於links配置項下,沒什麼毛病。
實現容器按順序啓動,須要用到
depends_on
。mysql可是會有一個問題:
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
文件裏gitDEBUG=false MYSQL_HOST=db MYSQL_DATABASE=mydb MYSQL_ROOT_PASSWORD=mypass
能夠定義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`目錄)。
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 filesserver { 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 appserver { # 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
比較簡單
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