返回部落格

在搭載 Ubuntu 18.04 的 Kubernetes 叢集上部署 PHP 應用程式

在搭載 Ubuntu 18.04 的 Kubernetes 叢集上部署 PHP 應用程式

Kubernetes(也稱為 k8s)是一個開源的協調系統。它允許使用者以最少的停機時間來部署、擴充和管理容器化應用程式。在本教學中,您將學習如何部署一個 PHP 應用程式到 Kubernetes 叢集上。

Nginx 的作用是作為代理伺服器指向 PHP-FPM,同時執行 PHP 應用程式。在單一容器中管理這兩個服務是一個困難的過程。Kubernetes 幫助我們在兩個不同的容器中管理它們,並減少了麻煩。它還允許使用者重複使用容器,而不用擔心為每個新版本的 PHP/Nginx 建立其容器映像檔。

您將在兩個獨立的容器中執行您的應用程式和代理服務。本教學還將提供有關如何使用本機儲存來建立 Persistent Volume (PV) 和持久性磁碟區宣告 (PVC)。接著,您將使用此 PVC 將您的設定檔和程式碼保留在容器映像檔之外。完成本教學後,您將能夠將 Nginx 映像檔重複用於其他需要代理伺服器的應用程式。您可以透過傳遞設定來實現此目的,而無需為其重新建置映像檔。

先決條件

  1. 對 Kubernetes (k8s) 及其物件有基本的瞭解。請參閱此指南以獲取 Kubernetes 生態系統的詳細概述.
  2. 一個在 Ubuntu 18.04 上正常執行的 Kubernetes 叢集。按照本教學來 使用 kubeadm 建立您的 Kubernetes 叢集.
  3. 此外,您需要將應用程式程式碼託管在公開的 URL 上,例如 GitHub.

步驟 1:建立 PHP-FPM 和 Nginx 服務

此步驟將協助您建立 PHP-FPM 和 Nginx 服務。任何服務都提供對叢集中一組 Pod 的存取。叢集中存在的所有服務都可以透過其名稱相互通訊,而無需 IP 地址。PHP-FPM 服務和 Nginx 服務將分別提供對 PHP-FPM 和 Nginx Pod 的存取。

您需要告訴 PHP-FPM 服務如何找到 Nginx Pod,因為它將作為 PHP-FPM Pod 的代理。為此,您將利用 Kubernetes’ 自動服務發現,並使用易於理解的名稱將請求路由到相應的服務。

為了建立任何服務,您需要建立一個 YAML 檔案,其中包含物件定義。此 YAML 檔案至少包含以下標籤:

  1. apiVersion: 該定義所屬的 Kubernetes API 版本。
  2. kind: 此 YAML 檔案建立的 Kubernetes 物件類型。例如:一個 service,一個 job,或一個 pod.
  3. metadata: 物件的名稱以及使用者可能想要套用至此物件的不同 labels 都定義在此標籤下。
  4. spec: 此標籤包含您物件的規格說明,例如環境變數 (ENV)、要使用的容器映像檔、可存取容器服務的連接埠。
建立 PHP-FPM 服務

首先,您應該建立一個目錄來存放您的 Kubernetes 物件定義。登入您的主節點並建立一個名為 “definitions:”

將目錄切換到 definitions 目錄:

接下來,建立您的 PHP-FPM 服務檔案,命名為 php_service.yaml 檔案:

之後,在 apiVersionkindphp_fpm_service.yaml 檔案中:

將您的服務命名為 phpphp-fpm,因為它將提供對您的 PHP-FPM 應用程式的存取:

將您的 php 服務標記為 tier: backend,因為 PHP 應用程式將在此服務背後執行:

服務使用 selector 標籤來確定要存取哪些 Pod。任何符合這些標籤的 Pod,無論該 Pod 是何時建立的,都會受到服務。您將在本教學的後面學習如何將標籤新增到您的 Pod 中。

