O Guia Definitivo sobre Pods e Serviços no Kubernetes

O Kubernetes é uma plataforma poderosa de orquestração de contêineres, mas para aproveitar todo o seu potencial, é importante entender seus componentes principais, com pods e serviços desempenhando papéis fundamentais. Neste artigo, vamos mergulhar no que eles são e como trabalham juntos para expor e gerenciar o acesso a aplicativos em execução dentro de um cluster Kubernetes.

O que é um Pod?

Pods são as menores unidades implantáveis de computação que você pode criar e gerenciar no Kubernetes.

Antes de criarmos um pod, vamos verificar os recursos da API disponíveis em seu cluster Kubernetes; você pode usar o comando kubectl api-resources. Esse comando lista os recursos da API que são suportados pelo servidor de API do Kubernetes, incluindo seus nomes curtos, grupos de API e se são ou não namespaced. Isso é útil para entender as capacidades do seu cluster, especialmente ao trabalhar com recursos personalizados ou explorar novos recursos do Kubernetes. O comando kubectl explain complementa isso fornecendo informações detalhadas sobre recursos individuais.

Vamos criar um arquivo de configuração básica de pod para um pod em execução de um contêiner Nginx simples.

Crie um arquivo com o nome nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Aqui está uma breve explicação dos termos utilizados:

  • apiVersion: v1: Especifica a versão da API.
  • kind: Pod: Indica que esta configuração é para um pod.
  • metadata:name: O nome do pod.
  • metadados: etiquetas: Pares de chave-valor que podem ser usados para organizar e selecionar o pod.
  • especificação:containers: Uma lista de containers que serão executados no pod.
  • especificação:containers:nome: O nome do container.
  • especificação:containers:imagem: A imagem do container a ser usada (neste caso, a última imagem do Nginx).
  • especificação:containers:portas: As portas a serem expostas pelo container.

Use kubectl para aplicar o arquivo de configuração e criar o pod:

  • kubectl apply -f nginx-pod.yaml

Verifique o status do pod para garantir que ele tenha sido criado e esteja em execução:

  • kubectl get pods

Você deverá ver uma saída semelhante a esta:

Shell

 

NAME         READY   STATUS    RESTARTS    AGE
nginx-pod    1/1     Running   0           10s

Em seguida, exclua o pod:

  • kubectl delete pod nginx-pod

A saída deve se parecer com o seguinte:

Shell

 

kubectl get pod
No resources found in default namespace.

O que é um Serviço?

Criar um serviço para um pod Nginx no Kubernetes permite expor a aplicação Nginx e torná-la acessível dentro ou fora do cluster. Aqui está um guia passo a passo para criar um Serviço para um pod Nginx.

Para garantir que você tenha um pod Nginx em execução, se você ainda não tiver um, crie um arquivo YAML chamado nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Aplique a configuração do Pod:

Crie um arquivo YAML chamado nginx-service.yaml para definir o Service:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
  type: ClusterIP

Aqui estão algumas coisas a serem observadas:

  • selector: Um seletor de rótulo para corresponder ao pod do Nginx.
  • app: nginx: Isso deve corresponder ao rótulo no pod do Nginx.
  • type: ClusterIP: O tipo de Service. ClusterIP torna o Service acessível apenas dentro do cluster. Você também pode usar NodePort ou LoadBalancer para expor o Service externamente.

Aplique a configuração do Service usando kubectl:

  • kubectl apply -f nginx-service.yaml
  • kubectl get services
Shell

 

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   10.96.0.1        <none>        80/TCP    10s

Como o Service é do tipo ClusterIP, ele é acessível apenas dentro do cluster. Para acessá-lo de fora do cluster, você pode alterar o tipo de Service para NodePort ou LoadBalancer.

Para expor o Service externamente usando NodePort, modifique o arquivo nginx-service.yaml:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
      nodePort: 30007  # Specify a node port in the range 30000-32767 (optional)
  type: NodePort

Aplique a configuração do Service atualizada:

  • kubectl apply -f nginx-service.yaml

