How To Deploy a PHP Application with Kubernetes on Ubuntu 16.04

O autor selecionou a Open Internet/Free Speech para receber uma doação como parte do programa Write for DOnations.

Introdução

O Kubernetes é um sistema de orquestração de contêiner de código aberto. Ele permite que você crie, atualize e escale contêineres sem se preocupar com o tempo de inatividade.

Para executar um aplicativo PHP, o Nginx age como um proxy para o PHP-FPM. A transformação em contêiner dessa configuração em um único contêiner pode ser um processo complicado, mas o Kubernetes ajudará a gerenciar ambos os serviços em contêineres separados. Ao usar o Kubernetes, é permitido que você mantenha seus contêineres reutilizáveis e intercambiáveis, e não será necessário reconstruir sua imagem do contêiner sempre que houver uma nova versão do Nginx ou do PHP.

Neste tutorial, você implantará um aplicativo PHP 7 em um cluster do Kubernetes com o Nginx e o PHP-FPM funcionando em contêineres separados. Você também aprenderá como manter seus arquivos de configuração e código de aplicativo fora da imagem do contêiner usando o sistema de armazenamento de blocos da DigitalOcean. Esta abordagem permitirá a reutilização da imagem do Nginx para qualquer aplicativo que precise de um servidor Web/proxy passando um volume de configuração, ao invés de reconstruir a imagem.

Pré-requisitos

  • Um entendimento básico sobre objetos do Kubernetes. Verifique nosso artigo Introdução ao Kubernetes para obter mais informações.
  • Um cluster do Kubernetes funcionando no Ubuntu 16.04. Você pode configurar o cluster seguindo o tutorial Como criar um cluster do Kubernetes 1.10 usando o Kubeadm no Ubuntu 16.04.
  • Uma conta DigitalOcean e um token de acesso da API com permissões de leitura e escrita para criar nosso volume de armazenamento. Se não tiver seu token de acesso da API, é possível criá-lo a partir daqui.
  • Seu código do aplicativo hospedado em um URL acessível publicamente, como o Github.

Passo 1 — Criando os serviços PHP-FPM e Nginx

Neste passo, serão criados os serviços PHP-FPM e Nginx. Um serviço permite o acesso a um conjunto de pods de dentro do cluster. Os serviços dentro de um cluster podem se comunicar diretamente através dos seus nomes, sem a necessidade de endereços IP. O serviço PHP-FPM permitirá o acesso aos pods do PHP-FPM, enquanto o serviço Nginx permitirá o acesso aos pods do Nginx.

Como os pods do Nginx irão servir de proxy para os pods do PHP-FPM, será necessário dizer ao serviço como encontrá-los. Ao invés de usar endereços IP, você tirará proveito da descoberta automática do serviço do Kubernetes para usar nomes legíveis para rotear pedidos para o serviço apropriado.

Para criar o serviço, você criará um arquivo de definição de objeto. Cada definição de objeto do Kubernetes é um arquivo YAML que contém pelo menos os seguintes itens:

  • apiVersion: a versão da API do Kubernetes à qual a definição pertence.
  • kind: o objeto do Kubernetes que este arquivo representa. Por exemplo, um pod ou service.
  • metadata: contém o name do objeto junto com quaisquer labels que você queira aplicar a ele.
  • spec: contém uma configuração específica dependendo do tipo de objeto que está sendo criado, como a imagem do contêiner ou as portas das quais o contêiner será acessível.

Primeiro, você criará um diretório para manter suas definições de objeto do Kubernetes.

Pelo SSH vá até seu master node e crie o diretório definitions que irá manter suas definições de objeto do Kubernetes.

  • mkdir definitions

Navegue até o diretório recém-criado definitions:

  • cd definitions

Crie seu serviço PHP-FPM criando um arquivo php_service.yaml:

  • nano php_service.yaml

Defina kind como Service para especificar que este objeto é um serviço:

php_service.yaml

... apiVersion: v1 kind: Service 

Nomeie o serviço php, já que ele fornecerá acesso ao PHP-FPM:

php_service.yaml

... metadata:   name: php 

Você agrupará logicamente objetos diferentes com rótulos. Neste tutorial, você usará os rótulos para agrupar os objetos em “camadas”, como frontend ou backend. Os pods do PHP serão executados por trás deste serviço, então você dará o rótulo de tier: backend.

