Kubernetes 部署 PHP-fpm 與 nginx 多容器應用

jxlwqq發表於2020-03-24

實驗前提

  • 需要你有 macOS 開發環境,本文以此為例,其他型別的開發環境請自行搭建。
  • 需要你對 YAML 這一專門用來寫配置檔案的語言有所瞭解。
  • 需要你對 Docker 有一些基本的瞭解。
  • 需要你對 Kubernetes 中的 Node、Pod、ReplicaSet、Deployment、Service、Ingress、ConfigMap 等一些核心基礎概念有一定的瞭解。

YAML 配置檔案下載地址:

git clone https://github.com/jxlwqq/kubernetes-examples.git
cd deploying-simple-php-app-with-fpm-and-nginx

安裝 Docker for Mac

下載地址:https://hub.docker.com/editions/community/...

啟動並開啟 Kubernetes 功能,功能開啟過程中,Docker 將會自動拉取 Kubernetes 相關映象,所以全程需要科學上網。

為啥不使用 minikube?minikube + virtualbox + kubectl 安裝起來太繁瑣了,而且即使科學上網了你也不一定能搞定。當然阿里雲提供了一篇安裝教程可以參考。

本地埠準備

請確保本地 localhost 的 80 埠沒有被佔用,已在使用的請在實驗期間暫時關閉佔用 80 埠的服務。

切換叢集

如果你本地有多個 Kubernetes 的叢集配置,請先切換至名為 docker-desktop 的叢集:

kubectl config use-context docker-desktop

拉取映象

原始碼在 php-info 目錄中。我這裡已經基於 Dockerfile 製作好了映象,pull 後可以直接使用。

docker pull jxlwqq/php-info

原始碼邏輯很簡單,列印 phpinfo 資訊,Dockerfile 內容如下所示:

php-info/Dockerfile 的程式碼:

FROM php:7.4-fpm
WORKDIR /app
COPY index.php /app

php-info/index.php 的程式碼:

<?php
    phpinfo();

部署

kubectl apply -f configmap.yaml # 配置物件,本示例存放 nginx.config
kubectl apply -f php-fpm-nginx-deployment-and-service.yaml # php-fpm 和 nginx 雙容器
kubectl apply -f ingress.yaml # ingress 路由規則

configmap.yaml 檔案解讀:

kind: ConfigMap # 物件型別
apiVersion: v1 # api 版本
metadata: # 後設資料
  name: nginx-config # 物件名稱
data: # key-value 資料集合
  nginx.conf: | # 將 nginx config 配置寫入 ConfigMap 中,經典的 php-fpm 代理設定,這裡就不再多說了
    events {
    }
    http {
      server {
        listen 80 default_server;
        listen [::]:80 default_server;
        root /var/www/html;
        index index.php;
        server_name _;
        location / {
          try_files $uri $uri/ =404;
        }
        location ~ \.php$ {
          include fastcgi_params;
          fastcgi_param REQUEST_METHOD $request_method;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_pass 127.0.0.1:9000;
        }
      }
    }

php-fpm-nginx-deployment-and-service.yaml 檔案解讀:

kind: Deployment # 物件型別
apiVersion: apps/v1 # api 版本
metadata: # 後設資料
  name: php-fpm-nginx # Deployment 物件名稱
