如何在Ubuntu16.04上使用Kubernetes部署PHP应用程序

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Open Internet/Free Speech 来接收捐赠。

介绍

Kubernetes 是一个开源的容器编排系统。 它允许您创建、更新和扩展容器,而无需担心停机时间。

为了运行 PHP 应用程序,Nginx 充当 PHP-FPM 的代理。 将此设置容器化在单个容器中可能是一个繁琐的过程,但 Kubernetes 将帮助在单独的容器中管理这两个服务。 使用 Kubernetes 将使您的容器保持可重用和可交换,并且每次有新版本的 Nginx 或 PHP 时您都不必重新构建容器映像。

在本教程中,您将在 Kubernetes 集群上部署 PHP 7 应用程序,其中 Nginx 和 PHP-FPM 在单独的容器中运行。 您还将学习如何使用 DigitalOcean 的块存储 系统将配置文件和应用程序代码保存在容器映像之外。 这种方法将允许您通过传递配置卷而不是重建映像来为任何需要 Web/代理服务器的应用程序重用 Nginx 映像。

注意: 本教程已经在使用 Kubeadm 制作的 Kubernetes 集群上进行了测试,与 DigitalOcean Managed Kubernetes (DOKS) 产品有很大不同。 如果您使用 DOKS,请查看我们的官方 DigitalOcean Kubernetes 产品文档 以获取最新信息和教程。


先决条件

  • 对 Kubernetes 对象的基本了解。 查看我们的 Kubernetes 简介 文章了解更多信息。
  • 在 Ubuntu 16.04 上运行的 Kubernetes 集群。 您可以按照 How To Create a Kubernetes 1.10 Cluster Using Kubeadm on Ubuntu 16.04 教程进行设置。
  • 一个 DigitalOcean 帐户和一个具有读写权限的 API 访问令牌来创建我们的存储卷。 如果您没有 API 访问令牌,您可以 从此处 创建它。
  • 您的应用程序代码托管在可公开访问的 URL 上,例如 Github

第 1 步 — 创建 PHP-FPM 和 Nginx 服务

在这一步中,您将创建 PHP-FPM 和 Nginx 服务。 服务允许从集群内访问一组 pod。 集群中的服务可以直接通过它们的名称进行通信,而不需要 IP 地址。 PHP-FPM 服务将允许访问 PHP-FPM pod,而 Nginx 服务将允许访问 Nginx pod。

由于 Nginx pod 将代理 PHP-FPM pod,因此您需要告诉服务如何找到它们。 您将利用 Kubernetes 的自动服务发现来使用人类可读的名称将请求路由到适当的服务,而不是使用 IP 地址。

要创建服务,您将创建一个对象定义文件。 每个 Kubernetes 对象定义都是一个 YAML 文件,其中至少包含以下各项:

  • apiVersion:定义所属的Kubernetes API版本。
  • kind:这个文件代表的 Kubernetes 对象。 例如,podservice
  • metadata:这包含对象的 name 以及您可能希望应用于它的任何 labels
  • spec:这包含一个特定的配置,具体取决于您正在创建的对象的类型,例如容器映像或可访问容器的端口。

首先,您将创建一个目录来保存您的 Kubernetes 对象定义。

SSH 到您的 主节点 并创建 definitions 目录来保存您的 Kubernetes 对象定义。

mkdir definitions

导航到新创建的 definitions 目录:

cd definitions

通过创建 php_service.yaml 文件来创建您的 PHP-FPM 服务:

nano php_service.yaml

kind 设置为 Service 以指定此对象是服务:

php_service.yaml

...
apiVersion: v1
kind: Service

将服务命名为 php,因为它将提供对 PHP-FPM 的访问:

php_service.yaml

...
metadata:
  name: php

您将使用标签对不同的对象进行逻辑分组。 在本教程中,您将使用标签将对象分组为“层”,例如前端或后端。 PHP pod 将在此服务之后运行,因此您将其标记为 tier: backend

php_service.yaml

...
  labels:
    tier: backend

服务通过使用 selector 标签来确定要访问的 pod。 匹配这些标签的 pod 将被服务,与该 pod 是在服务之前还是之后创建的无关。 您将在本教程的后面部分为您的 pod 添加标签。