包含 tier: backend 標籤,將您的 pod 分配到 backend 層,以及 app: php-fpm 標籤,以表示該 pod 運行 PHP-FPM 應用程式。您必須在 metadata 區段之後添加這些標籤:

接下來,您需要宣告存取此 php-fpm 服務的連接埠,位於 spec 之下。您可以添加任何您選擇的連接埠,但在本教學中我們將使用連接埠 9000

完成上述步驟後,您的 php_fpm_service.yaml 檔案將如下所示:

輸入 Ctrl + O 儲存檔案,然後輸入 Ctrl + X 離開 nano.

套用 kubectl 指令以建立 PHP 服務

建立服務的物件定義後,請執行 kubectl apply 指令並加上 -f 參數,指定您的 php_fpm_service.yaml 檔案:

上述指令的輸出應為:

執行以下指令以驗證您的 php-fpm 服務是否正在執行:

您將能夠看到 php-fpm 服務已啟動並正在執行:

注意: Kubernetes 支援多種 服務類型。您的 php-fpm 服務使用預設的 ClusterIP 服務類型。此類型的服務會分配一個內部 IP,並使該服務僅能從 Kubernetes 叢集內部存取。
建立 Nginx 服務

既然您的 PHP-FPM 服務已經準備就緒,現在也是建立 Nginx 服務的時候了。在編輯器中為此服務建立並開啟一個名為 nginx_service.yaml 的新 YAML 檔案:

將此服務命名為 nginx,因為它將以 Nginx pod 為目標。此服務也屬於 backend,因此您應該為其添加 tier: backend 標籤:

如同我們在 php-fpm 服務中所做的那樣,添加選擇器標籤 app: nginxtier: backend 以指定目標 pod。添加預設的 HTTP 連接埠 80 以存取此服務:

Nginx 服務可以透過公用 IP 位址在網際網路上公開存取。您可以將工作節點的 IP 新增為 your_public_ip。在 spec.externalIPs:

當您完成上述所有步驟後,您的 nginx_service.yaml 檔案應該如下所示:

新增上述所有必要參數後,儲存並關閉檔案。

套用 kubectl 指令以建立 Nginx 服務
您應該會看到上述命令的以下輸出:
現在,執行以下命令以查看所有執行中的服務:
透過執行上述命令,您應該能夠看到您的 PHP-FPM 和 Nginx 服務都已啟動並執行:
請注意,如果您想刪除任何執行中的服務,可以執行以下命令:

步驟 2:建立本機儲存和永續性磁碟區

Kubernetes 提供了各種儲存外掛程式,可協助您為環境建立儲存空間。本步驟將引導您如何建立本機 StorageClass 以及如何進一步使用此 Storage Class 來建立永續性磁碟區。

建立本機儲存

建立一個檔案,例如 storageClass.yaml,在您的編輯器中:

將 kind 新增為 "storageClass",並將 apiVersion 新增為 "storage.k8s.io/v1",如下所示:

將此 StorageClass 命名為 "my-local-storage",並新增 provisioner 和 volumeBindingMode,如下所示:

儲存並退出檔案,您最終的 storageClass.yaml 檔案應該如下所示:

現在,透過執行 kubectl create 命令來建立 StorageClass,如下所示:

執行上述命令後,您應該會得到以下輸出:

建立本機永續性磁碟區

建立本機儲存後,您可以建立本機永續性磁碟區。永續性磁碟區(也稱為 PV)是特定大小的區塊儲存,獨立於 Pod 的生命週期。本機永續性磁碟區只不過是 Kubernetes 叢集節點上可用的本機磁碟或目錄。此本機永續性磁碟區允許使用者以非常簡單且可移植的方式,透過使用本機永續性磁碟區宣告 (Persistent Volume Claim) 來存取本機儲存。您可以使用我們剛剛建立的此儲存類別來建立此本機永續性磁碟區。開啟一個檔案,例如 persistentVolume.yaml,在您的編輯器中:

為此永續性磁碟區命名,例如 "my-local-pv":

