Aceptamos 10 eventos en Yandex.Cloud. Parte 000

¡Hola a todos, amigos!

* Este artículo está basado en el taller abierto de REBRAIN & Yandex.Cloud, si prefieres ver el vídeo, puedes encontrarlo en este enlace - https://youtu.be/cZLezUm0ekE

Recientemente tuvimos la oportunidad de probar Yandex.Cloud en vivo. Como queríamos investigar mucho y detenidamente, inmediatamente abandonamos la idea de lanzar un blog simple de Wordpress con una base en la nube; era demasiado aburrido. Después de pensarlo un poco, decidimos implementar algo similar a una arquitectura de servicio de producción para recibir y analizar eventos casi en tiempo real.

Estoy absolutamente seguro de que la gran mayoría de las empresas online (y no sólo) de alguna manera recopilan una montaña de información sobre sus usuarios y sus acciones. Como mínimo, esto es necesario para tomar ciertas decisiones; por ejemplo, si administra un juego en línea, puede ver las estadísticas en qué nivel los usuarios se atascan con mayor frecuencia y eliminan su juguete. O por qué los usuarios abandonan su sitio sin comprar nada (hola, Yandex.Metrica).

Entonces, nuestra historia: cómo escribimos una aplicación en golang, probamos kafka vs Rabbitmq vs yqs, escribimos transmisión de datos en un clúster de Clickhouse y visualizamos los datos usando Yandex Datalens. Naturalmente, todo esto estuvo aderezado con delicias de infraestructura en forma de docker, terraform, gitlab ci y, por supuesto, prometheus. ¡Vamos!

Me gustaría hacer una reserva de inmediato de que no podremos configurar todo de una sola vez; para ello necesitaremos varios artículos de la serie. Un poco sobre la estructura:

Parte 1 (la estás leyendo). Decidiremos las especificaciones y la arquitectura de la solución y también escribiremos una aplicación en golang.
Parte 2. Lanzamos nuestra aplicación a producción, la hacemos escalable y probamos la carga.
Parte 3. Intentemos descubrir por qué necesitamos almacenar mensajes en un búfer y no en archivos, y también comparemos el servicio de cola Kafka, RabbitMQ y Yandex.
parte 4 Implementaremos un clúster de Clickhouse, escribiremos un servicio de transmisión para transferir datos desde el búfer allí y configuraremos la visualización en lentes de datos.
parte 5 Pongamos toda la infraestructura en su forma adecuada: configuremos ci/cd usando gitlab ci, conectemos el monitoreo y el descubrimiento de servicios usando prometheus y consul.

TK

Primero, formulemos los términos de referencia: qué es exactamente lo que queremos obtener como resultado.

  1. Queremos tener un punto final como events.kis.im (kis.im es el dominio de prueba que usaremos en todos los artículos), que debería recibir eventos usando HTTPS.
  2. Los eventos son un json simple como: {“event”: “view”, “os”: “linux”, “browser”: “chrome”}. En la etapa final agregaremos un poco más de campos, pero esto no jugará un papel importante. Si lo desea, puede cambiar a protobuf.
  3. El servicio debe poder procesar 10 eventos por segundo.
  4. Debería ser posible escalar horizontalmente simplemente agregando nuevas instancias a nuestra solución. Y sería bueno si pudiéramos mover la parte frontal a diferentes ubicaciones geográficas para reducir la latencia de las solicitudes de los clientes.
  5. Tolerancia a fallos. La solución debe ser lo suficientemente estable y capaz de resistir la caída de cualquier pieza (hasta un cierto número, por supuesto).

Arquitectura

En general, para este tipo de tareas hace tiempo que se inventan arquitecturas clásicas que permiten un escalado eficiente. La figura muestra un ejemplo de nuestra solución.

Aceptamos 10 eventos en Yandex.Cloud. Parte 000

Entonces lo que tenemos:

1. A la izquierda están nuestros dispositivos que generan varios eventos, ya sean jugadores que completan un nivel en un juguete en un teléfono inteligente o crean un pedido en una tienda en línea a través de un navegador normal. Un evento, como se especifica en la especificación, es un json simple que se envía a nuestro punto final: events.kis.im.

