*O autor escolheu a Electronic Frontier Foundation para receber uma doação como parte do programa Write for DOnations.*

Introdução

O Kubernetes é um sistema open source de orquestração de container. Ele permite criar, atualizar e escalar containers sem se preocupar com o tempo de inatividade.

Para executar uma aplicação PHP, o Nginx atua como um proxy para o PHP-FPM. *Containerizar* essa configuração em um único container pode ser um processo complicado, mas o Kubernetes ajudará a gerenciar os dois serviços em containers separados. O uso do Kubernetes permitirá a você manter seus containers reutilizáveis e substituíveis, e você não precisará reconstruir sua imagem de container toda vez que houver uma nova versão do Nginx ou do PHP.

Neste tutorial, você fará o deploy de uma aplicação PHP 7 em um cluster Kubernetes com o Nginx e o PHP-FPM em execução em containers separados. Você também aprenderá como manter os seus arquivos de configuração e o código da aplicação fora da imagem do container usando o sistema de Block Storage da the cloud provider. Essa abordagem o permitirá reutilizar a imagem do Nginx para qualquer aplicação que precise de um servidor web/proxy passando um volume de configuração, em vez de reconstruir a imagem.

Pré-requisitos

php illustration for: Pré-requisitos
  • Uma conta na the cloud provider e um token de acesso à API com permissões de leitura e gravação para criar nosso volume de armazenamento. Se você não possui seu token de acesso à API, pode criá-lo a partir daqui.
  • O código de sua aplicação hospedado em uma URL acessível ao público, como o Github.

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

Neste passo, você criará 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 em um cluster podem se comunicar diretamente por meio de seus nomes, sem a necessidade de endereços IP. O serviço PHP-FPM permitirá acesso aos pods PHP-FPM, enquanto o serviço Nginx permitirá acesso aos pods Nginx.

Como os pods do Nginx farão proxy dos pods do PHP-FPM, você precisará informar ao serviço como encontrá-los. Em vez de usar endereços IP, você aproveitará a descoberta automática de serviços do Kubernetes para usar nomes legíveis por humanos para rotear solicitações para o serviço apropriado.

Para criar o serviço, você criará um arquivo de definição de objeto. Toda definição de objeto 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 Kubernetes que este arquivo representa. Por exemplo, um pod ou service.
  • metadata: Isso contém o nome do objeto, juntamente com quaisquer labels que você queira aplicar a ele.
  • spec: Isso contém uma configuração específica, dependendo do tipo de objeto que você está criando, como a imagem do container ou as portas nas quais o container estará acessível.

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

Faça SSH no seu node master e crie o diretório definitions que conterá as definições do objeto Kubernetes.

				
					
mkdir definitions

				
			

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

				
					
cd definitions

				
			

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

				
					
[label php_service.yaml]

apiVersion: v1

kind: Service

				
			

Nomeie o serviço como php, pois ele fornecerá acesso ao PHP-FPM:

				
					
[label php_service.yaml]

...

metadata:

 name: php

				
			

Você agrupará logicamente diferentes objetos com labels ou etiquetas. Neste tutorial, você usará labels para agrupar os objetos em "camadas", como front-end ou back-end. Os pods do PHP serão executados por trás desse serviço, então você o etiquetará como tier: backend.

				
					
[label php_service.yaml]

...

 labels:

 tier: backend

				
			

Um serviço determina quais pods acessar usando labels selector. Um pod que corresponda a essas labels será atendido, independentemente de o pod ter sido criado antes ou depois do serviço. Você adicionará labels para seus pods posteriormente no tutorial.

Use a label tier: backend para atribuir o pod à camada de back-end. Você também adicionará o rótulo app: php para especificar que este pod executa o PHP. Adicione essas duas labels após a seção metadados.

				
					
[label php_service.yaml]

...

spec:

 selector:

 app: php

 tier: backend

				
			

Em seguida, especifique a porta usada para acessar este serviço. Você usará a porta 9000 neste tutorial. Adicione-a ao arquivo php_service.yaml abaixo de spec:

				
					
[label php_service.yaml]

...

 ports:

 - protocol: TCP

 port: 9000

				
			

