Skip to content

Experimentar um grupo do central no Docker

Redundância explica como um grupo do central é construído, e Um grupo do central em servidores separados explica como implantá-lo. Esta página trata de vê-lo funcionar com os próprios olhos: numa única máquina, a partir de contêineres, em dez minutos e sem alugar um único servidor.

O banco é descartável. Nele se pode — e se deve — fazer o que não se faz numa instalação em serviço: matar processos em pleno voo e ver o que sai disso.

O que é necessário

  • Docker com compose — não há mais nada a instalar.
  • Uma chave de licença. Cada processo precisa de uma: os dois central e os dois streamers.
  • Uma imagem com o grupo do central. O laboratório precisa de uma compilação cujo console tenha a seção Cluster → Central. Se essa seção não estiver lá, a imagem é anterior ao grupo do central e o banco não se monta.
  • As portas 8081 e 8082 livres na máquina local.

De que é feito o banco

Cinco contêineres:

  • postgres — um banco para todo o grupo.
  • central-a e central-b — duas instâncias do plano de controle sobre esse banco, com consoles nas portas 8081 e 8082.
  • streamer-1 e streamer-2 — dois streamers divididos entre as instâncias: o primeiro vai ao central-a, o segundo ao central-b.

Dividir os streamers entre instâncias não é enfeite, é o sentido do banco. A imagem do «agora mesmo» é uma só para o grupo, e todo o parque tem de ser visível a partir de qualquer um dos dois endereços, embora as máquinas reportem a instâncias diferentes.

Baixe o docker-compose.yaml para um diretório vazio. Abaixo estão as partes por causa das quais ele foi escrito; o resto é encanamento comum.

A primeira instância declara os quatro papéis, migrate incluído:

central:
  admin_keys:
    - lab-admin-key
  roles: [run, migrate, layouter, stats]
  advertise_url: http://central-a

A segunda é a mesma sem migrate: o esquema é aplicado por um único processo, ou dois lançam as migrações em disputa.

central:
  admin_keys:
    - lab-admin-key
  roles: [run, layouter, stats]
  advertise_url: http://central-b

Os papéis layouter e stats são declarados pelas duas, e isso não é partida dupla: um papel é uma declaração, e o executor é escolhido por um mandato.

A um streamer não se dá o endereço de uma instância, e sim a lista de endereços do grupo; a ordem é a ordem de preferência:

managed_by:
  name: streamer-1
  url:
    - http://central-a
    - http://central-b
  join_token: ${JOIN_TOKEN}

O segundo streamer tem a mesma lista em ordem inversa.

Subindo

O banco não se monta com um único docker compose up: a janela de adesão é aberta por um central vivo, e o token de adesão só existe depois que ele parte.

Primeiro o banco e as duas instâncias do plano de controle:

export CATENA_VERSION=latest
export LICENSE_KEY='sua chave'
docker compose up -d postgres central-a central-b

Espere o console abrir em http://127.0.0.1:8081 e entre como admin com a senha pass. No primeiro login o console pede para criar uma conta nominal — crie-a.

Abra Cluster → Streamers, clique em Permitir adesão e copie o token de adesão. Suba os streamers com ele:

JOIN_TOKEN=jt-... docker compose up -d streamer-1 streamer-2

As duas máquinas aparecem na lista de streamers em segundos. Feche a janela de adesão depois — o parque está montado.

Crie alguns streams para que o cluster tenha o que alocar. A entrada syntetic é o gerador embutido; o banco não precisa de nenhuma fonte externa:

for i in 1 2 3 4 5 6; do
  curl -s -X PUT -H 'Authorization: Bearer lab-admin-key' \
    -H 'Content-Type: application/json' \
    -d '{"inputs":[{"syntetic":{}}]}' \
    "http://127.0.0.1:8081/central/api-v4/streams/configs/cam$i"
done

O grupo inteiro

Abra Cluster → Central.

Instâncias do central: papéis reivindicados e mandatos

