kubernetes

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package kubernetes executa cada passo de um workflow como um POD proprio.

A dinamica e a da secao 2 do plano, e e o que separa este motor de um worker monolitico: o pod sobe com a imagem EXATA do passo, roda um comando, reporta e morre. Um passo de dbt sobe a imagem de dbt com 1Gi; o fetcher em Go ao lado sobe uma imagem de 10 MB com 32Mi. Numa imagem unica os dois pagariam o maior dos dois — em bytes de pull, em memoria reservada e em superficie.

O cliente e escrito sobre a stdlib, sem client-go. A biblioteca oficial traz centenas de dependencias e dezenas de MB para o que aqui sao quatro chamadas REST: criar pod, ler status, ler log, apagar pod. A mesma escolha ja foi feita para o React (bundle vendorizado) e para o CSS (Tailwind standalone): o custo de uma dependencia grande so se paga quando se usa uma fracao grande dela.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NomeDoPod

func NomeDoPod(t execution.TaskExec) string

NomeDoPod produz um nome valido e ESTAVEL para a mesma tentativa.

Estavel importa: se o processo morrer entre criar o pod e registrar isso, a tentativa seguinte encontra o pod existente (409 AlreadyExists) em vez de subir um segundo pod rodando o mesmo dbt em paralelo com o primeiro.

O sufixo de hash resolve a colisao que o corte de 63 caracteres criaria entre dois nodes de nome longo e prefixo comum.

Types

type API

type API interface {
	CriarPod(ctx context.Context, p Pod) (Pod, error)
	LerPod(ctx context.Context, nome string) (Pod, error)
	Logs(ctx context.Context, nome string, seguir bool) (io.ReadCloser, error)
	ApagarPod(ctx context.Context, nome string) error
}

API e o que o executor precisa do servidor. Interface no consumidor: e ela que permite testar o ciclo de vida inteiro do pod contra um servidor falso.

type Cliente

type Cliente struct {
	// contains filtered or unexported fields
}

Cliente fala com o servidor de API.

func NoCluster

func NoCluster() (*Cliente, error)

NoCluster monta o cliente a partir do ambiente que o kubelet injeta.

func (*Cliente) ApagarPod

func (c *Cliente) ApagarPod(ctx context.Context, nome string) error

ApagarPod remove o pod.

func (*Cliente) CriarPod

func (c *Cliente) CriarPod(ctx context.Context, p Pod) (Pod, error)

CriarPod cria o pod e devolve o nome atribuido.

func (*Cliente) LerPod

func (c *Cliente) LerPod(ctx context.Context, nome string) (Pod, error)

LerPod devolve o estado atual.

func (*Cliente) Logs

func (c *Cliente) Logs(ctx context.Context, nome string, seguir bool) (io.ReadCloser, error)

Logs abre o stream de saida do container. Com `follow`, a resposta so termina quando o container termina — e por isso que nao ha timeout no http.Client.

func (*Cliente) Namespace

func (c *Cliente) Namespace() string

Namespace onde os pods sao criados.

type Condicao

type Condicao struct {
	Type    string `json:"type"`
	Status  string `json:"status"`
	Reason  string `json:"reason,omitempty"`
	Message string `json:"message,omitempty"`
}

Condicao carrega o PodScheduled, onde o scheduler explica por que nao coube.

type Container

type Container struct {
	Name         string             `json:"name"`
	Image        string             `json:"image"`
	Command      []string           `json:"command,omitempty"`
	Args         []string           `json:"args,omitempty"`
	Env          []Var              `json:"env,omitempty"`
	EnvFrom      []FonteEnv         `json:"envFrom,omitempty"`
	Resources    *Recursos          `json:"resources,omitempty"`
	WorkingDir   string             `json:"workingDir,omitempty"`
	VolumeMounts []MontagemDeVolume `json:"volumeMounts,omitempty"`
}

type ErrForaDoCluster

type ErrForaDoCluster struct{ Motivo string }

ErrForaDoCluster e devolvido quando nao ha service account montada.

func (ErrForaDoCluster) Error

func (e ErrForaDoCluster) Error() string

type Executor

type Executor struct {

	// Intervalo de sondagem do status. Sondar e nao observar (watch) e
	// deliberado: um watch exige reconexao, resync e tratamento de eventos
	// perdidos para ganhar segundos numa task que dura minutos.
	Intervalo time.Duration
	// contains filtered or unexported fields
}

Executor roda cada passo como um pod.

O ciclo e sempre o mesmo: cria o pod, espera sair de Pending, acompanha o log enquanto roda, le o codigo de saida e apaga. Nenhum estado vive aqui alem dos pods em voo — se o processo reiniciar, os pods continuam rodando e o dispatcher os reencontra pelo nome deterministico.