使用 tier: backend 标签将 pod 分配到后端层。 您还将添加 app: php 标签以指定此 pod 运行 PHP。 在 metadata 部分之后添加这两个标签。

php_service.yaml

...
spec:
  selector:
    app: php
    tier: backend

接下来,指定用于访问此服务的端口。 您将在本教程中使用端口 9000。 将其添加到 spec 下的 php_service.yaml 文件中:

php_service.yaml

...
  ports:
    - protocol: TCP
      port: 9000

您完成的 php_service.yaml 文件将如下所示:

php_service.yaml

apiVersion: v1
kind: Service
metadata:
  name: php
  labels:
    tier: backend
spec:
  selector:
    app: php
    tier: backend
  ports:
  - protocol: TCP
    port: 9000

点击 CTRL + o 保存文件,然后点击 CTRL + x 退出 nano

现在您已经为您的服务创建了对象定义,要运行该服务,您将使用 kubectl apply 命令和 -f 参数并指定您的 php_service.yaml 文件。

创建您的服务:

kubectl apply -f php_service.yaml

此输出确认服务创建:

Outputservice/php created

验证您的服务是否正在运行:

kubectl get svc

您将看到您的 PHP-FPM 服务正在运行:

OutputNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    10m
php          ClusterIP   10.100.59.238   <none>        9000/TCP   5m

Kubernetes 支持多种 服务类型。 您的 php 服务使用默认服务类型 ClusterIP。 此服务类型分配一个内部 IP,并使该服务只能从集群内访问。

现在 PHP-FPM 服务已准备就绪,您将创建 Nginx 服务。 使用编辑器创建并打开一个名为 nginx_service.yaml 的新文件:

nano nginx_service.yaml

此服务将针对 Nginx pod,因此您将其命名为 nginx。 您还将添加一个 tier: backend 标签,因为它属于后端层:

nginx_service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    tier: backend

php 服务类似,使用选择器标签 app: nginxtier: backend 定位 pod。 使该服务可在端口 80(默认 HTTP 端口)上访问。

nginx_service.yaml

...
spec:
  selector:
    app: nginx
    tier: backend
  ports:
  - protocol: TCP
    port: 80

Nginx 服务将从您的 Droplet 的公共 IP 地址公开访问互联网。 your_public_ip 可以在您的 DigitalOcean Cloud Panel 中找到。 在 spec.externalIPs 下,添加:

nginx_service.yaml

...
spec:
  externalIPs:
  - your_public_ip

您的 nginx_service.yaml 文件将如下所示:

nginx_service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    tier: backend
spec:
  selector:
    app: nginx
    tier: backend
  ports:
  - protocol: TCP
    port: 80
  externalIPs:
  - your_public_ip    

保存并关闭文件。 创建 Nginx 服务:

kubectl apply -f nginx_service.yaml

服务运行时,您将看到以下输出:

Outputservice/nginx created

您可以通过执行以下命令查看所有正在运行的服务:

kubectl get svc

您将看到输出中列出的 PHP-FPM 和 Nginx 服务:

OutputNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    13m
nginx        ClusterIP   10.102.160.47   your_public_ip 80/TCP     50s
php          ClusterIP   10.100.59.238   <none>        9000/TCP   8m

请注意,如果要删除服务,可以运行:

kubectl delete svc/service_name

现在您已经创建了 PHP-FPM 和 Nginx 服务,您需要指定存储应用程序代码和配置文件的位置。

第 2 步 — 安装 DigitalOcean 存储插件

Kubernetes 提供了不同的存储插件,可以为您的环境创建存储空间。 在此步骤中,您将安装 DigitalOcean 存储插件 以在 DigitalOcean 上创建 块存储。 安装完成后,它将添加一个名为 do-block-storage 的存储类,您将使用它来创建块存储。

您将首先配置一个 Kubernetes Secret 对象来存储您的 DigitalOcean API 令牌。 Secret 对象用于与同一命名空间中的其他 Kubernetes 对象共享敏感信息,例如 SSH 密钥和密码。 命名空间提供了一种在逻辑上分离 Kubernetes 对象的方法。