spec: # Deployment 物件規約
  selector: # 選擇器
    matchLabels: # 標籤匹配
      app: php-fpm-nginx
  replicas: 1 # 副本數量
  template: # 模版
    metadata: # Pod 物件的後設資料
      labels: # Pod 物件的標籤
        app: php-fpm-nginx
    spec: # Pod 物件規約
      containers: # 這裡設定了兩個容器
        - name: php-fpm # 第一個容器名稱
          image: jxlwqq/php-info # 容器映象
          ports:
            - containerPort: 9000 # php-fpm 埠
          volumeMounts: # 掛載資料卷
            - mountPath: /var/www/html # 掛載兩個容器共享的 volume 
              name: nginx-www
          lifecycle: # 生命週期
            postStart: # 當容器處於 postStart 階段時,執行一下命令
              exec:
                command: ["/bin/sh", "-c", "cp -r /app/. /var/www/html"] # 將 /app/index.php 複製到掛載的 volume 
        - name: nginx # 第二個容器名稱
          image: nginx # 容器映象
          ports:
            - containerPort: 80 # nginx 埠
          volumeMounts: # nginx 容器掛載了兩個 volume,一個是與 php-fpm 容器共享的 volume,另外一個是配置了 nginx.conf 的 volume
            - mountPath: /var/www/html # 掛載兩個容器共享的 volume 
              name: nginx-www
            - mountPath: /etc/nginx/nginx.conf #  掛載配置了 nginx.conf 的 volume
              subPath: nginx.conf
              name: nginx-config
      volumes:
        - name: nginx-www # 這個 volume 是 php-fpm 容器 和 nginx 容器所共享的,兩個容器都 volumeMounts 了
          emptyDir: {}
        - name: nginx-config 
          configMap: # 有人好奇,這裡為啥可以將 configMap 物件透過 volumeMounts 的方式注入到容器中呢,因為本質上 configMap 是一類特殊的 volume
            name: nginx-config
---
kind: Service # 物件型別
apiVersion: v1 # api 版本
metadata: # 後設資料
  name: php-fpm-nginx
spec:
  selector:
    app: php-fpm-nginx
  ports:
    - port: 80 
      targetPort: 80 # Service 將 nginx 容器的 80 埠暴露出來

ingress.yaml 檔案解讀:

kind: Ingress # 物件型別
apiVersion: networking.k8s.io/v1beta1
metadata:
  name: php-fpm-nginx
spec:
  rules:
    - http:
        paths:
          - backend:
              serviceName: php-fpm-nginx # 流量轉發到名為 php-fpm-nginx 的 Server 是那個
              servicePort: 80 # 與 Service 的 port 一致

自動伸縮

kubectl apply -f horizontalpodautoscaler.yaml # hpa 水平自動伸縮物件

horizontalpodautoscaler.yaml 檔案解讀:

kind: HorizontalPodAutoscaler # 物件型別,簡稱 hpa,水平自動伸縮
apiVersion: autoscaling/v2beta2 # autoscaling/v2beta2 與 autoscaling/v1 的 API 有很大的不同,注意識別兩者的差異
metadata:
  name: php-fpm-nginx
spec:
  scaleTargetRef: # 伸縮的目標物件
    apiVersion: apps/v1 # 物件版本
    kind: Deployment # 目標物件的型別
    name: php-fpm-nginx # 目標物件的名稱
  minReplicas: 3 # 最小副本數
  maxReplicas: 10 # 最大副本數
  metrics: # 指標
    - type: Resource # 型別:資源
      resource:
        name: memory # 記憶體
        target:
          type: Utilization # 利用率
          averageUtilization: 1 # 1% 這個值是為了實驗,具體值請參考業務方實際情況而定

建立 Ingress-nginx 控制器

有了 Ingress 物件還不夠,還需要 Ingress-nginx 控制器。這裡又有一個不太好的比方了,Ingress 物件類似 Nginx 的 nginx.conf 檔案,單單有配置檔案是萬萬不行的,我們需要 Nginx 服務(軟體)本身。

為了讓 Ingress 資源工作,叢集必須有一個正在執行的 Ingress 控制器。 Kubernetes 官方目前支援和維護 GCE 和 nginx 控制器。

這裡我們選擇 Ingress-nginx 控制器:

cd ../ingress-nginx # 切換到 ingress-nginx 目錄
kubectl apply -f ingress-nginx-deployment-and-other-resources-mandatory.yaml
kubectl apply -f ingress-nginx-service.yaml

注:

詳細操作說明見:https://github.com/kubernetes/ingress-ngin...

訪問

curl http://localhost

撒花,結束。

清場

刪除本次示例所有的物件:

kubectl delete -f ./

鳴謝

部分內容參考了 https://matthewpalmer.net/kubernetes-app-d...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章