本章經過一個具體的demo來了解 docker-compose
在構建一個完整的服務時,咱們一般啓動一個容器, 一旦出現多個容器須要同時啓動的時候手打是下下之策, 由於時間一長不免會忘記細節,寫腳本也不是不能夠,可是你們沒有達成共識時腳本也很難維護...php
docker-compose
就是來解決這個痛點, 只須要按照統一的格式書寫,那麼你們生成的容器也都是一致的, 在團隊開發的時候扔一個配置好的 docker-compose
能節省不少時間和口水html
這是我構建的一個開發環境的容器: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
這個規定了文件的版本, 既然有 3 就確定不用 2 啊, 雖然二者沒衝突,可是我喜歡, 2 和 3 版本之間有輕微的變更,具體區別你能夠在寫配置文件時產生的報錯信息來體驗一下sql
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 一遍
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
就不必這麼搞了
這個是本章的重點, 咱們來看下面的例子中的註釋, 按序號來
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 名稱就行
這裏須要注意的時 ARG
和 ENV
的區別, 參考這篇文章: Docker中 Arg 和 Env 的區別
在配置好 .env
文件和 docker-compose.yml
配置文件後就能夠啓動它了, 命令也很簡單,在同級目錄下運行:
docker-compose up -d
它會自動建立volume
,network
,services
, 並且相關的運行參數都是按着配置文件來的, 這樣一來每一個完整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, 它如今作的太臃腫了。。。。 看看它裏面的鏡像是怎麼寫的仍是頗有收穫的