使用编辑器打开一个名为 secret.yaml 的文件:

nano secret.yaml

您将命名您的秘密对象 digitalocean 并将其添加到 kube-system namespacekube-system 命名空间是 Kubernetes 内部服务的默认命名空间,也被 DigitalOcean 存储插件用来启动各种组件。

秘密.yaml

apiVersion: v1
kind: Secret
metadata:
  name: digitalocean
  namespace: kube-system

Secret 使用 datastringData 密钥来保存所需信息,而不是 spec 密钥。 data 参数保存在检索时自动解码的 base64 编码数据。 stringData 参数保存非编码数据,在创建或更新时自动编码,检索 Secret 时不输出数据。 为方便起见,您将在本教程中使用 stringData

access-token 添加为 stringData

秘密.yaml

...
stringData:
  access-token: your-api-token

保存并退出文件。

您的 secret.yaml 文件将如下所示:

秘密.yaml

apiVersion: v1
kind: Secret
metadata:
  name: digitalocean
  namespace: kube-system
stringData:
  access-token: your-api-token

创建秘密:

kubectl apply -f secret.yaml

创建 Secret 后,您将看到以下输出:

Outputsecret/digitalocean created

您可以使用以下命令查看密钥:

kubectl -n kube-system get secret digitalocean

输出将类似于以下内容:

OutputNAME           TYPE      DATA      AGE
digitalocean   Opaque    1         41s

Opaque 类型表示这个 Secret 是只读的,这是 stringData Secrets 的标准。 您可以在 秘密设计规范 上阅读更多相关信息。 DATA 字段显示存储在此 Secret 中的项目数。 在这种情况下,它显示 1 因为您存储了一个密钥。

现在你的 Secret 已经就位,安装 DigitalOcean 块存储插件

kubectl apply -f https://raw.githubusercontent.com/digitalocean/csi-digitalocean/master/deploy/kubernetes/releases/csi-digitalocean-v0.3.0.yaml

您将看到类似于以下内容的输出:

Outputstorageclass.storage.k8s.io/do-block-storage created
serviceaccount/csi-attacher created
clusterrole.rbac.authorization.k8s.io/external-attacher-runner created
clusterrolebinding.rbac.authorization.k8s.io/csi-attacher-role created
service/csi-attacher-doplug-in created
statefulset.apps/csi-attacher-doplug-in created
serviceaccount/csi-provisioner created
clusterrole.rbac.authorization.k8s.io/external-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/csi-provisioner-role created
service/csi-provisioner-doplug-in created
statefulset.apps/csi-provisioner-doplug-in created
serviceaccount/csi-doplug-in created
clusterrole.rbac.authorization.k8s.io/csi-doplug-in created
clusterrolebinding.rbac.authorization.k8s.io/csi-doplug-in created
daemonset.apps/csi-doplug-in created

现在您已经安装了 DigitalOcean 存储插件,您可以创建块存储来保存您的应用程序代码和配置文件。

第 3 步 — 创建持久卷

准备好 Secret 并安装块存储插件后,您现在可以创建 Persistent Volume。 持久卷或 PV 是指定大小的块存储,独立于 pod 的生命周期而存在。 使用持久卷将允许您管理或更新您的 pod,而不必担心丢失您的应用程序代码。 通过使用 PersistentVolumeClaim 或 PVC 访问持久卷,它将 PV 安装在所需的路径上。

使用编辑器打开一个名为 code_volume.yaml 的文件:

nano code_volume.yaml

通过将以下参数和值添加到文件中来命名 PVC code

code_volume.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: code

PVC 的 spec 包含以下项目:

  • accessModes 因用例而异。 它们是:
  • resources – 您需要的存储空间

DigitalOcean 块存储仅挂载到单个节点,因此您将 accessModes 设置为 ReadWriteOnce。 本教程将指导您添加少量应用程序代码,因此在此用例中 1GB 就足够了。 如果您计划在卷上存储大量代码或数据,您可以修改 storage 参数以满足您的要求。 您可以在创建卷后增加存储量,但不支持收缩磁盘。