在建立本機永續性磁碟區時,您可以根據您的使用情況新增儲存容量。在本教學中,我們將使用 5 Gi 作為儲存空間:

新增 accessModes、persistentVolumeReclaimPolicy,並提供與 storageClass.yaml 中相同的 storageClassName:

Note: persistentVolumeReclaimPolicy 會告訴您當永續卷冊(Persistent Volume Claim)被釋放時,該永續卷冊(Persistent Volume)會發生什麼事。此參數有三個有效選項:Retain、Delete 和 Recycle。在我們的程式碼中,我們將使用 Retain 選項。如需更多詳細資訊,您可以在此處查看 persistentVolumeReclaimPolicy 欄位: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#persistentvolumeclaim-v1-core

新增 local.path 至您的 Persistent Volume,如下所示:

Note: 請確保此本機路徑 (/mnt/disk/vol) 存在於您的 Kubernetes 叢集節點上。

新增所有必要欄位後,您的 persistentVolume.yaml 檔案應該如下所示:

Note: 您必須使用您機器的正確節點名稱。在此案例中為:“worker.”
準備本機卷冊

現在,我們需要在 “worker” 節點上準備一個本機卷冊,正如我們在 persistentVolume.yaml 檔案中所新增的。在您於 persistentVolume 中設定的節點上執行以下指令。在此案例中,它是 “worker” 節點:

Note: 請確保您有足夠的權限來建立目錄並修改權限,如上所示。如果沒有,請使用正確的使用者執行指令。

在您的 persistentVolume.yaml 檔案所在的主節點上執行以下指令:

您應該會得到以下輸出:

由於您已成功建立本機儲存空間和永續卷冊,您現在可以繼續建立永續卷冊聲明(Persistent Volume Claim)來存放您的應用程式程式碼和設定檔。

步驟 3:建立永續卷冊

在您管理或更新 Pod 時,您的應用程式程式碼需要保持安全。為此,您將使用在上一步中建立的永續卷冊(Persistent Volume),並透過使用永續卷冊聲明(Persistent Volume Claim,簡稱 PVC)來存取它。此 PVC 會將 PV 掛載到所需的路徑上。

開啟一個檔案,例如 code_volume.yaml,在您的編輯器中:

透過在檔案中新增以下參數和值,將您的 PVC 命名為 code:

PVC 的 spec 區段包含以下項目:

  1. accessModes:此欄位有各種可能的取值,如下所示:
    • ReadWriteOnce – 為單一節點掛載具有讀取和寫入權限的卷冊。
    • ReadOnlyMany – 為多個節點掛載僅具有讀取權限的卷冊。
    • ReadWriteMany – 為多個節點掛載具有讀取和寫入權限的卷冊。
  2. resources:定義所需的儲存空間。

由於本地儲存僅掛載到單個節點,您需要將 accessMode 設置為 ReadWriteOnce。在本教學中,您只需添加一小部分應用程式代碼,因此這裡 1GB 的儲存空間就足夠了。但是,如果您希望儲存更大量的數據或代碼,可以根據您的需求修改 storage 參數。請注意,磁碟卷創建後,您將能夠增加儲存大小。但是,不支援減少儲存大小:

現在,聲明 Kubernetes 叢集將用於分配給磁碟卷的儲存類別(storage class)。在此處的 storageClassName 使用在上一步中創建的 my-local-storage 儲存類別:

完成上述步驟後,您的 code_volume.yaml 檔案應該如下所示:

現在儲存並退出檔案。

創建 PVC

執行 kubectl apply 命令來創建 code PVC:

您應該會得到以下輸出,表示該物件已成功創建,並準備好將您的 1GB PVC 掛載為磁碟卷:

您可以執行以下命令來檢查可用的持久性磁碟卷 (PV):

上述命令的輸出應該如下所示:

除了 Reclaim Policy 和 Status 之外,上述所有欄位都是您設定檔的概覽。Reclaim Policy 定義了當存取該 PV 的 PVC 被刪除時,PV 會發生什麼事。Delete 值會將 PV 從 Kubernetes 叢集以及儲存基礎架構中移除。您可以參考 Kubernetes PV 文件 以清楚了解 Reclaim Policy 和 Status。

由於您已成功使用本地儲存創建了持久性磁碟卷,現在可以使用 Deployment 來創建您的 Pod。

步驟 4:為您的 PHP-FPM 應用程式創建 Deployment

此步驟將協助您使用 Deployment。Deployment 使用 ReplicaSet 提供一種穩定的方式來創建、更新和管理您的 Pod。Deployment 會自動將其 Pod 回滾到先前的映像檔。

在 Deployment 中的 spec.selector 鍵列出了它所管理之 Pod 的所有標籤。它還使用 template 鍵來創建所需的 Pod。

在此步驟中,我們還將介紹 Init Containers 的應用。初始化容器(Init Containers)會在 Pod 範本中指定的常規容器之前執行一些命令。在這裡,初始化容器將使用 GitHub Gist (https://gist.github.com/) 來獲取範例 index.php 檔案。該範例檔案的內容為:

創建 PHP Deployment

在編輯器中打開一個名為 php_deployment.yaml 的新檔案以創建您的 Deployment:

現在,將 Deployment 物件命名為 PHP,因為此 Deployment 將管理您的 PHP-FPM pod。新增標籤 tier: backend,因為該 pod 將屬於 backend 層:

使用 replica 參數,指定應建立的此 pod 副本數量。副本數量可能會根據您的需求和可用資源而有所不同。在本教學中,您將僅建立該 pod 的一個副本:

新增 app: phptier:backend 標籤於 selector 鍵下,這表示此 Deployment 將管理與這兩個標籤相匹配的 pod:

現在,您的 pod’s 物件定義需要在您的 Deployment spec 下有一個 template。此範本定義了建立 pod 所需的規格。首先,新增為 php 服務選擇器 (service selector) 和 Deployment 的 matchLabels 指定的標籤。然後新增 app:phptier:backendtemplate.metadata.labels:

注意: 一個 pod 可以有多個容器 (container) 或磁碟卷 (volume),且每個容器或磁碟卷都需要不同的名稱以便區分。您可以為每個磁碟卷指定掛載路徑 (mount path),以選擇性地將該磁碟卷掛載到容器中。

首先,您需要指定容器將存取的所有磁碟卷。將此磁碟卷命名為 code,因為您之前已建立了一個名為 code 的 PVC 來存放您的應用程式程式碼:

接下來,指定容器名稱以及您要在 pod 內執行的映像檔。Docker store (https://hub.docker.com/explore/) 上有各種可用的映像檔,但在本教學中,我們將使用 php:7-fpm 映像檔:

現在,掛載容器需要存取的磁碟卷。由於此容器將執行您的 PHP 程式碼,因此它需要存取在上一步中建立的 code 磁碟卷。在此步驟中,您還將學習如何使用 Init Container 複製您的應用程式程式碼。

注意: 您可以使用單個 initContainer 來執行建置應用程式的指令碼,也可以為每個指令使用一個 initContainer,這取決於您設定流程的複雜程度。您需要確保磁碟卷已掛載到 initContainer。

為了下載程式碼,本教學將引導您如何使用帶有 busybox 的單個 Init Container。Busybox 是一個帶有 wget 工具的小型容器,您將使用它來實現此目的。

首先,在 spec.template.spec 下新增您的 initContainer,並指定 busybox 映像檔:

然後,為了將程式碼下載到 code 磁碟卷中,您的 Init Container 將需要存取它。將 code 磁碟卷掛載於 /code 路徑,位於 spec.template.spec.initContainers:

每個 Init Container 都需要執行指令。此 Init Container 將使用 wget 下載 codeGithub/code 目錄中。您可以傳遞 -O 選項來為此下載的檔案命名,您可以將此檔案命名為 index.php.

注意: 請確保您信任使用 Init Container 拉取到伺服器中的程式碼。您可以檢查原始碼,並確保您對其執行的操作感到放心。

此外,在 install 容器下方新增以下幾行於 spec.template.spec.initContainers:

完成所有這些步驟後,您的 php_deployment.yaml 檔案應該如下所示:

You can now save the file and exit. Next, create your PHP-FPM Deployment using kubectl apply command:

成功建立 Deployment 後,您應該會看到以下輸出:

此 Deployment 首先會下載指定的映像檔,然後它會向您的 PersistentVolume 請求 PersistentVolumeClaim,接著執行您的 initContainers。完成此步驟後,容器將會執行並將儲存卷掛載到指定的掛載點。完成所有這些步驟後,您的 Pod 將會啟動並執行。

您可以執行以下指令來檢視您的 Deployment:

執行上述指令後,您應該會得到以下輸出:

You can understand the current state of the Deployment with the help of this output. A Deployment is a controller that maintains the desired state. The DESIRED 欄位指定它有 1 個名為 php 的 Pod 副本。 CURRENT 欄位表示目前有多少個 DESIRED 狀態的副本正在執行。對於健康的 Pod,這應該與 DESIRED 狀態相符。您可以在 Kubernetes Deployments 文件.

之後,若要檢查正在執行的 Pod 狀態,您可以執行以下指令:

此指令的輸出可能會根據您建立 Deployment 後所經過的時間而有所不同。如果是在建立 Deployment 後不久執行,輸出將類似於:

說明:

這些欄位代表的資訊如下:

  • Ready:執行此 Pod 的目前/期望副本數量。
  • Status: 您的 Pod 狀態。Init:0/1 表示 Init 容器正在運行,且 1 個 Init 容器中有 0 個已完成運行。
  • Restarts: 這表示此程序為了啟動 Pod 而重新啟動的次數。

您的 Pod 可能需要幾分鐘的時間才能將狀態變更為 podInitializing,具體取決於您啟動指令碼的複雜程度:

這表示 Init 容器已成功運行,現在容器正在進行初始化:

如您所見,您的 Pod 現在已啟動並運行。然而,如果您的 Pod 未能啟動,您可以運行以下命令進行偵錯:

1. 檢視 Pod 的詳細資訊:

2.  檢視 Pod 的記錄檔:

注意: “kubectl logs” 命令有多個可用選項,您可以運行 “kubectl logs –help” 命令以探索更多相關資訊。

3. 檢視 Pod 中特定容器的記錄檔:

恭喜!您已成功掛載應用程式程式碼,且 PHP-FPM 服務已準備好處理連線。同樣地,您可以建立您的 Nginx 部署。

步驟 5:建立您的 Nginx 部署

本步驟將引導您如何使用 ConfigMapConfigMap 以鍵值(key-value)格式保存所有必要的設定,這些設定將在其他 Kubernetes 物件定義中使用。透過這種方法,您可以根據需要靈活地重複使用或更換不同版本的 Nginx 映像檔。您可以更新 ConfigMap,它會自動將這些變更複製到任何掛載此 ConfigMap.

首先,在您的編輯器中開啟 nginx_configmap.yaml 檔案:

現在,將此 ConfigMap 命名為 nginx-config 並將其新增至 tier: backend 微服務:

此外,您可以將資料新增至 ConfigMap。新增一個名為 config 的鍵,並將所有 Nginx 設定檔內容作為其值。

由於 Kubernetes 可以將請求路由到服務的對應主機,您可以在 fastcgi_pass 參數下輸入您的 PHP-FPM 服務名稱,而不是其 IP 地址。將以下幾行程式碼新增至您的 nginx_configMap.yaml 檔案中:

完成後,您的 nginx_configMap.yaml 檔案將如下所示:

您現在可以儲存並退出編輯器。現在執行 kubectl apply 命令以建立 ConfigMap:

之後,您應該會在螢幕上看到以下輸出:

您已成功建立 Nginx Configmap。現在您可以建立 Nginx Deployment。

建立 Nginx Deployment

首先,您可以在編輯器中建立一個名為 nginx_deployment.yaml 的新檔案:

將此 Deployment 命名為 nginx 並為其新增 tier: backend 標籤:

之後,透過在 Deployment spec 中新增 replica 欄位來指定副本數量,並為其新增 app: nginxtier: backend 標籤:

同樣地,新增 Pod 範本。請確保您新增的標籤與您在 Deployment 的 selector.matchLabels 中新增的標籤相同。您可以新增以下內容:

透過在以下位置新增以下參數,讓 Nginx 能夠存取先前建立的 code PVC:spec.template.spec.volumes:

注意: Pod 可以將 ConfigMap 掛載為磁碟卷。透過指定檔案名稱 and 鍵(key),我們將建立一個以其值為內容的檔案。若要使用此 ConfigMap,請將路徑設定為保存該鍵內容的檔案名稱。您可以從鍵 config 建立一個 site.conf 檔案。在 spec.template.spec.volumes 下新增以下內容:

警告:如果未指定檔案,鍵的內容將會取代 volume’s mountPath。換句話說,如果未明確指定路徑,您將會遺失目標資料夾中的所有內容。

現在,指定您要在 Pod 中使用的名稱、映像檔和連接埠。在這裡,我們將使用 nginx:1.7.9 映像檔和連接埠 80。將它們新增在 spec.template.spec 區段:

此外,將 code 儲存卷掛載於 /code ,因為 Nginx 和 PHP-FPM 都需要存取相同路徑下的檔案:

這個 nginx-1.7.9 映像檔會自動載入位於 /etc/nginx/conf.d 資料夾下的任何設定檔。現在,如果我們在此目錄中掛載 config 儲存卷,它將會建立 /etc/nginx/conf.d/site.conf。請在 volumeMount 區段下方新增以下內容:

完成上述所有步驟後,您的 nginx_deployment.yaml 檔案應該如下所示:

您現在可以儲存並關閉檔案,然後執行以下命令來建立 Nginx Deployment:

成功執行命令後,您應該會看到以下輸出:

您可以執行以下命令來列出所有的 Deployment:

您現在應該會看到 Nginx 和 PHP-FPM 的 Deployment:

kubernetes deployment status

此外,您可以執行以下命令來列出由上述兩個 Deployment 所管理的 Pod:

您將會看到您的兩個 Pod 都已啟動並運行,如下所示:

kubernetes pod status

由於此時您所有的 Kubernetes 物件都已處於作用狀態,您現在可以在瀏覽器上存取 Nginx 服務。

執行以下命令以列出服務:

記下您 Nginx 服務的 External IP:external ip of nginx Deploy a PHP Application on Kubernetes Cluster with Ubuntu 18.04

現在,使用此 Nginx 服務的 External IP,您可以透過在瀏覽器上輸入 http://your_public_ip 來造訪您的伺服器。您應該能夠看到 php_info() 的輸出,這確認了您的 Kubernetes 服務已啟動並運行。

結論

在本教學中,為了獨立管理您的 PHP-FPM 和 Nginx 服務,您將這兩個服務進行了容器化。透過這樣做,您不僅能提高專案的擴充性,還能有效率地利用資源。您也學習了如何建立本機儲存和 Persistent Volume,以便將應用程式程式碼儲存在磁碟卷上,並在未來輕鬆更新您的服務。透過這樣做,您提高了程式碼的可用性和可維護性。

此外,您可以查看我們其他專注於 Docker 和 Kubernetes 的教學,這些教學可以在我們的 部落格:

祝您運算愉快!

author

Hark Labs

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的創意設計師,專注於透過傳統與創新行銷渠道建立一致的企業形象。他擅長將藝術願景與策略行銷相融合,創造具有影響力的品牌敘事。

留言

目前尚無留言。成為第一個留言的人吧。