One place for hosting & domains

      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

      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.

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

      Defina seu serviço PHP-FPM criando um arquivo 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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

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

      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:

      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.



      Source link

      Como Fazer o Deploy de uma Aplicação Go Resiliente no Kubernetes da DigitalOcean


      O autor escolheu o Girls Who Code para receber uma doação como parte do programa Write for DOnations.

      Introdução

      O Docker é uma ferramenta de containerização utilizada para fornecer às aplicações um sistema de arquivos que armazena tudo o que eles precisam para executar, garantindo que o software tenha um ambiente de runtime consistente e se comporte da mesma maneira, independentemente de onde esteja implantado ou deployado. O Kubernetes é uma plataforma em nuvem para automatizar o deployment, a escalabilidade e o gerenciamento de aplicações containerizadas.

      Ao aproveitar o Docker, você pode fazer o deploy de uma aplicação em qualquer sistema que ofereça suporte ao Docker com a confiança de que ele sempre funcionará conforme o esperado. O Kubernetes, por sua vez, permite que você faça o deploy de sua aplicação em vários nodes em um cluster. Além disso, ele lida com as principais tarefas, como lançar novos containers em caso de queda de qualquer um dos seus containers. Juntas, essas ferramentas simplificam o processo de deployment de uma aplicação, permitindo que você se concentre no desenvolvimento.

      Neste tutorial, você vai criar uma aplicação de exemplo escrita em Go e a colocará em funcionamento localmente em sua máquina de desenvolvimento. Em seguida, você irá containerizar a aplicação com o Docker, fazer o deploy em um cluster Kubernetes e vai criar um balanceador de carga que servirá como ponto de entrada voltado ao público para a sua aplicação.

      Pré-requisitos

      Antes de começar este tutorial, você precisará do seguinte:

      • Um servidor de desenvolvimento ou máquina local a partir da qual você fará o deploy da aplicação. Embora as instruções deste guia funcionem em grande parte para a maioria dos sistemas operacionais, este tutorial pressupõe que você tenha acesso a um sistema Ubuntu 18.04 configurado com um usuário não-root com privilégios sudo, conforme descrito em nosso tutorial Configuração Inicial de servidor com Ubuntu 18.04.
      • A ferramenta de linha de comando docker instalada em sua máquina de desenvolvimento. Para instalar isto, siga os Passos 1 e 2 do nosso tutorial sobre Como Instalar e Usar o Docker no Ubuntu 18.04.
      • A ferramenta de linha de comando kubectl instalada em sua máquina de desenvolvimento. Para instalá-la, siga este guia da documentação oficial do Kubernetes.
      • Uma conta gratuita no Docker Hub para a qual você enviará sua imagem do Docker. Para configurar isso, visite o website do Docker Hub, clique no botão Get Started no canto superior direito da página e siga as instruções de registro.
      • Um cluster Kubernetes. Você pode provisionar um cluster Kubernetes na DigitalOcean seguindo nosso Guia de início rápido do Kubernetes. Você ainda pode concluir este tutorial se provisionar seu cluster em outro provedor de nuvem. Sempre que você adquirir seu cluster, certifique-se de definir um arquivo de configuração e garantir que você possa se conectar ao cluster a partir do seu servidor de desenvolvimento.

      Passo 1 — Criando uma Aplicação Web de Exemplo em Go

      Nesta etapa, você criará uma aplicação de exemplo escrita em Go. Após containerizar este app com o Docker, ele servirá My Awesome Go App em resposta a solicitações para o endereço IP do seu servidor na porta 3000.

      Comece atualizando as listas de pacotes do seu servidor, se você não tiver feito isso recentemente:

      Em seguida, instale o Go executando:

      Depois, verifique se você está em seu diretório home e crie um novo diretório que vai conter todos os seus arquivos do projeto:

      Em seguida, navegue até este novo diretório:

      Use o nano ou seu editor de texto preferido para criar um arquivo chamado main.go, que conterá o código da sua aplicação Go:

      A primeira linha em qualquer arquivo-fonte do Go é sempre uma instrução package que define a qual pacote de código o arquivo pertence. Para arquivos executáveis como este, a declaração package deve apontar para o pacote main:

      go-app/main.go

      package main
      

      Depois disso, adicione uma instrução import onde você pode listar todas as bibliotecas que a aplicação precisará. Aqui, inclua fmt, que lida com entrada e saída de texto formatada, e net/http, que fornece implementações de cliente e servidor HTTP:

      go-app/main.go

      package main
      
      import (
        "fmt"
        "net/http"
      )
      

      Em seguida, defina uma função homePage que terá dois argumentos: http.ResponseWriter e um ponteiro para http.Request. Em Go, uma interface ResponseWriter é usada para construir uma resposta HTTP, enquanto http.Request é um objeto que representa uma solicitação de entrada. Assim, este bloco lê solicitações HTTP de entrada e, em seguida, constrói uma resposta:

      go-app/main.go

      . . .
      
      import (
        "fmt"
        "net/http"
      )
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      

      Depois disso, adicione uma função setupRoutes que mapeará as solicitações de entrada para as funções planejadas do handler HTTP. No corpo desta função setupRoutes, adicione um mapeamento da rota / para sua função homePage recém-definida. Isso diz à aplicação para imprimir a mensagem My Awesome Go App mesmo para solicitações feitas a endpoints desconhecidos:

      go-app/main.go

      . . .
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      

      E finalmente, adicione a seguinte função main. Isso imprimirá uma string indicando que sua aplicação foi iniciada. Ela então chamará a função setupRoutes antes de começar a ouvir e servir sua aplicação Go na porta 3000.

      go-app/main.go

      . . .
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      
      func main() {
        fmt.Println("Go Web App Started on Port 3000")
        setupRoutes()
        http.ListenAndServe(":3000", nil)
      }
      

      Após adicionar essas linhas, é assim que o arquivo final ficará:

      go-app/main.go

      package main
      
      import (
        "fmt"
        "net/http"
      )
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      
      func main() {
        fmt.Println("Go Web App Started on Port 3000")
        setupRoutes()
        http.ListenAndServe(":3000", nil)
      }
      

      Salve e feche este arquivo. Se você criou este arquivo usando nano, faça-o pressionando CTRL + X, Y, depois ENTER.

      Em seguida, execute a aplicação usando o seguinte comando go run. Isto irá compilar o código no seu arquivo main.go e irá executá-lo localmente em sua máquina de desenvolvimento:

      Output

      Go Web App Started on Port 3000

      Esta saída confirma que a aplicação está funcionando conforme o esperado. Ela será executada indefinidamente, entretanto, feche-a pressionando CTRL + C.

      Ao longo deste guia, você usará essa aplicação de exemplo para experimentar com o Docker e o Kubernetes. Para esse fim, continue lendo para saber como containerizar sua aplicação com o Docker.

      Passo 2 — Dockerizando sua Aplicação Go

      Em seu estado atual, a aplicação Go que você acabou de criar está sendo executada apenas em seu servidor de desenvolvimento. Nesta etapa, você tornará essa nova aplicação portátil ao containerizá-la com o Docker. Isso permitirá que ela seja executada em qualquer máquina que ofereça suporte a containers Docker. Você irá criar uma imagem do Docker e a enviará para um repositório público central no Docker Hub. Dessa forma, seu cluster Kubernetes pode baixar a imagem de volta e fazer o deployment dela como um container dentro do cluster.

      O primeiro passo para a containerização de sua aplicação é criar um script especial chamado de Dockerfile. Um Dockerfile geralmente contém uma lista de instruções e argumentos que são executados em ordem sequencial para executar automaticamente determinadas ações em uma imagem base ou criar uma nova.

      Nota: Nesta etapa, você vai configurar um container Docker simples que criará e executará sua aplicação Go em um único estágio. Se, no futuro, você quiser reduzir o tamanho do container onde suas aplicações Go serão executadas em produção, talvez seja interessante dar uma olhada no mutli-stage builds ou compilação em múltiplos estágios.

      Crie um novo arquivo chamado Dockerfile:

      Na parte superior do arquivo, especifique a imagem base necessária para a aplicação Go:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      

      Em seguida, crie um diretório app dentro do container que vai conter os arquivos-fonte da aplicação:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      

      Abaixo disso, adicione a seguinte linha que copia tudo no diretório raiz dentro do diretório app:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      

      Em seguida, adicione a seguinte linha que altera o diretório de trabalho para app, significando que todos os comandos a seguir neste Dockerfile serão executados a partir desse local:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      

      Adicione uma linha instruindo o Docker a executar o comando go build -o main, que compila o executável binário da aplicação Go:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      RUN go build -o main .
      

      Em seguida, adicione a linha final, que irá rodar o executável binário:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      RUN go build -o main .
      CMD ["/app/main"]
      

      Salve e feche o arquivo depois de adicionar essas linhas.

      Agora que você tem esse Dockerfile na raiz do seu projeto, você pode criar uma imagem Docker baseada nele usando o seguinte comando docker build. Este comando inclui a flag -t que, quando passado o valor go-web-app, nomeará a imagem Docker como go-web-app e irá marcar ou colocar uma tag nela.

      Nota: No Docker, as tags permitem que você transmita informações específicas para uma determinada imagem, como o seu número de versão. O comando a seguir não fornece uma tag específica, portanto, o Docker marcará a imagem com sua tag padrão: latest. Se você quiser atribuir uma tag personalizada a uma imagem, você adicionaria o nome da imagem com dois pontos e a tag de sua escolha, assim:

      • docker build -t sammy/nome_da_imagem:nome_da_tag .

      Marcar ou "taggear" uma imagem como essa pode lhe dar maior controle sobre suas imagens. Por exemplo, você poderia fazer o deploy de uma imagem marcada como v1.1 em produção, mas fazer o deploy de outra marcada como v1.2 em seu ambiente de pré-produção ou teste.

      O argumento final que você vai passar é o caminho: .. Isso especifica que você deseja criar a imagem Docker a partir do conteúdo do diretório de trabalho atual. Além disso, certifique-se de atualizar sammy para o seu nome de usuário do Docker Hub:

      • docker build -t sammy/go-web-app .

      Este comando de compilação vai ler todas as linhas do seu Dockerfile, executá-las em ordem e armazenará em cache, permitindo que futuras compilações sejam executadas muito mais rapidamente:

      Output

      . . . Successfully built 521679ff78e5 Successfully tagged go-web-app:latest

      Quando este comando terminar a compilação, você poderá ver sua imagem quando executar o comando docker images da seguinte forma:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE sammy/go-web-app latest 4ee6cf7a8ab4 3 seconds ago 355MB

      Em seguida, use o seguinte comando para criar e iniciar um container com base na imagem que você acabou de criar. Este comando inclui a flag -it, que especifica que o container será executado no modo interativo. Ele também possui a flag -p que mapeia a porta na qual a aplicação Go está sendo executada em sua máquina de desenvolvimento — porta 3000 — para a porta 3000 em seu container Docker.

      • docker run -it -p 3000:3000 sammy/go-web-app

      Output

      Go Web App Started on Port 3000

      Se não houver mais nada em execução nessa porta, você poderá ver a aplicação em ação abrindo um navegador e navegando até a seguinte URL:

      http://ip_do_seu_servidor:3000
      

      Nota: Se você estiver seguindo este tutorial em sua máquina local em vez de um servidor, visite a aplicação acessando a seguinte URL:

      http://localhost:3000
      

      Your containerized Go App

      Depois de verificar se a aplicação funciona como esperado no seu navegador, finalize-a pressionando CTRL + C no seu terminal.

      Quando você faz o deploy de sua aplicação containerizada em seu cluster Kubernetes, você vai precisar conseguir extrair a imagem de um local centralizado. Para esse fim, você pode enviar sua imagem recém-criada para o repositório de imagens do Docker Hub.

      Execute o seguinte comando para efetuar login no Docker Hub a partir do seu terminal:

      Isso solicitará seu nome de usuário e sua senha do Docker Hub. Depois de inseri-los corretamente, você verá Login Succeeded na saída do comando.

      Após o login, envie sua nova imagem para o Docker Hub usando o comando docker push, assim:

      • docker push sammy/go-web-app

      Quando esse comando for concluído com êxito, você poderá abrir sua conta do Docker Hub e ver sua imagem do Docker lá.

      Agora que você enviou sua imagem para um local central, está pronto para fazer o seu deployment em seu cluster do Kubernetes. Primeiro, porém, vamos tratar de um breve processo que tornará muito menos tedioso executar comandos kubectl.

      Passo 3 — Melhorando a Usabilidade para o kubectl

      Nesse ponto, você criou uma aplicação Go funcional e fez a containerização dela com o Docker. No entanto, a aplicação ainda não está acessível publicamente. Para resolver isso, você fará o deploy de sua nova imagem Docker em seu cluster Kubernetes usando a ferramenta de linha de comando kubectl. Antes de fazer isso, vamos fazer uma pequena alteração no arquivo de configuração do Kubernetes que o ajudará a tornar a execução de comandos kubectl menos trabalhosa.

      Por padrão, quando você executa comandos com a ferramenta de linha de comando kubectl, você deve especificar o caminho do arquivo de configuração do cluster usando a flag --kubeconfig. No entanto, se o seu arquivo de configuração é chamado config e está armazenado em um diretório chamado ~/.kube, o kubectl saberá onde procurar pelo arquivo de configuração e poderá obtê-lo sem a flag --kubeconfig apontando para ele.

      Para esse fim, se você ainda não tiver feito isso, crie um novo diretório chamado ~/.kube:

      Em seguida, mova o arquivo de configuração do cluster para este diretório e renomeie-o como config no processo:

      • mv clusterconfig.yaml ~/.kube/config

      Seguindo em frente, você não precisará especificar a localização do arquivo de configuração do seu cluster quando executar o kubectl, pois o comando poderá encontrá-lo agora que está no local padrão. Teste esse comportamento executando o seguinte comando get nodes:

      Isso exibirá todos os nodes que residem em seu cluster Kubernetes. No contexto do Kubernetes, um node é um servidor ou uma máquina de trabalho na qual pode-se fazer o deployment de um ou mais pods:

      Output

      NAME STATUS ROLES AGE VERSION k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfd Ready <none> 1m v1.13.5 k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfi Ready <none> 1m v1.13.5 k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfv Ready <none> 1m v1.13.5

      Com isso, você está pronto para continuar e fazer o deploy da sua aplicação em seu cluster Kubernetes. Você fará isso criando dois objetos do Kubernetes: um que fará o deploy da aplicação em alguns pods no cluster e outro que criará um balanceador de carga, fornecendo um ponto de acesso à sua aplicação.

      Passo 4 — Criando um Deployment

      Recursos RESTful compõem todas as entidades persistentes dentro de um sistema Kubernetes, e neste contexto elas são comumente chamadas de Kubernetes objects. É útil pensar nos objetos do Kubernetes como as ordens de trabalho que você envia ao Kubernetes: você lista quais recursos você precisa e como eles devem funcionar, e então o Kubernetes trabalhará constantemente para garantir que eles existam em seu cluster.

      Um tipo de objeto do Kubernetes, conhecido como deployment, é um conjunto de pods idênticos e indistinguíveis. No Kubernetes, um pod é um agrupamento de um ou mais containers que podem se comunicar pela mesma rede compartilhada e interagir com o mesmo armazenamento compartilhado. Um deployment executa mais de uma réplica da aplicação pai de cada vez e substitui automaticamente todas as instâncias que falham, garantindo que a aplicação esteja sempre disponível para atender às solicitações do usuário.

      Nesta etapa, você criará um arquivo de descrição de objetos do Kubernetes, também conhecido como manifest, para um deployment. Esse manifest conterá todos os detalhes de configuração necessários para fazer o deploy da sua aplicação Go em seu cluster.

      Comece criando um manifest de deployment no diretório raiz do seu projeto: go-app/. Para projetos pequenos como este, mantê-los no diretório raiz minimiza a complexidade. Para projetos maiores, no entanto, pode ser benéfico armazenar seus manifests em um subdiretório separado para manter tudo organizado.

      Crie um novo arquivo chamado deployment.yml:

      Diferentes versões da API do Kubernetes contêm diferentes definições de objetos, portanto, no topo deste arquivo você deve definir a apiVersion que você está usando para criar este objeto. Para o propósito deste tutorial, você estará usando o agrupamento apps/v1, pois ele contém muitas das principais definições de objeto do Kubernetes que você precisará para criar um deployment. Adicione um campo abaixo de apiVersion, descrevendo o kind ou tipo de objeto do Kubernetes que você está criando. Neste caso, você está criando um Deployment:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      

      Em seguida, defina o metadata para o seu deployment. Um campo metadata é necessário para todos os objetos do Kubernetes, pois contém informações como o name ou nome exclusivo do objeto. Este name é útil, pois permite distinguir diferentes deployments e identificá-los usando nomes inteligíveis:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
          name: go-web-app
      

      Em seguida, você construirá o bloco spec do seu deployment.yml. Um campo spec é um requisito para todos os objetos do Kubernetes, mas seu formato exato é diferente para cada tipo de objeto. No caso de um deployment, ele pode conter informações como o número de réplicas que você deseja executar. No Kubernetes, uma réplica é o número de pods que você deseja executar em seu cluster. Aqui, defina o número de replicas para 5:

      go-app/deployment.yml

      . . .
      metadata:
          name: go-web-app
      spec:
        replicas: 5
      

      Depois, crie um bloco selector aninhado sob o bloco spec. Isso servirá como um seletor de label ou seletor de etiquetas para seus pods. O Kubernetes usa seletores de label para definir como o deployment encontra os pods que ele deve gerenciar.

      Dentro deste bloco selector, defina matchLabels e adicione a label name. Essencialmente, o campo matchLabels diz ao Kubernetes para quais pods o deployment se aplica. Neste exemplo, o deployment será aplicado a todos os pods com o nome go-web-app:

      go-app/deployment.yml

      . . .
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
      

      Depois disso, adicione um bloco template. Cada deployment cria um conjunto de pods usando as labels especificadas em um bloco template. O primeiro subcampo deste bloco é o metadata, que contém as labels que serão aplicadas a todos os pods deste deployment. Essas labels são pares de chave/valor que são usados como atributos de identificação de objetos do Kubernetes. Quando você definir seu serviço mais tarde, você pode especificar que deseja que todos os pods com essa label name sejam agrupados sob esse serviço. Defina esta label name para go-web-app:

      go-app/deployment.yml

      . . .
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
        template:
          metadata:
            labels:
              name: go-web-app
      

      A segunda parte deste bloco template é o bloco spec. Este é diferente do bloco spec que você adicionou anteriormente, já que este se aplica somente aos pods criados pelo bloco template, em vez de todo o deployment.

      Dentro deste bloco spec, adicione um campo containers e mais uma vez defina um atributo name. Este campo name define o nome de qualquer container criado por este deployment específico. Abaixo disso, defina a imagem ou image que você deseja baixar e fazer o deploy. Certifique-se de alterar sammy para seu próprio nome de usuário do Docker Hub:

      go-app/deployment.yml

      . . .
        template:
          metadata:
            labels:
              name: go-web-app
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
      

      Depois disso, adicione um campo imagePullPolicy definido como IfNotPresent, que direcionará o deployment para baixar uma imagem apenas se ainda não tiver feito isso antes. Então, por último, adicione um bloco ports. Lá, defina o containerPort que deve corresponder ao número da porta que sua aplicação Go está escutando. Neste caso, o número da porta é 3000:

      go-app/deployment.yml

      . . .
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 3000
      

      A versão completa do seu arquivo deployment.yml ficará assim:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: go-web-app
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
        template:
          metadata:
            labels:
              name: go-web-app
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 3000
      

      Salve e feche o arquivo.

      Em seguida, aplique seu novo deployment com o seguinte comando:

      • kubectl apply -f deployment.yml

      Nota: Para mais informações sobre todas as configurações disponíveis para seus deployments, confira a documentação oficial do Kubernetes aqui: Kubernetes Deployments

      Na próxima etapa, você criará outro tipo de objeto do Kubernetes que gerenciará como você vai acessar os pods existentes em seu novo deployment. Esse serviço criará um balanceador de carga que, então, vai expor um único endereço IP, e as solicitações para esse endereço IP serão distribuídas para as réplicas em seu deployment. Esse serviço também manipulará regras de encaminhamento de porta para que você possa acessar sua aplicação por HTTP.

      Passo 5 — Criando um Serviço

      Agora que você tem um deployment bem sucedido do Kubernetes, está pronto para expor sua aplicação ao mundo externo. Para fazer isso, você precisará definir outro tipo de objeto do Kubernetes: um service. Este serviço irá expor a mesma porta em todos os nodes do cluster. Então, seus nodes encaminharão qualquer tráfego de entrada nessa porta para os pods que estiverem executando sua aplicação.

      Nota: Para maior clareza, vamos definir esse objeto de serviço em um arquivo separado. No entanto, é possível agrupar vários manifests de recursos no mesmo arquivo YAML, contanto que estejam separados por ---. Veja esta página da documentação do Kubernetes para maiores detalhes.

      Crie um novo arquivo chamado service.yml:

      Inicie este arquivo novamente definindo os campos apiVersion e kind de maneira similar ao seu arquivo deployment.yml. Desta vez, aponte o campo apiVersion para v1, a API do Kubernetes comumente usada para serviços:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      

      Em seguida, adicione o nome do seu serviço em um bloco metadata como você fez em deployment.yml. Pode ser qualquer coisa que você goste, mas para clareza, vamos chamar de go-web-service:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      

      Em seguida, crie um bloco spec. Este bloco spec será diferente daquele incluído em seu deployment, e ele conterá o tipo ou type deste serviço, assim como a configuração de encaminhamento de porta e o seletor.

      Adicione um campo definindo o type deste serviço e defina-o para LoadBalancer. Isso provisionará automaticamente um balanceador de carga que atuará como o principal ponto de entrada para sua aplicação.

      Atenção: O método para criar um balanceador de carga descrito nesta etapa só funcionará para clusters Kubernetes provisionados por provedores de nuvem que também suportam balanceadores de carga externos. Além disso, esteja ciente de que provisionar um balanceador de carga de um provedor de nuvem incorrerá em custos adicionais. Se isto é uma preocupação para você, você pode querer olhar a exposição de um endereço IP externo usando um Ingress.

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
      

      Em seguida, adicione um bloco ports onde você definirá como deseja que seus apps sejam acessados. Aninhado dentro deste bloco, adicione os seguintes campos:

      • name, apontando para http
      • port, apontando para a porta 80
      • targetPort, apontando para a porta 3000

      Isto irá pegar solicitações HTTP de entrada na porta 80 e encaminhá-las para o targetPort de 3000. Este targetPort é a mesma porta na qual sua aplicação Go está rodando:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
        ports:
        - name: http
          port: 80
          targetPort: 3000
      

      Por último, adicione um bloco selector como você fez no arquivo deployments.yml. Este bloco selector é importante, pois mapeia quaisquer pods deployados chamados go-web-app para este serviço:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
        ports:
        - name: http
          port: 80
          targetPort: 3000
        selector:
          name: go-web-app
      

      Depois de adicionar essas linhas, salve e feche o arquivo. Depois disso, aplique este serviço ao seu cluster do Kubernetes novamente usando o comando kubectl apply assim:

      • kubectl apply -f service.yml

      Esse comando aplicará o novo serviço do Kubernetes, além de criar um balanceador de carga. Esse balanceador de carga servirá como o ponto de entrada voltado ao público para a sua aplicação em execução no cluster.

      Para visualizar a aplicação, você precisará do endereço IP do novo balanceador de carga. Encontre-o executando o seguinte comando:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE go-web-service LoadBalancer 10.245.107.189 203.0.113.20 80:30533/TCP 10m kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 3h4m

      Você pode ter mais de um serviço em execução, mas encontre o que está com a label go-web-service. Encontre a coluna EXTERNAL-IP e copie o endereço IP associado ao go-web-service. Neste exemplo de saída, este endereço IP é 203.0.113.20. Em seguida, cole o endereço IP na barra de URL do seu navegador para visualizar a aplicação em execução no seu cluster Kubernetes.

      Nota: Quando o Kubernetes cria um balanceador de carga dessa maneira, ele faz isso de forma assíncrona. Consequentemente, a saída do comando kubectl get services pode mostrar o endereço EXTERNAL-IP do LoadBalancer restante em um estado <pending> por algum tempo após a execução do comando kubectl apply. Se for esse o caso, aguarde alguns minutos e tente executar novamente o comando para garantir que o balanceador de carga foi criado e está funcionando conforme esperado.

      O balanceador de carga receberá a solicitação na porta 80 e a encaminhará para um dos pods em execução no seu cluster.

      Your working Go App!

      Com isso, você criou um serviço Kubernetes acoplado a um balanceador de carga, oferecendo um ponto de entrada único e estável para a aplicação.

      Conclusão

      Neste tutorial, você criou uma aplicação Go, containerizada com o Docker e, em seguida, fez o deploy dela em um cluster Kubernetes. Em seguida, você criou um balanceador de carga que fornece um ponto de entrada resiliente para essa aplicação, garantindo que ela permaneça altamente disponível, mesmo se um dos nodes do cluster falhar. Você pode usar este tutorial para fazer o deploy da sua própria aplicação Go em um cluster Kubernetes ou continuar aprendendo outros conceitos do Kubernetes e do Docker com a aplicação de exemplo que você criou no Passo 1.

      Seguindo em frente, você pode mapear o endereço IP do seu balanceador de carga para um nome de domínio que você controla para que você possa acessar a aplicação por meio de um endereço web legível em vez do IP do balanceador de carga. Além disso, os seguintes tutoriais de Kubernetes podem ser de seu interesse:

      Por fim, se você quiser saber mais sobre o Go, recomendamos que você confira nossa série sobre Como Programar em Go.



      Source link

      Uma Introdução aos Service Meshes


      Introdução

      Um service mesh é uma camada de infraestrutura que permite gerenciar a comunicação entre os microsserviços da sua aplicação. À medida que mais desenvolvedores trabalham com microsserviços, os service meshes evoluíram para tornar esse trabalho mais fácil e mais eficaz consolidando tarefas administrativas e de gerenciamento comuns em uma configuração distribuída.

      Aplicar uma abordagem de microsserviço à arquitetura de aplicações envolve dividir sua aplicação em uma coleção de serviços fracamente acoplados. Essa abordagem oferece certos benefícios: as equipes podem iterar projetos e escalar rapidamente, usando uma variedade maior de ferramentas e linguagens. Por outro lado, os microsserviços representam novos desafios para a complexidade operacional, consistência de dados e segurança.

      Service meshes são projetados para resolver alguns desses desafios, oferecendo um nível granular de controle sobre como os serviços se comunicam uns com os outros. Especificamente, eles oferecem aos desenvolvedores uma maneira de gerenciar:

      • Descoberta de serviço
      • Roteamento e configuração de tráfego
      • Criptografia e autenticação/autorização
      • Métricas e monitoramento

      Embora seja possível executar essas tarefas de forma nativa com orquestradores de containers como o Kubernetes, essa abordagem envolve uma maior quantidade de tomadas de decisão e administração antecipadas quando comparada com o que as soluções de service mesh como o Istio e o Linkerd oferecem por fora. Nesse sentido, service meshes podem agilizar e simplificar o processo de trabalho com componentes comuns em uma arquitetura de microsserviço. Em alguns casos, eles podem até ampliar a funcionalidade desses componentes.

      Por que Service Meshes?

      Service meshes são projetados para resolver alguns dos desafios inerentes às arquiteturas de aplicações distribuídas.

      Essas arquiteturas cresceram a partir do modelo de aplicação de três camadas, que dividia as aplicações em uma camada web, uma camada de aplicação e uma camada de banco de dados. Ao escalar, esse modelo se mostrou desafiador para organizações que experimentam um rápido crescimento. Bases de código de aplicações monolíticas podem se tornar bagunçadas, conhecidas como “big balls of mud”, impondo desafios para o desenvolvimento e o deployment.

      Em resposta a esse problema, organizações como Google, Netflix e Twitter desenvolveram bibliotecas “fat client” internas para padronizar as operações de runtime entre os serviços. Essas bibliotecas forneceram balanceamento de carga, circuit breaker , roteamento e telemetria — precursores para recursos de service mesh. No entanto, eles também impuseram limitações às linguagens que os desenvolvedores poderiam usar e exigiram mudanças nos serviços quando eles próprios foram atualizados ou alterados.

      Um design de microsserviço evita alguns desses problemas. Em vez de ter uma base de código grande e centralizada de aplicações, você tem uma coleção de serviços gerenciados discretamente que representam um recurso da sua aplicação. Os benefícios de uma abordagem de microsserviço incluem:

      • Maior agilidade no desenvolvimento e no deployment, já que as equipes podem trabalhar e fazer deploy de diferentes recursos de aplicações de forma independente.
      • Melhores opções para CI/CD, já que microsserviços individuais podem ser testados e terem deploys refeitos independentemente.
      • Mais opções para linguagens e ferramentas. Os desenvolvedores podem usar as melhores ferramentas para as tarefas em questão, em vez de se restringirem a uma determinada linguagem ou conjunto de ferramentas.
      • Facilidade de escalar.
      • Melhorias no tempo de atividade, experiência do usuário e estabilidade.

      Ao mesmo tempo, os microsserviços também criaram desafios:

      • Sistemas distribuídos exigem diferentes maneiras de pensar sobre latência, roteamento, fluxos de trabalho assíncronos e falhas.
      • As configurações de microsserviço podem não atender necessariamente aos mesmos requisitos de consistência de dados que as configurações monolíticas.
      • Níveis maiores de distribuição exigem designs operacionais mais complexos, particularmente quando se trata de comunicação de serviço a serviço.
      • A distribuição de serviços aumenta a área de superfície para vulnerabilidades de segurança.

      Service meshes são projetados para resolver esses problemas, oferecendo controle coordenado e granular sobre como os serviços se comunicam. Nas seções a seguir, veremos como service meshes facilitam a comunicação de serviço a serviço por meio da descoberta de serviços, roteamento e balanceamento interno de carga, configuração de tráfego, criptografia, autenticação e autorização, métricas e monitoramento. Vamos utilizar a aplicação de exemplo Bookinfo do Istio — quatro microsserviços que juntos exibem informações sobre determinados livros — como um exemplo concreto para ilustrar como os service meshes funcionam.

      Descoberta de Serviço

      Em um framework distribuído, é necessário saber como se conectar aos serviços e saber se eles estão ou não disponíveis. Os locais das instâncias de serviço são atribuídos dinamicamente na rede e as informações sobre eles estão em constante mudança, à medida que os containers são criados e destruídos por meio do escalonamento automático, upgrades e falhas.

      Historicamente, existiram algumas ferramentas para fazer a descoberta de serviços em uma estrutura de microsserviço. Repositórios de chave-valor como o etcd foram emparelhados com outras ferramentas como o Registrator para oferecer soluções de descoberta de serviços. Ferramentas como o Consul iteraram isso combinando um armazenamento de chave-valor com uma interface de DNS que permite aos usuários trabalhar diretamente com seu servidor ou nó DNS.

      Tomando uma abordagem semelhante, o Kubernetes oferece descoberta de serviço baseada em DNS por padrão. Com ele, você pode procurar serviços e portas de serviço e fazer pesquisas inversas de IP usando convenções comuns de nomenclatura de DNS. Em geral, um registro A para um serviço do Kubernetes corresponde a esse padrão: serviço.namespace.svc.cluster.local. Vamos ver como isso funciona no contexto do aplicativo Bookinfo. Se, por exemplo, você quisesse informações sobre o serviço details do aplicativo Bookinfo, poderia ver a entrada relevante no painel do Kubernetes:

      Details Service in Kubernetes Dash

      Isto lhe dará informações relevantes sobre o nome do serviço, namespace e ClusterIP, que você pode usar para se conectar ao seu serviço, mesmo que os containers individuais sejam destruídos e recriados.

      Um service mesh como o Istio também oferece recursos de descoberta de serviço. Para fazer a descoberta de serviços, o Istio confia na comunicação entre a API do Kubernetes, o próprio plano de controle do Istio, gerenciado pelo componente de gerenciamento de tráfego Pilot, e seu plano de dados, gerenciado pelos proxies sidecar Envoy. O Pilot interpreta os dados do servidor da API do Kubernetes para registrar as alterações nos locais do Pod. Em seguida, ele converte esses dados em uma representação canônica Istio e os encaminha para os proxies sidecar.

      Isso significa que a descoberta de serviço no Istio é independente de plataforma, o que podemos ver usando o add-on Grafana do Istio para olhar o serviço details novamente no painel de serviço do Istio:

      Details Service Istio Dash

      Nossa aplicação está sendo executada em um cluster Kubernetes, então, mais uma vez, podemos ver as informações relevantes do DNS sobre o Serviço details, juntamente com outros dados de desempenho.

      Em uma arquitetura distribuída, é importante ter informações atualizadas, precisas e fáceis de localizar sobre serviços. Tanto o Kubernetes quanto os service meshes, como o Istio, oferecem maneiras de obter essas informações usando convenções do DNS.

      Configuração de Roteamento e Tráfego

      Gerenciar o tráfego em uma estrutura distribuída significa controlar como o tráfego chega ao seu cluster e como ele é direcionado aos seus serviços. Quanto mais controle e especificidade você tiver na configuração do tráfego externo e interno, mais você poderá fazer com sua configuração. Por exemplo, nos casos em que você está trabalhando com deployments piloto (canary), migrando aplicativos para novas versões ou testando serviços específicos por meio de injeção de falhas, ter a capacidade de decidir quanto tráfego seus serviços estão obtendo e de onde ele vem será a chave para o sucesso de seus objetivos.

      O Kubernetes oferece diferentes ferramentas, objetos e serviços que permitem aos desenvolvedores controlar o tráfego externo para um cluster: kubectl proxy, NodePort, Load Balancers, e Ingress Controllers and Resources. O kubectl proxy e o NodePort permitem expor rapidamente seus serviços ao tráfego externo: O kubectl proxy cria um servidor proxy que permite acesso ao conteúdo estático com um caminho HTTP, enquanto o NodePort expõe uma porta designada aleatoriamente em cada node. Embora isso ofereça acesso rápido, as desvantagens incluem ter que executar o kubectl como um usuário autenticado, no caso do kubectl proxy, e a falta de flexibilidade nas portas e nos IPs do node, no caso do NodePort. E, embora um Balanceador de Carga otimize a flexibilidade ao se conectar a um serviço específico, cada serviço exige seu próprio Balanceador de Carga, o que pode custar caro.

      Um Ingress Resource e um Ingress Controller juntos oferecem um maior grau de flexibilidade e configuração em relação a essas outras opções. O uso de um Ingress Controller com um Ingress Resource permite rotear o tráfego externo para os serviços e configurar o roteamento interno e o balanceamento de carga. Para usar um Ingress Resource, você precisa configurar seus serviços, o Ingress Controller e o LoadBalancer e o próprio Ingress Resource, que especificará as rotas desejadas para os seus serviços. Atualmente, o Kubernetes suporta seu próprio Controlador Nginx, mas há outras opções que você pode escolher também, gerenciadas pelo Nginx, Kong, e outros.

      O Istio itera no padrão Controlador/Recurso do Kubernetes com Gateways do Istio e VirtualServices. Como um Ingress Controller, um gateway define como o tráfego de entrada deve ser tratado, especificando as portas e os protocolos expostos a serem usados. Ele funciona em conjunto com um VirtualService, que define rotas para serviços dentro da malha ou mesh. Ambos os recursos comunicam informações ao Pilot, que encaminha essas informações para os proxies Envoy. Embora sejam semelhantes ao Ingress Controllers and Resources, os Gateways e os VirtualServices oferecem um nível diferente de controle sobre o tráfego: em vez de combinar camadas e protocolos Open Systems Interconnection (OSI), Gateways e VirtualServices permitem diferenciar entre as camadas OSI nas suas configurações. Por exemplo, usando VirtualServices, as equipes que trabalham com especificações de camada de aplicação podem ter interesses diferenciados das equipes de operações de segurança que trabalham com diferentes especificações de camada. Os VirtualServices possibilitam separar o trabalho em recursos de aplicações distintos ou em diferentes domínios de confiança e podem ser usados para testes como canary, rollouts graduais, testes A/B, etc.

      Para visualizar a relação entre os serviços, você pode usar o add-on Servicegraph do Istio, que produz uma representação dinâmica da relação entre os serviços usando dados de tráfego em tempo real. A aplicação Bookinfo pode se parecer com isso sem qualquer roteamento personalizado aplicado:

      Bookinfo service graph

      Da mesma forma, você pode usar uma ferramenta de visualização como o Weave Scope para ver a relação entre seus serviços em um determinado momento. A aplicação Bookinfo sem roteamento avançado pode ter esta aparência:

      Weave Scope Service Map

      Ao configurar o tráfego de aplicações em uma estrutura distribuída, há várias soluções diferentes — de opções nativas do Kubernetes até service meshes como o Istio — que oferecem várias opções para determinar como o tráfego externo chegará até seus recursos de aplicação e como esses recursos se comunicarão entre si.

      Criptografia e Autenticação/Autorização

      Um framework distribuído apresenta oportunidades para vulnerabilidades de segurança. Em vez de se comunicarem por meio de chamadas internas locais, como aconteceria em uma configuração monolítica, os serviços em uma arquitetura de microsserviço transmitem informações, incluindo informações privilegiadas, pela rede. No geral, isso cria uma área de superfície maior para ataques.

      Proteger os clusters do Kubernetes envolve uma variedade de procedimentos; Vamos nos concentrar em autenticação, autorização e criptografia. O Kubernetes oferece abordagens nativas para cada um deles:

      • Autenticação: As solicitações de API no Kubernetes estão vinculadas a contas de usuário ou serviço, que precisam ser autenticadas. Existem várias maneiras diferentes de gerenciar as credenciais necessárias: Tokens estáticos, tokens de bootstrap, certificados de cliente X509 e ferramentas externas, como o OpenID Connect.
      • Autorização: O Kubernetes possui diferentes módulos de autorização que permitem determinar o acesso com base em funções como papéis, atributos e outras funções especializadas. Como todas as solicitações ao servidor da API são negadas por padrão, cada parte de uma solicitação da API deve ser definida por uma política de autorização.
      • Criptografia: Pode referir-se a qualquer um dos seguintes: conexões entre usuários finais e serviços, dados secretos, terminais no plano de controle do Kubernetes e comunicação entre componentes worker do cluster e componentes master. O Kubernetes tem diferentes soluções para cada um deles:

      A configuração de políticas e protocolos de segurança individuais no Kubernetes requer investimento administrativo. Um service mesh como o Istio pode consolidar algumas dessas atividades.

      O Istio foi projetado para automatizar parte do trabalho de proteção dos serviços. Seu plano de controle inclui vários componentes que lidam com segurança:

      • Citadel: gerencia chaves e certificados.
      • Pilot: supervisiona as políticas de autenticação e nomenclatura e compartilha essas informações com os proxies Envoy.
      • Mixer: gerencia autorização e auditoria.

      Por exemplo, quando você cria um serviço, o Citadel recebe essa informação do kube-apiserver e cria certificados e chaves SPIFFE para este serviço. Em seguida, ele transfere essas informações para Pods e sidecars Envoy para facilitar a comunicação entre os serviços.

      Você também pode implementar alguns recursos de segurança habilitando o TLS mútuo durante a instalação do Istio. Isso inclui identidades de serviço fortes para comunicação interna nos clusters e entre clusters, comunicação segura de serviço para serviço e de usuários para serviço, e um sistema de gerenciamento de chaves capaz de automatizar a criação, a distribuição e a rotação de chaves e certificados.

      Ao iterar em como o Kubernetes lida com autenticação, autorização e criptografia, service meshes como o Istio são capazes de consolidar e estender algumas das melhores práticas recomendadas para a execução de um cluster seguro do Kubernetes.

      Métricas e Monitoramento

      Ambientes distribuídos alteraram os requisitos para métricas e monitoramento. As ferramentas de monitoramento precisam ser adaptativas, respondendo por mudanças frequentes em serviços e endereços de rede, e abrangentes, permitindo a quantidade e o tipo de informações que passam entre os serviços.

      O Kubernetes inclui algumas ferramentas internas de monitoramento por padrão. Esses recursos pertencem ao seu pipeline de métricas de recursos, que garante que o cluster seja executado conforme o esperado. O componente cAdvisor coleta estatísticas de uso de rede, memória e CPU de containers e nodes individuais e passa essas informações para o kubelet; o kubelet, por sua vez, expõe essas informações por meio de uma API REST. O servidor de métricas obtém essas informações da API e as repassa para o kube-aggregator para formatação.

      Você pode estender essas ferramentas internas e monitorar os recursos com uma solução completa de métricas. Usando um serviço como o Prometheus como um agregador de métricas, você pode criar uma solução diretamente em cima do pipeline de métricas de recursos do Kubernetes. O Prometheus integra-se diretamente ao cAdvisor através de seus próprios agentes, localizados nos nodes. Seu principal serviço de agregação coleta e armazena dados dos nodes e os expõe através de painéis e APIs. Opções adicionais de armazenamento e visualização também estão disponíveis se você optar por integrar seu principal serviço de agregação com ferramentas de backend de armazenamento, registro e visualização, como InfluxDB, Grafana, ElasticSearch, Logstash, Kibana, e outros.

      Em um service mesh como o Istio, a estrutura do pipeline completo de métricas faz parte do design da malha. Os sidecars do Envoy operando no nível do Pod comunicam as métricas ao Mixer, que gerencia políticas e telemetria. Além disso, os serviços Prometheus e Grafana estão habilitados por padrão (embora se você estiver instalando o Istio com o Helm você precisará especificar granafa.enabled=true durante a instalação). Como no caso do pipeline completo de métricas, você também pode configurar outros serviços e deployments para opções de registro e visualização.

      Com essas ferramentas de métrica e visualização, você pode acessar informações atuais sobre serviços e cargas de trabalho em um local central. Por exemplo, uma visão global do aplicativo BookInfo pode ter esta aparência no painel Grafana do Istio:

      Bookinfo services from Grafana dash

      Ao replicar a estrutura de um pipeline completo de métricas do Kubernetes e simplificar o acesso a alguns de seus componentes comuns, service meshes como o Istio agilizam o processo de coleta e visualização de dados ao trabalhar com um cluster.

      Conclusão

      As arquiteturas de microsserviço são projetadas para tornar o desenvolvimento e o deployment de aplicações mais rápidos e confiáveis. No entanto, um aumento na comunicação entre serviços mudou as práticas recomendadas para determinadas tarefas administrativas. Este artigo discute algumas dessas tarefas, como elas são tratadas em um contexto nativo do Kubernetes e como elas podem ser gerenciadas usando service mesh – nesse caso, o Istio.

      Para obter mais informações sobre alguns dos tópicos do Kubernetes abordados aqui, consulte os seguintes recursos:

      Além disso, os hubs de documentação do Kubernetes e do Istio são ótimos lugares para encontrar informações detalhadas sobre os tópicos discutidos aqui.



      Source link