code_volume.yaml

...
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

接下来,指定 Kubernetes 将用于配置卷的存储类。 您将使用由 DigitalOcean 块存储插件创建的 do-block-storage 类。

code_volume.yaml

...
  storageClassName: do-block-storage

您的 code_volume.yaml 文件将如下所示:

code_volume.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: code
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: do-block-storage

保存并退出文件。

使用 kubectl 创建 code PersistentVolumeClaim:

kubectl apply -f code_volume.yaml

以下输出告诉您对象已成功创建,您已准备好将 1GB PVC 挂载为卷。

Outputpersistentvolumeclaim/code created

要查看可用的持久卷 (PV):

kubectl get pv

您将看到列出的 PV:

OutputNAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM          STORAGECLASS       REASON    AGE
pvc-ca4df10f-ab8c-11e8-b89d-12331aa95b13   1Gi        RWO            Delete           Bound     default/code   do-block-storage             2m

上面的字段是您的配置文件的概述,除了 Reclaim PolicyStatusReclaim Policy 定义了在访问它的 PVC 被删除后对 PV 所做的事情。 Delete 从 Kubernetes 以及 DigitalOcean 基础设施中删除 PV。 您可以从 Kubernetes PV 文档 中了解有关 Reclaim PolicyStatus 的更多信息。

您已使用 DigitalOcean 块存储插件成功创建了持久卷。 现在您的 Persistent Volume 已准备就绪,您将使用 Deployment 创建您的 pod。

第 4 步 — 创建 PHP-FPM 部署

在此步骤中,您将学习如何使用 Deployment 创建 PHP-FPM pod。 部署提供了一种使用 ReplicaSets 创建、更新和管理 pod 的统一方法。 如果更新没有按预期工作,部署将自动将其 pod 回滚到以前的映像。

Deployment spec.selector 键将列出它将管理的 Pod 的标签。 它还将使用 template 键来创建所需的 pod。

这一步还将介绍Init Containers的使用。 Init Containers 在 pod 的 template 键下指定的常规容器之前运行一个或多个命令。 在本教程中,您的 Init 容器将使用 wgetGitHub Gist 获取示例 index.php 文件。 这些是示例文件的内容:

索引.php

<?php
echo phpinfo(); 

要创建部署,请使用编辑器打开一个名为 php_deployment.yaml 的新文件:

nano php_deployment.yaml

此部署将管理您的 PHP-FPM pod,因此您将部署对象命名为 php。 Pod 属于后端层,因此您将使用 tier: backend 标签将 Deployment 分组到该组中:

php_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php
  labels:
    tier: backend

对于 Deployment spec,您将使用 replicas 参数指定要创建多少个此 Pod 的副本。 replicas 的数量将根据您的需求和可用资源而有所不同。 您将在本教程中创建一个副本:

php_deployment.yaml

...
spec:
  replicas: 1

此 Deployment 将管理与 app: phptier: backend 标签匹配的 pod。 在 selector 键下添加:

php_deployment.yaml

...
  selector:
    matchLabels:
      app: php
      tier: backend

接下来,部署 spec 需要 template 用于您的 pod 对象定义。 该模板将定义创建 pod 的规范。 首先,您将添加为 php 服务 selectors 和部署的 matchLabels 指定的标签。 在template.metadata.labels下添加app: phptier: backend

php_deployment.yaml

...
  template:
    metadata:
      labels:
        app: php
        tier: backend

一个 pod 可以有多个容器和卷,但每个都需要一个名称。 您可以通过为每个卷指定挂载路径来选择性地将卷挂载到容器。

首先,指定容器将访问的卷。 您创建了一个名为 code 的 PVC 来保存您的应用程序代码,因此也将此卷命名为 code。 在 spec.template.spec.volumes 下,添加以下内容:

php_deployment.yaml

...
    spec:
      volumes:
      - name: code
        persistentVolumeClaim:
          claimName: code

接下来,指定要在此 pod 中运行的容器。 您可以在 Docker 商店 上找到各种镜像,但在本教程中,您将使用 php:7-fpm 镜像。

spec.template.spec.containers 下,添加以下内容:

