Este post é um dos quatro tutoriais que ajudam você a colocar em prática os conceitos do Microservices de março de 2023: Comece a fornecer microsserviços :
Todos os aplicativos exigem configuração, mas as considerações ao configurar um microsserviço podem não ser as mesmas de um aplicativo monolítico . Podemos consultar o Fator 3 ( Armazenar configuração no ambiente ) do aplicativo de doze fatores para obter orientação aplicável a ambos os tipos de aplicativos, mas essa orientação pode ser adaptada para aplicativos de microsserviços. Em particular, podemos adaptar a maneira como definimos a configuração do serviço, fornecer a configuração para um serviço e disponibilizar um serviço como um valor de configuração para outros serviços que podem depender dele.
Para uma compreensão conceitual de como adaptar o Fator 3 para microsserviços – especificamente as melhores práticas para arquivos de configuração, bancos de dados e descoberta de serviços – leia Melhores práticas para configurar aplicativos de microsserviços em nosso blog. Esta postagem é uma ótima maneira de colocar esse conhecimento em prática.
Observação: Nossa intenção neste tutorial é ilustrar alguns conceitos básicos, não mostrar a maneira correta de implantar microsserviços em produção. Embora use uma arquitetura real de “microsserviços”, há algumas ressalvas importantes:
Este tutorial ilustra como os conceitos do Fator 3 se aplicam a aplicativos de microsserviços. Em quatro desafios, você explorará alguns padrões comuns de configuração de microsserviços e implantará e configurará um serviço usando esses padrões:
No Desafio 1 e no Desafio 2, você explora o primeiro padrão, que diz respeito a onde você localiza a configuração para um aplicativo de microsserviços. Há três localizações típicas:
O tutorial usa quatro tecnologias:
Assista a este vídeo para ter uma visão geral do tutorial. Os passos não correspondem exatamente aos deste post, mas ajudam a entender os conceitos.
Para concluir o tutorial em seu próprio ambiente, você precisa:
bash
(mas todo o código e comandos são fornecidos e explicados, para que você ainda possa ter sucesso com conhecimento limitado)Node.js 19.x ou posterior
o asdf
para obter exatamente a mesma versão do Node.js usada nos contêineres.curl
(já instalado na maioria dos sistemas)No seu diretório inicial, crie o diretório microservices-march e clone os repositórios do GitHub para este tutorial nele. (Você também pode usar um nome de diretório diferente e adaptar as instruções adequadamente.)
Observação: Ao longo do tutorial, o prompt na linha de comando do Linux é omitido para facilitar a cópia e colagem dos comandos no seu terminal. O til ( ~
) representa seu diretório inicial.
mkdir ~/microservices-marchcd ~/microservices-march
clone git https://github.com/microservices-march/platform.git --branch mm23-twelve-factor-start
clone git https://github.com/microservices-march/messenger.git --branch mm23-twelve-factor-start
Mude para o repositório da plataforma e inicie o Docker Compose:
cd platformdocker compose up -d --build
Isso inicia o RabbitMQ e o Consul, que serão usados em desafios subsequentes.
-d
instrui o Docker Compose a se desvincular dos contêineres quando eles forem iniciados (caso contrário, os contêineres permanecerão anexados ao seu terminal).--build
instrui o Docker Compose a reconstruir todas as imagens na inicialização. Isso garante que as imagens que você está executando permaneçam atualizadas mesmo com quaisquer alterações potenciais nos arquivos.Mude para o repositório do messenger e inicie o Docker Compose:
cd ../messengerdocker compose up -d --build
Isso inicia o banco de dados PostgreSQL para o serviço de mensagens , que chamaremos de messenger-database no restante do tutorial.
Neste desafio, você define a configuração no primeiro dos três locais que veremos no tutorial: o nível do aplicativo. ( O Desafio 2 ilustra o segundo e o terceiro locais, scripts de implantação e fontes externas.)
O aplicativo de doze fatores exclui especificamente a configuração em nível de aplicativo, porque essa configuração não precisa mudar entre diferentes ambientes de implantação (que o aplicativo de doze fatores chama de deploys ). No entanto, cobrimos todos os três tipos para completar – a maneira como você lida com cada categoria ao desenvolver, construir e implantar um serviço é diferente.
O serviço de mensagens é escrito em Node.js, com o ponto de entrada em app/index.mjs no repositório do messenger . Esta linha do arquivo:
aplicativo.use(express.json());
é um exemplo de configuração em nível de aplicativo. Ele configura a estrutura Express para desserializar corpos de solicitação do tipo application/json
em objetos JavaScript.
Essa lógica está intimamente acoplada ao código do seu aplicativo e não é o que o aplicativo de doze fatores considera “configuração”. Mas em software tudo depende da sua situação, não é?
Nas próximas duas seções, você modifica esta linha para implementar dois exemplos de configuração em nível de aplicativo.
Neste exemplo, você define o tamanho máximo do corpo de uma solicitação aceito pelo serviço de mensagens . Esse limite de tamanho é definido pelo argumento limit
da função express.json , conforme discutido na documentação da API Express . Aqui você adiciona o argumento limit
à configuração do middleware JSON do framework Express discutido acima .
No seu editor de texto preferido, abra app/index.mjs e substitua:
aplicativo.use(express.json())
com:
app.use(express.json({ limite: "20b" }));
No terminal do aplicativo (aquele que você usou em Configurar ), vá para o diretório do aplicativo e inicie o serviço de mensagens :
cd app npm install node index.mjs messenger_service escutando na porta 4000
Inicie uma segunda sessão de terminal separada (cujas instruções subsequentes chamarão o terminal do cliente ) e envie uma solicitação POST
ao serviço de mensagens . A mensagem de erro indica que a solicitação foi processada com sucesso, porque o corpo da solicitação estava abaixo do limite de 20 bytes definido na Etapa 1, mas que o conteúdo da carga JSON está incorreto:
curl -d '{ "text": "olá" }' -H "Tipo de conteúdo: application/json" -X POST http://localhost:4000/conversations ... { "erro": "A conversa deve ter 2 usuários únicos" }
Envie um corpo de mensagem um pouco mais longo (novamente no terminal do cliente). Há muito mais saída do que na Etapa 3, incluindo uma mensagem de erro que indica que desta vez o corpo da solicitação excede 20 bytes:
curl -d '{ "text": "hello, world" }' -H "Content-Type: application/json" -X POST http://localhost:4000/conversations ... \”PayloadTooLargeError: entidade de solicitação muito grande"
Este exemplo usa convict
, uma biblioteca que permite definir um “esquema” de configuração inteiro em um único arquivo. Ele também ilustra duas diretrizes do Fator 3 do aplicativo de doze fatores:
JSON_BODY_LIMIT
) em vez de ser codificado no código do aplicativo.O exemplo também configura algum “encanamento” que você aproveitará no Desafio 2 : o script de implantação do messenger que você criará nesse desafio define a variável de ambiente JSON_BODY_LIMIT
que você insere no código do aplicativo aqui, como uma ilustração da configuração especificada em um script de implantação.
Abra o arquivo de configuração do convict
, app/config/config.mjs , e adicione o seguinte como uma nova chave após a chave amqpport
:
jsonBodyLimit: { doc: `O tamanho máximo (com unidade incluída) que será analisado pelo
middleware JSON. A análise de unidade é feita pela
https://www.npmjs.com/package/bytes library.
ex: "100kb"`,
formato: String,
padrão: nulo,
env: "JSON_BODY_LIMIT",
},
A biblioteca convict
cuida da análise da variável de ambiente JSON_BODY_LIMIT
quando você a usa para definir o tamanho máximo do corpo na linha de comando na Etapa 3 abaixo:
String
)jsonBodyLimit
Em app/index.mjs substitua:
app.use(express.json({ limite: "20b" }));
com
app.use(express.json({ limite: config.get("jsonBodyLimit") }));
No terminal do aplicativo (onde você iniciou o serviço de mensagens na Etapa 2 do Exemplo 1 ), pressione Ctrl+c
para interromper o serviço. Em seguida, inicie-o novamente, usando a variável de ambiente JSON_BODY_LIMIT
para definir o tamanho máximo do corpo para 27 bytes:
^cJSON_BODY_LIMIT=27b nó index.mjs
Este é um exemplo de modificação do método de configuração quando isso faz sentido para seu caso de uso – você mudou de codificar um valor (neste caso, um limite de tamanho) no código do aplicativo para defini-lo com uma variável de ambiente, conforme recomendado pelo aplicativo de doze fatores.
Conforme mencionado acima, no Desafio 2, o uso da variável de ambiente JSON_BODY_LIMIT
se tornará um exemplo do segundo local para configuração, quando você usa o script de implantação do serviço de mensagens para definir a variável de ambiente em vez de defini-la na linha de comando.
No terminal do cliente, repita o comando curl
da Etapa 4 do Exemplo 1 (com o corpo da solicitação maior). Como você aumentou o limite de tamanho para 27 bytes, o corpo da solicitação não excede mais o limite e você recebe a mensagem de erro que indica que a solicitação foi processada, mas que o conteúdo da carga JSON está incorreto:
curl -d '{ "text": "olá, mundo" }' -H "Tipo de conteúdo: application/json" -X POST http://localhost:4000/conversations { "erro": "A conversa deve ter 2 usuários únicos" }
Você pode fechar o terminal do cliente se desejar. Você emitirá todos os comandos no restante do tutorial no terminal do aplicativo.
No terminal do aplicativo, pressione Ctrl+c
para interromper o serviço de mensagens (você interrompeu e reiniciou o serviço neste terminal na Etapa 3 acima).
^c
Pare o messenger-database . Você pode ignorar com segurança a mensagem de erro exibida, pois a rede ainda está em uso pelos elementos de infraestrutura definidos no repositório da plataforma . Execute este comando na raiz do repositório do messenger .
docker compose down ...falha ao remover a rede mm_2023....
À primeira vista, você pode interpretar isso como “não verifique a configuração no controle de origem”. Neste desafio, você implementa um padrão comum para ambientes de microsserviços que pode parecer quebrar essa regra, mas na realidade respeita a regra ao mesmo tempo em que fornece melhorias de processo valiosas que são essenciais para ambientes de microsserviços.
Neste desafio, você cria scripts de implantação para imitar a funcionalidade da infraestrutura como código e manifestos de implantação que fornecem configuração para um microsserviço, modifica os scripts para usar fontes externas de configuração, define um segredo e, em seguida, executa os scripts para implantar serviços e sua infraestrutura.
Crie os scripts de implantação em um diretório de infraestrutura recém-criado no repositório do messenger . Um diretório chamado infraestrutura (ou alguma variação desse nome) é um padrão comum em arquiteturas de microsserviços modernas, usado para armazenar coisas como:
Os benefícios desse padrão incluem:
Como mencionado anteriormente, nossa intenção com o tutorial não é mostrar como configurar um sistema real, e os scripts que você implanta neste desafio não se assemelham a um sistema de produção real. Em vez disso, eles ilustram alguns conceitos e problemas principais resolvidos pela configuração específica da ferramenta ao lidar com a implantação de infraestrutura relacionada a microsserviços, ao mesmo tempo em que abstraem os scripts para a quantidade mínima possível de ferramentas específicas.
No terminal do aplicativo, crie um diretório de infraestrutura na raiz do repositório do messenger e crie arquivos para conter os scripts de implantação para o serviço de messenger e o messenger-database . Dependendo do seu ambiente, pode ser necessário prefixar os comandos chmod
com sudo
:
infraestrutura mkdir infraestrutura cd
touch messenger-deploy.sh
chmod +x messenger-deploy.sh
touch messenger-db-deploy.sh
chmod +x messenger-db-deploy.sh
No seu editor de texto preferido, abra messenger-deploy.sh e adicione o seguinte para criar um script de implantação inicial para o serviço de mensagens :
#!/bin/bashset -e
JSON_BODY_LIMIT=20b
docker run \
--rm \
-e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \
mensageiro
Este script não está completo neste ponto, mas ilustra alguns conceitos:
-e
no comando docker
run
para injetar variáveis de ambiente no contêiner em tempo de execução.Pode parecer redundante definir o valor das variáveis de ambiente dessa forma, mas isso significa que, não importa o quão complexo esse script de implantação se torne, você pode dar uma olhada rápida no topo do script e entender como os dados de configuração estão sendo fornecidos para a implantação.
Além disso, embora um script de implantação real possa não invocar explicitamente o comando docker
run
, este script de exemplo tem como objetivo transmitir os principais problemas que estão sendo resolvidos por algo como um manifesto do Kubernetes. Ao usar um sistema de orquestração de contêineres como o Kubernetes, uma implantação inicia um contêiner e a configuração do aplicativo derivada dos seus arquivos de configuração do Kubernetes é disponibilizada para esse contêiner. Portanto, podemos considerar este arquivo de implantação de exemplo como uma versão mínima de um script de implantação que desempenha a mesma função que arquivos de implantação específicos da estrutura, como manifestos do Kubernetes.
Em um ambiente de desenvolvimento real, você pode verificar esse arquivo no controle de origem e submetê-lo à revisão de código. Isso dá ao restante da equipe a oportunidade de comentar sobre suas configurações e, assim, ajuda a evitar incidentes em que valores mal configurados levam a comportamentos inesperados. Por exemplo, nesta captura de tela, um membro da equipe está corretamente apontando que um limite de 20 bytes para corpos de solicitações JSON de entrada (definido com JSON_BODY_LIMIT
) é muito baixo.
Nesta parte do desafio, você configura o terceiro local para a configuração de um microsserviço: uma fonte externa que é consultada no momento da implantação. Registrar valores dinamicamente e buscá-los de uma fonte externa no momento da implantação é uma prática muito melhor do que codificar valores, que devem ser atualizados constantemente e podem causar falhas. Para uma discussão, consulte Melhores práticas para configurar aplicativos de microsserviços em nosso blog.
Neste ponto, dois componentes de infraestrutura estão sendo executados em segundo plano para fornecer serviços auxiliares exigidos pelo serviço de mensagens :
O esquema de condenado
para o serviço de mensagens em app/config/config.mjs define as variáveis de ambiente necessárias correspondentes a essas partes da configuração externa. Nesta seção, você configura esses dois componentes para fornecer configuração definindo os valores das variáveis em um local comumente acessível para que possam ser consultados pelo serviço de mensagens quando ele for implantado.
As informações de conexão necessárias para o RabbitMQ e o banco de dados do messenger são registradas no repositório Consul Key/Value (KV) , que é um local comum acessível a todos os serviços à medida que são implantados. O armazenamento Consul KV não é um local padrão para armazenar esse tipo de dado, mas este tutorial o utiliza por uma questão de simplicidade.
Substitua o conteúdo de infrastructure/messenger-deploy.sh (criado na Etapa 2 da seção anterior ) pelo seguinte:
#!/bin/bashset -e # Esta configuração requer um novo commit para alterar NODE_ENV=production PORT=4000 JSON_BODY_LIMIT=100kb # Configuração do banco de dados Postgres extraindo informações do # sistema POSTGRES_USER=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-application-user?raw=true) PGPORT=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-port?raw=true) PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true) # Configuração do RabbitMQ extraindo informações do sistema AMQPHOST=$(curl -X GET http://localhost:8500/v1/kv/amqp-host?raw=true) AMQPPORT=$(curl -X GET http://localhost:8500/v1/kv/amqp-port?raw=true) docker run \ --rm \ -e NODE_ENV="${NODE_ENV}" \ -e PORT="${PORT}" \ -e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \ -e PGUSER="${POSTGRES_USER}" \ -e PGPORT="${PGPORT}" \ -e PGHOST="${PGHOST}" \ -e AMQPPORT="${AMQPPORT}" \ -e AMQPHOST="${AMQPHOST}" \ messenger
Este script exemplifica dois tipos de configuração:
NODE_ENV
) e a porta ( PORT
), e altera JSON_BODY_LIMIT
para 100 KB, um valor mais realista do que 20 bytes.POSTGRES_USER
, PGPORT
, PGHOST
, AMQPHOST
e AMQPPORT
do armazenamento Consul KV. Você define os valores das variáveis de ambiente no armazenamento do Consul KV nas duas etapas a seguir.Abra messenger-db-deploy.sh e adicione o seguinte para criar um script de implantação inicial para o messenger-database :
#!/bin/bashset -e PORT=5432 POSTGRES_USER=postgres docker run \ -d \ --rm \ --name messenger-db \ -v db-data:/var/lib/postgresql/data/pgdata \ -e POSTGRES_USER="${POSTGRES_USER}" \ -e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ -e PGPORT="${PORT}" \ -e PGDATA=/var/lib/postgresql/data/pgdata \ --network mm_2023 \ postgres:15.1 # Registre detalhes sobre o banco de dados com o Consul curl -X PUT http://localhost:8500/v1/kv/messenger-db-port \ -H "Content-Type: application/json" \ -d "${PORT}" curl -X PUT http://localhost:8500/v1/kv/messenger-db-host \ -H "Content-Type: application/json" \ -d 'messenger-db' # Isso corresponde ao sinalizador "--name" acima # (o nome do host) curl -X PUT http://localhost:8500/v1/kv/messenger-db-application-user \ -H "Content-Type: application/json" \ -d "${POSTGRES_USER}"
Além de definir a configuração que pode ser consultada pelo serviço de mensagens no momento da implantação, o script ilustra os mesmos dois conceitos do script inicial para o serviço de mensagens em Criar scripts de implantação inicial ):
-e
para injetar variáveis de ambiente no contêiner em tempo de execução. Ele também define o nome do contêiner em execução como messenger-db , que se torna o nome do host do banco de dados na rede Docker que você criou quando iniciou o serviço da plataforma na Etapa 2 de Configuração .Em uma implantação real, geralmente é a equipe da plataforma (ou similar) que lida com a implantação e a manutenção de um serviço como o RabbitMQ no repositório da plataforma , assim como você faz para o messenger-database no repositório do messenger . A equipe da plataforma então garante que a localização dessa infraestrutura possa ser descoberta pelos serviços que dependem dela. Para os propósitos do tutorial, defina você mesmo os valores do RabbitMQ:
curl -X PUT --silent --output /dev/null --show-error --fail \ -H "Tipo de conteúdo: application/json" \
-d "rabbitmq" \
http://localhost:8500/v1/kv/amqp-host
curl -X PUT --silent --output /dev/null --show-error --fail \
-H "Tipo de conteúdo: application/json" \
-d "5672" \
http://localhost:8500/v1/kv/amqp-port
(Você pode se perguntar por que amqp
é usado para definir variáveis RabbitMQ – é porque AMQP é o protocolo usado pelo RabbitMQ.)
Há apenas um dado (crítico) faltando nos scripts de implantação do serviço de mensagens – a senha para o messenger-database !
Observação: O gerenciamento de segredos não é o foco deste tutorial, então, para simplificar, o segredo é definido em arquivos de implantação. Nunca faça isso em um ambiente real – desenvolvimento, teste ou produção – isso cria um enorme risco de segurança .
Para aprender sobre o gerenciamento adequado de segredos, confira a Unidade 2, Gerenciamento de Segredos de Microsserviços 101, do Microsserviços de março de 2023. (Spoiler: uma ferramenta de gerenciamento de segredos é o único método verdadeiramente seguro para armazenar segredos).
Substitua o conteúdo de infrastructure/messenger-db-deploy.sh pelo seguinte para armazenar o segredo da senha do messenger-database no armazenamento do Consul KV:
#!/bin/bashset -e PORT=5432 POSTGRES_USER=postgres # NOTA: Nunca faça isso em uma implantação no mundo real. Armazene senhas # somente em um repositório de segredos criptografados.
POSTGRES_PASSWORD=postgres docker run \ --rm \ --name messenger-db-primary \ -d \ -v db-data:/var/lib/postgresql/data/pgdata \ -e POSTGRES_USER="${POSTGRES_USER}" \ -e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ -e PGPORT="${PORT}" \ -e PGDATA=/var/lib/postgresql/data/pgdata \ --network mm_2023 \ postgres:15.1 echo "Registrar chave messenger-db-port\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-port \ -H "Tipo de conteúdo: application/json" \ -d "${PORT}" echo "Registrar chave messenger-db-host\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-host \ -H "Content-Type: application/json" \ -d 'messenger-db-primary' # Isso corresponde ao sinalizador "--name" acima # que para nossa configuração significa o nome do host echo "Registrar chave messenger-db-application-user\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-application-user \ -H "Content-Type: application/json" \ -d "${POSTGRES_USER}" echo "Registrar chave messenger-db-password-never-do-this\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-password-never-do-this \ -H "Content-Type: application/json" \ -d "${POSTGRES_PASSWORD}" printf "\nConcluído o registro dos detalhes do postgres com o Consul\n"
Substitua o conteúdo de infrastructure/messenger-deploy.sh pelo seguinte para buscar o segredo da senha do banco de dados do messenger no armazenamento do Consul KV:
#!/bin/bashset -e # Esta configuração requer um novo commit para alterar NODE_ENV=production PORT=4000 JSON_BODY_LIMIT=100kb # Configuração do banco de dados Postgres obtendo informações do # sistema POSTGRES_USER=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-application-user?raw=true) PGPORT=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-port?raw=true) PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true) # OBSERVAÇÃO: Nunca faça isso em uma implantação no mundo real. Armazene senhas # somente em um repositório de segredos criptografados.
PGPASSWORD=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-password-never-do-this?raw=true) # Configuração do RabbitMQ puxando do sistema AMQPHOST=$(curl -X GET http://localhost:8500/v1/kv/amqp-host?raw=true) AMQPPORT=$(curl -X GET http://localhost:8500/v1/kv/amqp-port?raw=true) docker run \ --rm \ -d \ -e NODE_ENV="${NODE_ENV}" \ -e PORT="${PORT}" \ -e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \ -e PGUSER="${POSTGRES_USER}" \ -e PGPORT="${PGPORT}" \ -e PGHOST="${PGHOST}" \ -e PGPASSWORD="${PGPASSWORD}" \ -e AMQPPORT="${AMQPPORT}" \ -e AMQPHOST="${AMQPHOST}" \ --network mm_2023 \ mensageiro
Mude para o diretório do aplicativo no repositório do messenger e crie a imagem do Docker para o serviço de messenger :
cd ../appdocker build -t messenger .
Verifique se apenas os contêineres que pertencem ao serviço da plataforma estão em execução:
docker ps --format '{{.Names}}' cônsul-servidor cônsul-cliente rabbitmq
Mude para a raiz do repositório do messenger e implante o messenger-database e o serviço do messenger :
cd .../infraestrutura/messenger-db-deploy.sh
./infraestrutura/messenger-deploy.sh
O script messenger-db-deploy.sh inicia o messenger-database e registra as informações apropriadas no sistema (que neste caso é o armazenamento Consul KV).
O script messenger-deploy.sh então inicia o aplicativo e extrai a configuração registrada pelo messenger-db-deploy.sh do sistema (novamente, o armazenamento Consul KV).
Dica: Se um contêiner não iniciar, remova o segundo parâmetro do comando docker
run
(a linha -d
\
) no script de implantação e execute o script novamente. O contêiner então inicia em primeiro plano, o que significa que seus logs aparecem no terminal e podem identificar o problema. Quando você resolver o problema, restaure a linha -d
\
para que o contêiner real seja executado em segundo plano.
Envie uma solicitação simples de verificação de integridade ao aplicativo para verificar se a implantação foi bem-sucedida:
curl localhost:4000/saúde curl: (7) Falha ao conectar à porta 4000 do host local após 11 ms: Ligação recusada
Opa, fracasso! Acontece que ainda falta uma parte crítica da configuração e o serviço de mensagens não fica exposto ao sistema mais amplo. Ele está funcionando perfeitamente dentro da rede mm_2023 , mas essa rede só é acessível pelo Docker.
Pare o contêiner em execução para preparar a criação de uma nova imagem no próximo desafio:
docker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))
Em um ambiente de produção, geralmente você não expõe serviços diretamente. Em vez disso, você segue um padrão comum de microsserviços e coloca um serviço de proxy reverso na frente do seu serviço principal.
Neste desafio, você expõe o serviço de mensagens ao mundo externo configurando a descoberta de serviços: o registro de novas informações de serviço e a atualização dinâmica dessas informações conforme acessadas por outros serviços. Para fazer isso, você usa estas tecnologias:
Para saber mais sobre descoberta de serviços, consulte Disponibilizar um serviço como configuração em Práticas recomendadas para configuração de aplicativos de microsserviços em nosso blog.
O arquivo app/consul/index.mjs no repositório do messenger contém todo o código necessário para registrar o serviço de messenger com o Consul na inicialização e cancelar o registro no desligamento normal. Ele expõe uma função, register
, que registra qualquer serviço recém-implantado no registro de serviços do Consul.
No seu editor de texto preferido, abra app/index.mjs e adicione o seguinte snippet após as outras instruções de importação
para importar a função de registro
de app/consul/index.mjs :
importar { registrar como registerConsul } de "./consul/index.mjs";
Em seguida, modifique a seção SERVER
START
no final do script, conforme mostrado, para chamar registerConsul()
após o aplicativo ter iniciado:
/* ================= INÍCIO DO SERVIDOR
=================== */
app.listen(porta, async () => {
console.log(`messenger_service escutando na porta ${porta}`);
registerConsul();
});
export default app;
Abra o esquema convict
em app/config/config.mjs e adicione os seguintes valores de configuração após a chave jsonBodyLimit
que você adicionou na Etapa 1 do Exemplo 2 .
consulServiceName: { doc: "O nome pelo qual o serviço é registrado no Consul. Se não for especificado, o serviço não será registrado",
format: "*",
default: null,
env: "CONSUL_SERVICE_NAME",
},
consulHost: {
doc: "O host onde o cliente Consul é executado",
formato: String,
padrão: "consul-client",
env: "CONSUL_HOST",
},
consulPort: {
doc: "A porta para o cliente Consul",
formato: "porta",
padrão: 8500,
ambiente: "CONSUL_PORT",
},
Isso configura o nome sob o qual um novo serviço é registrado e define o nome do host e a porta para o cliente Consul. Na próxima etapa, você modifica o script de implantação do serviço de mensagens para incluir essa nova conexão do Consul e informações de registro de serviço.
Abra infrastructure/messenger-deploy.sh e substitua seu conteúdo pelo seguinte para incluir na configuração do serviço de mensagens as informações de conexão e registro de serviço do Consul que você definiu na etapa anterior:
#!/bin/bashset -e # Esta configuração requer um novo commit para alterar NODE_ENV=production PORT=4000 JSON_BODY_LIMIT=100kb CONSUL_SERVICE_NAME="messenger" # O host e a porta do cônsul são incluídos em cada host, pois # não podemos consultar o cônsul até conhecê-los CONSUL_HOST="${CONSUL_HOST}" CONSUL_PORT="${CONSUL_PORT}" # Configuração do banco de dados Postgres obtendo informações do # sistema POSTGRES_USER=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-application-user?raw=true") PGPORT=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-port?raw=true") PGHOST=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-host?raw=true") # NOTA: Nunca faça isso em uma implantação no mundo real. Armazene senhas # somente em um repositório de segredos criptografados.
PGPASSWORD=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-password-never-do-this?raw=true") # Configuração do RabbitMQ puxando do sistema AMQPHOST=$(curl -X GET "http://localhost:8500/v1/kv/amqp-host?raw=true") AMQPPORT=$(curl -X GET "http://localhost:8500/v1/kv/amqp-port?raw=true") docker run \ --rm \ -d \ -e NODE_ENV="${NODE_ENV}" \ -e PORT="${PORT}" \ -e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \ -e PGUSER="${POSTGRES_USER}" \ -e PGPORT="${PGPORT}" \ -e PGHOST="${PGHOST}" \ -e PGPASSWORD="${PGPASSWORD}" \ -e AMQPPORT="${AMQPPORT}" \ -e AMQPHOST="${AMQPHOST}" \ -e CONSUL_HOST="${CONSUL_HOST}" \ -e CONSUL_PORT="${CONSUL_PORT}" \ -e CONSUL_SERVICE_NAME="${CONSUL_SERVICE_NAME}" \ --network mm_2023 \ mensageiro
As principais coisas a serem observadas são:
CONSUL_SERVICE_NAME
informa à instância do serviço de mensagens qual nome usar ao se registrar no Consul.CONSUL_HOST
e CONSUL_PORT
são para o cliente Consul em execução no local onde o script de implantação é executado.Observação: Em uma implantação no mundo real, este é um exemplo de configuração que deve ser acordada entre as equipes: a equipe responsável pelo Consul deve fornecer as variáveis de ambiente CONSUL_HOST
e CONSUL_PORT
em todos os ambientes, pois um serviço não pode consultar o Consul sem essas informações de conexão.
No terminal do aplicativo, vá para o diretório do aplicativo , interrompa todas as instâncias em execução do serviço de mensagens e reconstrua a imagem do Docker para incorporar o novo código de registro do serviço:
cd appdocker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))
docker build -t messenger .
Navegue até http://localhost:8500 em um navegador para ver a interface do usuário do Consul em ação (embora nada de interessante esteja acontecendo ainda).
Na raiz do repositório do messenger , execute o script de implantação para iniciar uma instância do serviço de messenger :
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infraestrutura/messenger-deploy.sh
Na interface do usuário do cônsul no navegador, clique em Serviços na barra de cabeçalho para verificar se um único serviço de mensagens está em execução.
Execute o script de implantação mais algumas vezes para iniciar mais instâncias do serviço de mensagens . Verifique na interface do usuário do Consul se eles estão em execução.
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infraestrutura/messenger-deploy.sh
O próximo passo é adicionar o NGINX Open Source como um proxy reverso e balanceador de carga para rotear o tráfego de entrada para todas as instâncias do messenger em execução.
No terminal do aplicativo, mude o diretório para a raiz do repositório do messenger e crie um diretório chamado load-balancer e três arquivos:
mkdir balanceador de cargarcd balanceador de carga
toque nginx.ctmpl
toque consul-template-config.hcl
toque Dockerfile
O Dockerfile define o contêiner onde o NGINX e o modelo Consul são executados. O modelo do cônsul usa os outros dois arquivos para atualizar dinamicamente os upstreams do NGINX quando o serviço de mensagens muda (instâncias de serviço são ativadas ou desativadas) em seu registro de serviço.
Abra o arquivo nginx.ctmpl criado na Etapa 1 e adicione o seguinte snippet de configuração do NGINX, que o modelo do Consul usa para atualizar dinamicamente o grupo upstream do NGINX:
upstream messenger_service { {{- range service "messenger" }}
servidor {{ .Address }}:{{ .Port }};
{{- end }}
}
servidor {
listen 8085;
server_name localhost;
location / {
proxy_pass http://messenger_service;
add_header Upstream-Host $upstream_addr;
}
}
Este snippet adiciona o endereço IP e o número da porta de cada instância do serviço de mensagens registrada no Consul ao grupo upstream NGINX messenger_service . O NGINX envia solicitações de entrada para o conjunto definido dinamicamente de instâncias de serviço upstream.
Abra o arquivo consul-template-config.hcl criado na Etapa 1 e adicione a seguinte configuração:
consul { endereço = "consul-client:8500"
retry {
enabled = true
tentativas = 12
backoff = "250ms"
}
}
template {
source = "/usr/templates/nginx.ctmpl"
destination = "/etc/nginx/conf.d/default.conf"
perms = 0600
command = "if [ -e /var/run/nginx.pid ]; then nginx -s reload; else nginx; fi"
}
Esta configuração para o modelo do Consul informa para renderizar novamente o modelo de origem
(o snippet de configuração do NGINX criado na etapa anterior), colocá-lo no destino
especificado e, finalmente, executar o comando
especificado (que informa ao NGINX para recarregar sua configuração).
Na prática, isso significa que um novo arquivo default.conf é criado toda vez que uma instância de serviço é registrada, atualizada ou cancelada no Consul. O NGINX então recarrega sua configuração sem tempo de inatividade, garantindo que o NGINX tenha um conjunto de servidores atualizados e saudáveis (instâncias de serviço de mensagens ) para os quais ele pode enviar tráfego.
Abra o arquivo Dockerfile criado na Etapa 1 e adicione o seguinte conteúdo, que cria o serviço NGINX. (Você não precisa entender o Dockerfile para os propósitos deste tutorial, mas o código está documentado em linha para sua conveniência.)
DE nginx:1.23.1 ARG CONSUL_TEMPLATE_VERSION=0.30.0 # Defina uma variável de ambiente para o local do cluster Consul. Por padrão, ele tenta resolver para consul-client:8500 # que é o comportamento se o Consul estiver sendo executado como um contêiner no # mesmo host e vinculado a este contêiner NGINX (com o alias # consul, é claro). Mas essa variável de ambiente também pode ser # substituída quando o contêiner for iniciado, se quisermos resolver para # outro endereço.
ENV CONSUL_URL consul-client:8500 # Baixe a versão especificada do modelo Consul ADD https://releases.hashicorp.com/consul-template/${CONSUL_TEMPLATE_VERSION}/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip /tmp RUN apt-get update \ && apt-get install -y --no-install-recommends dumb-init unzip \ && unzip /tmp/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip -d /usr/local/bin \ && rm -rf /tmp/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip COPY consul-template-config.hcl ./consul-template-config.hcl COPIAR nginx.ctmpl /usr/templates/nginx.ctmpl EXPOR 8085 SINAL DE PARADA SIGQUIT CMD ["dumb-init", "consul-template", "-config=consul-template-config.hcl"]
Crie uma imagem do Docker:
docker build -t messenger-lb .
Vá para a raiz do diretório do messenger e crie um arquivo chamado messenger-load-balancer-deploy.sh como um arquivo de implantação para o serviço NGINX (assim como com o restante dos serviços que você implantou ao longo do tutorial). Dependendo do seu ambiente, pode ser necessário prefixar o comando chmod
com sudo
:
cd ..
touch infraestrutura/messenger-load-balancer-deploy.sh
chmod +x infraestrutura/messenger-load-balancer-deploy.sh
Abra messenger-load-balancer-deploy.sh e adicione o seguinte conteúdo:
#!/bin/bashset -e # O host e a porta do cônsul são incluídos em cada host, pois # não podemos consultar o cônsul até conhecê-los CONSUL_HOST="${CONSUL_HOST}" CONSUL_PORT="${CONSUL_PORT}" docker run \ --rm \ -d \ --name messenger-lb \ -e CONSUL_URL="${CONSUL_HOST}:${CONSUL_PORT}" \ -p 8085:8085 \ --network mm_2023 \ messenger-lb
Agora que você tem tudo pronto, implante o serviço NGINX:
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infraestrutura/messenger-load-balancer-deploy.sh
Veja se você consegue acessar o serviço de mensagens externamente:
curl -X GET http://localhost:8085/health OK
Funciona! O NGINX agora está fazendo balanceamento de carga em todas as instâncias do serviço de mensagens que foram criadas. Você pode perceber isso porque o cabeçalho X-Forwarded-For
está mostrando os mesmos endereços IP do serviço de mensagens que os da interface do usuário do Consul na Etapa 8 da seção anterior.
Grandes aplicativos geralmente usam “job runners” com pequenos processos de trabalho que podem ser usados para executar tarefas únicas, como modificar dados (exemplos são Sidekiq e Celery ). Essas ferramentas geralmente exigem infraestrutura de suporte adicional, como Redis ou RabbitMQ . Neste caso, você usa o próprio serviço de mensagens como um “executor de tarefas” para executar tarefas únicas. Isso faz sentido porque ele já é muito pequeno, é totalmente capaz de interagir com o banco de dados e outras partes da infraestrutura das quais depende e é executado de forma completamente separada do aplicativo que está servindo o tráfego.
Há três benefícios em fazer isso:
Neste desafio, você explorará como um artefato pode ser modificado para preencher uma nova função alterando alguns valores de configuração do banco de dados e migrando o banco de dados do messenger para usar os novos valores e testar seu desempenho .
Para uma implantação de produção no mundo real, você pode criar dois usuários distintos com permissões diferentes: um “usuário do aplicativo” e um “usuário do migrador”. Para simplificar, neste exemplo você usa o usuário padrão como o usuário do aplicativo e cria um usuário migrador com privilégios de superusuário. Em uma situação real, vale a pena gastar mais tempo decidindo quais permissões mínimas específicas são necessárias para cada usuário com base em sua função.
No terminal do aplicativo, crie um novo usuário do PostgreSQL com privilégios de superusuário:
echo "CRIAR USUÁRIO messenger_migrator COM SENHA DE SUPERUSUÁRIO 'migrator_password';" | docker exec -i messenger-db-primary psql -U postgres
Abra o script de implantação do banco de dados ( infrastructure/messenger-db-deploy.sh ) e substitua seu conteúdo para adicionar as credenciais do novo usuário.
Observação: Vamos reservar um tempo para reiterar: para uma implantação no mundo real, NUNCA coloque segredos como credenciais de banco de dados em um script de implantação ou em qualquer lugar que não seja uma ferramenta de gerenciamento de segredos. Para mais detalhes, veja a Unidade 2: Segredos de microsserviços - Gerenciamento 101 de microsserviços, março de 2023.
#!/bin/bash set -e PORT=5432 POSTGRES_USER=postgres # NOTA: Nunca faça isso em uma implantação no mundo real. Armazene senhas # somente em um repositório de segredos criptografados. # Como estamos nos concentrando em outros conceitos neste tutorial, # definimos a senha desta forma aqui por conveniência.
POSTGRES_PASSWORD=postgres # Usuário de migração POSTGRES_MIGRATOR_USER=messenger_migrator # OBSERVAÇÃO: Como acima, nunca faça isso em uma implantação real.
POSTGRES_MIGRATOR_PASSWORD=migrator_password docker run \ --rm \ --name messenger-db-primary \ -d \ -v db-data:/var/lib/postgresql/data/pgdata \ -e POSTGRES_USER="${POSTGRES_USER}" \ -e POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ -e PGPORT="${PORT}" \ -e PGDATA=/var/lib/postgresql/data/pgdata \ --network mm_2023 \ postgres:15.1 echo "Registrar chave messenger-db-port\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-port \ -H "Tipo de conteúdo: application/json" \ -d "${PORT}" echo "Registrar chave messenger-db-host\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-host \ -H "Content-Type: application/json" \ -d 'messenger-db-primary' # Isso corresponde ao sinalizador "--name" acima # que para nossa configuração significa o nome do host echo "Registrar chave messenger-db-application-user\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-application-user \ -H "Content-Type: application/json" \ -d "${POSTGRES_USER}" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-password-never-do-this \ -H "Tipo de conteúdo: application/json" \ -d "${POSTGRES_PASSWORD}" echo "Registrar chave messenger-db-application-user\n" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-migrator-user \ -H "Tipo de conteúdo: application/json" \ -d "${POSTGRES_MIGRATOR_USER}" curl -X PUT --silent --output /dev/null --show-error --fail http://localhost:8500/v1/kv/messenger-db-migrator-password-never-do-this \ -H "Tipo de conteúdo: application/json" \ -d "${POSTGRES_MIGRATOR_PASSWORD}" printf "\nConcluído o registro dos detalhes do postgres com o Consul\n"
Essa alteração apenas adiciona o usuário migrador ao conjunto de usuários definido no Consul após a implantação do banco de dados.
Crie um novo arquivo no diretório de infraestrutura chamado messenger-db-migrator-deploy.sh (novamente, talvez seja necessário prefixar o comando chmod
com sudo
):
infraestrutura de toque/messenger-db-migrator-deploy.shchmod +x infraestrutura/messenger-db-migrator-deploy.sh
Abra messenger-db-migrator-deploy.sh e adicione o seguinte:
#!/bin/bashset -e # Esta configuração requer um novo commit para alterar NODE_ENV=production PORT=4000 JSON_BODY_LIMIT=100kb CONSUL_SERVICE_NAME="messenger-migrator" # O host e a porta do cônsul são incluídos em cada host, pois # não podemos consultar o cônsul até conhecê-los CONSUL_HOST="${CONSUL_HOST}" CONSUL_PORT="${CONSUL_PORT}" # Obtenha o nome de usuário e a senha do migrador POSTGRES_USER=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-migrator-user?raw=true") PGPORT=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-port?raw=true") PGHOST=$(curl -X GET http://localhost:8500/v1/kv/messenger-db-host?raw=true) # NOTA: Nunca faça isso em uma implantação no mundo real. Armazene senhas # somente em um repositório de segredos criptografados.
PGPASSWORD=$(curl -X GET "http://localhost:8500/v1/kv/messenger-db-migrator-password-never-do-this?raw=true") # Configuração do RabbitMQ puxando do sistema AMQPHOST=$(curl -X GET "http://localhost:8500/v1/kv/amqp-host?raw=true") AMQPPORT=$(curl -X GET "http://localhost:8500/v1/kv/amqp-port?raw=true") docker run \--rm \ -d \ --name messenger-migrator \ -e NODE_ENV="${NODE_ENV}" \ -e PORT="${PORT}" \ -e JSON_BODY_LIMIT="${JSON_BODY_LIMIT}" \ -e PGUSER="${POSTGRES_USER}" \ -e PGPORT="${PGPORT}" \ -e PGHOST="${PGHOST}" \ -e PGPASSWORD="${PGPASSWORD}" \ -e AMQPPORT="${AMQPPORT}" \ -e AMQPHOST="${AMQPHOST}" \ -e CONSUL_HOST="${CONSUL_HOST}" \ -e CONSUL_PORT="${CONSUL_PORT}" \ -e CONSUL_SERVICE_NAME="${CONSUL_SERVICE_NAME}" \ --network mm_2023 \ mensageiro
Este script é bastante semelhante ao script infrastructure/messenger-deploy.sh em sua forma final, que você criou na Etapa 3 de Configurar o Consul . A principal diferença é que o CONSUL_SERVICE_NAME
é messenger-migrator
em vez de messenger
, e o PGUSER
corresponde ao superusuário “migrator” que você criou na Etapa 1 acima.
É importante que o CONSUL_SERVICE_NAME
seja messenger-migrator
. Se fosse definido como messenger
, o NGINX colocaria esse serviço automaticamente em rotação para receber chamadas de API e não deveria manipular nenhum tráfego.
O script implanta uma instância de curta duração na função de migrador. Isso evita que problemas com a migração afetem o atendimento de tráfego pelas principais instâncias do serviço de mensagens .
Reimplante o banco de dados PostgreSQL. Como você está usando scripts bash
neste tutorial, é necessário parar e reiniciar o serviço de banco de dados. Em um aplicativo de produção, normalmente você apenas executa um script de infraestrutura como código para adicionar apenas os elementos que foram alterados.
docker stop messenger-db-primaryCONSUL_HOST=consul-client CONSUL_PORT=8500 ./infrastructure/messenger-db-deploy.sh
Implante o serviço de migração de banco de dados PostgreSQL:
CONSUL_HOST=consul-client CONSUL_PORT=8500 ./infraestrutura/messenger-db-migrator-deploy.sh
Verifique se a instância está sendo executada conforme o esperado:
docker ps --format "{{.Nomes}}" ... messenger-migrator
Você também pode verificar na interface do usuário do Consul se o serviço de migração de banco de dados foi registrado corretamente no Consul como messenger-migrator (novamente, ele não é registrado com o nome do messenger porque não manipula tráfego):
Agora para a etapa final – execute os scripts de migração do banco de dados! Esses scripts não se parecem com nenhum script real de migração de banco de dados, mas usam o serviço messenger-migrator para executar scripts específicos do banco de dados. Após a migração do banco de dados, pare o serviço messenger-migrator :
docker exec -i -e PGDATABASE=postgres -e CREATE_DB_NAME=messenger messenger-migrator node scripts/create-db.mjsdocker exec -i messenger-migrator node scripts/create-schema.mjs
docker exec -i messenger-migrator node scripts/create-seed-data.mjs
docker stop messenger-migrator
Agora que você migrou o banco de dados do Messenger para seu formato final, o serviço de mensagens está finalmente pronto para você assistir em ação! Para fazer isso, execute algumas consultas curl
básicas no serviço NGINX (você configurou o NGINX como o ponto de entrada do sistema em Configurar o NGINX ).
Alguns dos comandos a seguir usam a biblioteca jq
para formatar a saída JSON. Você pode instalá-lo conforme necessário ou omiti-lo da linha de comando, se desejar.
Crie uma conversa:
curl -d '{"participant_ids": [1, 2]}' -H "Tipo de conteúdo: application/json" -X POST 'http://localhost:8085/conversations' { "conversation": { "id": "1", "inserido_em": " AAAA - MM - DD T06:41:59.000Z" } }
Envie uma mensagem para a conversa de um usuário com ID 1:
curl -d '{"conteúdo": "Esta é a primeira mensagem"}' -H "User-Id: 1" -H "Tipo de conteúdo: application/json" -X POST 'http://localhost:8085/conversations/1/messages' | jq { "mensagem": { "id": "1", "conteúdo": "Esta é a primeira mensagem", "index": 1, "id_do_usuário": 1, "nome de usuário": "James Blanderphone", "conversation_id": 1, "inserido_em": " AAAA - MM - DD T06:42:15.000Z" } }
Responder com uma mensagem de um usuário diferente (com ID 2):
curl -d '{"conteúdo": "Esta é a segunda mensagem"}' -H "User-Id: 2" -H "Tipo de conteúdo: application/json" -X POST 'http://localhost:8085/conversations/1/messages' | jq { "mensagem": { "id": "2", "conteúdo": "Esta é a segunda mensagem", "index": 2, "id_do_usuário": 2, "nome de usuário": "Cordoeiro da Normandia", "conversation_id": 1, "inserido_em": " AAAA - MM - DD T06:42:25.000Z" } }
Buscar as mensagens:
curl -X GET 'http://localhost:8085/conversations/1/messages' | jq { "mensagens": [ { "id": "1", "conteúdo": "Esta é a primeira mensagem", "user_id": "1", "id_canal": "1", "índice": "1", "inserido_em": " AAAA - MM - DD T06:42:15.000Z", "nome de usuário": "James Blanderphone" }, { "id": "2", "conteúdo": "Esta é a segunda mensagem", "user_id": "2", "id_canal": "1", "índice": "2", "inserido_em": " AAAA - MM - DD T06:42:25.000Z", "nome de usuário": "Cordoeiro Normalaviano" } ] }
Você criou um número significativo de contêineres e imagens ao longo deste tutorial! Use os seguintes comandos para remover quaisquer contêineres e imagens do Docker que você não deseja manter.
Para remover qualquer contêiner Docker em execução:
docker rm $(docker stop $(docker ps -a -q --filter ancestor=messenger --format="{{.ID}}"))docker rm $(docker stop messenger-db-primary)
docker rm $(docker stop messenger-lb)
Para remover os serviços da plataforma :
# Do repositório da plataforma docker compose down
Para remover todas as imagens do Docker usadas ao longo do tutorial:
docker rmi messengerdocker rmi messenger-lb
docker rmi postgres:15.1
docker rmi hashicorp/consul:1.14.4
docker rmi rabbitmq:3.11.4-management-alpine
Você pode estar pensando “Parece muito trabalho para configurar algo simples” – e você está certo! A mudança para uma arquitetura focada em microsserviços exige meticulosidade em relação à forma como você estrutura e configura os serviços. Apesar de toda a complexidade, você fez um progresso sólido:
Para continuar sua educação em microsserviços, confira Microservices março de 2023. A Unidade 2, Microservices Secrets Management 101 , fornece uma visão geral detalhada, mas fácil de usar, do gerenciamento de segredos em ambientes de microsserviços.
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."