Tutorial

Como implantar um aplicativo PHP com o Kubernetes no Ubuntu 16.04

Published on January 9, 2020
Português
Como implantar um aplicativo PHP com o Kubernetes no 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

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.

  1. mkdir definitions

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

  1. cd definitions

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

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

  1. kubectl apply -f php_service.yaml

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

Output
service/php created

Verifique se seu serviço está funcionando:

  1. kubectl get svc

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

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

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

  1. kubectl apply -f nginx_service.yaml

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

Output
service/nginx created

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

  1. kubectl get svc

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

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13m nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 50s php ClusterIP 10.100.59.238 <none> 9000/TCP 8m

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

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

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

  1. kubectl apply -f secret.yaml

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

Output
secret/digitalocean created

Você pode ver o segredo com o seguinte comando:

  1. kubectl -n kube-system get secret digitalocean

O resultado será semelhante a este:

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

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

Output
storageclass.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:

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

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

Output
persistentvolumeclaim/code created

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

  1. kubectl get pv

Você verá seu PV listado:

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

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

  1. kubectl apply -f php_deployment.yaml

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

Output
deployment.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:

  1. kubectl get deployments

Você verá o resultado:

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

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

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

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

Output
NAME 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:
  1. kubectl describe pods pod-name
  • Ver registros gerados por um pod:
  1. kubectl logs pod-name
  • Ver registros para um contêiner específico em um pod:
  1. 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:

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

  1. kubectl apply -f nginx_configMap.yaml

Você verá o seguinte resultado:

Output
configmap/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:

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

  1. kubectl apply -f nginx_deployment.yaml

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

Output
deployment.apps/nginx created

Liste suas implantações com este comando:

  1. kubectl get deployments

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

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 ambas as implantações:

  1. kubectl get pods

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

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, é possível visitar o serviço Nginx no seu navegador.

Liste os serviços em execução:

  1. kubectl get services -o wide

Obtenha o IP externo para seu serviço Nginx:

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39m <none> nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 27m app=nginx,tier=backend php ClusterIP 10.100.59.238 <none> 9000/TCP 34m app=php,tier=backend

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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel