Aceitamos 10.000 eventos na Yandex.Cloud. Parte 1

Olá a todos, amigos!

* Este artigo foi escrito com base no workshop aberto REBRAIN & Yandex.Cloud; se você preferir assistir ao vídeo, pode encontrá-lo neste link — https://youtu.be/cZLezUm0ekE

Recentemente, tivemos a oportunidade de experimentar o Yandex.Cloud ao vivo. Como queríamos explorar profundamente, imediatamente descartamos a ideia de lançar um simples blog wordpress com uma base de dados em nuvem — isso seria muito entediante. Após algumas considerações rápidas, decidimos implementar algo semelhante a uma arquitetura de produção para receber e analisar eventos em tempo quase real.

Estou absolutamente certo de que a grande maioria dos negócios online (e não só) coleta uma quantidade enorme de informações sobre seus usuários e suas ações. No mínimo, isso é necessário para tomar certas decisões — por exemplo, se você gerencia um jogo online, pode verificar a estatística de em que nível os usuários costumam ficar presos e deletar seu jogo. Ou por que os usuários abandonam seu site sem comprar nada (olá, Yandex.Metrica).

Então, nossa história: como desenvolvemos um aplicativo em golang, testamos kafka vs rabbitmq vs yqs, escrevemos streaming de dados para um cluster Clickhouse e visualizamos os dados com o yandex datalens. Naturalmente, tudo isso foi complementado por desafios de infraestrutura como docker, terraform, gitlab ci e, é claro, prometheus. Vamos lá!

Quero deixar claro desde o início que não conseguiremos configurar tudo de uma só vez — precisaremos de vários artigos nesta série. Um pouco sobre a estrutura:

Parte 1 (você está lendo). Vamos definir os requisitos e a arquitetura da solução, além de escrever um aplicativo em golang.
Parte 2. Vamos implantar nosso aplicativo em produção, torná-lo escalável e testar a carga.
Parte 3. Vamos investigar por que precisamos armazenar mensagens em um buffer, e não em arquivos, além de comparar kafka, rabbitmq e yandex queue service.
Parte 4. Vamos implantar um cluster Clickhouse, escrever o streaming para transferir dados do buffer para lá e configurar a visualização no datalens.
Parte 5. Vamos estruturar toda a infraestrutura adequadamente — configuraremos ci/cd utilizando gitlab ci, e conectaremos monitoramento e descoberta de serviços com prometheus e consul.

Especificações

Primeiro, vamos formular o dever de serviço — o que exatamente queremos obter como resultado.

  1. Queremos ter um endpoint do tipo events.kis.im (kis.im — um domínio de teste que vamos usar ao longo de todos os artigos), que deve receber eventos através de HTTPS.
  2. Os eventos são um JSON simples do tipo: {"event": "view", "os": "linux", "browser": "chrome"}. Na fase final, vamos adicionar um pouco mais de campos, mas isso não terá um grande impacto. Se houver interesse, podemos mudar para protobuf.
  3. O serviço deve ser capaz de processar 10.000 eventos por segundo.
  4. Deve haver a possibilidade de escalar horizontalmente — simplesmente adicionando novas instâncias à nossa solução. E seria bom se pudéssemos levar a parte frontal para diferentes localizações geográficas para reduzir a latência nas requisições dos clientes.
  5. Tolerância a falhas. A solução deve ser suficientemente estável e capaz de sobreviver à falha de qualquer parte (até um certo número, naturalmente).

Arquitetura

De fato, para esse tipo de tarefa, arquiteturas clássicas que permitem escalar de forma eficiente já foram há muito tempo pensadas. A figura mostra um exemplo da nossa solução.

Aceitamos 10.000 eventos na Yandex.Cloud. Parte 1

Então, o que temos:

1. À esquerda estão nossos dispositivos, que geram vários eventos, sejam eles a passagem de níveis de jogadores em um jogo no smartphone ou a criação de um pedido em uma loja online através de um navegador comum. O evento, como especificado no documento, é um JSON simples que é enviado para nosso endpoint — events.kis.im.

