返回博客

在 Ubuntu 18.04 的 Kubernetes 集群上部署 PHP 应用程序

在 Ubuntu 18.04 的 Kubernetes 集群上部署 PHP 应用程序

Kubernetes(也称为 k8s)是一个开源编排系统。它允许用户以最少的停机时间部署、扩展和管理容器化应用程序。在本教程中,您将学习如何部署一个 PHP 应用程序到 Kubernetes 集群上。

Nginx 作为代理指向 PHP-FPM ,同时运行 PHP 应用程序。在单个容器中管理这两个服务是一个困难的过程。Kubernetes 帮助我们在两个不同的容器中管理它们,并减少了麻烦。它还允许用户重用容器,而无需担心为每个新版本的 PHP/Nginx 构建其容器镜像。

您将在两个独立的容器中运行您的应用程序和代理服务。本教程还将深入介绍如何使用本地存储来创建 Persistent Volume (PV) 和 Persistent Volume Claim (PVC)。然后,您将使用此 PVC 将配置文件和代码保留在容器镜像之外。完成本教程后,您将能够将 Nginx 镜像重用于需要代理服务器的其他应用程序。您可以通过传递配置来实现这一点,而无需为此重新构建镜像。

Prerequisites

  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 对象的种类。例如:servicejobpod.
  3. metadata:对象的名称以及用户可能想要应用于此对象的不同 labels 都定义在此标签下。
  4. spec:此标签包含对象的规格说明,例如环境变量(ENV)、要使用的容器镜像、可访问容器服务的端口。
创建 PHP-FPM 服务

首先,您应该创建一个目录来保存您的 Kubernetes 对象定义。登录到您的主节点并创建一个名为 “definitions:”

将目录切换到 definitions 目录:

接下来,创建您的 PHP-FPM 服务文件,命名为 php_service.yaml 文件:

之后,在 apiVersionkind 中设置 php_fpm_service.yaml 文件:

将您的服务命名为 phpphp-fpm ,因为它将提供对您的 PHP-FPM 应用程序的访问:

将您的 php 服务标记为 tier: backend ,因为 PHP 应用程序将在此服务后运行:

服务使用 selector 标签来确定要访问哪些 Pod。任何与这些标签匹配的 Pod,无论该 Pod 是何时创建的,都会被提供服务。您将在本教程稍后学习如何向 Pod 添加标签。

包含 tier: backend 标签,该标签将您的 pod 分配到后端层,以及 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 支持各种 types of services。您的 php-fpm 服务使用默认的 ClusterIP service type。这种类型的服务会分配一个内部 IP,并使该服务仅能从 Kubernetes 集群内部访问。
创建 Nginx 服务

既然您的 PHP-FPM 服务已经准备就绪,现在是时候创建您的 Nginx 服务了。在编辑器中为该服务创建并打开一个新的 YAML 文件,命名为 nginx_service.yaml

将此服务命名为 nginx ,因为它将针对 Nginx pod。此服务也属于后端,因此您应该为其添加一个 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 来创建持久卷(Persistent Volume)。

创建本地存储

创建一个文件,例如 storageClass.yaml,在您的编辑器中:

将 kind 添加为 "storageClass",将 apiVersion 添加为 "storage.k8s.io/v1",如下所示:

将此 StorageClass 命名为 "my-local-storage",并添加 provisioner 和 volumeBindingMode,如下所示:

保存并退出文件,您最终的 storageClass.yaml 文件应该如下所示:

现在,通过运行 kubectl create 命令来创建 StorageClass,如下所示:

运行上述命令后,您应该会得到以下输出:

创建本地持久卷