A tabela tem duas linhas — o grupo inteiro — e qualquer instância a mostra igual: o registro está no banco comum.

  • Os papéis reivindicados são quase iguais nas duas: migrate só é declarado pelo central-a, todo o resto é declarado pelas duas máquinas.
  • Os mandatos detidos só estão preenchidos numa linha. Essa é a resposta a «quem manda aqui»: ninguém manda, há titulares de mandatos específicos.
  • A segunda linha diz nenhum — apenas atende pedidos. Uma instância assim não é reserva nem está dormindo: ela responde por completo ao console, à API e aos streamers; simplesmente não é ela quem faz o trabalho de fundo agora.

No seu banco os mandatos podem ficar de outro jeito — os dois numa máquina ou um em cada. Os mandatos são independentes e o arranjo deles depende de quem chegou primeiro; aqui não existe arranjo errado.

O parque é visível de qualquer endereço

Sem sair da instância, abra Cluster → Streamers.

Os dois streamers no ar

As duas máquinas estão no ar, embora a esta instância apenas uma delas reporte. A outra manda sua sincronização ao vizinho e é vista aqui porque a imagem do «agora mesmo» é uma só para o grupo: uma instância sem o mandato stats chega a ela pela rede, justamente por aquele endereço anunciado.

Abra a mesma página em http://127.0.0.1:8082 e verá o mesmo. É essa a verificação para a qual os streamers estão divididos entre instâncias.

Matamos o titular do mandato

Agora aquilo por que o banco é descartável. Mate a instância que tem os mandatos — nas capturas acima é o central-b:

docker compose stop central-b

Volte a Cluster → Central na instância viva e espere alguns segundos.

Os mandatos se mudaram, a linha do vizinho apagou

Três coisas mudaram:

  • A linha da instância matada não sumiu, ela está marcada: «em silêncio — o processo provavelmente morreu». O grupo lembra sua composição, não apenas os vivos.
  • Os mandatos se mudaram para a instância viva. Ninguém os entregou: um mandato vive numa conexão própria com o PostgreSQL e é liberado com a morte dessa sessão, e o vizinho vem buscar o liberado por conta própria.
  • O número da época cresceu. Ele cresce a cada troca de titular e viaja com cada escrita: uma instância que acorda já sem ser a titular recebe uma recusa na escrita, em vez de estragar a alocação depois do fato.

A mudança leva segundos. Não é preciso confirmá-la à mão, nem há com o quê.

O ar não percebeu

Abra Streams.

Todos os streams seguem no ar

Os seis streams seguem. Metade vive no streamer que reportava à instância matada: ele passou ao segundo endereço da sua lista após uma requisição malsucedida, e o central nem chegou a dá-lo por perdido.

É exatamente por isso que o segundo endereço da lista é obrigatório. Remova-o, repita o experimento e um minuto e meio depois verá o layouter mover streams de uma máquina viva, porque ela deixou de dar sinais de vida.

Devolvemos a instância

docker compose start central-b

A linha acende de novo, mas não há mudança de volta — e isso é uma decisão, não algo por terminar.

  • Os mandatos ficam na instância viva. Não há nada a ganhar tirando-os: o titular está trabalhando, e uma troca de titular custa uma nova encarnação da imagem do «agora mesmo».
  • O streamer fica no endereço para o qual foi. Enquanto esse endereço responder, não há nada a ganhar trocando-o; a ordem da lista é uma preferência de partida, não uma vinculação permanente.

Dá para devolver o arranjo original com um reinício — é para isso que o banco é descartável —, mas em produção não é preciso: o grupo funciona em qualquer arranjo.

Retiramos o banco

docker compose down -v

A opção -v retira também os volumes: o banco, o estado dos streamers e a identidade deles no cluster. Sem ela a próxima subida herda um estado meio alheio.

O que este banco não mostra

  • Uma falha do banco de dados. Aqui ele é único e sem réplica: mate-o e a gestão para por completo enquanto o ar segue. É verdade, mas a redundância do banco é tarefa do próprio banco.
  • A rede. Todos os contêineres estão numa mesma rede do docker, sem perdas nem latência entre eles.
  • A carga. Seis streams sintéticos não dizem nada sobre como o grupo se comporta num parque real.
  • O ponto de entrada do operador. No banco há dois, um por instância; em produção é preciso um único endereço com comutação.