不正宗 docker 入門教程-使用 docker-compose (3/3)

本章經過一個具體的demo來了解 docker-compose

docker-compose 是作什麼的

在構建一個完整的服務時,咱們一般啓動一個容器, 一旦出現多個容器須要同時啓動的時候手打是下下之策, 由於時間一長不免會忘記細節,寫腳本也不是不能夠,可是你們沒有達成共識時腳本也很難維護...php

docker-compose 就是來解決這個痛點, 只須要按照統一的格式書寫,那麼你們生成的容器也都是一致的, 在團隊開發的時候扔一個配置好的 docker-compose 能節省不少時間和口水html

配置 docker-compose

這是我構建的一個開發環境的容器:dnmpmysql

首先下載下來nginx

git clone https://github.com/gaopengfei123123/dnmp.git && cd dnmp

咱們第一件事就是先瞄一眼 .env 文件, 這裏設置了不少常量,一會根據我的需求來調整git

第二步纔是打開 docker-compose.yml 文件, 看後綴都能猜到這是一個配置文件, 另外 docker-compose.yml 是根據縮進來進行分層的,注意書寫格式github

# docker-compose.yml
# 語法版本( 3 和 2 區別有點大, 好比 3 取消了 volume_from 的相關語法)
version: "3"

networks:
  frontend:
    driver: ${NETWORKS_DRIVER}
  backend:
    driver: ${NETWORKS_DRIVER}


volumes:
  mysql_volume:
    driver: ${VOLUMES_DRIVER}
  redis_volume:
    driver: ${VOLUMES_DRIVER}
  rabbitmq_volume:
    driver: ${VOLUMES_DRIVER}
# 服務編排
services:
  # workspace:
  #   image: tianon/true
  #   container_name: dnmp-www
  #   volumes:
  #     - ./www:/usr/share/nginx/html

# NGINX #############################################
  nginx:
    container_name: dnmp-nginx
    build: 
      context: ./nginx
      args:
          - PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER}
          - PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT}
    depends_on:
      - php-fpm
    ports:
      - "${NGINX_HOST_HTTP_PORT}:80"
      - "${NGINX_HOST_HTTPS_PORT}:443"
    volumes:
      # 不必把配置文件用捲來掛載, 否則就算配置更新了 nginx 也是要重啓的

      # 掛載運行代碼目錄
      - ${APP_CODE_PATH_HOST}:/var/www
      # 掛載日誌目錄
      - ${NGINX_HOST_LOG_PATH}:/var/log/nginx
    # 使用 networks 取代 links 在同一個網絡模式下的服務是互通的
    # 在service 中使用其餘的 service 就直接調用 service 名就行, 不用管 ip 地址, docker 會本身維護一套
    networks:
      - frontend
      - backend


# PHP-FPM #############################################
  php-fpm:
    container_name: dnmp-php-fpm
    # 這裏的args 是屬於 build 下面的,用於構建./php-fpm/Dockerfile 文件中 ARG 參數指定 php 版本
    build: 
      context: ./php-fpm
      args:
        - PHP_VERSION=${PHP_VERSION}
    volumes:
      - ${APP_CODE_PATH_HOST}:/var/www
      - ./php-fpm/php${PHP_VERSION}.ini:/usr/local/etc/php/php.ini
    expose:
      - "9000"
    networks:
      - backend
    
  redis:
    container_name: dnmp-redis
    build:
      context: ./redis
      args:
        - REDIS_SET_PASSWORD=${REDIS_SET_PASSWORD}
    ports:
      - ${REDIS_HOST_PORT}:6379
    volumes:
      # 這裏卷掛載的是本地文件
      # - ${DATA_PATH_HOST}/redis:/data
      # 這裏建立一個 redis_volume來存放數據
      - redis_volume:/data