func NewExecutor

func NewExecutor(api API, o Opcoes) *Executor

func (*Executor) Cancel

func (e *Executor) Cancel(ctx context.Context, execID string) error

Cancel apaga o pod da execucao em voo.

func (*Executor) Execute

func (e *Executor) Execute(ctx context.Context, t execution.TaskExec) (<-chan execution.Event, error)

Execute cria o pod e devolve o canal de eventos. O canal fecha quando o pod termina — mesma forma do executor local, entao o runner nao distingue os dois.

func (*Executor) Name

func (e *Executor) Name() string

type FonteEnv

type FonteEnv struct {
	SecretRef    *RefLocal `json:"secretRef,omitempty"`
	ConfigMapRef *RefLocal `json:"configMapRef,omitempty"`
}

type FontePVC

type FontePVC struct {
	ClaimName string `json:"claimName"`
}

type FonteVar

type FonteVar struct {
	SecretKeyRef *RefChave `json:"secretKeyRef,omitempty"`
}

FonteVar aponta uma variavel para uma chave de um Secret. O valor nunca passa pelo motor: quem le e o kubelet, na hora de subir o container.

type Metadata

type Metadata struct {
	Name        string            `json:"name,omitempty"`
	Namespace   string            `json:"namespace,omitempty"`
	Labels      map[string]string `json:"labels,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type MontagemDeVolume

type MontagemDeVolume struct {
	Name      string `json:"name"`
	MountPath string `json:"mountPath"`
}

type Opcoes

type Opcoes struct {
	Namespace         string
	ServiceAccount    string
	PullSecrets       []string
	NodeSelector      map[string]string
	Tolerations       []Toleracao
	EnvFromSecrets    []string
	EnvFromConfigMaps []string

	// CredencialPVC e CredencialPath montam um volume onde o SDK guarda a
	// credencial rotacionada entre execucoes.
	//
	// Com os dois definidos, TODO pod de passo ganha o volume e a env
	// BREVIS_CREDENTIAL_DIR apontando para o mount. Sem eles nada muda -- e e
	// assim que a feature continua sendo atalho, e nao requisito.
	//
	// A credencial no volume vai cifrada; a chave e um Secret comum, que entra
	// por EnvFromSecrets. O motor nao a ve nem precisa dela.
	CredencialPVC  string
	CredencialPath string

	// SecretsPermitidos sao os Secrets que um YAML pode citar em `secrets:`.
	//
	// Existe porque `secrets:` inverte quem escolhe. EnvFromSecrets vem do
	// ambiente do scheduler: a INSTALACAO decide. `secrets:` esta no arquivo,
	// e o arquivo e escrito por outra pessoa -- sem esta lista, um workflow
	// poderia montar qualquer Secret do namespace, inclusive o do banco do
	// proprio Brevis, e rodar um comando arbitrario com ele em maos.
	//
	// Vazia nega tudo. Negar por padrao custa uma variavel na instalacao;
	// permitir por padrao custa o inverso, e o inverso e irreversivel.
	//
	// A divisao final e essa: a instalacao diz QUAIS segredos existem para
	// workflows, o YAML diz QUAL passo recebe cada um.
	SecretsPermitidos []string
	Labels            map[string]string
	Shell             []string
	// EsperaParaIniciar e quanto um pod pode ficar sem comecar antes de o passo
	// desistir. Existe porque `Pending` nao e erro para o Kubernetes: um pod que
	// nao cabe em no nenhum fica ali para sempre, e sem este limite a etapa
	// espera junto — sem log, sem falha, sem retry. Aconteceu em dev com um
	// request de CPU maior que o livre no pool.
	EsperaParaIniciar time.Duration

	// ManterPodEmFalha deixa o pod para inspecao quando o passo falha. O de
	// sucesso e sempre apagado: milhares de pods Completed poluem o namespace e
	// nao dizem nada que o historico do Brevis nao diga melhor.
	ManterPodEmFalha bool
}

Opcoes parametriza como os pods sao criados. Sao decisoes da INSTALACAO — credenciais, pool de nos, conta de servico —, nao do autor do workflow: um YAML de pipeline nao deve poder escolher a service account com que roda.

type Pod

type Pod struct {
	APIVersion string   `json:"apiVersion,omitempty"`
	Kind       string   `json:"kind,omitempty"`
	Metadata   Metadata `json:"metadata"`
	Spec       PodSpec  `json:"spec,omitempty"`
	// Ponteiro porque `omitempty` nao omite struct vazia: sem ele, todo pod
	// criado enviaria `"status":{}` ao servidor — inofensivo, mas e ruido num
	// objeto que se le para depurar.
	Status *PodStatus `json:"status,omitempty"`
}

Pod e o subconjunto do objeto que este motor usa. Escrever as structs a mao, em vez de importar as do client-go, mantem a arvore de dependencias pequena e deixa visivel exatamente o que se envia ao servidor de API.

func MontarPod

func MontarPod(t execution.TaskExec, o Opcoes) (Pod, error)

MontarPod traduz uma task no objeto que vai para o servidor de API.

Funcao pura: recebe task e opcoes, devolve o objeto. E o que permite testar o spec inteiro — imagem, comando, recursos, rotulos — sem cluster nenhum.

func (Pod) Fase

func (p Pod) Fase() string

Fase devolve a fase atual; vazia enquanto o servidor nao respondeu com status.

func (Pod) Motivo

func (p Pod) Motivo() string

Motivo e o `reason` do status (DeadlineExceeded, OOMKilled, Evicted) — a diferenca entre "o codigo falhou" e "o cluster matou o processo".

func (Pod) MotivoDeEspera

func (p Pod) MotivoDeEspera() string

MotivoDeEspera explica por que o container ainda nao rodou.

E a informacao mais util quando um passo "nao faz nada": ImagePullBackOff e CreateContainerConfigError sao problemas de configuracao que, sem isto, apareceriam apenas como um pod parado ate o timeout.

func (Pod) Saida

func (p Pod) Saida() (int, bool)

Saida devolve o codigo de saida do container e se ele ja terminou.

func (Pod) Terminou

func (p Pod) Terminou() bool

Terminou diz se o pod chegou a um estado final.

type PodSpec

type PodSpec struct {
	RestartPolicy         string            `json:"restartPolicy,omitempty"`
	ServiceAccountName    string            `json:"serviceAccountName,omitempty"`
	ImagePullSecrets      []RefLocal        `json:"imagePullSecrets,omitempty"`
	NodeSelector          map[string]string `json:"nodeSelector,omitempty"`
	Tolerations           []Toleracao       `json:"tolerations,omitempty"`
	ActiveDeadlineSeconds *int64            `json:"activeDeadlineSeconds,omitempty"`
	Volumes               []Volume          `json:"volumes,omitempty"`
	Containers            []Container       `json:"containers"`
}

type PodStatus

type PodStatus struct {
	Phase             string            `json:"phase,omitempty"`
	Conditions        []Condicao        `json:"conditions,omitempty"`
	Reason            string            `json:"reason,omitempty"`
	Message           string            `json:"message,omitempty"`
	ContainerStatuses []StatusContainer `json:"containerStatuses,omitempty"`
}

type Recursos

type Recursos struct {
	Requests map[string]string `json:"requests,omitempty"`
	Limits   map[string]string `json:"limits,omitempty"`
}

type RefChave

type RefChave struct {
	Name string `json:"name"`
	Key  string `json:"key"`
}

type RefLocal

type RefLocal struct {
	Name string `json:"name"`
}

type StatusContainer

type StatusContainer struct {
	Name  string `json:"name"`
	State struct {
		Waiting *struct {
			Reason  string `json:"reason"`
			Message string `json:"message"`
		} `json:"waiting,omitempty"`
		Running *struct {
			StartedAt string `json:"startedAt"`
		} `json:"running,omitempty"`
		Terminated *struct {
			ExitCode int    `json:"exitCode"`
			Reason   string `json:"reason"`
			Message  string `json:"message"`
		} `json:"terminated,omitempty"`
	} `json:"state"`
}

type Toleracao

type Toleracao struct {
	Key      string `json:"key,omitempty"`
	Operator string `json:"operator,omitempty"`
	Value    string `json:"value,omitempty"`
	Effect   string `json:"effect,omitempty"`
}

type Var

type Var struct {
	Name string `json:"name"`
	// Value com omitempty porque uma Var que vem de secret manda `valueFrom`,
	// e mandar `"value":""` junto faz o servidor recusar as duas.
	Value     string    `json:"value,omitempty"`
	ValueFrom *FonteVar `json:"valueFrom,omitempty"`
}

type Volume

type Volume struct {
	Name string    `json:"name"`
	PVC  *FontePVC `json:"persistentVolumeClaim,omitempty"`
}

Volume e um PersistentVolumeClaim montado no pod.

So PVC, e nao a uniao de tudo que o Kubernetes aceita: o motor monta volume para um proposito -- guardar a credencial rotacionada entre execucoes -- e um campo que existe para um proposito nao deve aceitar dez formas.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL