Contents
前言
我為啥會寫這篇文章?大家知道很多應用程式部署都需要LNMP環境,這個環境的搭建說簡單也不算難,說難也不算簡單,況且現在還有各種linux面板能貼心的提供一鍵一站式安裝,我最開始的時候也是習慣使用寶塔linux面板,後來也嘗試過1Panel面板,其實都不錯。
後來,主要我常常折騰,各種資料倒騰來倒騰去,涉及到資料遷移的時候,docker的優勢就發揮出來了,比如我忽然想利舊吃灰的第一代m1版macmini,就想把應用都容器化部署上去,這時候我原本都是在寶塔面板裡源碼部署的應用要遷移就很麻煩了。當然還有一種方式是直接docker方式安裝寶塔面板,不過我個人並不喜歡這種方式,我覺得要么就裸機部署(linux面板本來就是為了裸機而生),要么就全容器化,所以才有了這篇文章。
面板的一個好處是多站點、多PHP版本、多資料庫的靈活支持,如下圖:
資料庫切換好說,就是設定檔裡改個指向就行,但php版本的切換這種方式的確是非常的方便。而如果我要用容器化環境來替代,理想狀態下應該要達到以下目標:
1、復用
能夠像面板這種方式一樣,新建一個網站只需要新增對應的目錄(以及一個網站對應的conf設定檔)。
2、靈活切換
如果要更換php版本,也要簡單方便(幾秒鐘)。
所以總結下來說,就是只需要建立一個nginx容器和一個php容器(這裡的一個指的是一個版本只需要一個,例如下面要用到的php7.4),就能多站點同時使用。
註:這裡簡單提一句我的理念,我用docker基本上不用docker compose,因為我的理念就是複用,我不會每次都拉一堆容器起來,比如我有一個mariadb的容器,那我所有的應用要用資料庫並且能夠用mariadb的,我都會用這個,這樣備份也方便。當然這只是針對我的環境和習慣而言,如果是其他環境並且有應用隔離的需求的另當別論。
部署nginx和php7.4 fpm容器
終於步入正題了,接下來進行實操,依序創建bridge及建立一個nginx容器和一個PHP7.4 fpm的容器:
建立bridge
因為下面要用到一個名為public-net的bridge,所以需要提前建立:
docker network create public-net
部署nginx容器:
docker run --name=nginx -d --restart=always --net=public-net \ -p 9000:80 \ -v /docker/nginx/html:/usr/share/nginx/html \ -v /docker /nginx/conf/conf.d:/etc/nginx/conf.d \ -v /docker/nginx/log:/var/log/nginx \ nginx:latest
註:nginx有預設文件,有預設檔的都不能直接-v掛載空資料夾,需要先不用-v參數創建一個容器,用指令將文件拷貝出來刪除,然後重新用-v掛載磁碟區來創建,拷貝文件類似如下:
docker cp nginx:/usr/share/nginx/html /docker/nginx/ docker cp nginx:/etc/nginx/conf.d /docker/nginx/conf/
部署php7.4 fpm的容器:
docker run --name=php_74 -d --restart=always --net=public-net \ --privileged=true \ -v /docker/nginx/html:/var/www \ php:7.4-fpm
單nginx容器、單php7.4 fpm之多站點共用
這樣就基本大功告成了。但是如何實現我們上面提到的複用和靈活切換?
關鍵點:
1、目錄結構:
其實目錄結構很簡單,例如:
nginx容器裡網站根資料夾(/usr/share/nginx/html)在宿主機的掛載目錄為/docker/nginx/html,則php容器內的根資料夾(/var/www)在宿主機的掛載目錄也必須是這個,這樣的好處在於nginx和php容器的文件路徑統一,並且未來nginx創建新的站點時,只需要在這個掛載的目錄(/docker/nginx/html)里新建站點文件夾即可,實現了我們前面說的複用。
2、default.conf不用動,每次新建站點只需要新建一個對應的.conf文件,這裡我們用wow.conf來示例,這是我們在另一篇文章裡要講到的搭建魔獸世界註冊網站的時候要用到:
在/docker/nginx/conf/conf.d資料夾裡新建wow.conf檔,其設定腳本裡關於fastcgi如下:
location ~/ .php {
root /var/www;
fastcgi_pass php7_4:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME document_root$fastcgi_script_name;;
include fastcgi_params;
}
灵活切换的关键点就在这部分,为什么我们php容器镜像用的是php:7.4-fpm,fpm就是:FastCGI Process Manager,就是说这个镜像的php是支持fastcgi的。因为nginx无法理解php语言,所以在需要解读的时候,就会通过fastcgi的方式,根据fastcgi_pass参数提供的网络地址和端口(php7_4:9000)去找php容器解读(为啥php7_4能够表示php容器的网络地址?只要前面创建的时候nginx和php容器都加了–net=public-net参数就行,具体原因不展开讲了,又是一大篇幅),而fastcgi_index指定了需要解读的文件名index.php。那么这个文件位置在哪里呢?就由fastcgi_param指定的变量document_root来确定,而 document_root变量的内容就是上面的root /var/www来确定(这个的默认值是root html,如果是正常裸机通过面板安装的一站式方案的话,这么写没毛病,但是现在是容器化部署,就不合时宜了)。其实如果是多站点php部署,这个conf本来就是特定站点的,这里完全可以不用$ document_root这种方式,而是直接使用根路径名字,比如/var/www/wow,前面root那行都可以不要了,如下:
location ~/ .php {
fastcgi_pass php7_4:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/wow/fastcgi_script_name;;
include fastcgi_params;
}
大功告成!
總結下關鍵點:nginx在指定的位址和連接埠找到php,然後讓php在指定的路徑去尋找index.php解讀。為什麼php能去指定的路徑找到index.php?這個站點資料夾不是在nginx容器上?啊,因為php也掛載了nginx的那個目錄,所以也能找到對應的網站資料夾了。
另:php對應版本的容器裡推薦把各種擴充都安裝好,這個我在另一篇文章裡講。