php_service.yaml

...   labels:     tier: backend 

Um serviço determina quais pods acessar usando os rótulos selector. Um pod que corresponda a esses rótulos será atendido, independentemente de se o pod tenha sido criado antes ou após o serviço. Você adicionará rótulos para seus pods mais tarde no tutorial.

Use o rótulo tier: backend para atribuir o pod à camada backend. Você também adicionará o rótulo app: php para especificar que este pod executa o PHP. Adicione esses dois rótulos após a seção metadata.

php_service.yaml

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

Em seguida, especifique a porta usada para acessar este serviço. A porta 9000 será usada neste tutorial. Adicione-a ao arquivo php_service.yaml em spec:

php_service.yaml

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

Seu arquivo final php_service.yaml se parecerá com isso:

php_service.yaml

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

Pressione CTRL + o para salvar o arquivo e, depois, CTRL + x para sair do nano.

Agora que criou a definição de objeto para seu serviço, para executar o serviço você usará o comando kubectl apply junto com o argumento -f e especificará seu arquivo php_service.yaml.

Crie seu serviço:

  • kubectl apply -f php_service.yaml

Este resultado confirma a criação do serviço:

Outputservice/php created 

Verifique se seu serviço está funcionando:

  • kubectl get svc

Você verá seu serviço PHP-FPM funcionando:

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 

Existem vários tipos de serviço que o Kubernetes suporta. Seu serviço php usa o tipo padrão de serviço, o ClusterIP. Este tipo de serviço atribui um IP interno e torna o serviço acessível apenas a partir de dentro do cluster.

Agora que o serviço PHP-FPM está pronto, você criará o serviço Nginx. Crie e abra um novo arquivo chamado nginx_service.yaml com o editor:

  • nano nginx_service.yaml

Este serviço irá atingir os pods do Nginx, então você irá chamá-lo de nginx. Um rótulo tier: backend também será adicionado, já que ele pertence à camada backend:

nginx_service.yaml

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

De forma similar ao serviço php, mire nos pods com os rótulos seletores app: nginx e tier: backend. Torne este serviço acessível na porta 80, a porta padrão HTTP.

nginx_service.yaml

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

O serviço Nginx estará acessível publicamente na Internet do endereço IP público do seu Droplet. O your_public_ip pode ser encontrado no seu painel na nuvem DigitalOcean. Em spec.externalIPs, adicione:

nginx_service.yaml

... spec:   externalIPs:   - your_public_ip 

Seu arquivo nginx_service.yaml se parecerá com isto:

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     

Salve e feche o arquivo. Crie o serviço Nginx:

  • kubectl apply -f nginx_service.yaml

Você verá o seguinte resultado quando o serviço estiver funcionando:

Outputservice/nginx created 

Você pode ver todos os serviços em funcionamento executando:

  • kubectl get svc

Você verá tanto os serviços PHP-FPM como os serviços Nginx listados no resultado:

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 

Note, se quiser excluir um serviço, execute:

  • kubectl delete svc/service_name

Agora que você criou seus serviços PHP-FPM e Nginx, será necessário especificar onde armazenar seu código de aplicativo e arquivos de configuração.

Passo 2 — Instalando o plug-in de armazenamento da DigitalOcean

O Kubernetes fornece plug-ins de armazenamento diferentes que podem criar o espaço de armazenamento para seu ambiente. Neste passo, será instalado o plug-in de armazenamento da DigitalOcean para criar o armazenamento de bloco na DigitalOcean. Assim que a instalação for concluída, será adicionada uma classe de armazenamento chamada do-block-storage que você usará para criar seu armazenamento de bloco.

Primeiro, você irá configurar um objeto segredo do Kubernetes para armazenar seu token de API da DigitalOcean. Os objetos segredo são usados para compartilhar informações sensíveis, como chaves SSH e senhas, com outros objetos do Kubernetes dentro do mesmo namespace. Os namespaces fornecem uma maneira de separar seus objetos do Kubernetes logicamente.

Abra um arquivo chamado secret.yaml com o editor:

  • nano secret.yaml

Você irá nomear seu segredo digitalocean e adicioná-lo ao namespace kube-system. O namespace kube-system é o nome padrão de namespace para serviços internos do Kubernetes e é usado também pelo plug-in de armazenamento da DigitalOcean para inicializar vários componentes.