2. Os dois primeiros servidores são balanceadores simples, suas principais tarefas são:

  • Estar sempre disponíveis. Para isso, podemos usar, por exemplo, keepalived, que alternará o IP virtual entre os nós em caso de problemas.
  • Terminar o TLS. Sim, terminaremos o TLS neles. Primeiro, para que nossa solução atenda aos requisitos, e segundo, para aliviar a carga de estabelecer uma conexão criptografada com nossos servidores de backend.
  • Balancear as requisições de entrada para os servidores de backend disponíveis. A palavra-chave aqui é disponíveis. A partir disso, chegamos à compreensão de que os balanceadores de carga devem ser capazes de monitorar nossos servidores com aplicativos e parar de balancear o tráfego para nós que falharam.

3. Atrás dos balanceadores de carga, temos servidores de aplicativo, nos quais um aplicativo simples está em execução. Ele deve ser capaz de receber requisições de entrada via HTTP, validar o JSON enviado e armazenar os dados em um buffer.

4. Na diagrama, o kafka é representado como um buffer, embora, claro, outros serviços semelhantes possam ser usados neste nível. Compararemos Kafka, RabbitMQ e YQS no terceiro artigo.

5. A penúltima parte da nossa arquitetura é o Clickhouse – um banco de dados em colunas que permite armazenar e processar enormes volumes de dados. Neste nível, precisamos transferir os dados do buffer para, de fato, o sistema de armazenamento (sobre isso – no quarto artigo).

Esse esquema nos permite escalar horizontalmente cada camada de forma independente. Se os servidores backend já não suportarem a carga, podemos adicionar mais — já que são aplicações stateless, podemos fazer isso até de forma automática. Se o buffer em forma de Kafka não der conta, basta adicionar mais servidores e mover parte das partições do nosso tópico para eles. Se o Clickhouse não der conta — isso é impossível 🙂 Na verdade, também adicionaremos servidores e faremos a fragmentação dos dados.

Aliás, se você quiser implementar a parte opcional do nosso T.O., e realizar escalonamento em várias geolocalizações, não há nada mais simples:

Aceitamos 10.000 eventos na Yandex.Cloud. Parte 1

Em cada geolocalização, implementamos um load balancer com uma aplicação e Kafka. No geral, são suficientes 2 servidores de aplicação, 3 nós Kafka e um balanceador de carga em nuvem, por exemplo, Cloudflare, que verificará a disponibilidade dos nós da aplicação e equilibrará as solicitações por geolocalização com base no endereço IP de origem do cliente. Assim, os dados enviados por um cliente americano serão direcionados para servidores americanos. E os dados da África — para servidores africanos.

A partir daí, tudo fica bem simples — utilizamos o mirror tool do conjunto Kafka e copiamos todos os dados de todas as localizações para o nosso data center central, localizado na Rússia. Internamente, analisamos os dados e os gravamos no Clickhouse para visualização posterior.

Então, entendemos a arquitetura — vamos começar a testar o Yandex.Cloud!

Escrevendo uma aplicação

Ainda teremos que esperar um pouco até o Cloud e escrever um serviço bastante simples para processar eventos de entrada. Vamos usar Golang, pois se mostrou muito eficaz como linguagem para desenvolvimento de aplicações de rede.

Depois de gastar uma hora (talvez, duas), obtemos algo assim: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

Quais são os principais pontos que gostaria de destacar aqui:

1. Ao iniciar o aplicativo, é possível especificar duas flags. Uma delas é responsável pela porta na qual escutaremos as requisições http de entrada (-addr). A outra é para o endereço do servidor kafka, onde gravaremos nossos eventos (-kafka):

addr     = flag.String("addr", ":8080", "Endereço TCP para escutar")
kafka    = flag.String("kafka", "127.0.0.1:9092", "Endpoints Kafka")

2. O aplicativo utiliza a biblioteca sarama ([] github.com/Shopify/sarama) para enviar mensagens para o cluster kafka. Imediatamente configuramos as definições para máxima velocidade de processamento:

config := sarama.NewConfig()
config.Producer.RequiredAcks = sarama.WaitForLocal
config.Producer.Compression = sarama.CompressionSnappy
config.Producer.Return.Successes = true

3. Também incorporamos ao nosso aplicativo um cliente prometheus, que coleta várias métricas, como:

  • o número de requisições ao nosso aplicativo;
  • o número de erros na execução da requisição (não foi possível ler a requisição post, json corrompido, não foi possível gravar no kafka);
  • o tempo de processamento de uma requisição do cliente, incluindo o tempo de gravação da mensagem no kafka.

4. Três endpoints que nosso aplicativo processa:

  • /status — просто возвращаем ok, чтобы показать, что мы живы. Хотя можно и добавить некоторые проверки, типа доступности кафка кластера.
  • /metrics — по этому url prometheus client будет возвращать собранные им метрики.
  • /post — основной endpoint, куда будут приходить POST запросы с json внутри. Наше приложение проверяет json на валидность и если все ок — записывает данные в кафка-кластер.

Vale ressaltar que o código não é perfeito - pode (e deve!) ser melhorado. Por exemplo, podemos desistir do uso da biblioteca net/http integrada e mudar para o fasthttp, que é mais rápido. Ou podemos economizar tempo de processamento e recursos de cpu, adiando a validação do json para uma fase posterior - quando os dados forem transferidos do buffer para o cluster clickhouse.

Além da parte de desenvolvimento, pensamos imediatamente em nossa futura infraestrutura e decidimos implantar nosso aplicativo via docker. O Dockerfile final para a construção do aplicativo é https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. No geral, ele é bastante simples, e o único ponto que gostaria de destacar é a construção multistage, que permite reduzir a imagem final do nosso contêiner.

Primeiros passos na nuvem

Em primeiro lugar, registramos em cloud.yandex.ru. Após preencher todos os campos necessários, uma conta será criada para você e um crédito irá lhe ser concedido, que pode ser usado para testar os serviços da nuvem. Se você quiser repetir todos os passos de nosso artigo, esse crédito deve ser suficiente.

Após o registro, uma nuvem separada e um diretório padrão serão criados para você, onde você pode começar a criar recursos de nuvem. No Yandex.Cloud, a relação entre os recursos é a seguinte:

Aceitamos 10.000 eventos na Yandex.Cloud. Parte 1

Em uma conta, você pode criar vários núcleos. Dentro do núcleo, é possível fazer diferentes diretórios para os diversos projetos da empresa. Saiba mais sobre isso na documentação — https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. A propósito, mais adiante farei muitas referências a ela. Quando configurei toda a infraestrutura do zero — a documentação me ajudou várias vezes, então recomendo que a estude.

Para gerenciar o núcleo, você pode usar tanto a interface web quanto a ferramenta de console — yc. A instalação é feita com um único comando (para Linux e Mac OS):

curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash

Se, a respeito da execução de scripts da internet, seu segurança interno ficou agitado — primeiro, você pode abrir o script e lê-lo, e segundo, o executamos sob nosso próprio usuário — sem direitos de root.

Se você quiser instalar o cliente para Windows, pode seguir as instruções aqui e em seguida rodar yc init, para configurá-lo completamente:

vozerov@mba:~ $ yc init
Bem-vindo! Este comando o guiará pelo processo de configuração.
Por favor, vá até https://oauth.yandex.ru/authorize?response_type=token&client_id= para obter o token OAuth.

Por favor, insira o token OAuth:
Por favor, selecione o núcleo a ser utilizado:
 [1] cloud-b1gv67ihgfu3bp (id = b1gv67ihgfu3bpt24o0q)
 [2] fevlake-cloud (id = b1g6bvup3toribomnh30)
Por favor, insira sua escolha numérica: 2
Seu núcleo atual foi definido como 'fevlake-cloud' (id = b1g6bvup3toribomnh30).
Por favor, escolha a pasta a ser utilizada:
 [1] default (id = b1g5r6h11knotfr8vjp7)
 [2] Criar uma nova pasta
Por favor, insira sua escolha numérica: 1
Sua pasta atual foi definida como 'default' (id = b1g5r6h11knotfr8vjp7).
Você gostaria de configurar uma zona de Computação padrão? [Y/n]
Qual zona você deseja usar como padrão de perfil?
 [1] ru-central1-a
 [2] ru-central1-b
 [3] ru-central1-c
 [4] Não configurar zona padrão
Por favor, insira sua escolha numérica: 1
Sua zona de Computação padrão foi definida como 'ru-central1-a'.
vozerov@mba:~ $