# Mysql #############################################
  mysql:
    container_name: dnmp-mysql
    # 鏡像來源: https://github.com/docker-library/mysql/blob/fc3e856313423dc2d6a8d74cfd6b678582090fc7/5.7/Dockerfile
    image: mysql:${MYSQL_VERSION}
    volumes:
      # - ${DATA_PATH_HOST}/mysql:/var/lib/mysql
      - mysql_volume:/var/lib/mysql
    # 容器只要中止就會重啓
    restart: always
    environment: 
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    ports:
      - ${MYSQL_HOST_PORT}:3306

接下來看看它的關鍵詞都起着什麼做用:redis

version

這個規定了文件的版本, 既然有 3 就確定不用 2 啊, 雖然二者沒衝突,可是我喜歡, 2 和 3 版本之間有輕微的變更,具體區別你能夠在寫配置文件時產生的報錯信息來體驗一下sql

network
networks:
  frontend:
    driver: ${NETWORKS_DRIVER}
  backend:
    driver: ${NETWORKS_DRIVER}

${NETWORKS_DRIVER} 是從 .env 文件中取的值, 下面的同理docker

這一塊就至關於執行 docker network create -d bridge frontend && docker network create -d bridge backend
在本地持久化的創建一個網絡配置,稍後方便容器進行鏈接, 固然這裏也不止是一個 driver 參數,具體配置狀況仍是參考docker network inspect dnmp_frontend 來看一下segmentfault

沒有設置名字的配置當須要名字的時候會 {當前docker-compose.yml文件名}_{key} 這種格式

有了 network 配置就極大的簡化了老版的 --links 命令, 只要屬於同一個 network 就能互相訪問到, 而不是每新增一個服務就要把原來的服務都 link 一遍

volume
volumes:
  mysql_volume:
    driver: ${VOLUMES_DRIVER}
  redis_volume:
    driver: ${VOLUMES_DRIVER}
  rabbitmq_volume:
    driver: ${VOLUMES_DRIVER}

network 部分同樣, 持久化的建立幾個 volume, 至關於命令 docker network create mysql_volume等等

這算是 v3 的一個新特性, 在 v2 的時候, 爲了共享數據你們會建立一個什麼鏡像都不繼承的image, 全部容器的 volume 都會和它鏈接, 如今有了 volume 就不必這麼搞了

service

這個是本章的重點, 咱們來看下面的例子中的註釋, 按序號來

services:

  #1 建立一個服務叫作nginx服務
  nginx:
    #2 爲了顯得個性化一點,咱們指定這個容器的名字叫作 dnmp-nginx
    container_name: dnmp-nginx
    #3 標明這個服務的 Dockerfile 的地址,用相對路徑方便項目遷移
    build: 
      #3.1 至關於命令: 
      # docker build ./nginx -t dnmp-nginx \
      #     --build-arg PHP_UPSTREAM_CONTAINER=xxx \
      #     --build-arg PHP_UPSTREAM_PORT=zzz
      context: ./nginx
      #3.2 這裏 ${NGINX_PHP_UPSTREAM_PORT} 的值是從 .env 文件中取的, args 屬於構建時傳入的參數
      args:
          - PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER}
          - PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT}
    #4  在啓動這個容器以前先啓動 php-fpm 這個容器 
    depends_on:
      - php-fpm
    #5 將本地端口和容器端口綁定, 本地哪一個端口就看 .env 裏怎麼寫的
    ports:
      - "${NGINX_HOST_HTTP_PORT}:80"
      - "${NGINX_HOST_HTTPS_PORT}:443"
    
    #6 設置須要掛載的卷, 這裏時將本地目錄和容器綁定, 也能夠像 services.redis 那樣和建立好的卷綁定 
    volumes:
      # 不必把配置文件用捲來掛載, 否則就算配置更新了 nginx 也是要重啓的

      # 掛載運行代碼目錄
      - ${APP_CODE_PATH_HOST}:/var/www
      # 掛載日誌目錄
      - ${NGINX_HOST_LOG_PATH}:/var/log/nginx
    # 使用 networks 取代 links 在同一個網絡模式下的服務是互通的
    # 在service 中使用其餘的 service 就直接調用 service 名就行, 不用管 ip 地址, docker 會本身維護一套
    
    #7 設置容器從屬的網絡, 同一個網絡下可互相訪問
    networks:
      - frontend
      - backend