secret.yaml

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

Ao invés de uma chave spec, um segredo usa uma chave data ou stringData para reter as informações necessárias. O parâmetro data retém os dados na base64 codificados que são automaticamente decodificados quando recuperados. O parâmetro stringData retém dados não codificados que são automaticamente codificados durante a criação ou atualizações e não gera os exibe os dados ao recuperar os segredos. Você usará o stringData neste tutorial por conveniência.

Adicione o access-token como stringData:

secret.yaml

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

Salve e saia do arquivo.

Seu arquivo secret.yaml se parecerá com isso:

secret.yaml

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

Crie o segredo:

  • kubectl apply -f secret.yaml

Você verá este resultado após a criação do segredo:

Outputsecret/digitalocean created 

Você pode ver o segredo com o seguinte comando:

  • kubectl -n kube-system get secret digitalocean

O resultado será semelhante a este:

OutputNAME           TYPE      DATA      AGE digitalocean   Opaque    1         41s 

O tipo Opaque significa que este segredo é apenas de leitura, que é o padrão para os segredos stringData. Você pode ler mais sobre isso nas Especificações de design do segredo. O campo DATA mostra o número de itens armazenados neste segredo. Neste caso, ele mostra 1 porque você tem uma única chave armazenada.

Agora que seu segredo está funcionando, instale o plug-in de armazenamento de bloco da DigitalOcean:

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

Você verá um resultado similar ao seguinte:

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 

Agora que você instalou o plug-in de armazenamento da DigitalOcean, é possível criar o armazenamento de bloco para reter seu código de aplicativo e arquivos de configuração.

Passo 3 — Criando o volume persistente

Com seu segredo funcionando e o plug-in de armazenamento de bloco instalado, você está pronto para criar seu Volume Persistente. Um Volume Persistente, ou PV, é o armazenamento de bloco de um tamanho específico que vive independentemente do ciclo de vida de um pod. Usar um Volume Persistente permitirá que você gerencie ou atualize seus pods sem se preocupar em perder o código do seu aplicativo. Um Volume Persistente é acessado usando um PersistentVolumeClaim, ou PVC, que monta o PV no caminho necessário.

Abra um arquivo chamado code_volume.yaml com seu editor:

  • nano code_volume.yaml

Nomeie o code do PVC adicionando os seguintes parâmetros e valores ao seu arquivo:

code_volume.yaml

apiVersion: v1 kind: PersistentVolumeClaim metadata:   name: code 

A spec para um PVC contém os seguintes itens:

  • accessModes que variam com o caso de uso. Esses são:
    • ReadWriteOnce — monta o volume como leitura-escrita por um único nó
    • ReadOnlyMany — monta o volume como apenas leitura por muitos nós
    • ReadWriteMany — monta o volume como leitura-escrita por muitos nós
  • resources — o espaço de armazenamento que você precisa

O armazenamento de bloco da DigitalOcean é montado apenas em um único nó, então você irá definir o accessModes para ReadWriteOnce. Este tutorial irá guiá-lo na adição de uma pequena quantidade de códigos do aplicativo, então 1GB de uso será o bastante neste caso. Se você planeja armazenar uma maior quantidade de código ou dados no volume, é possível modificar o parâmetro storage para satisfazer seus requisitos. Você pode aumentar a quantidade de armazenamento após a criação do volume, mas a redução do disco não é suportada.

code_volume.yaml

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

Em seguida, especifique a classe de armazenamento que o Kubernetes usará para fornecer os volumes. Você usará a classe do-block-storage criada pelo plug-in de armazenamento de bloco da DigitalOcean.

code_volume.yaml

...   storageClassName: do-block-storage 

Seu arquivo code_volume.yaml se parecerá com isto:

code_volume.yaml

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

Salve e saia do arquivo.

Crie o code PersistentVolumeClaim usando o kubectl:

  • kubectl apply -f code_volume.yaml

O resultado a seguir diz que o objeto foi criado com sucesso e você está pronto para montar seu PVC de 1GB como um volume.

Outputpersistentvolumeclaim/code created 

Para ver os Volumes Persistentes (PV) disponíveis:

  • kubectl get pv

Você verá seu PV listado:

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 

