在第二篇文章中,我們學會了使用 dockerfile 構建 docker 映象,看起來已經能夠滿足我們的日常需求了。無論需要什麼環境,在 dockerfile 裡逐步構建,然後 build、run,就 ok 了,也滿足了我們docker 隔離性、快速部署的要求,那為什麼還會有這一節?
來看一個網站開發最常見的場景:我們要有資料庫,網站應用,nginx,互相配合才是完整的環境。是的,我們完全可以以 ubuntu 為基礎映象,把這些一股腦全裝進去,然後執行。但是這樣有很多缺點,比如我們每次都要重新裝 mysql 而不是直接利用 mysql 官方的基礎映象,升級維護不方便;如果我們的應用要擴充套件也很難,因為每個應用都連線的自己內部的資料庫,無法共享資料;事實上,這種方式是典型的虛擬機器的使用方式,不是 docker 的正確開啟方式。
docker 是輕量化的應用程式,docker 官方推薦每個 docker 容器中只執行一個程式(下篇文章你將明白這是為什麼),那麼就是說,我們需要分別為我們的應用、資料庫、nginx 建立單獨的 docker 容器,然後分別啟動它。想象一下,構建好 docker 之後,每次啟動我們的網站,都要至少 docker run 三次,是不是很繁瑣?而且此時這幾個 docker 是分散獨立的,很不方便管理。既然這幾個 docker 都是為了同一個網站服務,是不是應該把它們放到一起?這就引出了 docker-compose 專案。
docker-compose是 docker 官方的開源專案,使用 python 編寫,實現上呼叫了 Docker 服務的 API 進行容器管理。其官方定義為為 「定義和執行多個 Docker 容器的應用(Defining and running multi-container Docker applications)),其實就是上面所講的功能。
一:安裝
預設情況下,windows 和 mac 下的 docker 已經自帶了 docker-compose 工具,可以使用 docker-compose -v
命令檢視。
對於 linux 系統,需要自己手動安裝,可以直接下載二進位制檔案安裝,參考官方文件,更酷的是,可以直接使用 pip 安裝,甚至可以使用 docker-compose 容器(比較複雜,不推薦~)。
二:簡介
類似 docker 的Dockerfile檔案,docker-compose使用 YAML 檔案對容器進行管理。
對於 docker-compose 有兩個基本的概念:
服務(service):一個應用容器,即 docker 容器,比如之前所說的mysql 容器、nginx 容器
專案(project):由一組關聯的應用容器組成的一個完整業務單元,比如上面所講的由 mysql、web app、nginx 容器組成的網站。docker-compose 面向專案進行管理。
再簡單說下 YAML 檔案格式。
- 大小寫敏感,縮排表示表示層級關係
- 縮排空格數不重要,相同層級左側對齊即可。(不允許使用 tab 縮排!)
- 由冒號分隔的鍵值對錶示物件;一組連詞線開頭的行,構成一個陣列;字串預設不使用引號
這些基本夠我們使用了,詳細的格式說明可參考這篇YAML 語言教程-阮一峰。
三:構建
接下來我們使用 docker-compose 構建一個php 網站專案,並逐步講解其使用。
我們需要一個網站專案,這裡以 summerblue 的larabbs論壇系統為例,這個專案使用了 mysql、redis,我們可以驗證搭建是否成功。
-
從遠端倉庫把其克隆到本地,然後開始我們今天的工作。
-
在專案資料夾下建立 docker-compose.yml檔案。
-
先在 docker-compose.yml 檔案裡新增如下程式碼,構建我們的 php 應用。
version: '2' services: # our web application app: build: context: ./ dockerfile: app.dockerfile volumes: - ./:/var/www working_dir: /var/www environment: - DB_HOST=database - REDIS_HOST=redis
下面解釋下我們的程式碼。
- version: 表示我們的compose檔案的版本,目前有1,2,3,每個版本語法不盡相同,這裡以版本2為例。
- services: 即我們要開始定義服務,每個docker容器為一個服務。
- app: 這裡我們定義了第一個服務,app 為其名字
- build: 指定該容器構建引數
- volumes: 與 dockerfile 中 -v 引數相似,這裡是將當前資料夾掛載到容器的/var/www 目錄下
- working_dir: 指定容器工作目錄
- environment: 設定環境變數。由於 laravel 框架在環境變數已有值的情況下不會載入.env 配置,這裡 DB_HOST和 REDIS_HOST 就是.env 檔案中配置資料庫連線的引數,我們設定它以便連線docker 的資料庫,database 和 redis 是接下來定義的服務名稱。
這是 app.dockerfile 檔案的內容,之前都講過,不再細說。
FROM php:7.1.22-fpm # 安裝必要的 php 依賴包 RUN apt-get update \ && apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev \ && apt-get clean # 安裝 php 擴充套件 RUN docker-php-ext-install pdo pdo_mysql mcrypt zip gd
- 建立一個 composer 服務以安裝 composer 依賴,docker-compose.yml 檔案新增以下內容
# install dependencies composer: image: prooph/composer:7.1 volumes: - ./:/var/www working_dir: /var/www command: install
注意這裡同樣將當前資料夾掛載到了容器中,因此對檔案所做的更改都直接作用於本地檔案,而我們的 app 容器也掛載了當前資料夾,這裡安裝的包檔案都能生效。
- 建立一個 nginx 服務,docker-compose.yml 檔案新增以下內容
# web server
nginx:
build:
context: ./
dockerfile: nginx.dockerfile
volumes:
- ./public:/var/www/public
ports:
- 80:80
* 這裡將 public 資料夾掛載到了容器中, nginx 直接返回了靜態檔案,否則你將看到網站格式亂了,因為獲取不到 css 等檔案,如果是單純後端可以不掛載此資料夾
* ports 將nginx容器的80埠對映到本機80埠
nginx.dockerfile 檔案內容,為了新增預設配置檔案
```
FROM nginx:1.10
ADD vhost.conf /etc/nginx/conf.d/default.conf
```
vhost.conf 檔案,nginx 配置檔案
```
server {
listen 80;
server_name www.larabbs.test
index index.php index.html;
root /var/www/public;
error_log /var/log/nginx/error.log notice;
access_log /var/log/nginx/access.log main;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
```
* 這裡配置了 server_name,因為 larabbs 使用了sudo-su包,不配置域名訪問會有許可權問題。
* fastcgi_pass app:9000 這裡將動態請求轉發給了 app 容器的9000埠,即 php-fpm 服務的埠,預設 docker-compose 同一專案下的容器是在同一個網路中,無需對映可以直接互相訪問。
-
建立資料庫服務,docker-compose.yml 檔案新增以下內容
# mysql database database: image: mysql:5.7 environment: - "MYSQL_ROOT_PASSWORD=root" - "MYSQL_DATABASE=larabbs" - "MYSQL_USER=homestead" - "MYSQL_PASSWORD=secret" # redis database redis: image: redis:5
- 這裡 database 和 redis 是服務名,也即在 app 服務的 environment 變數設定的引數,因此 app 才能訪問到我們容器中的資料庫,當然你也可以使用其它名字。
- environment 這裡我們設定了 mysql 的資料庫及使用者名稱密碼,即是 env 檔案中配置的使用者名稱密碼,mysql 容器會自動初始化,然後應用才有許可權連線。
到目前為止配置檔案已經寫完了,完整的檔案可以在我的 github 看到。
四:使用
- 啟動專案
docker-compose 最常用的命令就是docker-compose up
了,該命令十分強大,它將嘗試自動完成包括構建映象,(重新)建立服務,啟動服務,並關聯服務相關容器的一系列操作。
因此,在專案資料夾下執行此命令。注意要在專案資料夾下,否則 docker-compose 找不到 docker-compose.yml 檔案,也不知道你是如何配置的。
時間可能較長,請耐心等待。如果遇到網路故障,可以重試。
簡單介紹下輸出:
可以看到 此時app 服務已啟動,等待連線。
redis 服務已啟動。
database 服務已啟動,在3306埠等待連線。
composer 服務準備開始安裝依賴。
composer 服務完成任務退出。
當然順序可能不同,但正常情況下nginx、mysql、redis、app 服務都已經啟動,執行正常。
另外,你可以給命令加上-d 引數,以忽略輸出,當然第一次執行還是仔細觀察輸出為好,將來使用時可以這麼做。
-
專案使用
首先執行下docker ps
,可以看到目前有4個容器,容器名都加上了專案字首。
此時你可以使用 docker exec 命令進入相應容器執行初始化操作,因為 docker-compose 本身也是呼叫的 docker api,但是既然使用了 docker-compose 來管理專案,我們必然有更方便的方式。執行
docker-compose ps
,可以至檢視當前專案的容器狀態。可以看到,四個服務正在執行,而 composer 服務已經執行完任務退出。
如果要容器執行命令,直接 docker-compose exec service_name command 更方便。
比如,進入我們的 nginx 容器,nginx 即是 YAML 檔案裡定義的服務名。接下來,我們進行網站的初始化工作。即生成祕鑰、初始化資料庫等。
app 也是 YAML 檔案裡定義的服務名。一切都順利進行。
對了,因為上面提到 sudo-su的原因,你必須使用域名訪問網站,在 host 檔案新增 larabbs.test到127.0.0.1的對映即可。
然後,你應該就可以正常訪問 http://larabbs.test 網站了。 - 容器的停止
直接 control-c 或者docker-compose stop
即可。
注意下次docker-compose up
預設仍會繼續使用之前的容器和資料。
必要時你可以新增--build 引數重新構建映象,或者--force-recreate引數重新建立容器。
更多資料:
docker 三劍客-compose
docker-compose 官方文件
閒言
這個系列寫了三篇了,算是把 docker 的基本使用介紹完了,更準確的說,應該是把我會用的介紹完了。因為本身是開發工程師,更著重於日常開發過程中使用,經驗不多,對於運維視角的 docker不甚瞭解,而 docker 更大的意義應該是在運維層,所以有介紹的不合適甚至錯誤的地方,歡迎指出,或者分享你對 docker 的理解與使用。
另外,接下來會介紹 docker 與虛擬機器的區別,docker 的原理等,寫起來會比較難,但我會盡快完成。相信看了之後,會對 docker 的實質有更深的理解,就算是吹牛逼也會更有自信,歡迎關注~
原文見我的知乎專欄