创建本地存储后,您可以创建本地持久卷(Persistent Volume)。持久卷(也称为 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 到您的持久卷,如下所示:

Note: 确保此本地路径 (/mnt/disk/vol) 存在于您的 Kubernetes 集群节点上。

添加所有必需的字段后,您的 persistentVolume.yaml 文件应该像这样:

Note: 您必须使用机器的正确节点名称。在这种情况下,它是:“worker.”
准备本地卷

现在,我们需要在 “worker” 节点上准备一个本地卷,正如我们在 persistentVolume.yaml 文件中添加的那样。在您配置了 persistentVolume 的节点上运行以下命令。在这种情况下,它是 “worker” 节点:

Note: 确保您有足够的权限来创建目录并更改如上所示的权限。如果没有,请使用正确的用户运行命令。

在您的 persistentVolume.yaml 文件所在的主节点上运行以下命令:

您应该会得到以下输出:

由于您已成功创建本地存储和持久卷(Persistent Volume),您现在可以继续创建持久卷声明(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 集群将用于分配给卷的存储类。在此处将上一步中创建的 my-local-storage 存储类用于您的 storageClassName:

完成上述步骤后,您的 code_volume.yaml 文件应该像这样:

现在保存并退出文件。

创建 PVC

通过运行 kubectl apply 命令来创建 code PVC:

您应该会得到以下输出,表明该对象已成功创建,并准备好将您的 1GB PVC 挂载为卷:

您可以执行以下命令来检查可用的持久卷 (PV):

上述命令的输出应该如下所示:

除回收策略 (Reclaim Policy) 和状态 (Status) 外,上述所有字段都是配置文件的概述。回收策略定义了在删除访问 PV 的 PVC 后,PV 会发生什么。值 Delete 会将 PV 从 Kubernetes 集群以及存储基础设施中移除。您可以参考 Kubernetes PV 文档 以清楚地了解回收策略和状态。

由于您已成功使用本地存储创建了持久卷,现在可以使用 Deployment 创建 Pod 了。

第 4 步:为您的 PHP-FPM 应用程序创建 Deployment

此步骤将帮助您使用 Deployment 创建 PHP-FPM Pod。Deployment 使用 ReplicaSet 提供了一种创建、更新和管理 Pod 的稳定方法。Deployment 会自动将其 Pod 回滚到以前的镜像。

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

在此步骤中,我们还将介绍 Init 容器 的应用。Init 容器在 Pod 模板中指定的常规容器之前运行一些命令。在这里,Init 容器将使用 GitHub Gist (https://gist.github.com/) 来获取一个示例 index.php 文件。示例文件的内容为:

创建 PHP Deployment

在编辑器中打开一个名为 php_deployment.yaml 的新文件以创建您的 Deployment:

现在,将 Deployment 对象命名为 PHP,因为此 Deployment 将管理您的 PHP-FPM pod。添加标签 tier: backend,因为该 pod 将属于后端层:

使用 replica 参数,指定应创建的此 pod 的副本数量。副本数量可能会根据您的需求和可用资源而有所不同。在本教程中,您将仅创建 pod 的一个副本:

添加 app: phptier:backend 标签在 selector 键下,这表示此 Deployment 将管理与这两个标签匹配的 pod:

现在,您的 pod’s 对象定义需要在您的 Deployment spec 下有一个模板。此模板定义了创建 pod 所需的规范。首先,添加为 php 服务选择器和 Deployment 的 matchLabels 指定的标签。然后添加 app:phptier:backendtemplate.metadata.labels:

注意: 一个 pod 可以有多个容器或卷,每个容器或卷都需要一个不同的名称以便能够区分它们。您可以为每个卷指定一个挂载路径,以选择性地将该卷挂载到容器中。

首先,您需要指定容器将访问的所有卷。将此卷命名为 code,因为您之前创建了一个名为 code 的 PVC 来保存您的应用程序代码:

接下来,指定容器名称以及您要在 pod 内运行的镜像。Docker 商店中有各种可用的镜像(https://hub.docker.com/explore/),但在本教程中,我们将使用 php:7-fpm 镜像:

现在,挂载容器需要访问的卷。由于此容器将运行您的 php 代码,它将需要访问在上一步中创建的 code 卷。在这一步中,您还将学习如何使用 Init 容器复制您的应用程序代码。

注意: 您可以使用单个 initContainer 来运行构建应用程序的脚本,也可以为每个命令使用一个 initContainer,具体取决于您设置过程的复杂程度。您需要确保将卷挂载到 initContainer。

为了下载代码,本教程将指导您如何使用带有 busybox 的单个 Init 容器。Busybox 是一个带有 wget 工具的小型容器,您将使用它来实现此目的。

首先,在 spec.template.spec 下添加您的 initContainer 并指定 busybox 镜像:

然后,为了在 code 卷中下载代码,您的 Init 容器将需要访问它。将卷 code 挂载到 /code 路径下,位于 spec.template.spec.initContainers:

每个 Init 容器都需要运行一个命令。此 Init 容器将使用 wget 从 code 下载 Github/code 目录中。您可以传递一个 -O 选项来为这个下载的文件命名,您可以将此文件命名为 index.php.

注意:确保您信任使用 Init 容器拉取到服务器中的代码。您可以检查源代码并确保您对其执行的操作感到放心。

此外,在 install 容器下添加以下行,位于 spec.template.spec.initContainers:

完成所有这些步骤后,您的 php_deployment.yaml 文件应该像这样:

您现在可以保存文件并退出。接下来,使用 kubectl apply 命令创建您的 PHP-FPM Deployment:

成功创建 Deployment 后,您应该会看到以下输出:

此 Deployment 首先会下载指定的镜像,然后它将从您的 PersistentVolume 请求 PersistentVolumeClaim,然后运行您的 initContainers。完成此步骤后,容器将运行并将卷挂载到指定的挂载点。完成所有这些步骤后,您的 pod 将启动并运行。

您可以运行以下命令来查看您的 Deployment:

运行上述命令后,您应该会得到以下输出:

您可以通过此输出了解 Deployment 的当前状态。Deployment 是一个维护期望状态的控制器。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 部署

本步骤将指导您如何使用 ConfigMap。一个 ConfigMap 以键值格式保存所有所需的配置,这些配置将在其他 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 键,我们将创建一个以其值作为内容的文件。要使用此 ConfigMap,请将路径设置为保存该键内容的文件名称。您可以从键 config 创建一个文件 site.conf。在 spec.template.spec.volumes 下添加以下内容:

警告:如果未指定文件,键的内容将替换卷的 mountPath。换句话说,如果未明确指定路径,您将丢失目标文件夹中的所有内容。

现在,指定您要在 pod 中使用的名称、镜像和端口。在这里,我们将使用 nginx:1.7.9 镜像和端口 80。将它们添加在以下位置下方:spec.template.spec 部分:

此外,将代码卷挂载到 /code,因为 Nginx 和 PHP-FPM 都需要访问相同路径下的文件:

The nginx-1.7.9 镜像会自动加载 /etc/nginx/conf.d 文件夹。现在,如果我们在此目录中挂载配置卷,它将创建 /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 的创意设计师,专注于通过传统和创新营销渠道打造一致的企业形象。他擅长将艺术愿景与战略营销相融合,创造具有影响力的品牌叙事。

评论

暂无评论。发表第一条评论吧。