Os campos acima são uma visão geral do seu arquivo de configuração, exceto para o Reclaim Policy e Status. O Reclaim Policy define o que é feito com o PV após o acesso do PVC for deletado. O Delete remove o PV do Kubernetes assim como a infraestrutura da DigitalOcean. Você pode aprender mais sobre o Reclaim Policy e Status na documentação PV do Kubernetes.

Você criou um Volume Persistente usando o plug-in de armazenamento de bloco da DigitalOcean com sucesso. Agora que seu Volume Persistente está pronto, você criará seus pods usando uma implantação.

Passo 4 — Criando uma implantação do PHP-FPM

Neste passo, você aprenderá como usar uma implantação para criar seu pod PHP-FPM. Implantações fornecem uma maneira uniforme de criar, atualizar e gerenciar pods usando o ReplicaSets. Se uma atualização não funcionar como esperado, uma implantação irá mudar automaticamente seus pods para uma imagem anterior.

A chave da implantação spec.selector listará os rótulos dos pods que irá gerenciar. Ela também usará a chave template para criar os pods necessários.

Este passo também irá introduzir o uso dos contêineres de inicialização. Os Init Containers executam um ou mais comandos antes dos contêineres regulares especificados na chave template do pod. Neste tutorial, seu contêiner de inicialização trará um arquivo de amostra index.php do GitHub Gist usando o wget. Este é o conteúdo do arquivo de amostra:

index.php

<?php echo phpinfo(); 

Para criar sua implantação, abra um novo arquivo chamado php_deployment.yaml com seu editor:

  • nano php_deployment.yaml

Esta implantação irá gerenciar seus pods PHP-FPM. Assim, você irá nomear o objeto de implantação como php. Os pods pertencem à camada backend, então a implantação será agrupada neste grupo usando o rótulo tier: backend:

php_deployment.yaml

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

Para a spec da implantação, serão especificadas quantas cópias deste pod serão criadas usando o parâmetro replicas. O número de replicas irá variar dependendo das suas necessidades e recursos disponíveis. Você criará uma réplica neste tutorial:

php_deployment.yaml

... spec:   replicas: 1 

Esta implantação irá gerenciar pods que correspondam aos rótulos app: php e tier: backend. Sob a chave selector, adicione:

php_deployment.yaml

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

Em seguida, a spec da implantação exige o template para a definição de objeto do seu pod. Este modelo definirá as especificações para criação do pod. Primeiro, serão adicionados rótulos que foram especificados para os selectors de serviço php e os matchLabels da implantação. Adicione app: php e tier: backend em template.metadata.labels:

php_deployment.yaml

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

Um pod pode ter vários contêineres e volumes, mas cada um precisará de um nome. Você pode montar volumes de modo seletivo para um contêiner ao especificar um caminho de montagem para cada volume.

Primeiro, especifique os volumes que seus contêineres irão acessar. Você criou um PVC chamado code para reter seu código do aplicativo, então chame este volume de code também. Em spec.template.spec.volumes, adicione o seguinte:

php_deployment.yaml

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

Em seguida, especifique o contêiner que você quer executar neste pod. Você pode encontrar uma variedade de imagens na loja do Docker, mas neste tutorial você usará a imagem php:7-fpm.

Em spec.template.spec.containers, adicione o seguinte:

php_deployment.yaml

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

Em seguida, serão montados os volumes aos quais o contêiner exige acesso. Este contêiner executará seu código PHP, então ele precisará de acesso ao volume code. Você também usará o mountPath para especificar /code como o ponto de montagem.

Em spec.template.spec.containers.volumeMounts, adicione:

php_deployment.yaml

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

Agora que você montou seu volume, será necessário colocar seu código do aplicativo no volume. Você pode ter usado anteriormente o FTP/SFTP ou clonado o código em uma conexão via protocolo SSH para fazer isso, mas este passo irá mostrar como copiar o código usando um contêiner de inicialização.

Dependendo da complexidade do seu processo de configuração, você pode usar um único initContainer para executar um script que constrói seu aplicativo, ou usar um initContainer por comando. Certifique-se de que os volumes são montados no initContainer.

Neste tutorial, será usado um único contêiner de inicialização com o busybox para baixar o código. O busybox é uma pequena imagem que contém o utilitário wget que você usará para fazer isso.

Em spec.template.spec, adicione seu initContainer​​​ e especifique a imagem busybox:

php_deployment.yaml

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

Seu contêiner de inicialização precisará de acesso ao volume code para que ele possa baixar o código naquele local. Em spec.template.spec.initContainers, monte o volume code no caminho /code:

php_deployment.yaml

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

Cada contêiner de inicialização precisa executar um command. Seu contêiner de inicialização usará o wget para baixar o código do Github para o diretório de trabalho /code. A opção -O dá ao arquivo baixado um nome e você irá nomear este arquivo index.php.

Nota: Certifique-se de confiar no código que você está fazendo o pull. Antes de fazer o pull dele para seu servidor, inspecione o código fonte para garantir que você se sinta confortável com o que o código faz.

Sob o contêiner install em spec.template.spec.initContainers, adicione estas linhas:

php_deployment.yaml

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

Seu arquivo final php_deployment.yaml se parecerá com isso:

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 

Salve o arquivo e saia do editor.

Crie a implantação PHP-FPM com o kubectl:

  • kubectl apply -f php_deployment.yaml

Você verá o seguinte resultado após a criação da implantação:

Outputdeployment.apps/php created 

Para resumir, essa implantação irá começar baixando as imagens especificadas. Então, solicitará o PersistentVolume do seu PersistentVolumeClaim e executará seus initContainers​​​ em série. Assim que terminar, os contêiners executarão e montarão os volumes no ponto de montagem especificado. Assim que todos esses passos estiverem completos, seu pod estará em funcionamento.

Você pode ver sua implantação executando:

  • kubectl get deployments

Você verá o resultado:

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

Este resultado pode ajudar você a compreender o estado atual da implantação. Uma Deployment é um dos controladores que mantêm um estado desejado. O template que você criou especifica que o estado DESIRED terá 1 replicas do pod chamado php. O campo CURRENT indica quantas réplicas estão funcionando, e isso deve corresponder ao estado DESIRED. Você pode ler sobre os campos restantes na documentação de implantações do Kubernetes.

Você pode ver os pods que essa implantação iniciou com o seguinte comando:

  • kubectl get pods

O resultado deste comando varia dependendo de quanto tempo passou desde a criação da implantação. Se você executá-lo pouco após a criação, o resultado se parecerá com isso:

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

As colunas representam as seguintes informações:

  • Ready: o número de replicas que está funcionando neste pod.
  • Status: o status do pod. Init indica que os contêineres de inicialização estão em funcionamento. Neste resultado, 0 de 1 contêineres de inicialização terminaram de executar.
  • Restarts: quantas vezes este processo foi reiniciado para iniciar o pod. Este número aumentará se algum dos seus contêineres de inicialização falhar. A implantação irá reiniciar até chegar no estado desejado.

Dependendo da complexidade dos seus scripts de inicialização, pode levar alguns minutos para o status mudar para podInitializing:

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

Isso significa que os contêineres de inicialização finalizaram e os contêineres estão inicializando. Se você executar o comando quando todos os contêineres estiverem funcionando, verá a mudança de status do pod para Running.

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

Agora, seu pod está funcionando com sucesso. Se seu pod não iniciar, você pode depurá-lo com os comandos a seguir:

  • Ver informações detalhadas de um pod:
  • kubectl describe pods pod-name
  • Ver registros gerados por um pod:
  • kubectl logs pod-name
  • Ver registros para um contêiner específico em um pod:
  • kubectl logs pod-name container-name

Seu código do aplicativo está montado e o serviço PHP-FPM está agora pronto para lidar com conexões. Agora, você pode criar sua implantação do Nginx.

Passo 5 — Criando a implantação do Nginx

Neste passo, será usado um ConfigMap para configurar o Nginx. Um ConfigMap retém suas configurações em um formato de valor de chave que você pode referenciar em outras definições de objeto do Kubernetes. Esta abordagem dará a você a flexibilidade de reutilização ou de alternar a imagem com uma versão diferente do Nginx caso necessário. Ao atualizar o ConfigMap, serão replicadas automaticamente as alterações em qualquer pod montado nele.

Crie um arquivo nginx_configMap.yaml para seu ConfigMap com seu editor:

  • nano nginx_configMap.yaml

Nomeie o ConfigMap nginx-config e agrupe-o no micro serviço tier: backend:

nginx_configMap.yaml

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