2. Los dos primeros servidores son balanceadores simples, sus principales tareas son:

  • Estar constantemente disponible. Para hacer esto, puede usar, por ejemplo, keepalived, que cambiará la IP virtual entre nodos en caso de problemas.
  • Terminar TLS. Sí, cancelaremos TLS en ellos. En primer lugar, para que nuestra solución cumpla con las especificaciones técnicas y, en segundo lugar, para aliviar la carga de establecer una conexión cifrada desde nuestros servidores backend.
  • Equilibre las solicitudes entrantes a los servidores backend disponibles. La palabra clave aquí es accesible. En base a esto, llegamos a comprender que los balanceadores de carga deben poder monitorear nuestros servidores con aplicaciones y dejar de equilibrar el tráfico hacia los nodos fallidos.

3. Después de los equilibradores, tenemos servidores de aplicaciones que ejecutan una aplicación bastante sencilla. Debería poder aceptar solicitudes entrantes a través de HTTP, validar el json enviado y colocar los datos en un búfer.

4. El diagrama muestra a Kafka como buffer, aunque, por supuesto, se pueden utilizar otros servicios similares en este nivel. Compararemos Kafka, Rabbitmq e yqs en el tercer artículo.

5. El penúltimo punto de nuestra arquitectura es Clickhouse, una base de datos en columnas que le permite almacenar y procesar una gran cantidad de datos. En este nivel, necesitamos transferir datos desde el búfer al propio sistema de almacenamiento (más sobre esto en el artículo 4).

Este diseño nos permite escalar cada capa de forma independiente de forma horizontal. Los servidores backend no dan abasto; agreguemos una cosa más: después de todo, son aplicaciones sin estado y, por lo tanto, esto se puede hacer incluso de forma automática. El búfer estilo Kafka no funciona; agreguemos más servidores y transfiramos algunas de las particiones de nuestro tema a ellos. Clickhouse no puede manejarlo, es imposible :) De hecho, también conectaremos los servidores y fragmentaremos los datos.

Por cierto, si quieres implementar la parte opcional de nuestras especificaciones técnicas y escalar en diferentes geolocalizaciones, entonces no hay nada más sencillo:

Aceptamos 10 eventos en Yandex.Cloud. Parte 000

En cada geolocalización desplegamos un balanceador de carga con aplicación y kafka. En general, son suficientes 2 servidores de aplicaciones, 3 nodos Kafka y un equilibrador de nube, por ejemplo, Cloudflare, que verificará la disponibilidad de los nodos de la aplicación y equilibrará las solicitudes por geolocalización en función de la dirección IP de origen del cliente. Así, los datos enviados por un cliente americano aterrizarán en servidores americanos. Y los datos de África están en africano.

Entonces todo es bastante simple: utilizamos la herramienta espejo del conjunto Kafka y copiamos todos los datos de todas las ubicaciones a nuestro centro de datos central ubicado en Rusia. Internamente analizamos los datos y los registramos en Clickhouse para su posterior visualización.

Entonces, hemos resuelto la arquitectura: ¡comencemos a sacudir Yandex.Cloud!

Escribir una solicitud

Antes de la Nube, aún había que tener un poco de paciencia y escribir un servicio bastante simple para procesar los eventos entrantes. Usaremos golang porque ha demostrado ser muy bueno como lenguaje para escribir aplicaciones de red.

Después de pasar una hora (tal vez un par de horas), obtenemos algo como esto: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

¿Cuáles son los puntos principales que me gustaría señalar aquí?

1. Al iniciar la aplicación, puede especificar dos indicadores. Uno es responsable del puerto en el que escucharemos las solicitudes http entrantes (-addr). El segundo es para la dirección del servidor kafka donde registraremos nuestros eventos (-kafka):