php_deployment.yaml

...
      containers:
      - name: php
        image: php:7-fpm

接下来,您将挂载容器需要访问的卷。 此容器将运行您的 PHP 代码,因此它需要访问 code 卷。 您还将使用 mountPath 指定 /code 作为安装点。

spec.template.spec.containers.volumeMounts 下,添加:

php_deployment.yaml

...
        volumeMounts:
        - name: code
          mountPath: /code

现在您已经挂载了您的卷,您需要在该卷上获取您的应用程序代码。 您之前可能使用过 FTP/SFTP 或通过 SSH 连接克隆代码来完成此操作,但此步骤将向您展示如何使用 Init Container 复制代码。

根据设置过程的复杂程度,您可以使用单个 initContainer 来运行构建应用程序的脚本,也可以为每个命令使用一个 initContainer。 确保卷已安装到 initContainer

在本教程中,您将使用带有 busybox 的单个 Init Container 来下载代码。 busybox 是一个包含 wget 实用程序的小图像,您将使用它来完成此操作。

spec.template.spec 下,添加您的 initContainer 并指定 busybox 图像:

php_deployment.yaml

...
      initContainers:
      - name: install
        image: busybox

您的 Init Container 需要访问 code 卷,以便它可以下载该位置的代码。 在 spec.template.spec.initContainers 下,将卷 code 挂载到 /code 路径:

php_deployment.yaml

...
        volumeMounts:
        - name: code
          mountPath: /code

每个 Init Container 都需要运行一个 command。 您的 Init Container 将使用 wgetGithub 下载 代码/code 工作目录。 -O 选项为下载的文件命名,您将把这个文件命名为 index.php

注意: 一定要相信你提取的代码。 在将其拉到您的服务器之前,请检查源代码以确保您对代码的作用感到满意。


spec.template.spec.initContainers 中的 install 容器下,添加以下行:

php_deployment.yaml

...
        command:
        - wget
        - "-O"
        - "/code/index.php"
        - https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php

您完成的 php_deployment.yaml 文件将如下所示:

php_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php
  labels:
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php
      tier: backend
  template:
    metadata:
      labels:
        app: php
        tier: backend
    spec:
      volumes:
      - name: code
        persistentVolumeClaim:
          claimName: code
      containers:
      - name: php
        image: php:7-fpm
        volumeMounts:
        - name: code
          mountPath: /code
      initContainers:
      - name: install
        image: busybox
        volumeMounts:
        - name: code
          mountPath: /code
        command:
        - wget
        - "-O"
        - "/code/index.php"
        - https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php

保存文件并退出编辑器。

使用 kubectl 创建 PHP-FPM 部署:

kubectl apply -f php_deployment.yaml

创建部署后,您将看到以下输出:

Outputdeployment.apps/php created

总而言之,这个部署将从下载指定的镜像开始。 然后它将从您的 PersistentVolumeClaim 请求 PersistentVolume 并串行运行您的 initContainers。 完成后,容器将运行并将 volumes 挂载到指定的挂载点。 完成所有这些步骤后,您的 pod 将启动并运行。

您可以通过运行以下命令查看您的部署:

kubectl get deployments

您将看到输出:

OutputNAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
php       1         1         1            0           19s

此输出可以帮助您了解部署的当前状态。 Deployment控制器 中的一个,它保持所需状态。 您创建的 template 指定 DESIRED 状态将有名为 php 的 pod 的 1 个 replicasCURRENT 字段表示有多少副本正在运行,因此这应该与 DESIRED 状态相匹配。 您可以在 Kubernetes 部署文档 中阅读有关其余字段的信息。

您可以使用以下命令查看此 Deployment 启动的 pod:

kubectl get pods

此命令的输出取决于自创建部署以来经过的时间。 如果您在创建后不久运行它,输出可能如下所示:

OutputNAME                   READY     STATUS     RESTARTS   AGE
php-86d59fd666-bf8zd   0/1       Init:0/1   0          9s

