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

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:

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:

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:

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:

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:

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

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

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

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

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.

Output
persistentvolumeclaim/code created

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

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

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:

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:

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:

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.

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

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:

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:

Output
deployment.apps/nginx created

Liste seus Deployments com este comando:

  • kubectl get deployments

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

  • kubectl get pods

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

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:

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

0 Comments

Creative Commons License