Em seguida, adicione o data para o ConfigMap. Nomeie a chave config e adicione o conteúdo do seu arquivo de configuração do Nginx como o valor. Você pode usar a configuração exemplo do Nginx deste tutorial.

Como o Kubernetes pode rotear pedidos para o host apropriado para um serviço, você pode digitar o nome do seu serviço PHP-FPM no parâmetro fastcgi_pass ao invés de seu endereço IP. Adicione o seguinte ao seu arquivo 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;         }     } 

Seu arquivo nginx_configMap.yaml se parecerá com isto:

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;         }     } 

Salve o arquivo e saia do editor.

Crie o ConfigMap:

  • kubectl apply -f nginx_configMap.yaml

Você verá o seguinte resultado:

Outputconfigmap/nginx-config created 

Você terminou de criar seu ConfigMap e agora pode construir sua implantação do Nginx.

Inicie abrindo um novo arquivo nginx_deployment.yaml no editor:

  • nano nginx_deployment.yaml

Nomeie a implantação nginx e adicione o rótulo tier: backend:

nginx_deployment.yaml

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

Especifique que você quer uma replicas na spec da implantação. Esta implantação irá gerenciar pods com rótulos app: nginx e tier: backend. Adicione os parâmetros e valores a seguir:

nginx_deployment.yaml

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

Em seguida, adicione o pod template. Você precisa usar os mesmos rótulos que adicionou para o selector.matchLabels da implantação. Adicione o seguinte:

nginx_deployment.yaml

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

Forneça ao Nginx acesso ao code PVC que criou mais cedo. Em spec.template.spec.volumes, adicione:

nginx_deployment.yaml

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

Os pods podem montar um ConfigMap como um volume. Especificar um nome de arquivo e chave criará um arquivo com seu valor como conteúdo. Para usar o ConfigMap, defina path como nome do arquivo que irá reter o conteúdo da key. Você quer criar um arquivo site.conf a partir da config da chave. Em spec.template.spec.volumes, adicione o seguinte:

nginx_deployment.yaml

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

Aviso: Se um arquivo não for especificado, o conteúdo da key substituirá o mountPath do volume. Isso significa que se um caminho não for especificado explicitamente, você perderá todo o conteúdo na pasta de destino.

Em seguida, você irá especificar a imagem da qual irá criar seu pod. Este tutorial usará a imagem nginx:1.7.9 por motivos de estabilidade, mas você pode encontrar outras imagens do Nginx na loja do Docker. Além disso, torne o Nginx disponível na porta 80. Em spec.template.spec adicione:

nginx_deployment.yaml

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

O Nginx e o PHP-FPM precisam acessar o arquivo no mesmo caminho, então monte o volume code em /code:

nginx_deployment.yaml

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

A imagem nginx:1.7.9 irá carregar automaticamente quaisquer arquivos de configuração no diretório /etc/nginx/conf.d. Ao montar o volume config neste diretório, será criado o arquivo /etc/nginx/conf.d/site.conf. Em volumeMounts, adicione o seguinte:

nginx_deployment.yaml

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

Seu arquivo nginx_deployment.yaml se parecerá com isto:

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 

Salve o arquivo e saia do editor.

Crie a implantação Nginx:

  • kubectl apply -f nginx_deployment.yaml

O resultado a seguir indica que sua implantação foi criada:

Outputdeployment.apps/nginx created 

Liste suas implantações com este comando:

  • kubectl get deployments

Você verá as implantações do Nginx e do PHP-FPM:

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

Liste os pods gerenciados por ambas as implantações:

  • kubectl get pods

Você verá os pods que estão em funcionamento:

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

Agora que todos os objetos do Kubernetes estão ativos, é possível visitar o serviço Nginx no seu navegador.

Liste os serviços em execução:

  • kubectl get services -o wide

Obtenha o IP externo para seu serviço Nginx:

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 

No seu navegador, visite seu servidor digitando http://your_public_ip. Você verá o resultado do php_info() e terá confirmado que seus serviços do Kubernetes estão funcionando.

Conclusão

Neste guia, você transformou em contêiner os serviços PHP-FPM e Nginx para gerenciá-los independentemente. Esta abordagem não só irá melhorar a escalabilidade do seu projeto conforme for crescendo, como também permitirá que você use recursos de maneira eficiente. Você também armazenou seu código do aplicativo em um volume para que você possa atualizar facilmente seus serviços no futuro.