No geral, o processo não é complicado — primeiro, é necessário obter o token OAuth para gerenciar o núcleo, escolher o núcleo e a pasta que você vai usar.

Se você tiver várias contas ou pastas dentro de um único núcleo, pode criar perfis adicionais com configurações separadas através de yc config profile create e alternar entre eles.

Além das maneiras mencionadas acima, a equipe do Yandex.Cloud escreveu um ótimo plugin para terraform para gerenciar recursos em nuvem. Da minha parte, preparei um repositório Git onde descrevi todos os recursos que serão criados ao longo do artigo — https://github.com/rebrainme/yandex-cloud-events/. Estamos interessados no branch master, vamos cloná-lo localmente:


vozerov@mba:~ $ git clone https://github.com/rebrainme/yandex-cloud-events/ events
Clonando para 'events'...
remote: Enumerando objetos: 100, concluído.
remote: Contando objetos: 100% (100/100), concluído.
remote: Comprimindo objetos: 100% (68/68), concluído.
remote: Total 100 (delta 37), reutilizado 89 (delta 26), pack-reused 0
Recebendo objetos: 100% (100/100), 25.65 KiB | 168.00 KiB/s, concluído.
Resolvendo deltas: 100% (37/37), concluído.
vozerov@mba:~ $ cd events/terraform/

Todas as variáveis principais usadas no terraform estão escritas no arquivo main.tf. Para começar, criamos na pasta terraform o arquivo private.auto.tfvars com o seguinte conteúdo:

# Yandex Cloud Oauth token
yc_token = ""
# Yandex Cloud ID
yc_cloud_id = ""
# Yandex Cloud folder ID
yc_folder_id = ""
# Default Yandex Cloud Region
yc_region = "ru-central1-a"
# Cloudflare email
cf_email = ""
# Cloudflare token
cf_token = ""
# Cloudflare zone id
cf_zone_id = ""

Todas as variáveis podem ser obtidas a partir do yc config list, já que a utilidade de console foi configurada. Recomendo adicionar o private.auto.tfvars ao .gitignore para não publicar acidentalmente dados privados.

No private.auto.tfvars, também especificamos os dados do Cloudflare — para criar registros DNS e para proxy do domínio principal events.kis.im em nossos servidores. Se você não deseja usar o cloudflare, remova a inicialização do provedor cloudflare no main.tf e o arquivo dns.tf, que é responsável pela criação dos registros DNS necessários.

Na nossa abordagem, iremos combinar os três métodos — a interface da web, a utilidade de console e o terraform.

Redes Virtuais

