Como Fazer o Deploy de uma aplicação PHP com Kubernetes no Ubuntu 18.04

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 DigitalOcean. 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

  • Uma compreensão básica dos objetos do Kubernetes. Confira nosso artigo Uma Introdução ao Kubernetes para mais informações.
  • Um cluster Kubernetes em execução no Ubuntu 18.04. Você pode configurar isso seguindo o tutorial Como Criar um Cluster Kubernetes 1.11 Usando Kubeadm no Ubuntu 18.04
  • Uma conta na DigitalOcean 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:

php_service.yaml

apiVersion: v1 kind: Service 

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

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.

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.

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:

php_service.yaml

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

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

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:

Outputservice/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:

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

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.

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 DigitalOcean. Sob spec.externalIPs, adicione:

nginx_service.yaml

... spec:   externalIPs:   - seu_ip_público 

Seu arquivo nginx_service.yaml será parecido com este:

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:   - seu_ip_público     

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:

Outputservice/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:

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   seu_ip_público 80/TCP     50s php          ClusterIP   10.100.59.238   <none>        9000/TCP   8m 

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

  • kubectl delete svc/nome_do_serviço

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 DigitalOcean

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 DigitalOcean para criar block storage na DigitalOcean. 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 DigitalOcean. 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 digitalocean 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 DigitalOcean para ativar vários componentes.

secret.yaml

apiVersion: v1 kind: Secret metadata:   name: digitalocean   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:

secret.yaml

... stringData:   access-token: seu_token_de_api 

Salve e saia do arquivo.

O seu arquivo secret.yaml ficará assim:

secret.yaml

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

Crie o secret:

  • kubectl apply -f secret.yaml

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

Outputsecret/digitalocean created 

Você pode ver o Secret com o seguinte comando:

  • kubectl -n kube-system get secret digitalocean

A saída será semelhante a esta:

OutputNAME           TYPE      DATA      AGE digitalocean   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 DigitalOcean:

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

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

Outputcsidriver.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" 

Para este tutorial, é seguro ignorar os erros.

Agora que você instalou o plug-in de armazenamento da DigitalOcean, é 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:

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 DigitalOcean é 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.

code_volume.yaml

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

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 DigitalOcean.

code_volume.yaml

...   storageClassName: do-block-storage 

O seu arquivo code_volume.yaml ficará assim:

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 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.

Outputpersistentvolumeclaim/code created 

Para visualizar 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 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 DigitalOcean. 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 DigitalOcean. 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:

index.php

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

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:

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:

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:

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:

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:

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:

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

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 volumecode no caminho /code:

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:

php_deployment.yaml

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

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

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:

Outputdeployment.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:

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

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

OutputNAME                   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.

OutputNAME                   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 nome-do-pod
  • Ver os logs gerados por um pod:
  • kubectl logs nome-do-pod
  • Visualizar os logs de um container específico em um pod:
  • kubectl logs nome-do-pod nome-do-container

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:

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:

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

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:

Outputconfigmap/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:

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:

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:

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:

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:

nginx_deployment.yaml

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

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:

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, portanto, monte o volume code em /code:

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:

nginx_deployment.yaml

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

Seu arquivo nginx_deployment.yaml será parecido com este:

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 o Deployment do Nginx:

  • kubectl apply -f nginx_deployment.yaml

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

Outputdeployment.apps/nginx created 

Liste seus Deployments com este comando:

  • kubectl get deployments

Você verá os Deployments Nginx e 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 ambos os deployments:

  • kubectl get pods

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

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

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   seu_ip_público 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://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.