[Docker實踐系列-02]利用DockerCompose編排完整的PHP開發環境
Docker 重要性不用多做解釋,我們天天吵著雲原生,最重要的一門技術,你是否掌握了呢?從今天,一起來Docker吧!
1. 目標
1、利用 docker-compose
編排一個PHP開發環境;
2、PHP
常見擴充套件安裝;
3、Nginx
php-fpm
Mysql
Redis
等容器互聯;
4、PHP
程式能夠操作 Mysql
Redis
;
2、蒐集相關日誌便於排查;
2. 工具
1、作業系統:Ubuntu
2、編輯器:VSCode
3、Docker
4、Docker Compose 官方檔案
5、Compose 中文手冊
6、如果Docker映象拉取慢,可以嘗試這個 www.daocloud.io/mirror
3. 步驟
3.1 檢查軟體
確保 Docker 和 Docker Compose 已安裝好
比如
docker -v Docker version 19.03.1,build 74b1e89
docker-compose -v docker-compose version 1.17.1,build 6d101fb
3.2 建立 docker-compose.yml
檔案
在你的資料夾中新增這個檔案,這是我們編排的模板檔案,格式如下
version: '3'
services:
php-workspace:
image: php:7.3-fpm-alpine
nginx:
image: nginx:alpine
複製程式碼
注意點:
1、模板中定義的 version 欄位宣告瞭模板的格式和支援宣告欄位,3 是目前比較推薦也用的比較多的的版本
2、注意 key 的層級和空格,我們可以使用命令 docker-compose config
命令檢查格式是否正確
3、使用 VSCode
方便的一點是可以看到可以程式碼可以根據層級摺疊
4、alpine是一種小型輕量的Linux,我們使用基於 alpine 的映象是因為做出的映象體積比較小,關於後期容器構建的優化,這個是另外一個話題,這裡不展開闡述。
3.3 “讓子彈飛起來”
docker-compose up --build
構建映象並啟動容器
這時能看到有兩個已經在執行的容器和映象
3.4 讓 Nginx 工作起來
剛剛啟動的容器可以使用 docker-compose down
來關閉專案,還會自動刪除容器。
現在,我們要指定埠讓 Nginx 能處理請求,可以參考 Compose 中文手冊的模板檔案的語法。
3.4.1 增加 ports 引數
指定宿主機埠和容器埠的對映關係,如下;
version: '3'
services:
php-workspace:
image: php:7.3-fpm-alpine
nginx:
image: nginx:alpine
ports:
- "8080:8080"
複製程式碼
3.4.2 執行 docker-compose up
去瀏覽器請求 localhost:8080
3.5 PHP檔案交給 PHP-FPM 處理
其實選中容器右鍵能管理容器,
Attach Shell
就能快速進入容器,我們進入容器就能看到內部情況,比如,nginx 的www目錄和配置目錄,php-fpm 的預設配置等等。
3.5.1 增加 nginx 的站點配置
新增檔案 nginx/conf.d/site.conf
檔案,內容如下,下面的思路也可以參考上篇《利用Docker搭建PHP開發環境》做法。
server {
listen 8080;
root /usr/share/nginx/html;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location ~ \.php$ {
root /var/www/html; # 這裡指向的php容器的專案根目錄
fastcgi_pass php-workspace:9000; #php-workspace是模板檔案中的php-fpm服務名
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
複製程式碼
3.5.2 修改 docker-compose.yml
檔案
讓 nginx 和 php-fpm 服務基於Dockerfile 構建
version: '3'
services:
php-workspace:
build: ./php # 這裡php指我們的建立的目錄
nginx:
build: ./nginx # 這裡nginx指我們的建立的目錄
ports:
- "8080:8080"
複製程式碼
3.5.3 新增 nginx/Dockerfile
檔案
FROM nginx:alpine
COPY conf.d /etc/nginx/conf.d
複製程式碼
3.5.4 新增 php/Dockerfile
檔案
FROM php:7.3-fpm-alpine
複製程式碼
3.5.5 增加code資料夾作為php專案,新增index.php檔案
<?php
phpinfo();
複製程式碼
3.5.6 重新修改 docker-compose.yml
檔案
讓專案資料夾以掛載的形式,讓php-fpm容器可以直接讀取宿主機檔案目錄,這樣我們可以很方便的修改程式碼除錯
version: '3'
services:
php-workspace:
build: ./php
volumes: # 這裡指定資料卷,可以指定多個, 中劃線代表值為陣列的一個成員
- ./code:/var/www/html
nginx:
build: ./nginx #這裡nginx指我們的建立的目錄
ports:
- "8080:8080"
複製程式碼
3.5.7 走一下
重啟之前,再確定下程式碼檔案大概位置
docker-compose up --build
重新啟動專案,我們看到在前臺控制器的一些日誌
兩個容器都構建好了,php也啟動了。如果我們現在請求
localhost:8080
,還能看到nginx的請求日誌3.6 連線Mysql
用法我們依然參考了映象的介紹 >> hub.docker.com/_/mysql
3.6.1 新增 db 的服務
version: '3'
services:
php-workspace:
build: ./php
volumes:
- ./code:/var/www/html
nginx:
build: ./nginx
ports:
- "8080:8080"
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment: # 設定環境變數,只給定名稱的變數會自動獲取執行 Compose 主機上對應變數的值
MYSQL_ROOT_PASSWORD: root
複製程式碼
3.6.2 重新構建
docker-compose up --build
在
VSCode
容器管理中右鍵連線shell中進入容器執行 mysql -u root -p
,確認密碼 root
,確定我們的資料庫可用3.6.3 安裝 pdo mysql
在操作之前我們確定下pdo是不支援mysql驅動的
修改 php 的
Dockerfile
檔案如下RUN 的第一條命令是修改了 alpine 系統的軟體源,方便後續安裝會更快點
FROM php:7.3-fpm-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& docker-php-ext-install pdo_mysql
複製程式碼
重新構建專案 docker-compose up --build
3.6.4 修改 index.php 檔案,程式碼如下
<?php
$dsn = 'mysql:host=db;port=3306'; // host=db,這裡的db其實是mysql的服務名
$user = 'root';
$password = 'root';
try {
$dbh = new PDO($dsn,$user,$password);
print_r($dbh);
} catch (PDOException $e) {
echo 'Connection failed: '.$e->getMessage();
}
複製程式碼
3.6.5 測試 Mysql
3.7 連線 Redis
3.7.1 容器安裝PHP擴充套件的兩種方式
在Docker Hub 中 php映象檔案中說的很清楚
- 第一種是PHP核心的擴充套件可以通過 docker-php-ext-install ext_name 安裝
- 第二種是PECL
- 第三種通過原始碼包編譯
3.7.2 修改 docker-compose.yml 檔案,增加redis服務
version: '3'
services:
php-workspace:
build: ./php
volumes:
- ./code:/var/www/html
nginx:
build: ./nginx
ports:
- "8080:8080"
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
redis:
image: redis:5.0.5-alpine
複製程式碼
3.7.3 重新構建
docker-compose up --build
構建後,我們同樣可以進入容器,使用 redis-cli 命令確定redis是否可用
3.7.4 修改 php Dockerfile
因為pecl在alpine容器中安裝擴充套件會少一些東西,所以我們先安裝了一個phpize_deps,用後刪除即可,保持映象瘦小
FROM php:7.3-fpm-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& docker-php-ext-install pdo_mysql \
&& apk add ${PHPIZE_DEPS} \
&& pecl install redis-4.0.1 \
&& docker-php-ext-enable redis \
&& apk del ${PHPIZE_DEPS}
複製程式碼
重新構建,我們修改index.php 程式碼 phpinfo();能看到 redis擴充套件已開啟
3.7.5 連線 Redis
修改 index.php
檔案內容如下測試
<?php
$redis = new Redis();
$redis->pconnect('redis',6379);
$key = 'first';
$redis->incr($key);
echo '頁面瀏覽了:'.$redis->get($key); die;
複製程式碼
3.8 日誌蒐集
我們回顧一下 nginx/conf.d/site.conf
的配置
server {
listen 8080;
root /usr/share/nginx/html;
index index.php index.html;
server_name localhost;
# 我們已經把nginx相關日誌寫到這裡了,如何放到宿主機呢?
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
# ... more something
}
複製程式碼
docker日誌採集固然有很多方案,但是暫時不考慮叢集管理工具的日誌蒐集方案,這裡以資料掛載的形式,把 nginx 請求日誌落地到宿主機。
3.8.1 修改 docker-compose.yml
檔案如下
version: '3'
services:
php-workspace:
build: ./php
volumes:
- ./code:/var/www/html
nginx:
build: ./nginx
volumes: # 新增這兩行
- ./log/nginx:/var/log/nginx/
ports:
- "8080:8080"
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
redis:
image: redis:5.0.5-alpine
複製程式碼
3.8.2 重啟專案
docker-compose up
執行後,就可以看到我們的資料夾多了兩個目錄,還有兩個檔案
3.9 優化
depends_on
可以指定依賴項,解決容器啟動先後問題,比如一個應用如果依賴資料庫,要讓資料庫容器先啟動可以設定
depends_on:
- db
- redis
複製程式碼
環境變數
當然其實還有其他很多有用的引數設定,比如感敏資料讀取,環境變數,配置host等等,後續都可以在開發中嘗試使用。
4. 總結
以上思路可以解決本地開發中的很多問題了,如果專案中有使用 memcached 或者其他應用,做法都可以參考Docker Hub中的映象檔案說明中引入。
除此之外,在Laravel 開發中之前早就有一個開源專案叫做 Laradock
來搭建Docker化的PHP應用,不僅如此,還有很多中介軟體都可以利用 docker-compose 啟動,可以參看 >> laradock.io/ ,但是裡邊有很多很多東西,因為要滿足大部分人的擴充套件性,加了很多環境變數,if else 判斷,讓原本的 Dockerfile 更為複雜,增加了很多邏輯。但是思路基本上是相同的。
另外還有幾點要點出:
1、docker-compose.yml 定義的一個專案會以所在的資料夾名為專案名。
2、一個專案有一個預設網路,專案中的服務彼此可以互通,所以我們剛剛在 site.conf 轉發php請求可以直接用 php-workspace:9000 服務名來轉發,連線 資料庫也是可以用 db redis 等他們的服務名來連線。
5. 完整程式碼
6. 遺留問題
1、指定資料庫掛載的資料卷,比如Mysql,我們可以把其他環境的資料庫直接以檔案的形式拷貝,然後直接利用。這樣比我們手動匯入sql會更快遷移資料。
2、Mysql 映象如何瘦身,現在Mysql映象檔案最大,如圖有445M
7. 下篇預告
其實PHP的Docker環境已經有一個開源專案 Laradock,使用方便 易於擴充套件,但是最大的問題是 感覺臃腫 有時候安裝特別慢,特別是要考慮太多擴充套件外掛等等製作出來映象特別大。所以下一篇的思路可能會圍繞如何優化今天做的這個 demo-docker-compose,或者做 Laradock 本地化工作?
其他兩個思路:
1、直接進入到 k8s 課題
2、Docker化後如何做CI/CD