这些列代表以下信息:

  • Ready:运行此 pod 的 replicas 的数量。
  • Status:pod 的状态。 Init 表示 Init Containers 正在运行。 在此输出中,1 个 Init 容器中有 0 个已完成运行。
  • Restarts:这个进程重启了多少次来启动 pod。 如果您的任何 Init 容器发生故障,此数字将增加。 部署将重新启动它,直到它达到所需的状态。

根据启动脚本的复杂程度,状态可能需要几分钟才能更改为 podInitializing

OutputNAME                   READY     STATUS            RESTARTS   AGE
php-86d59fd666-lkwgn   0/1       podInitializing   0          39s

这意味着 Init Containers 已经完成并且容器正在初始化。 如果在所有容器都在运行时运行该命令,您将看到 pod 状态更改为 Running

OutputNAME                   READY     STATUS            RESTARTS   AGE
php-86d59fd666-lkwgn   1/1       Running   0          1m

您现在看到您的 pod 正在成功运行。 如果您的 pod 没有启动,您可以使用以下命令进行调试:

  • 查看一个pod的详细信息:
kubectl describe pods pod-name
  • 查看 pod 生成的日志:
kubectl logs pod-name
  • 查看 pod 中特定容器的日志:
kubectl logs pod-name container-name

您的应用程序代码已挂载,PHP-FPM 服务现在已准备好处理连接。 您现在可以创建 Nginx 部署。

第 5 步 — 创建 Nginx 部署

在这一步中,您将使用 ConfigMap 来配置 Nginx。 ConfigMap 以键值格式保存您的配置,您可以在其他 Kubernetes 对象定义中引用该格式。 如果需要,这种方法将使您能够灵活地重用图像或使用不同的 Nginx 版本交换图像。 更新 ConfigMap 会自动将更改复制到任何挂载它的 pod。

使用编辑器为您的 ConfigMap 创建一个 nginx_configMap.yaml 文件:

nano nginx_configMap.yaml

将 ConfigMap 命名为 nginx-config 并将其分组到 tier: backend 微服务中:

nginx_configMap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  labels:
    tier: backend

接下来,您将为 ConfigMap 添加 data。 将键命名为 config 并将 Nginx 配置文件的内容添加为值。 您可以使用 本教程 中的示例 Nginx 配置。

因为 Kubernetes 可以将请求路由到服务的适当主机,所以您可以在 fastcgi_pass 参数中输入 PHP-FPM 服务的名称,而不是其 IP 地址。 将以下内容添加到您的 nginx_configMap.yaml 文件中:

nginx_configMap.yaml