Agora você pode acessar a aplicação Nginx usando o endereço IP do nó e a porta do nó (por exemplo, http://<node-ip>:30007).

Multi-Container Pods

O uso de um único contêiner por pod fornece a máxima granularidade e desacoplamento. No entanto, existem cenários em que implantar múltiplos contêineres, às vezes referidos como contêineres compostos, dentro de um único pod é benéfico. Esses contêineres secundários podem desempenhar várias funções: lidar com o registro ou aprimorar o contêiner principal (conceito de sidecar), atuar como um proxy para sistemas externos (conceito de embaixador) ou modificar dados para se adequarem a um formato externo (conceito de adaptador). Esses contêineres secundários complementam o contêiner principal ao realizar tarefas que ele não gerencia.

Abaixo está um exemplo de configuração de Pod do Kubernetes que inclui um contêiner principal executando um servidor Nginx e um contêiner secundário atuando como um sidecar para lidar com o registro. O contêiner sidecar utiliza um contêiner de registro simples como BusyBox para demonstrar como ele pode seguir os registros de acesso do Nginx.

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-logging-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-sidecar
    image: busybox:latest
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

Em seguida, você fará o seguinte:

  • Salve a configuração YAML em um arquivo, por exemplo, nginx-with-logging-sidecar.yaml
  • Aplique a configuração usando kubectl:kubectl apply -f nginx-with-logging-sidecar.yaml
  • Verifique se o Pod está em execução: kubectl get pods
  • Verifique os logs do contêiner sidecar para ver os logs de acesso do Nginx: kubectl logs -f <pod-name> -c log-sidecar.

Ao seguir esses passos, você excluirá o Pod existente e aplicará a nova configuração, configurando um Pod com um contêiner Nginx e um contêiner sidecar para registro. Isso garantirá que a nova configuração esteja ativa e em execução em seu cluster Kubernetes.

Pods com vários contêineres no Kubernetes oferecem várias vantagens, possibilitando implantação e gerenciamento de aplicativos mais flexíveis e eficientes.

Padrões de Pod com Múltiplos Contêineres

Padrão Sidecar

Os contêineres sidecar podem aprimorar o aplicativo principal, fornecendo funções auxiliares como registro, gerenciamento de configuração ou proxy. Esse padrão ajuda a estender a funcionalidade sem modificar o contêiner principal. Um contêiner sidecar pode lidar com o registro coletando e encaminhando logs do contêiner do aplicativo principal.

Padrão Ambassador

Os contêineres Ambassador atuam como um proxy, gerenciando a comunicação entre o aplicativo principal e os serviços externos. Isso pode simplificar a integração e a configuração. Um contêiner Ambassador pode lidar com a terminação SSL ou funções de gateway de API.

O padrão Ambassador envolve o uso de um contêiner sidecar para gerenciar a comunicação entre o aplicativo principal e os serviços externos. Esse padrão pode lidar com tarefas como proxy, balanceamento de carga ou gerenciamento de conexões seguras, abstraindo assim a complexidade do contêiner do aplicativo principal.

  • Contêiner de Aplicativo Principal: Um servidor web simples que faz solicitações HTTP
  • Contêiner Ambassador: Proxy Envoy configurado para gerenciar solicitações para a API externa
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-ambassador
spec:
  containers:
  - name: web-app
    image: python:3.8-slim
    command: ["python", "-m", "http.server", "8000"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.18.3
    args: ["-c", "/etc/envoy/envoy.yaml"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  volumes:
  - name: config-volume
    configMap:
      name: envoy-config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-config
data:
  envoy.yaml: |
    static_resources:
      listeners:
      - name: listener_0
        address:
          socket_address:
            address: 0.0.0.0
            port_value: 8080
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match:
                      prefix: "/"
                    route:
                      cluster: external_service
              http_filters:
              - name: envoy.filters.http.router
      clusters:
      - name: external_service
        connect_timeout: 0.25s
        type: LOGICAL_DNS
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: external_service
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: api.example.com
                    port_value: 80

Este exemplo demonstra o padrão Ambassador no Kubernetes, onde um proxy Envoy atua como intermediário para gerenciar a comunicação externa para o contêiner de aplicativo principal. Este padrão ajuda a abstrair complexidades de comunicação e aprimora a modularidade e a manutenibilidade.

Padrão Adaptador

Contêineres Adaptadores podem modificar ou transformar dados entre o aplicativo principal e os sistemas externos, garantindo compatibilidade e integração. Por exemplo, um contêiner adaptador pode reformatar dados de log para atender aos requisitos de um serviço de log externo.

O padrão Adaptador no Kubernetes envolve o uso de um contêiner sidecar para transformar dados entre o contêiner de aplicativo principal e os sistemas externos. Isso pode ser útil quando o aplicativo principal requer dados em um formato específico que difere do formato fornecido ou exigido pelos sistemas externos.

Suponha que você tenha um contêiner de aplicativo principal que gera logs em um formato personalizado. Você precisa enviar esses logs para um serviço de log externo que requer logs em um formato padronizado específico. Um contêiner adaptador pode ser usado para transformar os dados de log no formato necessário antes de enviá-los para o serviço externo.

  • Contêiner de Aplicativo Principal: Um aplicativo simples que escreve logs em um formato personalizado.
  • Contêiner Adaptador: Um contêiner que lê os logs personalizados, os transforma em formato JSON e os envia para um serviço de log externo.
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-adapter
spec:
  containers:
  - name: log-writer
    image: busybox
    command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
  - name: log-adapter
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
    - name: json-logs
      mountPath: /var/log/json
  - name: log-sender
    image: busybox
    command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
    volumeMounts:
    - name: json-logs
      mountPath: /var/log/json
  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: json-logs
    emptyDir: {}

Este exemplo demonstra o padrão Adapter no Kubernetes, onde um contêiner adaptador transforma dados do contêiner de aplicativo principal no formato necessário antes de enviá-lo para um sistema externo. Este padrão ajuda a integrar aplicativos com serviços externos, lidando com transformações de formato de dados dentro do contêiner sidecar.

Resumo

Em resumo, pods:

  • São as menores unidades implantáveis no Kubernetes.
  • Representam uma única instância de um processo em execução.
  • Podem conter um ou mais contêineres.

Serviços:

  • Fornece um endereço IP estável e um nome DNS para acessar pods.
  • Permite o balanceamento de carga em um conjunto de pods.
  • Facilita a descoberta de serviços dentro do cluster.

Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services