在上文的 #3 步驟看其餘的service也有直接使用image的, 這是直接從遠程獲取鏡像的方式

配置文件寫完了, 咱們看下nginx的構建文件

# in file ./nginx/Dockerfile

#1 選擇繼承的鏡像
FROM nginx:1.13.1-alpine
#2 各類標籤
LABEL maintainer="GPF <5173180@qq.com>"

#3 容器中執行命令, 且把本地的配置文件添加進去
#https://yeasy.gitbooks.io/docker_practice/content/image/build.html
RUN mkdir -p /etc/nginx/cert \
    && mkdir -p /etc/nginx/conf.d \
    && mkdir -p /etc/nginx/sites

COPY ./nginx.conf /etc/ngixn/nginx.conf
COPY ./conf.d/ /etc/nginx/conf.d/
COPY ./cert/ /etc/nginx/cert/

COPY ./sites /etc/nginx/sites/


#4 這裏也是設置構建參數, 不過相同 key 值會被 docker-compose 中的給覆蓋掉
ARG PHP_UPSTREAM_CONTAINER=php-fpm
ARG PHP_UPSTREAM_PORT=9000
#5 ${PHP_UPSTREAM_CONTAINER} 就在構建時的參數使用方式
RUN echo "upstream php-upstream { server ${PHP_UPSTREAM_CONTAINER}:${PHP_UPSTREAM_PORT}; }" > /etc/nginx/conf.d/upstream.conf

#6 設置掛載的目錄, 該目錄下文件變化不會影響到容器
VOLUME ["/var/log/nginx", "/var/www"]

#7 設置目錄運行時所處在容器中的目錄地址
WORKDIR /usr/share/nginx/html

#5 就是顯示了在 nginx 容器中怎麼去訪問 php-fpm 這個容器, 直接調用 service 名稱就行

這裏須要注意的時 ARGENV 的區別, 參考這篇文章: Docker中 Arg 和 Env 的區別

啓動docker-compse

在配置好 .env 文件和 docker-compose.yml 配置文件後就能夠啓動它了, 命令也很簡單,在同級目錄下運行:

docker-compose up -d

它會自動建立volumenetworkservices, 並且相關的運行參數都是按着配置文件來的, 這樣一來每一個完整docker-compose.yml中的service就至關於時一個總體,每一個服務又屬於各自的容器,這樣操控是否是節省了不少代碼呢?

查看這些容器的運行情況也非常簡單

docker-compose ps
# 或者使用更方便的一個工具: ctop , github地址: https://github.com/bcicen/ctop

可操控單一容器同樣, 可是它會把這一組容器都囊括了進去,操控起來只須要知道操控哪一個服務,而一些參數就寫在配置文件當中已經默認添加了

一些經常使用的命令:

# 終止整個服務集合
docker-compose stop

# 終止指定的服務 (這有個點就是啓動的時候會先啓動 depond_on 中的容器,關閉的時候不會影響到 depond_on 中的)
docker-compose stop nginx

# 查看容器的輸出日誌
docker-compose logs -f [services...]

# 構建鏡像時不使用緩存(能避免不少由於緩存形成的問題)
docker-compose build --no-cache --force-rm

# 移除指定的容器
docker-compose rm nginx
原本熟悉命令的最好方式就是 用->犯錯->排錯->用 這種循環, 有什麼不懂的 谷歌bing 都能查到, 直接 docker-compose --help 也能猜出命令的大概做用, 這裏就不細說了

還有個很不錯的 docker-compose 項目就是 laradock, dnmp 就是仿照着它寫的, 不過網絡很差的狀況下別運行 laradock, 它如今作的太臃腫了。。。。 看看它裏面的鏡像是怎麼寫的仍是頗有收穫的

相關

  1. 不正宗 Docker 入門教程-啓動一個容器(1/3)
  2. 不正宗 Docker 入門教程-構建一個鏡像(2/3)
  3. 不正宗 Docker 入門教程-使用 Docker-Compose (3/3)

博客原文

相關文章
相關標籤/搜索