A porta de entrada
O API Server (kube-apiserver) é o único componente que fala com o etcd. Toda operação no cluster passa por ele. kubectl fala com o API Server. Os controllers falam com o API Server. O scheduler fala com o API Server. O kubelet fala com o API Server.
Não existe acesso direto ao etcd (só o API Server tem). Isso é por design: o API Server é a camada de autenticação, autorização e validação do cluster.
REST
O API Server expõe uma API RESTful com Verbos HTTP padrão:
GET /api/v1/pods lista todos os pods
POST /api/v1/namespaces/default/pods cria um pod
GET /api/v1/namespaces/default/pods/nginx lê um pod específico
PUT /api/v1/namespaces/default/pods/nginx substitui o pod inteiro
PATCH /api/v1/namespaces/default/pods/nginx atualiza campos específicos
DELETE /api/v1/namespaces/default/pods/nginx deleta o podTodo recurso tem um path REST. Pods, services, deployments, configmaps, secrets, nodes: cada um tem seu endpoint. O kubectl é só um cliente HTTP que fala essa API.
kubectl é um cliente REST
Vamos ver as chamadas HTTP que o kubectl faz. O flag -v=6 mostra o log de requisições:
kubectl get pods -v=6 2>&1 | grep GET
I0524 22:38:13.870636 9299 round_trippers.go:560] GET https://172.31.45.35:6443/api/v1/namespaces/default/pods?limit=500 200 OK in 11 millisecondsO que está acontecendo:
kubectlcarregou o kubeconfig (/home/ubuntu/.kube/config)- Conectou via HTTPS na porta
6443(API Server) - Fez um
GET /api/v1/namespaces/default/pods?limit=500 - O API Server respondeu
200 OKem 11 milissegundos
Toda operação do kubectl é uma chamada REST. Criar um deployment é um POST. Listar pods é um GET. Deletar é um DELETE. O kubectl só traduz sua linha de comando em HTTP.
Você pode usar -v=8 pra ver ainda mais detalhes (headers, corpo da resposta, TLS handshake). Mas o -v=6 já mostra o essencial: qual endpoint foi chamado, quanto tempo levou e o código de resposta.
Watch
Assim como o etcd, o API Server suporta watch. Adiciona ?watch=true na query string e a conexão fica aberta, enviando eventos em streaming.
O scheduler assiste GET /api/v1/pods?watch=true pra descobrir pods novos sem polling. O kubelet assiste pods atribuídos ao seu nó. O controller manager assiste deployments, replicasets e tudo mais que gerencia.
É um pattern consistente: cada componente abre watches nos recursos que lhe interessam e reage a eventos (ADDED, MODIFIED, DELETED). Sem watch, cada componente teria que fazer polling. Com milhares de recursos, polling não escala.
RBAC (Role-Based Access Control)
O API Server decide quem pode fazer o quê. O modelo é simples:
- Subject: quem (usuário, grupo, service account)
- Resource: o quê (pods, deployments, secrets, nodes)
- Verb: ação (get, list, create, delete, watch, update, patch)
- Role: conjunto de permissões (resources + verbs)
- RoleBinding: liga um subject a uma role
Vamos testar na prática com kubectl auth can-i:
kubectl auth can-i get pods -n kube-system
yesPodemos listar pods no kube-system.
kubectl auth can-i delete pods -n default
yesPodemos deletar pods no default namespace.
Agora uma service account sem permissões:
kubectl auth can-i create pods --as system:serviceaccount:default:default
noA service account default no namespace default não pode criar pods.
kubectl auth can-i create deployments -n kube-system --as system:serviceaccount:default:default
noEla também não pode criar deployments no kube-system. Toda service account nasce sem permissões. Você tem que criar Roles e RoleBindings explicitamente.
Exemplo de Role e RoleBinding
Uma Role que permite listar pods no namespace default:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]E um RoleBinding que dá essa permissão pra uma service account:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: default
name: read-pods
subjects:
- kind: ServiceAccount
name: my-app
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioA lógica é: Role define permissões. RoleBinding conecta a permissão a alguém. Sem RoleBinding, a Role não serve pra nada. Sem Role, o RoleBinding não tem o que conceder.
Para permissões que valem no cluster inteiro (todos os namespaces), use ClusterRole e ClusterRoleBinding. A estrutura é idêntica, mas sem o campo namespace.
Fluxo completo de uma requisição
Quando você faz kubectl delete pod nginx, o caminho é:
- TLS handshake:
kubectlapresenta certificado de cliente (do kubeconfig) - Authentication: API Server valida o certificado contra a CA do cluster
- Authorization: API Server verifica se o usuário tem permissão pra
delete podsno namespace - Admission Control: plugins podem modificar ou rejeitar a requisição. Exemplo:
NamespaceLifecycleimpede deletar namespaces protegidos - Validação: API Server valida o JSON/YAML contra o schema do recurso
- Escrita no etcd: API Server escreve o objeto (marca pra deleção)
- Resposta:
200 OKvolta prokubectl
A resposta volta antes do pod ser deletado. A deleção real acontece quando o kubelet recebe o watch event e manda o containerd parar o container. O API Server não executa nada, ele só orquestra.
Configuração real do nosso API Server
kubectl get pod -n kube-system kube-apiserver-ip-172-31-45-35 -o yaml
Argumentos principais que você vai ver no output:
--advertise-address=172.31.45.35
--authorization-mode=Node,RBAC
--client-ca-file=/etc/kubernetes/pki/ca.crt
--etcd-servers=https://127.0.0.1:2379
--secure-port=6443
--service-cluster-ip-range=10.96.0.0/12
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt
--tls-private-key-file=/etc/kubernetes/pki/apiserver.keyAlguns pontos importantes:
--authorization-mode=Node,RBAC: dois modos. Node autoriza kubelets automaticamente. RBAC autoriza usuários e service accounts.--etcd-servers=https://127.0.0.1:2379: etcd está no mesmo nó, escutando em localhost com TLS.--secure-port=6443: porta padrão do API Server. Toda comunicação é TLS.--service-cluster-ip-range=10.96.0.0/12: range de IPs virtuais (ClusterIP). Não são IPs reais de rede. O Cilium (ou kube-proxy) traduz esses IPs pros pods reais.