addr     = flag.String("addr", ":8080", "TCP address to listen to")
kafka    = flag.String("kafka", "127.0.0.1:9092", "Kafka endpoints”)

2. La aplicación utiliza la biblioteca sarama ([] github.com/Shopify/sarama) para enviar mensajes al clúster de Kafka. Inmediatamente configuramos la configuración destinada a la máxima velocidad de procesamiento:

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

3. Nuestra aplicación también tiene un cliente prometheus integrado, que recopila varias métricas, como por ejemplo:

  • número de solicitudes a nuestra aplicación;
  • número de errores al ejecutar la solicitud (imposible leer la solicitud de publicación, json roto, imposible escribir en Kafka);
  • tiempo de procesamiento para una solicitud del cliente, incluido el tiempo para escribir un mensaje a Kafka.

4. Tres puntos finales que procesa nuestra aplicación:

  • /status: simplemente regresa ok para mostrar que estamos vivos. Aunque puedes agregar algunas comprobaciones, como la disponibilidad del clúster de Kafka.
  • /metrics: según esta URL, el cliente Prometheus devolverá las métricas que ha recopilado.
  • /post es el punto final principal donde se enviarán las solicitudes POST con json dentro. Nuestra aplicación verifica la validez del json y, si todo está bien, escribe los datos en el clúster de Kafka.

Haré una reserva de que el código no es perfecto: puede (¡y debe!) completarse. Por ejemplo, puede dejar de utilizar el net/http integrado y cambiar al fasthttp más rápido. O puede ganar tiempo de procesamiento y recursos de CPU moviendo la verificación de validez de json a una etapa posterior, cuando los datos se transfieren del búfer al clúster de clickhouse.

Además del aspecto del desarrollo, inmediatamente pensamos en nuestra infraestructura futura y decidimos implementar nuestra aplicación a través de Docker. El Dockerfile final para construir la aplicación es https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. En general es bastante sencillo, el único punto al que me gustaría prestar atención es el montaje multietapa, que nos permite reducir la imagen final de nuestro contenedor.

Primeros pasos en la nube

Primero que nada, regístrate en nube.yandex.ru. Después de completar todos los campos necesarios, se nos creará una cuenta y se nos otorgará una subvención por una determinada cantidad de dinero, que podremos utilizar para probar los servicios en la nube. Si desea repetir todos los pasos de nuestro artículo, esta subvención debería ser suficiente para usted.

Después del registro, se creará una nube separada y un directorio predeterminado para usted, en el que podrá comenzar a crear recursos en la nube. En general, en Yandex.Cloud, la relación de recursos se ve así:

Aceptamos 10 eventos en Yandex.Cloud. Parte 000

Puede crear varias nubes para una cuenta. Y dentro de la nube, crear diferentes directorios para diferentes proyectos de la empresa. Puede leer más sobre esto en la documentación: https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. Por cierto, a menudo me referiré a ello más adelante en el texto. Cuando configuré toda la infraestructura desde cero, la documentación me ayudó más de una vez, así que te aconsejo que la estudies.

Para administrar la nube, puede utilizar tanto la interfaz web como la utilidad de la consola: yc. La instalación se realiza con un comando (para Linux y Mac Os):

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

Si su especialista en seguridad interna está furioso por ejecutar scripts desde Internet, entonces, en primer lugar, puede abrir el script y leerlo y, en segundo lugar, ejecutarlo con nuestro usuario, sin derechos de root.

Si desea instalar un cliente para Windows, puede utilizar las instrucciones aquí y luego ejecutar yc initpara personalizarlo completamente:

vozerov@mba:~ $ yc init
Welcome! This command will take you through the configuration process.
Please go to https://oauth.yandex.ru/authorize?response_type=token&client_id= in order to obtain OAuth token.

Please enter OAuth token:
Please select cloud to use:
 [1] cloud-b1gv67ihgfu3bp (id = b1gv67ihgfu3bpt24o0q)
 [2] fevlake-cloud (id = b1g6bvup3toribomnh30)
Please enter your numeric choice: 2
Your current cloud has been set to 'fevlake-cloud' (id = b1g6bvup3toribomnh30).
Please choose folder to use:
 [1] default (id = b1g5r6h11knotfr8vjp7)
 [2] Create a new folder
Please enter your numeric choice: 1
Your current folder has been set to 'default' (id = b1g5r6h11knotfr8vjp7).
Do you want to configure a default Compute zone? [Y/n]
Which zone do you want to use as a profile default?
 [1] ru-central1-a
 [2] ru-central1-b
 [3] ru-central1-c
 [4] Don't set default zone
Please enter your numeric choice: 1
Your profile default Compute zone has been set to 'ru-central1-a'.
vozerov@mba:~ $

En principio, el proceso es simple: primero debe obtener un token de oauth para administrar la nube, seleccionar la nube y la carpeta que usará.

Si tiene varias cuentas o carpetas dentro de la misma nube, puede crear perfiles adicionales con configuraciones separadas a través de la creación de perfiles de configuración yc y alternar entre ellos.

Además de los métodos anteriores, el equipo de Yandex.Cloud escribió un muy buen complemento para terraformar para gestionar los recursos de la nube. Por mi parte, preparé un repositorio de git, donde describí todos los recursos que se crearán como parte del artículo: https://github.com/rebrainme/yandex-cloud-events/. Estamos interesados ​​en la rama master, clonémosla localmente:


vozerov@mba:~ $ git clone https://github.com/rebrainme/yandex-cloud-events/ events
Cloning into 'events'...
remote: Enumerating objects: 100, done.
remote: Counting objects: 100% (100/100), done.
remote: Compressing objects: 100% (68/68), done.
remote: Total 100 (delta 37), reused 89 (delta 26), pack-reused 0
Receiving objects: 100% (100/100), 25.65 KiB | 168.00 KiB/s, done.
Resolving deltas: 100% (37/37), done.
vozerov@mba:~ $ cd events/terraform/

Todas las variables principales que se utilizan en terraform están escritas en el archivo main.tf. Para comenzar, cree un archivo private.auto.tfvars en la carpeta terraform con el siguiente contenido:

# 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 las variables se pueden tomar de la lista de configuración de yc, ya que ya hemos configurado la utilidad de la consola. Le aconsejo que agregue inmediatamente private.auto.tfvars a .gitignore para no publicar accidentalmente datos privados.

En private.auto.tfvars también especificamos datos de Cloudflare para crear registros DNS y enviar el dominio principal events.kis.im a nuestros servidores. Si no desea utilizar Cloudflare, elimine la inicialización del proveedor de Cloudflare en main.tf y el archivo dns.tf, que es responsable de crear los registros DNS necesarios.

En nuestro trabajo combinaremos los tres métodos: la interfaz web, la utilidad de la consola y terraform.

Redes virtuales

Para ser honesto, podría omitir este paso, ya que cuando cree una nueva nube, automáticamente tendrá una red separada y 3 subredes creadas, una para cada zona de disponibilidad. Pero todavía nos gustaría crear una red separada para nuestro proyecto con su propio direccionamiento. El diagrama general de cómo funciona la red en Yandex.Cloud se muestra en la siguiente figura (sinceramente tomada de https://cloud.yandex.ru/docs/vpc/concepts/)

Aceptamos 10 eventos en Yandex.Cloud. Parte 000

Entonces, crea una red común dentro de la cual los recursos pueden comunicarse entre sí. Para cada zona de disponibilidad se crea una subred con su propio direccionamiento y se conecta a la red general. Como resultado, todos los recursos de la nube que contiene pueden comunicarse, incluso si se encuentran en diferentes zonas de disponibilidad. Los recursos conectados a diferentes redes en la nube solo pueden verse entre sí a través de direcciones externas. Por cierto, ¿cómo funciona esta magia por dentro? fue bien descrito en Habré.

La creación de la red se describe en el archivo network.tf del repositorio. Allí creamos una red privada común interna y le conectamos tres subredes en diferentes zonas de disponibilidad: interna-a (172.16.1.0/24), interna-b (172.16.2.0/24), interna-c (172.16.3.0/24 ).

Inicialice terraform y cree redes:

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

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

... skipped ...

Plan: 4 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

yandex_vpc_network.internal: Creating...
yandex_vpc_network.internal: Creation complete after 3s [id=enp2g2rhile7gbqlbrkr]
yandex_vpc_subnet.internal-a: Creating...
yandex_vpc_subnet.internal-b: Creating...
yandex_vpc_subnet.internal-c: Creating...
yandex_vpc_subnet.internal-a: Creation complete after 6s [id=e9b1dad6mgoj2v4funog]
yandex_vpc_subnet.internal-b: Creation complete after 7s [id=e2liv5i4amu52p64ac9p]
yandex_vpc_subnet.internal-c: Still creating... [10s elapsed]
yandex_vpc_subnet.internal-c: Creation complete after 10s [id=b0c2qhsj2vranoc9vhcq]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

¡Excelente! Hemos creado nuestra red y ahora estamos listos para crear nuestros servicios internos.

Creando máquinas virtuales

Para probar la aplicación, solo necesitaremos crear dos máquinas virtuales: necesitaremos la primera para compilar y ejecutar la aplicación, la segunda para ejecutar Kafka, que usaremos para almacenar los mensajes entrantes. Y crearemos otra máquina donde configuraremos Prometheus para monitorear la aplicación.

Las máquinas virtuales se configurarán utilizando ansible, por lo que antes de iniciar terraform, asegúrese de tener una de las últimas versiones de ansible. E instale los roles necesarios con ansible galaxy:

vozerov@mba:~/events/terraform (master) $ cd ../ansible/
vozerov@mba:~/events/ansible (master) $ ansible-galaxy install -r requirements.yml
- cloudalchemy-prometheus (master) is already installed, skipping.
- cloudalchemy-grafana (master) is already installed, skipping.
- sansible.kafka (master) is already installed, skipping.
- sansible.zookeeper (master) is already installed, skipping.
- geerlingguy.docker (master) is already installed, skipping.
vozerov@mba:~/events/ansible (master) $

Dentro de la carpeta ansible hay un archivo de configuración .ansible.cfg de ejemplo que uso. Puede resultar útil.

Antes de crear máquinas virtuales, asegúrese de tener ssh-agent en ejecución y una clave ssh agregada; de lo contrario, terraform no podrá conectarse a las máquinas creadas. Por supuesto, encontré un error en OS X: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Para evitar que esto vuelva a suceder, agregue una pequeña variable a env antes de iniciar Terraform:

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

En la carpeta con terraform creamos los recursos necesarios:

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: Refreshing state... [id=enp2g2rhile7gbqlbrkr]
data.yandex_compute_image.ubuntu_image: Refreshing state...
yandex_vpc_subnet.internal-a: Refreshing state... [id=e9b1dad6mgoj2v4funog]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

... skipped ...

Plan: 3 to add, 0 to change, 0 to destroy.

... skipped ...

Si todo terminó exitosamente (y debería ser así), entonces tendremos tres máquinas virtuales:

  1. build: una máquina para probar y crear una aplicación. Ansible instaló Docker automáticamente.
  2. monitoreo - una máquina de monitoreo - prometheus y grafana instalados en él. Estándar de inicio de sesión/contraseña: admin/admin
  3. Kafka es una pequeña máquina con Kafka instalado, accesible en el puerto 9092.

Asegurémonos de que estén todos en su lugar:

vozerov@mba:~/events (master) $ yc compute instance list
+----------------------+------------+---------------+---------+---------------+-------------+
|          ID          |    NAME    |    ZONE ID    | STATUS  |  EXTERNAL IP  | INTERNAL IP |
+----------------------+------------+---------------+---------+---------------+-------------+
| fhm081u8bkbqf1pa5kgj | monitoring | ru-central1-a | RUNNING | 84.201.159.71 | 172.16.1.35 |
| fhmf37k03oobgu9jmd7p | kafka      | ru-central1-a | RUNNING | 84.201.173.41 | 172.16.1.31 |
| fhmt9pl1i8sf7ga6flgp | build      | ru-central1-a | RUNNING | 84.201.132.3  | 172.16.1.26 |
+----------------------+------------+---------------+---------+---------------+-------------+

Los recursos están disponibles y desde aquí podemos obtener sus direcciones IP. A lo largo de lo que sigue, usaré direcciones IP para conectarme a través de ssh y probar la aplicación. Si tiene una cuenta de Cloudflare conectada a Terraform, no dude en utilizar nombres DNS recién creados.
Por cierto, al crear una máquina virtual, se proporciona una IP interna y un nombre DNS interno, para que puedas acceder a los servidores dentro de la red por su nombre:

ubuntu@build:~$ ping kafka.ru-central1.internal
PING kafka.ru-central1.internal (172.16.1.31) 56(84) bytes of data.
64 bytes from kafka.ru-central1.internal (172.16.1.31): icmp_seq=1 ttl=63 time=1.23 ms
64 bytes from kafka.ru-central1.internal (172.16.1.31): icmp_seq=2 ttl=63 time=0.625 ms
^C
--- kafka.ru-central1.internal ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.625/0.931/1.238/0.308 ms

Esto nos será útil para indicarle a la aplicación el punto final con kafk.

Montaje de la aplicación

Genial, hay servidores, hay una aplicación, solo queda ensamblarla y publicarla. Para la compilación usaremos la compilación habitual de Docker, pero como almacenamiento de imágenes usaremos un servicio de Yandex: registro de contenedores. Pero primero lo primero.

Copiamos la aplicación a la máquina de compilación, iniciamos sesión mediante ssh y ensamblamos la imagen:

vozerov@mba:~/events/terraform (master) $ cd ..
vozerov@mba:~/events (master) $ rsync -av app/ [email protected]:app/

... skipped ...

sent 3849 bytes  received 70 bytes  7838.00 bytes/sec
total size is 3644  speedup is 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 .
Sending build context to Docker daemon  6.144kB
Step 1/9 : FROM golang:latest AS build
... skipped ...

Successfully built 9760afd8ef65
Successfully tagged app:latest

La mitad de la batalla está hecha: ahora podemos comprobar la funcionalidad de nuestra aplicación iniciándola y enviándola a Kafka:

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

С локальной машинки можно отправить тестовый event и посмотреть на ответ:

<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) $

La aplicación respondió con éxito de la grabación e indicando el id de la partición y offset en el que estaba incluido el mensaje. Todo lo que queda por hacer es crear un registro en Yandex.Cloud y cargar nuestra imagen allí (cómo hacerlo usando tres líneas se describe en el archivo registro.tf). Crear un almacenamiento:

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

... skipped ...

Plan: 1 to add, 0 to change, 0 to destroy.

... skipped ...

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Hay varias formas de autenticarse en el registro de contenedores: utilizando un token oauth, un token iam o una clave de cuenta de servicio. Se pueden encontrar más detalles sobre estos métodos en la documentación. https://cloud.yandex.ru/docs/container-registry/operations/authentication. Usaremos la clave de la cuenta de servicio, por lo que creamos una cuenta:

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

... skipped ...

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Ahora sólo queda hacerle una clave:

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

Recibimos información sobre la identificación de nuestro almacenamiento, transferimos la clave e iniciamos sesión:

vozerov@mba:~/events/terraform (master) $ scp key.json [email protected]:
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! Your password will be stored unencrypted in /home/ubuntu/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
ubuntu@build:~$

Para cargar la imagen en el registro, necesitamos el ID del registro del contenedor, lo tomamos de la utilidad yc:

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

Después de eso, etiquetamos nuestra imagen con un nuevo nombre y la subimos:

ubuntu@build:~$ sudo docker tag app cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
ubuntu@build:~$ sudo docker push cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
The push refers to repository [cr.yandex/crpdgj6c9umdhgaqjfmm/events]
8c286e154c6e: Pushed
477c318b05cb: Pushed
beee9f30bc1f: Pushed
v1: digest: sha256:1dd5aaa9dbdde2f60d833be0bed1c352724be3ea3158bcac3cdee41d47c5e380 size: 946

Podemos verificar que la imagen se cargó exitosamente:

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

Por cierto, si instala la utilidad yc en una máquina Linux, puede usar el comando

yc container registry configure-docker

para configurar la ventana acoplable.

Conclusión

Hemos trabajado mucho y como resultado:

  1. Se nos ocurrió la arquitectura de nuestro futuro servicio.
  2. Escribimos una aplicación en golang que implementa nuestra lógica empresarial.
  3. Lo recogimos y lo vertimos en un registro de contenedores privado.

En la siguiente parte, pasaremos a las cosas interesantes: lanzaremos nuestra aplicación a producción y finalmente iniciaremos la carga. ¡No cambies!

Este material está en la grabación de video del taller abierto REBRAIN & Yandex.Cloud: Aceptamos 10 solicitudes por segundo en Yandex Cloud. https://youtu.be/cZLezUm0ekE

Si está interesado en asistir a dichos eventos en línea y hacer preguntas en tiempo real, conéctese a canal DevOps por REBRAIN.

Nos gustaría agradecer especialmente a Yandex.Cloud por la oportunidad de organizar un evento de este tipo. Enlace a ellos - https://cloud.yandex.ru/prices

Si necesita migrar a la nube o tiene preguntas sobre su infraestructura, no dudes en dejar una solicitud.

PD: Tenemos 2 auditorías gratuitas al mes, quizás tu proyecto sea uno de ellos.

Fuente: habr.com

Añadir un comentario