O arquivo php_service.yaml completo será semelhante a este:

				
					
[label 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 você criou a definição de objeto para o seu serviço, para executar o serviço, você usará o comando kubectl apply junto com a flag -f e especificará seu arquivo php_service.yaml.

Crie seu serviço:

				
					
kubectl apply -f php_service.yaml

				
			

Esta saída confirma a criação do serviço:

				
					
[secondary_label Output]

service/php created

				
			

Verifique se o seu serviço está em execução:

				
					
kubectl get svc

				
			

Você verá seu serviço PHP-FPM em execução:

				
					
[secondary_label Output]

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

				
			

Existem vários tipos de serviço que o Kubernetes suporta. Seu serviço php usa o tipo de serviço padrão, ClusterIP. Esse tipo de serviço atribui um IP interno e torna o serviço acessível apenas 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 terá como alvo os pods do Nginx, então você o chamará de nginx. Você também adicionará uma label tier: backend, pois ele pertence à camada de backend:

				
					
[label nginx_service.yaml]

apiVersion: v1

kind: Service

metadata:

 name: nginx

 labels:

 tier: backend

				
			

Semelhante ao serviço php, marque os pods com as labels app: nginx e tier: backend. Torne este serviço acessível na porta 80, a porta HTTP padrão.

				
					
[label nginx_service.yaml]

...

spec:

 selector:

 app: nginx

 tier: backend

 ports:

 - protocol: TCP

 port: 80

				
			

O serviço Nginx estará publicamente acessível na Internet a partir do endereço IP público do seu Droplet. <^>seu_ip_público<^> pode ser encontrado em seu Painel de Controle da the cloud provider. Sob spec.externalIPs, adicione:

				
					
[label nginx_service.yaml]

...

spec:

 externalIPs:

 - &lt;^&gt;seu_ip_público&lt;^&gt;

				
			

Seu arquivo nginx_service.yaml será parecido com este:

				
					
[label 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:

 - &lt;^&gt;seu_ip_público&lt;^&gt; 

				
			

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

				
					
kubectl apply -f nginx_service.yaml

				
			

Você verá a seguinte saída quando o serviço estiver sendo executado:

				
					
[secondary_label Output]

service/nginx created

				
			

Você pode visualizar todos os serviços em execução executando:

				
					
kubectl get svc

				
			

Você verá os serviços PHP-FPM e Nginx listados na saída:

				
					
[secondary_label Output]

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

kubernetes ClusterIP 10.96.0.1 &lt;none&gt; 443/TCP 13m

nginx ClusterIP 10.102.160.47 &lt;^&gt;seu_ip_público&lt;^&gt; 80/TCP 50s

php ClusterIP 10.100.59.238 &lt;none&gt; 9000/TCP 8m

				
			

Observe que, se você deseja excluir um serviço, você pode executar:

				
					
kubectl delete svc/&lt;^&gt;nome_do_serviço&lt;^&gt;

				
			

Agora que você criou seus serviços PHP-FPM e Nginx, precisará especificar onde armazenar o código da aplicação e os arquivos de configuração.

Passo 2 — Instalando o Plug-in de Armazenamento da the cloud provider

O Kubernetes fornece diferentes plug-ins de armazenamento que podem criar o espaço de armazenamento para o seu ambiente. Neste passo, você instalará o plug-in de Armazenamento da the cloud provider para criar block storage na the cloud provider. Quando a instalação estiver concluída, ela adicionará uma classe de armazenamento denominada do-block-storage que você usará para criar seu armazenamento em blocos ou block storage.

Você primeiro configurará um objeto Kubernetes Secret para armazenar seu token da API da the cloud provider. Objetos Secret são usados para compartilhar informações confidenciais, como chaves e senhas SSH, com outros objetos do Kubernetes no mesmo namespace. Os namespaces fornecem uma maneira de separar logicamente os objetos do Kubernetes.

Abra um arquivo chamado secret.yaml com o editor:

				
					
nano secret.yaml

				
			

Você nomeará seu objeto Secret como the cloud provider e o adicionará ao namespace kube-system. O namespace kube-system é o namespace padrão para os serviços internos do Kubernetes e também é usado pelo plug-in de armazenamento da the cloud provider para ativar vários componentes.

				
					
[label secret.yaml]

apiVersion: v1

kind: Secret

metadata:

 name: the cloud provider

 namespace: kube-system

				
			

Em vez de uma chave spec, um Secret usa uma chave data ou stringData para armazenar as informações necessárias. O parâmetro data contém dados codificados em base64 que são decodificados automaticamente quando recuperados. O parâmetro stringData contém dados não codificados que são codificados automaticamente durante a criação ou atualizações e não mostra os dados ao recuperar Secrets. Você usará stringData neste tutorial por conveniência.

Adicione access-token como stringData:

				
					
[label secret.yaml]

...

stringData:

 access-token: &lt;^&gt;seu_token_de_api&lt;^&gt;

				
			

Salve e saia do arquivo.

O seu arquivo secret.yaml ficará assim:

				
					
[label secret.yaml]

apiVersion: v1

kind: Secret

metadata:

 name: the cloud provider

 namespace: kube-system

stringData:

 access-token: &lt;^&gt;seu_token_de_api&lt;^&gt;

				
			

Crie o secret:

				
					
kubectl apply -f secret.yaml

				
			

Você verá esta saída na criação do Secret:

				
					
[secondary_label Output]

secret/the cloud provider created

				
			

Você pode ver o Secret com o seguinte comando:

				
					
kubectl -n kube-system get secret the cloud provider

				
			

A saída será semelhante a esta:

				
					
[secondary_label Output]

NAME TYPE DATA AGE

the cloud provider Opaque 1 41s

				
			

O tipo Opaque significa que esse Secret é somente leitura, o que é padrão para os Secrets stringData. Você pode ler mais sobre isso em Secret design spec. O campo DATA mostra o número de itens armazenados neste Secret. Neste caso, mostra 1 porque você tem uma única chave armazenada.

Agora que seu Secret está no lugar, instale o plug-in de armazenamento em bloco da the cloud provider:

				
					
kubectl apply -f https://kubernetes.io/docs/home/

				
			

Você verá uma saída semelhante à seguinte:

				
					
[secondary_label Output]

csidriver.storage.k8s.io/www.progressiverobot.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://kubernetes.io/docs/home/": no matches for kind "VolumeSnapshotClass" in version "snapshot.storage.k8s.io/v1alpha1"

				
			

Para este tutorial, é seguro ignorar os erros.

Agora que você instalou o plug-in de armazenamento da the cloud provider, é possível criar armazenamento em bloco para armazenar o código da aplicação e os arquivos de configuração.

Passo 3 — Criando um Volume Persistente

Com o seu Secret no lugar e o plug-in de armazenamento em bloco instalado, agora você está pronto para criar seu *Volume Persistente*. Um Volume Persistente, ou PV, é um armazenamento em bloco de um tamanho especificado que vive independentemente do ciclo de vida de um pod. O uso de um volume persistente lhe permitirá gerenciar ou atualizar seus pods sem se preocupar em perder o código da aplicação. Um Volume Persistente é acessado usando um PersistentVolumeClaim ou PVC, que monta o PV no caminho especificado.

Abra um arquivo chamado code_volume.yaml com seu editor:

				
					
nano code_volume.yaml

				
			

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

				
					
[label code_volume.yaml]

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

 name: code

				
			

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

  • accessModes que variam de acordo com o caso de uso. Eles são:
  • ReadWriteOnce – monta o volume como leitura e gravação para um único node
  • ReadOnlyMany – monta o volume como somente leitura para muitos nodes
  • ReadWriteMany – monta o volume como leitura e gravação par muitos nodes
  • resources – o espaço de armazenamento que você precisa

O armazenamento em bloco da the cloud provider é montado apenas em um único node, portanto, você definirá o accessModes como ReadWriteOnce. Este tutorial o guiará na adição de uma pequena quantidade de código da aplicação, portanto, 1 GB será suficiente nesse caso de uso. Se você planeja armazenar uma quantidade maior de código ou dados no volume, pode modificar o parâmetro storage para atender aos 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.

				
					
[label code_volume.yaml]

...

spec:

 accessModes:

 - ReadWriteOnce

 resources:

 requests:

 storage: &lt;^&gt;1Gi&lt;^&gt;

				
			

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

				
					
[label code_volume.yaml]

...

 storageClassName: do-block-storage

				
			

O seu arquivo code_volume.yaml ficará assim:

				
					
[label code_volume.yaml]

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

 name: code

spec:

 accessModes:

 - ReadWriteOnce

 resources:

 requests:

 storage: &lt;^&gt;1Gi&lt;^&gt;

 storageClassName: do-block-storage

				
			

Salve e saia do arquivo.

Crie o PVC code usando kubectl:

				
					
kubectl apply -f code_volume.yaml

				
			

A saída a seguir informa que o objeto foi criado com sucesso e você está pronto para montar seu PVC de 1 GB como um volume.

				
					
[secondary_label Output]

persistentvolumeclaim/code created

				
			

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

				
					
kubectl get pv

				
			

Você verá seu PV listado:

				
					
[secondary_label Output]

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

				
			

Os campos acima são uma visão geral do seu arquivo de configuração, exceto Reclaim Policy e Status. A Reclaim Policy ou política de recuperação define o que é feito com o PV depois que o PVC que o está acessando é excluído. Delete remove o PV do Kubernetes e da infraestrutura da the cloud provider. Você pode aprender mais sobre Reclaim Policy e Status na documentação do Kubernetes PV.

Você criou com sucesso um Volume Persistente usando o plug-in de armazenamento em bloco da the cloud provider. Agora que seu volume persistente está pronto, você criará seus pods usando um Deployment.

Passo 4 — Criando um Deployment PHP-FPM

Nesta etapa, você aprenderá como usar um Deployment para criar seu pod PHP-FPM. Os Deployments fornecem uma maneira uniforme de criar, atualizar e gerenciar pods usando ReplicaSets.

A chave spec.selector do Deployment listará as labels dos pods que ela gerenciará. Ela também usará a chave template para criar os pods necessários.

Este passo também apresentará o uso de Init Containers. *Init Containers* executa um ou mais comandos antes dos containers regulares especificados na chave template do pod. Neste tutorial, seu Init Container buscará um arquivo de exemplo index.php no GitHub Gist usando o wget. Este é o conteúdo do arquivo de amostra:

				
					
[label index.php]

&lt;?php

echo phpinfo(); 

				
			

Para criar seu Deployment, abra um novo arquivo chamado php_deployment.yaml com seu editor:

				
					
nano php_deployment.yaml

				
			

Este Deployment gerenciará seus pods do PHP-FPM, assim você nomeará o objeto do Deployment como php. Os pods pertencem à camada de back-end, portanto, você agrupará o Deployment nesse grupo usando a label tier: backend:

				
					
[label php_deployment.yaml]

apiVersion: apps/v1

kind: Deployment

metadata:

 name: php

 labels:

 tier: backend

				
			

Para o Deployment spec, você especificará quantas cópias deste pod criar usando o parâmetro replicas. O número de replicas irá variar dependendo de suas necessidades e recursos disponíveis. Você criará uma réplica neste tutorial:

				
					
[label php_deployment.yaml]

...

spec:

 replicas: 1

				
			

Este Deployment gerenciará os pods que correspondem às labels app: php e tier: backend. Sob a chave seletor, adicione:

				
					
[label php_deployment.yaml]

...

 selector:

 matchLabels:

 app: php

 tier: backend

				
			

A seguir, o Deployment spec requer o template para a definição de objeto do seu pod. Este template ou modelo definirá especificações para a criação do pod. Primeiro, você adicionará as labels que foram especificadas para os seletores ou selectors do serviço php e os matchLabels do Deployment. Adicione app: php e tier: backend sob template.metadata.labels:

				
					
[label php_deployment.yaml]

...

 template:

 metadata:

 labels:

 app: php

 tier: backend

				
			

Um pod pode ter vários containers e volumes, mas cada um precisará de um nome. Você pode montar seletivamente volumes em um container, especificando um caminho de montagem para cada volume.

Primeiro, especifique os volumes que seus containers acessarão. Você criou um PVC chamado code para armazenar o código da aplicação, portanto, nomeie esse volume como code. Sob spec.template.spec.volumes, adicione o seguinte:

				
					
[label php_deployment.yaml]

...

 spec:

 volumes:

 - name: code

 persistentVolumeClaim:

 claimName: code

				
			

Em seguida, especifique o container que você deseja executar neste pod. Você pode encontrar várias imagens na Docker store, mas neste tutorial você usará a imagem php:7-fpm.

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

				
					
[label php_deployment.yaml]

...

 containers:

 - name: php

 image: php:7-fpm

				
			

Em seguida, você montará os volumes aos quais o container requer acesso. Este container executará seu código PHP e, portanto, precisará acessar o volume code. Você também usará mountPath para especificar /code como o ponto de montagem.

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

				
					
[label php_deployment.yaml]

...

 volumeMounts:

 - name: code

 mountPath: /code

				
			

Agora que você montou seu volume, é necessário inserir o código da sua aplicação no volume. Você pode ter usado anteriormente FTP/SFTP ou clonado o código em uma conexão SSH para fazer isso, mas este passo mostrará como copiar o código usando um Init Container.

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

Neste tutorial, você usará um único Init Container com busybox para baixar o código. busybox é uma pequena imagem que contém o utilitário wget que você usará para fazer isso.

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

				
					
[label php_deployment.yaml]

...

 initContainers:

 - name: install

 image: busybox

				
			

Seu Init Container precisará acessar o volume do code para que possa fazer o download do código nesse local. Sob spec.template.spec.initContainers, monte o volume code no caminho /code:

				
					
[label php_deployment.yaml]

...

 volumeMounts:

 - name: code

 mountPath: /code

				
			

Cada Init Container precisa executar um comando. Seu Init Container usará o wget para baixar o código a partir do Github dentro do diretório de trabalho /code. A flag -O atribui um nome ao arquivo baixado e você nomeará esse arquivo como index.php.

Nota: Certifique-se de confiar no código que você está enviando. Antes de baixá-lo para o seu servidor, inspecione o código-fonte para garantir que você esteja confortável com o que o código faz.

Abaixo do container install em spec.template.spec.initContainers, adicione estas linhas:

				
					
[label php_deployment.yaml]

...

 command:

 - wget

 - "-O"

 - "/code/index.php"

 - &lt;^&gt;https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php&lt;^&gt;

				
			

Seu arquivo php_deployment.yaml completo será semelhante a este:

				
					
[label 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 o deployment PHP-FPM com o kubectl:

				
					
kubectl apply -f php_deployment.yaml

				
			

Você verá a seguinte saída na criação do Deployment:

				
					
[secondary_label Output]

deployment.apps/php created

				
			

Para resumir, esse Deployment começará baixando as imagens especificadas. Ele então solicitará o PersistentVolume do seu PersistentVolumeClaim e executará em série o seu initContainers. Depois de concluídos, os containers irão executar e montar os volumes no ponto de montagem especificado. Quando todas essas etapas estiverem concluídas, seu pod estará em funcionamento.

Você pode visualizar seu Deployment executando:

				
					
kubectl get deployments

				
			

Você verá a saída:

				
					
[secondary_label Output]

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE

php 1 1 1 0 19s

				
			

Esta saída pode ajudá-lo a entender o estado atual do Deployment. Um Deployment é um dos controladores que mantém um estado desejado. O template que você criou especifica que o estado desejado ou DESIRED terá 1 replicas do pod chamado php. O campo CURRENT indica quantas réplicas estão executando, portanto, isso deve corresponder ao estado DESIRED. Você pode ler sobre os campos restantes na documentação do Kubernetes Deployments.

Você pode visualizar os pods que esse Deployment iniciou com o seguinte comando:

				
					
kubectl get pods

				
			

A saída deste comando varia dependendo de quanto tempo se passou desde a criação do Deployment. Se você executá-lo logo após a criação, a saída provavelmente será assim:

				
					
[secondary_label Output]

NAME 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 executando nesse pod.
  • Status: O status do pod. Init indica que os Init Containers estão executando. Nesta saída, 0 de 1 Init Containers terminaram a execução.
  • Restarts: Quantas vezes esse processo foi reiniciado para iniciar o pod. Esse número aumentará se algum dos seus Init Containers falhar. O Deployment irá reiniciá-lo até atingir o estado desejado.

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

				
					
[secondary_label Output]

NAME READY STATUS RESTARTS AGE

php-86d59fd666-lkwgn 0/1 podInitializing 0 39s

				
			

Isso significa que os Init Containers foram finalizados e os containers estão inicializando. Se você executar o comando quando todos os containers estiverem em execução, o status do pod será alterado para Running.

				
					
[secondary_label Output]

NAME READY STATUS RESTARTS AGE

php-86d59fd666-lkwgn 1/1 Running 0 1m

				
			

Agora você vê que seu pod está sendo executado com êxito. Se o seu pod não iniciar, você poderá depurar com os seguintes comandos:

  • Ver informações detalhadas de um pod:
				
					
kubectl describe pods &lt;^&gt;nome-do-pod&lt;^&gt;

				
			
  • Ver os logs gerados por um pod:
				
					
kubectl logs &lt;^&gt;nome-do-pod&lt;^&gt;

				
			
  • Visualizar os logs de um container específico em um pod:
				
					
kubectl logs &lt;^&gt;nome-do-pod&lt;^&gt; &lt;^&gt;nome-do-container&lt;^&gt;

				
			

O código da sua aplicação está montado e o serviço PHP-FPM está pronto para lidar com as conexões. Agora você pode criar seu Deployment do Nginx.

Passo 5 — Criando o Deployment do Nginx

Neste passo, você usará um *ConfigMap* para configurar o Nginx. Um ConfigMap mantém sua configuração em um formato de chave-valor que você pode referenciar em outras definições de objeto do Kubernetes. Essa abordagem concederá a flexibilidade de reutilizar ou trocar a imagem por uma versão diferente do Nginx, se necessário. A atualização do ConfigMap replicará automaticamente as alterações em qualquer pod que o monte.

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

				
					
nano nginx_configMap.yaml

				
			

Nomeie o ConfigMap como nginx-config e agrupe-o no microsserviço tier: backend:

				
					
[label nginx_configMap.yaml]

apiVersion: v1

kind: ConfigMap

metadata:

 name: nginx-config

 labels:

 tier: backend

				
			

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

Como o Kubernetes pode rotear solicitações para o host apropriado para um serviço, você pode inserir o nome do seu serviço PHP-FPM no parâmetro fastcgi_pass em vez de seu endereço IP. Adicione o seguinte ao seu arquivo nginx_configMap.yaml:

				
					
[label 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 &lt;^&gt;/code&lt;^&gt;;



 location / {

 try_files $uri $uri/ /index.php?$query_string;

 }



 location ~ \.php$ {

 try_files $uri =404;

 fastcgi_split_path_info ^(.+\.php)(/.+)$;

 fastcgi_pass &lt;^&gt;php:9000&lt;^&gt;;

 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 será parecido com este:

				
					
[label 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á a seguinte saída:

				
					
[secondary_label Output]

configmap/nginx-config created

				
			

Você terminou de criar o seu ConfigMap e agora pode criar seu Deployment do Nginx.

Comece abrindo um novo arquivo nginx_deployment.yaml no editor:

				
					
nano nginx_deployment.yaml

				
			

Nomeie o Deployment como nginx e adicione a label tier: backend:

				
					
[label nginx_deployment.yaml]

apiVersion: apps/v1

kind: Deployment

metadata:

 name: nginx

 labels:

 tier: backend

				
			

Especifique que você quer uma replicas na spec do Deployment. Esse Deployment gerenciará os pods com labels app: nginx e tier: backend. Adicione os seguintes parâmetros e valores:

				
					
[label nginx_deployment.yaml]

...

spec:

 replicas: 1

 selector:

 matchLabels:

 app: nginx

 tier: backend

				
			

Em seguida, adicione o template do pod. Você precisa usar as mesmas labels que você adicionou para o Deployment selector.matchLabels. Adicione o seguinte:

				
					
[label nginx_deployment.yaml]

...

 template:

 metadata:

 labels:

 app: nginx

 tier: backend

				
			

Dê ao Nginx acesso ao PVC code que você criou anteriormente. Sob spec.template.spec.volumes, adicione:

				
					
[label nginx_deployment.yaml]

...

 spec:

 volumes:

 - name: code

 persistentVolumeClaim:

 claimName: code

				
			

Os pods podem montar um ConfigMap como um volume. A especificação de um nome de arquivo e chave criará um arquivo com seu valor como conteúdo. Para usar o ConfigMap, defina path como o nome do arquivo que armazenará o conteúdo da key. Você deseja criar um arquivo site.conf a partir da chave config. Sob spec.template.spec.volumes, adicione o seguinte:

				
					
[label nginx_deployment.yaml]

...

 - name: config

 configMap:

 name: nginx-config

 items:

 - key: config

 path: site.conf

				
			

[warning]

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

A seguir, você especificará a imagem a partir da qual criar seu pod. Este tutorial usará a imagem nginx:1.7.9 para estabilidade, mas você pode encontrar outras imagens Nginx na Docker store. Além disso, torne o Nginx disponível na porta 80. Sob spec.template.spec, adicione:

				
					
[label nginx_deployment.yaml]

...

 containers:

 - name: nginx

 image: &lt;^&gt;nginx:1.7.9&lt;^&gt;

 ports:

 - containerPort: 80

				
			

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

				
					
[label nginx_deployment.yaml]

...

 volumeMounts:

 - name: code

 mountPath: /code

				
			

A imagem nginx:1.7.9 carregará automaticamente quaisquer arquivos de configuração no diretório /etc/nginx/conf.d. A montagem do volume config neste diretório criará o arquivo /etc/nginx/conf.d/site.conf. Sob volumeMounts, adicione o seguinte:

				
					
[label nginx_deployment.yaml]

...

 - name: config

 mountPath: /etc/nginx/conf.d

				
			

Seu arquivo nginx_deployment.yaml será parecido com este:

				
					
[label 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: &lt;^&gt;nginx:1.7.9&lt;^&gt;

 ports:

 - containerPort: 80

 volumeMounts:

 - name: code

 mountPath: /code

 - name: config

 mountPath: /etc/nginx/conf.d

				
			

Salve o arquivo e saia do editor.

Crie o Deployment do Nginx:

				
					
kubectl apply -f nginx_deployment.yaml

				
			

A seguinte saída indica que seu Deployment foi criado agora:

				
					
[secondary_label Output]

deployment.apps/nginx created

				
			

Liste seus Deployments com este comando:

				
					
kubectl get deployments

				
			

Você verá os Deployments Nginx e PHP-FPM:

				
					
[secondary_label Output]

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE

nginx 1 1 1 0 16s

php 1 1 1 1 7m

				
			

Liste os pods gerenciados por ambos os deployments:

				
					
kubectl get pods

				
			

Você verá os pods em execução:

				
					
[secondary_label Output]

NAME 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, você pode 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 o seu serviço Nginx:

				
					
[secondary_label Output]

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR

kubernetes ClusterIP 10.96.0.1 &lt;none&gt; 443/TCP 39m &lt;none&gt;

nginx ClusterIP 10.102.160.47 &lt;^&gt;seu_ip_público&lt;^&gt; 80/TCP 27m app=nginx,tier=backend

php ClusterIP 10.100.59.238 &lt;none&gt; 9000/TCP 34m app=php,tier=backend

				
			

No seu navegador, visite seu servidor digitando http://<^>seu_ip_público<^>. Você verá a saída de php_info() e irá confirmar que seus serviços do Kubernetes estão funcionando.

Conclusão

Neste guia, você *containerizou* os serviços PHP-FPM e Nginx para poder gerenciá-los independentemente. Essa abordagem não apenas melhorará a escalabilidade do seu projeto à medida que você cresce, mas também permitirá que você use os recursos com eficiência. Você também armazenou o código da sua aplicação em um volume para poder atualizar facilmente seus serviços no futuro.