Label Selector Tester · Kubernetes
Veja quais pods o seu selector casa — e por quê.
Cole os pods e o selector — uma string kubectl -l ou um bloco matchLabels / matchExpressions — e receba um veredito por recurso com a cláusula exata que decidiu. Incluindo a regra que quase todo mundo responde ao contrário: NotIn e != casam com um recurso que não tem essa label de jeito nenhum.
Roda no seu navegador — nada do que você cola sai desta página. Como comprovamos isso
Playground do Kubernetes Label Selector Tester
Equality-based clauses (=, !=) and set-based ones (in, notin, a bare key, !key) can be mixed freely in one -l string — commas mean AND. A Deployment's spec.selector accepts both forms but is immutable after creation; a Service's spec.selector is a plain label map and supports equality only.
Results update as you type — press Enter to run now.
Paste one manifest, a --- stream, a kind: List or a YAML list. Press Esc to release keyboard focus from the editor; ⌘/Ctrl + Enter runs and leaves it. Nothing you paste is uploaded.
Paste the resources above — or tap an example — to see, per resource, whether the selector matches it and which clause decided.
A lacuna
Um selector que não casa com nada não é erro em nenhum lugar do Kubernetes.
kubectl apply aceita. O API server aceita. Nenhum controlador registra aviso, nenhum evento é emitido, nenhum campo é marcado como inválido. O único sintoma de um Service cujo selector erra os pods por um caractere é um objeto Endpoints sem endereços — e quando você está olhando para isso, já está depurando no lugar errado. O mesmo silêncio cobre uma NetworkPolicy cujo podSelector não seleciona nada, que falha aberta exatamente como um controle de segurança não deveria.
As regras em si são a outra metade do problema, porque duas delas se leem ao contrário. env!=prod casa com um pod que não tem nenhuma label env — NotIn é satisfeito por uma chave ausente, por design, em um ramo do Requirement.Matches. E um selector vazio casa com tudo, enquanto um selector nil casa com nada. Cada fato é uma linha de Go, e os dois são lembrados invertidos com frequência.
É por isso que isto é uma ferramenta e não um artigo. Pergunte a um assistente « env!=prod casa com um pod sem label env?» e você recebe uma resposta fluente com cinquenta por cento de chance de estar errada — e manifestos gerados colocam matchExpressions dentro do spec.selector de um Service com naturalidade, um campo que só aceita um mapa simples de labels. Cole a afirmação aqui e a resposta sai da mesma semântica que o apimachinery implementa, com o motivo anexado, em uma aba que não manda nada para lugar nenhum.
Quer dimensionar o workload em vez de selecioná-lo? Kubernetes Resource Calculator soma requests e limits entre réplicas, e Env Example Checker encontra as variáveis que um contêiner espera e nunca recebe.
O pipeline
Como funciona.
Quatro passos, todos dentro da sua aba, reexecutados enquanto você digita.
-
Parsear o selector como o apimachinery faz.
A gramática `-l` passa por um port do lexer e do parser dele — sensível ao contexto, então `op in (in,notin)` é legal, e tolerante a espaços, então `env in ( prod , dev )` é o mesmo selector. Selectors estruturados seguem as regras do `LabelSelectorAsSelector`.
-
Ler o que estiver na área de transferência.
Um manifesto, um fluxo `---`, um `kind: List` ou uma lista YAML. O `spec.template.metadata.labels` de um workload vira a própria linha, porque um Service seleciona labels de pod e não as do Deployment.
-
Avaliar cláusula por cláusula.
`Requirement.Matches`, uma vez por recurso e por cláusula: `In` exige a chave presente, `NotIn` é satisfeito por uma chave ausente, `Exists` aceita o valor vazio e `DoesNotExist` não.
-
Mostrar a razão, não só o veredito.
Cada cláusula carrega a frase que a decidiu, nomeando o valor real da label. As correspondências por chave ausente ganham uma anotação âmbar, porque são as que pessoas e modelos de linguagem respondem ao contrário.
Referência
Cada operador, e o que uma chave ausente faz.
Sete formas de escrever uma cláusula, quatro operadores atrás delas e a coluna que quase nunca aparece ao lado da sintaxe: o que acontece quando o recurso não carrega a chave. Três das sete casam nesse caso.
| Escrito como | Operador | Forma estruturada | Chave ausente |
|---|---|---|---|
| key=value | In | matchLabels: {key: value} Um valor. `=` e `==` são o mesmo operador. | não casa |
| key==value | In | matchLabels: {key: value} Idêntico a `=`; só a forma escrita é preservada. | não casa |
| key!=value | NotIn | operator: NotIn, values: [value] O que as pessoas invertem. Uma chave ausente o satisfaz. | CASA |
| key in (a,b) | In | operator: In, values: [a, b] Exige pelo menos um valor; o conjunto é deduplicado e ordenado. | não casa |
| key notin (a,b) | NotIn | operator: NotIn, values: [a, b] A mesma regra de chave ausente do `!=`, porque é o mesmo operador. | CASA |
| key | Exists | operator: Exists Qualquer valor, inclusive a string vazia. Values são proibidos. | não casa |
| !key | DoesNotExist | operator: DoesNotExist Falha se a chave existir com valor vazio — presente continua presente. | CASA |
«Tem a label, e ela não é prod»
Uma cláusula sozinha não diz isso. env!=prod também leva todo recurso sem label env. Coloque Exists ao lado — vírgulas significam AND.
# também leva pods sem a label
kubectl get pods -l 'env!=prod'
# tem uma label env, e ela não é prod
kubectl get pods -l 'env,env!=prod' O selector vazio, de três formas
Vazio significa tudo; nil significa nada; e um Service omite o campo quando está vazio, o que o deixa sem endpoints gerenciados.
# todos os pods do namespace
podSelector: {}
# de novo, todos os recursos
selector:
matchLabels: {}
# um Service SEM selector: os endpoints
# são você quem gerencia
spec:
ports: [{ port: 80 }] A cerca
O que ele deliberadamente não faz.
Cada item foi estudado e recusado, porque a alternativa era uma resposta plausível que podia estar errada. Um tester que você não consegue auditar é um tester em que você tem que acreditar.
Field selectors
Outro mecanismo, com uma lista de campos indexados por kind e por versão, quase sempre sem operadores baseados em conjunto. Simular offline significaria adivinhar quais campos o seu cluster indexa.
Gt e Lt do node affinity
Pertencem ao NodeSelectorRequirement, não ao LabelSelectorRequirement. Digitar replicas>2 devolve uma mensagem que explica isso, não uma comparação que um label selector não expressa.
A semântica de namespaceSelector
Um peer de NetworkPolicy combina um namespaceSelector com um podSelector entre namespaces. Sem os objetos Namespace, a resposta honesta é o podSelector sozinho.
Qualquer coisa que precise do cluster
Nenhum API server é contatado, então não há lista de pods ao vivo, nem resultado de admission, nem objeto Endpoints. Tudo aqui vem do texto que você colou.
Limites ditos em vez de escondidos: até 500 documentos de recursos de uma colagem de no máximo 500.000 caracteres, e no máximo 100 cláusulas em um selector. O nome de uma chave de label é validado em 63 caracteres, o prefixo de subdomínio DNS opcional em 253 e um valor de label em 63 — os mesmos limites que o API server aplica.
Próximo passo
Cole o rastro no canal do incidente.
«Copy report» entrega a execução inteira em texto puro: o selector canônico e depois um bloco por recurso com o veredito e cada cláusula que decidiu. E então siga — some o que o workload realmente reserva, ou verifique as variáveis que os contêineres esperam.
Kubernetes Label Selector Tester — 3 of 5 resources match
selector: app=web,tier=frontend
NO MATCH — Pod/web-d
metadata.labels: app=web, tier=frontnd
[ok] app=web — label app="web" = "web"
[no] tier=frontend — label tier="frontnd" ≠ "frontend" FAQ
Suas perguntas, respondidas.
Toque em uma pergunta para expandir a resposta.
Por que env!=prod casa com um pod que não tem nenhuma label env?
Porque é o que a regra diz, e é a linha mais surpreendente de toda a API de label selectors. No k8s.io/apimachinery, o Requirement.Matches resolve NotIn e != em um único ramo: se o conjunto de labels não tem a chave, o resultado é true. In e == tomam o ramo oposto: se a chave falta, o resultado é false. Então env!=prod significa «nenhuma label env valendo prod», e um pod sem label env cumpre isso perfeitamente. Se você queria dizer «tem uma label env, e ela não é prod», precisa de duas cláusulas: env,env!=prod — Exists E NotIn. Este tester anota toda cláusula que se cumpre porque a chave está ausente, então você nunca precisa lembrar em que sentido isso vai.
Qual é a diferença entre matchLabels e matchExpressions?
matchLabels é um mapa simples, e cada par vira um requisito de igualdade: {app: web, tier: frontend} é exatamente app=web,tier=frontend. matchExpressions é uma lista de entradas {key, operator, values} e é o único jeito de escrever os operadores baseados em conjunto In, NotIn, Exists e DoesNotExist. Quando um selector tem os dois, o apimachinery junta tudo com AND — o LabelSelectorAsSelector adiciona cada par de matchLabels e cada expressão à mesma lista de requisitos. Não existe OR em nenhum nível de um label selector.
Um selector de Service pode usar matchExpressions?
Não, e esse é o erro que os manifestos gerados cometem com mais frequência. O spec.selector de um Service é tipado como map[string]string, não como LabelSelector: ele aceita um mapa simples de labels e só suporta igualdade. Se você escrever matchLabels ou matchExpressions ali, o API server rejeita o campo na hora. Deployments, StatefulSets, DaemonSets, Jobs e o podSelector de uma NetworkPolicy aceitam um LabelSelector de verdade e admitem as duas formas. Cole um manifesto de Service com matchExpressions neste tester e ele avisa, e depois mostra o que um Deployment TERIA casado — assim você vê o erro e a intenção ao mesmo tempo.
Um selector vazio casa com tudo ou com nada?
Depende de o campo estar vazio ou ausente, e não é a mesma coisa. Um LabelSelector vazio — {}, ou matchLabels: {} — é labels.Everything(): casa com todos os objetos, e é justamente por isso que uma NetworkPolicy com podSelector: {} vale para todos os pods do namespace. Um selector nil, ao contrário, não casa com nada: LabelSelectorAsSelector(nil) devolve labels.Nothing(). E um Service é um terceiro caso: o campo selector é omitido quando está vazio, então um Service com selector: {} é um Service sem selector, e o controlador de endpoints não gerencia os endpoints dele de forma alguma.
Algo que eu colo sai do meu navegador?
Não. Os dois parsers, a validação e o matcher são JavaScript rodando na sua aba — não há servidor, nem chamada de API, nem log, então 0 bytes são enviados. Aqui isso conta porque um dump de pods não é texto neutro: ele carrega referências de imagens internas, nomes de nós, annotations e às vezes um token montado como variável de ambiente. Esta é a ferramenta que você pode usar em saída de produção sem abrir uma conversa sobre tratamento de dados.
Meu Service está com zero endpoints. O que eu verifico primeiro?
As labels dos pods, não o Service. Cole o manifesto do Service como selector e os pods reais como recursos: o tester lê o spec.selector para você e mostra um rastro por cláusula em cada pod, então um erro de digitação de um caractere aparece como label tier="frontnd" ≠ "frontend" em vez de uma lista de endpoints vazia. Descarte também duas armadilhas estruturais. Primeiro, um Service seleciona labels de POD, não os metadata.labels do próprio Deployment — é exatamente por isso que este tester lista o spec.template.metadata.labels de um workload como a própria linha «Pod template». Segundo, um selector que não casa com nada não é erro em nenhum lugar do Kubernetes: o kubectl aceita, o API server aceita, e o único sintoma é um objeto Endpoints vazio.
Ele suporta field selectors como --field-selector status.phase=Running?
Não, e isso é uma fronteira deliberada, não uma lacuna. Field selectors são outro mecanismo: filtram pelos campos do próprio objeto, são avaliados pelo API server contra uma lista curta de campos permitidos que varia por tipo de recurso, e quase nenhum suporta operadores baseados em conjunto. Simulá-los offline significaria codificar quais campos cada versão do Kubernetes indexa para cada kind, e errar de forma sutil. Esta ferramenta cobre label selectors, que funcionam igual em todos os tipos de recurso e ficam totalmente definidos pelo objeto que você já tem na área de transferência.
E os operadores Gt e Lt que eu vi em node affinity?
Eles existem, mas não em um label selector. Node affinity usa NodeSelectorRequirement, um tipo separado cujo conjunto de operadores é In, NotIn, Exists, DoesNotExist, Gt e Lt. Um LabelSelectorRequirement — o de matchExpressions, spec.selector e podSelector — tem só os quatro primeiros. Então Gt e Lt são válidos em nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution e inválidos em tudo o que este tester olha. Digite replicas>2 no campo do selector e ele diz isso, em vez de inventar uma comparação que um label selector não tem.
Quanto ele aguenta, e quais são os limites?
Ele avalia os primeiros 500 documentos de recursos de uma colagem de até 500.000 caracteres, e um selector de no máximo 100 cláusulas — cada limite se anuncia na tela com o número real, então uma execução truncada nunca parece completa. Chaves e valores são validados contra os limites reais: o nome de uma chave de label vai até 63 caracteres, o prefixo de subdomínio DNS opcional antes da / vai até 253, e um valor de label vai até 63 (valor vazio é legal). Uma chave ou valor inválido no SELECTOR é erro que bloqueia, porque o API server rejeitaria; uma label inválida em um RECURSO é só uma nota, porque a pergunta que você fez foi se o selector casa com ele.
More free, private DevOps tools.
O Label Selector Tester é uma ferramenta do OpsCanopy — uma copa crescente de validadores, conversores e testers que rodam no navegador e nunca encostam em um servidor.
39 free tools, every one offline-capable — opscanopy.com works with no signup and nothing uploaded.
Relacionado: Kubernetes Resource Calculator para o que um workload reserva, Env Example Checker para as variáveis que um contêiner espera, o Alertmanager Route Tester para a outra árvore de correspondência por labels que descarta coisas em silêncio, e o Conversor JSON ↔ YAML quando um manifesto precisa ser remodelado para kubectl patch — ou navegue pelo diretório de ferramentas completo.
Fornecido como está, por conveniência; confirme sempre configuração crítica contra o cluster que vai consumi-la. O OpsCanopy é gratuito e aberto.