如何在Ubuntu 18.04上使用Kubernetes部署PHP应用程序

Kubernetes是一个开源容器编排系统。它允许您创建,更新和扩展容器,而无需担心停机时间。在本教程中,您将在Kubernetes集群上部署PHP 7应用程序,其中Nginx和PHP-FPM在不同的容器中运行。

作者选择电子前沿基金会作为Write for DOnations计划的一部分接受捐赠。

介绍

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

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

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

先决条件

第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到主节点并创建将保存Kubernetes对象定义的definitions目录。

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

此输出确认服务创建:

service/php created

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

kubectl get svc

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

NAME         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控制面板中找到 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

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

service/nginx created

您可以通过执行以下命令查看所有运行

kubectl get svc

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

NAME         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令牌。 秘密对象用于与同一名称空间内的其他Kubernetes对象共享敏感信息,如SSH密钥和密码。 命名空间提供了一种逻辑分隔Kubernetes对象的方法。

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

nano secret.yaml

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

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

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

access-token添加为stringData

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

保存并退出该文件。

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

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

创建秘密:

kubectl apply -f secret.yaml

秘密创建时你会看到这个输出:

secret/digitalocean created

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

kubectl -n kube-system get secret digitalocean

输出看起来类似于:

NAME           TYPE      DATA      AGE
digitalocean   Opaque    1         41s

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

现在您的秘密就位,安装DigitalOcean块存储插件

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

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

csidriver.storage.k8s.io/dobs.csi.digitalocean.com created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io created
storageclass.storage.k8s.io/do-block-storage created
statefulset.apps/csi-do-controller created
serviceaccount/csi-do-controller-sa created
clusterrole.rbac.authorization.k8s.io/csi-do-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/csi-do-provisioner-binding created
clusterrole.rbac.authorization.k8s.io/csi-do-attacher-role created
clusterrolebinding.rbac.authorization.k8s.io/csi-do-attacher-binding created
clusterrole.rbac.authorization.k8s.io/csi-do-snapshotter-role created
clusterrolebinding.rbac.authorization.k8s.io/csi-do-snapshotter-binding created
daemonset.apps/csi-do-node created
serviceaccount/csi-do-node-sa created
clusterrole.rbac.authorization.k8s.io/csi-do-node-driver-registrar-role created
clusterrolebinding.rbac.authorization.k8s.io/csi-do-node-driver-registrar-binding created
error: unable to recognize "https://raw.githubusercontent.com/digitalocean/csi-digitalocean/master/deploy/kubernetes/releases/csi-digitalocean-v1.1.0.yaml": no matches for kind "VolumeSnapshotClass" in version "snapshot.storage.k8s.io/v1alpha1"

对于本教程,可以安全地忽略错误。

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

第3步 - 创建持久卷

在安装了Secret并安装了块存储插件后,您现在可以创建持久卷 永久卷(PV)是指定大小的块存储,独立于pod的生命周期。 使用永久卷可以让您管理或更新您的pod,而无需担心丢失应用程序代码。 通过使用PersistentVolumeClaim或PVC访问持久卷,该PVC将PV安装在所需的路径上。

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

nano code_volume.yaml

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

code_volume.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: code

PVC的spec包含以下项目:

  • accessModes因用例而异。 这些是:
    • ReadWriteOnce - 将卷安装为单个节点的读写
    • ReadOnlyMany - 将卷安装为许多节点的只读
    • ReadWriteMany - 将卷安装为许多节点的读写
  • 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 PVC:

kubectl apply -f code_volume.yaml

以下输出告诉您该对象已成功创建,并且您已准备好将1GB PVC安装为卷。

persistentvolumeclaim/code created

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

kubectl get pv

您将看到列出的PV:

NAME                                       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 PolicyStatus除外。 Reclaim Policy定义在删除PVC访问后对PV执行的操作。 Delete将从Kubernetes以及DigitalOcean基础架构中删除PV。 您可以从Kubernetes PV文档中了解有关Reclaim PolicyStatus更多信息

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

第4步 - 创建PHP-FPM部署

在此步骤中,您将学习如何使用Deployment来创建PHP-FPM pod。 部署提供了使用ReplicaSet创建,更新和管理pod的统一方法。 如果更新无法按预期工作,则部署将自动将其pod回滚到上一个映像。

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

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

的index.php
<?php
echo phpinfo(); 

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

nano php_deployment.yaml

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

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

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

php_deployment.yaml
...
spec:
  replicas: 1

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

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

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

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

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

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

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

接下来,指定要在此窗格中运行的容器。 您可以在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容器复制代码。

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

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

spec.template.spec ,添加spec.template.spec并指定busybox图像:

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

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

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

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

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

spec.template.spec.initContainersinstall容器spec.template.spec.initContainers ,添加以下行:

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

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

deployment.apps/php created

总而言之,此部署将从下载指定的映像开始。 然后,它将从您的PersistentVolumeClaim请求PersistentVolumeClaim并连续运行您的initContainers 完成后,容器将运行并将volumes装入指定的装入点。 完成所有这些步骤后,您的pod将启动并运行。

您可以通过运行来查看部署:

kubectl get deployments

你会看到输出:

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

此输出可帮助您了解部署的当前状态。 Deployment是维持所需状态的控制器之一 您创建的template指定DESIRED状态将具有名为php的pod的1个replicas CURRENT字段指示正在运行的副本数量,因此这应该与DESIRED状态匹配。 您可以阅读Kubernetes Deployments文档中的其余字段。

您可以使用以下命令查看此部署启动的窗格:

kubectl get pods

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

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

列代表以下信息:

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

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

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

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

NAME                   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

您将看到以下输出:

configmap/nginx-config created

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

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

nano nginx_deployment.yaml

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

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

在部署spec指定您需要一个replicas 此部署将使用标签app: nginxtier: backend管理pod。 添加以下参数和值:

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

接下来,添加pod 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

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

接下来,您将指定要从中创建pod的图像。 本教程将使用nginx:1.7.9映像进行稳定性,但您可以在Docker存储上找到其他Nginx映像。 此外,在端口80上使Nginx可用。 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

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

deployment.apps/nginx created

使用以下命令列出部署:

kubectl get deployments

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

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

列出由两个部署管理的pod:

kubectl get pods

您将看到正在运行的pod:

NAME                     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:

NAME         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服务容器化,以便您可以独立管理它们。 这种方法不仅可以在您增长时提高项目的可扩展性,还可以让您有效地使用资源。 您还将应用程序代码存储在卷上,以便将来轻松更新服务。