...
data:
  config : |
    server {
      index index.php index.html;
      error_log  /var/log/nginx/error.log;
      access_log /var/log/nginx/access.log;
      root ^/code^;

      location / {
          try_files $uri $uri/ /index.php?$query_string;
      }

      location ~ \.php$ {
          try_files $uri =404;
          fastcgi_split_path_info ^(.+\.php)(/.+)$;
          fastcgi_pass php:9000;
          fastcgi_index index.php;
          include fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }

您的 nginx_configMap.yaml 文件将如下所示:

nginx_configMap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  labels:
    tier: backend
data:
  config : |
    server {
      index index.php index.html;
      error_log  /var/log/nginx/error.log;
      access_log /var/log/nginx/access.log;
      root /code;
      
      location / {
          try_files $uri $uri/ /index.php?$query_string;
      }

      location ~ \.php$ {
          try_files $uri =404;
          fastcgi_split_path_info ^(.+\.php)(/.+)$;
          fastcgi_pass php:9000;
          fastcgi_index index.php;
          include fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }

保存文件并退出编辑器。

创建 ConfigMap:

kubectl apply -f nginx_configMap.yaml

您将看到以下输出:

Outputconfigmap/nginx-config created

您已经完成了 ConfigMap 的创建,现在可以构建您的 Nginx 部署。

首先在编辑器中打开一个新的 nginx_deployment.yaml 文件:

nano nginx_deployment.yaml

将部署命名为 nginx 并添加标签 tier: backend

nginx_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    tier: backend

在部署 spec 中指定您想要一个 replicas。 此 Deployment 将管理标签为 app: nginxtier: backend 的 Pod。 添加以下参数和值:

nginx_deployment.yaml

...
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      tier: backend

接下来,添加吊舱 template。 您需要使用为部署 selector.matchLabels 添加的相同标签。 添加以下内容:

nginx_deployment.yaml

...
  template:
    metadata:
      labels:
        app: nginx
        tier: backend

让 Nginx 访问您之前创建的 code PVC。 在 spec.template.spec.volumes 下,添加:

nginx_deployment.yaml

...
    spec:
      volumes:
      - name: code
        persistentVolumeClaim:
          claimName: code

Pod 可以将 ConfigMap 挂载为卷。 指定文件名和键将创建一个文件,其值作为内容。 要使用 ConfigMap,请将 path 设置为将保存 key 内容的文件的名称。 您想从键 config 创建一个文件 site.conf。 在 spec.template.spec.volumes 下,添加以下内容:

nginx_deployment.yaml

...
      - name: config
        configMap:
          name: nginx-config
          items:
          - key: config
            path: site.conf

Warning:如果没有指定文件,key的内容将替换卷的mountPath。 这意味着如果没有明确指定路径,您将丢失目标文件夹中的所有内容。


接下来,您将指定要从中创建 pod 的映像。 本教程将使用 nginx:1.7.9 镜像来保证稳定性,但您可以在 Docker 商店 上找到其他 Nginx 镜像。 另外,使 Nginx 在端口 80 上可用。 在 spec.template.spec 下添加:

nginx_deployment.yaml

...
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Nginx 和 PHP-FPM 需要访问同一路径下的文件,因此将 code 卷挂载到 /code

nginx_deployment.yaml

...
        volumeMounts:
        - name: code
          mountPath: /code

nginx:1.7.9镜像会自动加载/etc/nginx/conf.d目录下的所有配置文件。 在此目录中挂载 config 卷将创建文件 /etc/nginx/conf.d/site.conf。 在 volumeMounts 下添加以下内容:

nginx_deployment.yaml

...
        - name: config
          mountPath: /etc/nginx/conf.d

您的 nginx_deployment.yaml 文件将如下所示:

nginx_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      tier: backend
  template:
    metadata:
      labels:
        app: nginx
        tier: backend
    spec:
      volumes:
      - name: code
        persistentVolumeClaim:
          claimName: code
      - name: config
        configMap:
          name: nginx-config
          items:
          - key: config
            path: site.conf
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        volumeMounts:
        - name: code
          mountPath: /code
        - name: config
          mountPath: /etc/nginx/conf.d

保存文件并退出编辑器。

创建 Nginx 部署:

kubectl apply -f nginx_deployment.yaml

以下输出表明您的部署现已创建:

Outputdeployment.apps/nginx created

使用以下命令列出您的部署:

kubectl get deployments

您将看到 Nginx 和 PHP-FPM 部署:

OutputNAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     1         1         1            0           16s
php       1         1         1            1           7m

列出两个 Deployment 管理的 pod:

kubectl get pods

您将看到正在运行的 pod:

OutputNAME                     READY     STATUS    RESTARTS   AGE
nginx-7bf5476b6f-zppml   1/1       Running   0          32s
php-86d59fd666-lkwgn     1/1       Running   0          7m

现在所有 Kubernetes 对象都处于活动状态,您可以在浏览器上访问 Nginx 服务。

列出正在运行的服务:

kubectl get services -o wide

获取 Nginx 服务的外部 IP:

OutputNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE       SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    39m       <none>
nginx        ClusterIP   10.102.160.47   your_public_ip 80/TCP     27m       app=nginx,tier=backend
php          ClusterIP   10.100.59.238   <none>        9000/TCP   34m       app=php,tier=backend

在您的浏览器上,通过输入 http://your_public_ip 访问您的服务器。 您将看到 php_info() 的输出,并确认您的 Kubernetes 服务已启动并正在运行。

结论

在本指南中,您将 PHP-FPM 和 Nginx 服务容器化,以便您可以独立管理它们。 这种方法不仅可以随着您的成长提高项目的可扩展性,还可以让您有效地使用资源。 您还将应用程序代码存储在一个卷上,以便您将来可以轻松地更新您的服务。