Honestamente, este passo poderia ser pulado, pois ao criar uma nova nuvem, uma rede separada e 3 sub-redes — uma para cada zona de disponibilidade — serão criadas automaticamente. Mas ainda assim, gostaríamos de criar uma rede separada para nosso projeto com endereçamento próprio. O diagrama geral do funcionamento da rede na Yandex.Cloud é apresentado na imagem abaixo (retirado de https://cloud.yandex.ru/docs/vpc/concepts/)

Aceitamos 10.000 eventos na Yandex.Cloud. Parte 1

Então, você cria uma rede comum, dentro da qual os recursos poderão se comunicar entre si. Para cada zona de disponibilidade, é criada uma sub-rede com seu próprio endereçamento, conectando-se à rede comum. Ao final, todos os recursos da nuvem nela podem se comunicar, mesmo estando em diferentes zonas de disponibilidade. Recursos conectados a diferentes redes de nuvem só podem se ver através de endereços externos. A propósito, como essa mágica funciona internamente, foi bem descrito no Habr.

A criação da rede está descrita no arquivo network.tf do repositório. Lá, criamos uma rede privada comum chamada internal e conectamos a ela três sub-redes em diferentes zonas de disponibilidade — internal-a (172.16.1.0/24), internal-b (172.16.2.0/24), internal-c (172.16.3.0/24).

Inicializamos o terraform e criamos as redes:

vozerov@mba:~\/events\/terraform (master) $ terraform init
... pulado ..

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_vpc_subnet.internal-a -target yandex_vpc_subnet.internal-b -target yandex_vpc_subnet.internal-c

... pulado ...

Plano: 4 a adicionar, 0 a mudar, 0 a destruir.

Você deseja realizar estas ações?
  O Terraform executará as ações descritas acima.
  Apenas 'sim' será aceito para aprovar.

  Digite um valor: sim

yandex_vpc_network.internal: Criando...
yandex_vpc_network.internal: Criação completa após 3s [id=enp2g2rhile7gbqlbrkr]
yandex_vpc_subnet.internal-a: Criando...
yandex_vpc_subnet.internal-b: Criando...
yandex_vpc_subnet.internal-c: Criando...
yandex_vpc_subnet.internal-a: Criação completa após 6s [id=e9b1dad6mgoj2v4funog]
yandex_vpc_subnet.internal-b: Criação completa após 7s [id=e2liv5i4amu52p64ac9p]
yandex_vpc_subnet.internal-c: Ainda criando... [10s transcorridos]
yandex_vpc_subnet.internal-c: Criação completa após 10s [id=b0c2qhsj2vranoc9vhcq]

Aplicação completa! Recursos: 4 adicionados, 0 alterados, 0 destruídos.

Ótimo! Criamos nossa rede e agora estamos prontos para criar nossos serviços internos.

Criação de máquinas virtuais

Para testar o aplicativo, precisaremos criar duas máquinas virtuais — a primeira será necessária para compilar e executar o aplicativo, a segunda — para rodar o Kafka, que usaremos para armazenar as mensagens recebidas. E criaremos mais uma máquina, onde configuraremos o Prometheus para monitorar o aplicativo.

As máquinas virtuais serão configuradas com o Ansible, então antes de executar o Terraform, verifique se você tem uma das versões mais recentes do Ansible instalada. E instale os papéis necessários do Ansible Galaxy:

vozerov@mba:~\/events\/terraform (master) $ cd ..\/ansible\/\nvozerov@mba:~\/events\/ansible (master) $ ansible-galaxy install -r requirements.yml
- cloudalchemy-prometheus (master) já está instalado, pulando.
- cloudalchemy-grafana (master) já está instalado, pulando.
- sansible.kafka (master) já está instalado, pulando.
- sansible.zookeeper (master) já está instalado, pulando.
- geerlingguy.docker (master) já está instalado, pulando.
vozerov@mba:~\/events\/ansible (master) $

Dentro da pasta ansible, há um exemplo de arquivo de configuração .ansible.cfg que eu uso. Pode ser útil.

Antes de criar as máquinas virtuais, verifique se o ssh-agent está em execução e se a chave ssh foi adicionada, caso contrário, o Terraform não conseguirá se conectar às máquinas criadas. Claro, encontrei um bug no OS X: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Para que você não tenha um incidente semelhante, antes de executar o Terraform, adicione uma pequena variável ao env:

vozerov@mba:~\/events\/terraform (master) $ export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

Na pasta com o Terraform, criamos os recursos necessários:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_compute_instance.build -target yandex_compute_instance.monitoring -target yandex_compute_instance.kafka
yandex_vpc_network.internal: Atualizando estado... [id=enp2g2rhile7gbqlbrkr]
data.yandex_compute_image.ubuntu_image: Atualizando estado...
yandex_vpc_subnet.internal-a: Atualizando estado... [id=e9b1dad6mgoj2v4funog]

Um plano de execução foi gerado e é mostrado abaixo.
As ações dos recursos são indicadas pelos seguintes símbolos:
  + criar

... pulado ...

Plano: 3 a adicionar, 0 a modificar, 0 a destruir.

... pulado ...

Se tudo correu bem (e deve correr), teremos três máquinas virtuais:

  1. build — máquina para testar e construir a aplicação. Docker foi instalado automaticamente pelo ansible.
  2. monitoring — máquina para monitoramento — nela estão instalados prometheus & grafana. Login / senha padrão: admin / admin
  3. kafka — pequena máquina com kafka instalada, acessível através da porta 9092.

Vamos confirmar que todas elas estão no lugar:

vozerov@mba:~\/events (master) $ yc compute instance list
+----------------------+------------+---------------+---------+---------------+-------------+
|          ID          |    NOME    |    ZONA ID    | STATUS  |  IP EXTERNO   | IP INTERNO  |
+----------------------+------------+---------------+---------+---------------+-------------+
| fhm081u8bkbqf1pa5kgj | monitoring | ru-central1-a | RODANDO | 84.201.159.71 | 172.16.1.35 |
| fhmf37k03oobgu9jmd7p | kafka      | ru-central1-a | RODANDO | 84.201.173.41 | 172.16.1.31 |
| fhmt9pl1i8sf7ga6flgp | build      | ru-central1-a | RODANDO | 84.201.132.3  | 172.16.1.26 |
+----------------------+------------+---------------+---------+---------------+-------------+

Os recursos estão no lugar, e daqui podemos extrair seus endereços IP. Em todo o lugar, utilizarei os endereços IP para conexão via ssh e para testar a aplicação. Se você tiver uma conta na cloudflare conectada ao terraform, pode usar os novos nomes DNS.
A propósito, ao criar a máquina virtual, um IP interno e um nome DNS interno são fornecidos, então você pode se referir aos servidores dentro da rede pelos nomes:

ubuntu@build:~$ ping kafka.ru-central1.internal
PING kafka.ru-central1.internal (172.16.1.31) 56(84) bytes of data.
64 bytes de kafka.ru-central1.internal (172.16.1.31): icmp_seq=1 ttl=63 time=1.23 ms
64 bytes de kafka.ru-central1.internal (172.16.1.31): icmp_seq=2 ttl=63 time=0.625 ms
^C
--- estatísticas de ping kafka.ru-central1.internal ---
2 pacotes transmitidos, 2 recebidos, 0% de perda de pacotes, tempo 1001ms
rtt min/média/máx/mdev = 0.625/0.931/1.238/0.308 ms

Isso será útil para especificar o endpoint da aplicação com kafka.

Construindo a aplicação

Ótimo, as máquinas estão disponíveis, a aplicação está pronta — agora só precisamos compilá-la e publicá-la. Para construção, usaremos o docker build comum, e como armazenamento de imagens, utilizaremos o serviço da yandex — container registry. Mas vamos por partes.

Copiamos a aplicação para a máquina build, entramos via ssh e construímos a imagem:

vozerov@mba:~\/events\/terraform (master) $ cd ..
vozerov@mba:~\/events (master) $ rsync -av app\/ ubuntu@84.201.132.3:app\/ 

... pulado ...

enviado 3849 bytes  recebido 70 bytes  7838.00 bytes\/sec
tamanho total é 3644  velocidade de melhoria é 0.93

vozerov@mba:~\/events (master) $ ssh 84.201.132.3 -l ubuntu
ubuntu@build:~$ cd app
ubuntu@build:~\/app$ sudo docker build -t app .
Enviando contexto de build para o daemon do Docker  6.144kB
Passo 1\/9 : FROM golang:latest AS build
... pulado ...

Construído com sucesso 9760afd8ef65
Marcado com sucesso app:latest

Metade do trabalho está feito — agora podemos verificar o funcionamento da nossa aplicação, executando-a e direcionando para kafka:

ubuntu@build:~\/app$ sudo docker run --name app -d -p 8080:8080 app \/app\/app -kafka=kafka.ru-central1.internal:9092<\/code>

Do seu computador local, você pode enviar um evento de teste e ver a resposta:

<code>vozerov@mba:~\/events (master) $ curl -D - -s -X POST -d '{"key1":"data1"}' http:\/\/84.201.132.3:8080\/post
HTTP\/1.1 200 OK
Content-Type: application\/json
Date: Mon, 13 Apr 2020 13:53:54 GMT
Content-Length: 41

{"status":"ok","partition":0,"Offset":0}
vozerov@mba:~\/events (master) $

A aplicação respondeu com sucesso ao registro, indicando o id da partição e o offset onde a mensagem foi armazenada. O próximo passo é criar um registry no Yandex.Cloud e enviar nossa imagem para lá (como fazer isso em três linhas está descrito no arquivo registry.tf). Criamos um armazenamento:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_container_registry.events

... pulado ...

Plano: 1 a adicionar, 0 a alterar, 0 a destruir.

... pulado ...

Aplicação completa! Recursos: 1 adicionado, 0 alterado, 0 destruído.

Para autenticação no container registry, existem várias maneiras — usando um token oauth, token iam ou a chave de uma conta de serviço. Mais detalhes sobre essas formas estão na documentação https://cloud.yandex.ru/docs/container-registry/operations/authentication. Vamos usar a chave da conta de serviço, então criamos uma conta:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_iam_service_account.docker -target yandex_resourcemanager_folder_iam_binding.puller -target yandex_resourcemanager_folder_iam_binding.pusher

... pulado ...

Aplicação completa! Recursos: 3 adicionados, 0 alterados, 0 destruídos.

Agora precisamos criar uma chave para isso:

vozerov@mba:~\/events\/terraform (master) $ yc iam key create --service-account-name docker -o key.json
id: ajej8a06kdfbehbrh91p
service_account_id: ajep6d38k895srp9osij
created_at: "2020-04-13T14:00:30Z"
key_algorithm: RSA_2048

Obtendo informações sobre o id do nosso armazenamento, transferimos a chave e nos autenticamos:

vozerov@mba:~\/events\/terraform (master) $ scp key.json ubuntu@84.201.132.3:
key.json                                                                                                                    100% 2392   215.1KB\/s   00:00

vozerov@mba:~\/events\/terraform (master) $ ssh 84.201.132.3 -l ubuntu

ubuntu@build:~$ cat key.json | sudo docker login --username json_key --password-stdin cr.yandex
WARNING! Sua senha será armazenada sem criptografia em \/home\/ubuntu\/.docker\/config.json.
Configure um helper de credenciais para remover este aviso. Veja
https:\/\/docs.docker.com\/engine\/reference\/commandline\/login\/#credentials-store

Login Sucedido
ubuntu@build:~$

Para carregar a imagem no repositório, precisaremos do ID do container registry, que obtemos da ferramenta yc:

vozerov@mba:~ $ yc container registry get events
id: crpdgj6c9umdhgaqjfmm
folder_id:
name: events
status: ACTIVE
created_at: "2020-04-13T13:56:41.914Z"

Depois disso, etiquetamos nossa imagem com um novo nome e a carregamos:

ubuntu@build:~$ sudo docker tag app cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
ubuntu@build:~$ sudo docker push cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
A referência do push é para o repositório [cr.yandex/crpdgj6c9umdhgaqjfmm/events]
8c286e154c6e: Enviado
477c318b05cb: Enviado
beee9f30bc1f: Enviado
v1: digest: sha256:1dd5aaa9dbdde2f60d833be0bed1c352724be3ea3158bcac3cdee41d47c5e380 tamanho: 946

Podemos verificar se a imagem foi carregada com sucesso:

vozerov@mba:~/events/terraform (master) $ yc container repository list
+----------------------+-----------------------------+
|          ID          |            NAME             |
+----------------------+-----------------------------+
| crpe8mqtrgmuq07accvn | crpdgj6c9umdhgaqjfmm/events |
+----------------------+-----------------------------+

A propósito, se você instalar a ferramenta yc em uma máquina com linux, poderá usar o comando

yc container registry configure-docker

para configurar o Docker.

Conclusão

Fizemos um grande e difícil trabalho e, como resultado:

  1. Pensamos na arquitetura do nosso futuro serviço.
  2. Escrevemos um aplicativo em golang que implementa nossa lógica de negócios.
  3. Compilamos e despejamos ele em um registro de container privado.

Na próxima parte, vamos para o interessante — despejaremos nosso aplicativo em produção e finalmente o testaremos com carga. Não saia daí!

Este material está disponível na gravação do workshop aberto REBRAIN & Yandex.Cloud: Recebendo 10.000 requisições por segundo na Yandex.Cloud — https://youtu.be/cZLezUm0ekE

Se você está interessado em participar de eventos online como esse e fazer perguntas em tempo real, junte-se a canal DevOps by REBRAIN.

Um agradecimento especial ao Yandex.Cloud pela oportunidade de realizar esse evento. O link para eles é — https://cloud.yandex.ru/prices

Se você precisa de uma migração para a nuvem ou tem perguntas sobre sua infraestrutura, sinta-se à vontade para deixar um pedido.

P.S. Temos 2 auditorias gratuitas por mês, talvez seu projeto seja um deles.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster