Прымаем 10 000 івэнтаў у Яндэкс.Аблокі. Частка 1

Прывітанне ўсім, сябры!

* Гэты артыкул напісаны па матывах адкрытага практыкума REBRAIN & Yandex.Cloud, калі вам больш падабаецца глядзець відэа, можаце знайсці яго па гэтай спасылцы. https://youtu.be/cZLezUm0ekE

Нядаўна нам прадставілася магчымасць памацаць ужывую Яндэкс.Хмара. Паколькі мацаць хацелася доўга і шчыльна, то мы адразу адмовіліся ад ідэі запуску простага wordpress блога з хмарнай базай – занадта сумна. Пасля непрацяглых роздумаў вырашылі разгарнуць нешта падобнае на прадакшн архітэктуру сэрвісу для прыёму і аналізу івэнтаў у near real time рэжыме.

Я абсалютна ўпэўнены, што пераважная большасць анлайн (і не толькі) бізнэсаў так ці інакш збіраюць гару інфармацыі аб сваіх карыстачах і іх дзеяннях. Як мінімум, гэта неабходна для прыняцця вызначаных рашэнняў - напрыклад, калі вы кіруеце анлайн-гульнёй - то можаце паглядзець статыстыку, на якім узроўні карыстачы часцей за ўсё затрымаюцца і выдаляюць вашу цацку. Або чаму карыстачы сыходзяць з вашага сайта, так нічога і не купіўшы (прывітанне, Яндекс.Метрика).

Такім чынам, наша гісторыя: як мы пісалі дадатак на golang, тэставалі kafka vs rabbitmq vs yqs, пісалі стрымінг дадзеных у Clickhouse кластар і візуалізавалі дадзеныя з дапамогай yandex datalens. Натуральна, усё гэта было запраўлена інфраструктурнымі вынаходствамі ў выглядзе docker, terraform, gitlab ci і, вядома ж, prometheus. Пагналі!

Адразу хочацца абмовіцца, што наладзіць усё за адзін прысест мы не зможам - для гэтага нам спатрэбіцца некалькі артыкулаў у серыі. Трохі аб структуры:

1 частка (вы яе чытаеце). Мы вызначымся з ТЗ і архітэктурай рашэння, а таксама напішам дадатак на golang.
2 частка. Выліваем наша дадатак на прод, які робіцца які маштабуецца і тэстуем нагрузку.
3 частка. Паспрабуем разабрацца, навошта нам трэба захоўваць паведамленні ў буферы, а не ў файлах, а таксама параўнаем паміж сабой kafka, rabbitmq і yandex queue service.
4 частка. Будзем разгортваць Clickhouse кластар, пісаць стрымінг для перакладання туды дадзеных з буфера, наладзім візуалізацыю ў datalens.
5 частка. Прывядзем усю інфраструктуру ў належны выгляд - наладзім ci/cd, выкарыстоўваючы gitlab ci, падлучым маніторынг і service discovery з дапамогай prometheus і consul.

ТЗ

Спачатку сфармулюем тэхзаданне - што менавіта мы хочам атрымаць на выхадзе.

  1. Мы хочам мець endpoint выгляду events.kis.im (kis.im - тэставы дамен, які будзем выкарыстоўваць на працягу ўсіх артыкулаў), які павінен прымаць event-ы з дапамогай HTTPS.
  2. Падзеі - гэта простая json'ка выгляду: {"event": "view", "os": "linux", "browser": "chrome"}. На фінальным этапе мы дадамо крыху больш палёў, але вялікай ролі гэта не адыграе. Калі ёсць жаданне - можна пераключыцца на protobuf.
  3. Сэрвіс павінен умець апрацоўваць 10 падзей у секунду.
  4. Павінна быць магчымасць маштабавацца гарызантальна - простым даданнем новых інстанс ў наша рашэнне. І будзе нядрэнна, калі мы зможам выносіць фронт-частку ў розныя геолокации для памяншэння latency пры запытах кліентаў.
  5. Адмаўстойлівасць. Рашэнне павінна быць дастаткова стабільным і ўмець выжываць пры падзенні любых частак (да пэўнай колькасці, натуральна).

Архітэктура

Наогул для такога віду задач даўно прыдуманы класічныя архітэктуры, якія дазваляюць эфектыўна маштабавацца. На малюнку прыведзены прыклад нашага рашэння.

Прымаем 10 000 івэнтаў у Яндэкс.Аблокі. Частка 1

Такім чынам, што ў нас ёсць:

1. Злева намаляваныя нашы прылады, якія генеруюць розныя падзеі, няхай гэта будзе праходжання ўзроўню гульцоў у цаццы на смартфоне або стварэнне замовы ў інтэрнэт-краме праз звычайны браўзэр. Падзея, як паказана ў ТЗ, - просты json, які адпраўляецца на наш endpoint - events.kis.im.

2. Першыя два серверы - простыя балансавальнікі, іх асноўныя задачы:

  • Быць стала даступнымі. Для гэтага можна выкарыстоўваць, напрыклад, keepalived, які будзе перамыкаць віртуальны IP паміж нодамі ў выпадку праблем.
  • Тэрмінаваць TLS. Так, тэрмінаваць TLS мы будзем менавіта на іх. Па-першае, каб нашае рашэнне адпавядала ТЗ, а па-другое, для таго, каб зняць нагрузку па ўсталяванні шыфраванага злучэння з нашых backend сервераў.
  • Балансаваць уваходныя запыты на даступныя backend сервера. Ключавое слова тут - даступныя. Зыходзячы з гэтага, мы прыходзім да разумення, што load balancer'ы павінны ўмець маніторыць нашы серверы з прыкладаннямі і пераставаць балансаваць трафік на падалі ноды.

3. За балансавальнікамі ў нас ідуць application сервера, на якіх запушчана досыць простае прыкладанне. Яно павінна ўмець прымаць уваходныя запыты па HTTP, валідаваць дасланы json і складаць дадзеныя ў буфер.

4. У якасці буфера на схеме намаляваная kafka, хоць, вядома, на гэтым узроўні можна выкарыстоўваць і іншыя падобныя сэрвісы. Kafka, rabbitmq і yqs мы параўнаем у трэцім артыкуле.

5. Перадапошняй кропкай нашай архітэктуры з'яўляецца Clickhouse - калоначная база дадзеных, якая дазваляе захоўваць і апрацоўваць велізарны аб'ём дадзеных. На дадзеным узроўні нам неабходна перанесці дадзеныя з буфера ў, уласна, сістэму захоўвання (аб гэтым - у 4 артыкуле).

Такая схема дазваляе нам незалежна гарызантальна маштабаваць кожны пласт. Не спраўляюцца backend сервера - дадамо яшчэ - бо яны з'яўляюцца stateless прыкладаннямі, а такім чынам, гэта можна зрабіць хоць у аўтаматычным рэжыме. Не цягне буфер у выглядзе кафкі - дакінём яшчэ сервераў і перанясем на іх частка партыцый нашага топіка. Не спраўляецца клікхаус - гэта немагчыма 🙂 На самай справе таксама дакінём сервераў і зашардуем дадзеныя.

Дарэчы, калі вы захочаце рэалізаваць апцыянальную частку нашага ТЗ і зрабіць маштабаванне ў розных геолокациях, то няма нічога прасцей:

Прымаем 10 000 івэнтаў у Яндэкс.Аблокі. Частка 1

У кожнай геолокации мы разгортваем load balancer з application і kafka. У цэлым, дастаткова 2 application сервера, 3 kafka ноды і хмарнага балансавальніка, напрыклад, cloudflare, які будзе правяраць даступнасць нод прыкладання і балансаваць запыты па геолокациям на аснове зыходнага IP-адрасы кліента. Такім чынам дадзеныя, адпраўленыя амерыканскім кліентам, прызямляцца на амерыканскіх серверах. А дадзеныя з Афрыкі - на афрыканскіх.

Далей усё зусім проста – выкарыстоўваем mirror tool з набору кафкі і капіяваны ўсе дадзеныя з усіх лакацый у наш цэнтральны дата-цэнтр, размешчаны ў Расіі. Унутры мы разбіраем дадзеныя і запісваем іх у Clickhouse для наступнай візуалізацыі.

Такім чынам, з архітэктурай разабраліся - пачынаем хістаць Яндэкс.Хмара!

Пішам дадатак

Да Аблокі яшчэ прыйдзецца крыху пацярпець і напісаць дастаткова просты сэрвіс для апрацоўкі ўваходных падзей. Выкарыстоўваць мы будзем golang, таму што ён вельмі добра сябе зарэкамендаваў як мову для напісання сеткавых прыкладанняў.

Выдаткаваўшы гадзіну часу (можа, і пару гадзін), атрымліваем прыкладна такую ​​штуку: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

Якія асноўныя моманты тут хацелася б адзначыць:

1. Пры старце прыкладання можна пазначыць два сцягі. Адзін адказвае за порт, на якім мы будзем слухаць уваходныя http запыты (-addr). Другі - за адрас kafka сервера, куды мы будзем запісваць нашы падзеі (-kafka):

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

2. Дадатак выкарыстоўвае бібліятэку sarama ([] github.com/Shopify/sarama) для адпраўкі паведамленняў у kafka кластар. Мы адразу выставілі наладкі, арыентаваныя на максімальную хуткасць апрацоўкі:

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

3. Таксама ў наша дадатак убудаваны кліент prometheus, які збірае розныя метрыкі, такія як:

  • колькасць запытаў да нашага з дадаткам;
  • колькасць памылак пры выкананні запыту (немагчыма прачытаць post запыт, біты json, немагчыма запісаць у кафку);
  • час апрацоўкі аднаго запыту ад кліента, у тым ліку час запісу паведамлення ў кафку.

4. Тры endpoint'а, якія апрацоўвае наша дадатак:

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

Абмоўлюся, што код не ідэальны - яго можна (і трэба!) дапілоўваць. Да прыкладу, можна адмовіцца ад выкарыстання ўбудаванага net/http і пераключыцца на хутчэйшы fasthttp. Ці ж выйграць час апрацоўкі і cpu рэсурсы, вынесучы праверку валіднасці json на пазнейшы этап — калі дадзеныя будуць перакладацца з буфера ў клікхаус кластар.

Апроч распрацоўчага боку пытання, мы адразу падумалі аб нашай будучай інфраструктуры і прынялі рашэнне разгортваць наша дадатак праз docker. Выніковы Dockerfile для зборкі прыкладання https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. У цэлым, ён досыць просты, адзіны момант, на які жадаецца звярнуць увагу, гэта multistage зборка, якая дазваляе паменшыць выніковую выяву нашага кантэйнера.

Першыя крокі ў воблаку

Перш за ўсё рэгіструемся на cloud.yandex.ru. Пасля запаўнення ўсіх неабходных палёў нам створаць рахунак і выдадуць грант на некаторую суму грошай, якую можна выкарыстаць для тэставання сэрвісаў аблокі. Калі вы захочаце паўтарыць усе крокі з нашага артыкула, гэтага гранта вам павінна хапіць.

Пасля рэгістрацыі для вас будзе створана асобнае воблака і каталог default, у якім можна пачаць ствараць хмарныя рэсурсы. Наогул у Яндэкс.Аблокі ўзаемасувязь рэсурсаў выглядае наступным чынам:

Прымаем 10 000 івэнтаў у Яндэкс.Аблокі. Частка 1

На адзін рахунак вы можаце стварыць некалькі аблокаў. А ўнутры аблокі зрабіць розныя каталогі для розных праектаў кампаніі. Падрабязней пра гэта можна пачытаць у дакументацыі. https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. Дарэчы, ніжэй па тэксце я буду часта на яе спасылацца. Калі я наладжваў усю інфраструктуру з нуля - дакументацыя выбаўляла мяне не раз, так што раю павывучаць.

Для кіравання воблакам можна выкарыстоўваць як вэб-інтэрфейс, так і кансольную ўтыліту - yc. Усталёўка выконваецца адной камандай (для Linux і Mac Os):

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

Калі з нагоды запуску скрыптоў з інтэрнэту ўнутры вас разбушаваўся ўнутраны бяспечнік - то, па-першае, можаце адкрыць скрыптык і прачытаць яго, а па-другое, мы запускаем яго пад сваім карыстальнікам - без рутавых правоў.

Калі вы жадаеце ўсталяваць кліента для windows, то можна скарыстацца інструкцыяй тут і затым выканаць yc init, каб цалкам яе наладзіць:

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:~ $

У прынцыпе, працэс нескладаны - спачатку трэба атрымаць oauth токен для кіравання воблакам, абраць воблака і тэчку, якую будзеце выкарыстоўваць.

Калі ў вас некалькі акаўнтаў ці тэчак усярэдзіне аднаго аблокі, можаце стварыць дадатковыя профілі з асобнымі наладамі праз yc config profile create і перамыкацца паміж імі.

Апроч вышэйпералічаных спосабаў, каманда Яндэкс.Аблокі напісала вельмі добры убудова для terraform для кіравання хмарнымі рэсурсамі. Са свайго боку, я падрыхтаваў git-рэпазітар, дзе апісаў усе рэсурсы, якія будуць створаны ў рамках артыкула. https://github.com/rebrainme/yandex-cloud-events/. Нас цікавіць галінка master, давайце схілюем яе сабе лакальна:


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/

Усе асноўныя зменныя, якія выкарыстоўваюцца ў terraform, прапісаны ў файле main.tf. Для пачатку працы ствараем у тэчцы terraform файл private.auto.tfvars наступнага зместу:

# 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 = ""

Усе зменныя можна ўзяць з yc config list, бо кансольную ўтыліту мы ўжо наладзілі. Раю адразу дадаць private.auto.tfvars у .gitignore, каб незнарок не апублікаваць прыватныя дадзеныя.

У private.auto.tfvars мы таксама паказалі дадзеныя ад Cloudflare - для стварэння dns-запісаў і праксіравання асноўнага дамена events.kis.im на нашы сервера. Калі вы не жадаеце выкарыстоўваць cloudflare, то выдаліце ​​ініцыялізацыю правайдэра cloudflare у main.tf і файл dns.tf, які адказвае за стварэнне неабходных dns запісаў.

Мы ў сваёй працы будзем камбінаваць усе тры спосабы - і вэб-інтэрфейс, і кансольную ўтыліту, і terraform.

Віртуальныя сеткі

Шчыра кажучы, гэты крок можна было б і прапусціць, паколькі пры стварэнні новага аблокі ў вас аўтаматычна створыцца асобная сетка і 3 падсеткі - па адной на кожную зону даступнасці. Але ўсё ж хацелася б зрабіць для нашага праекта асобную сетку са сваім адрасаваннем. Агульная схема працы сеткі ў Яндэкс.Аблокі прадстаўлена на малюнку ніжэй (сумленна ўзятая з https://cloud.yandex.ru/docs/vpc/concepts/)

Прымаем 10 000 івэнтаў у Яндэкс.Аблокі. Частка 1

Такім чынам, вы ствараеце агульную сетку, усярэдзіне якой рэсурсы змогуць мець зносіны паміж сабой. Для кожнай зоны даступнасці робіцца падсетку са сваім адрасаваннем і падлучаецца да агульнай сеткі. У выніку, усе хмарныя рэсурсы ў ёй могуць мець зносіны, нават знаходзячыся ў розных зонах даступнасці. Рэсурсы, падлучаныя да розных хмарных сетак, могуць убачыць адзін аднаго толькі праз вонкавыя адрасы. Дарэчы, як гэтая магія працуе ўнутры, было добра апісана на Хабры.

Стварэнне сеткі апісана ў файле network.tf з рэпазітара. Тамака мы ствараем адну агульную прыватную сетку internal і падлучальны да яе тры падсеткі ў розных зонах даступнасці — internal-a (172.16.1.0/24), internal-b (172.16.2.0/24), internal-c (172.16.3.0/24) ).

Ініцыялізуем terraform і ствараем сеткі:

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.

Выдатна! Мы зрабілі сваю сетку і зараз гатовы да стварэння нашых унутраных сэрвісаў.

Стварэнне віртуальных машын

Для тэставання прыкладання нам будзе дастаткова стварыць дзве віртуалкі - першая нам спатрэбіцца для зборкі і запуску прыкладання, другая - для запуску kafka, якую мы будзем выкарыстоўваць для захоўвання ўваходных паведамленняў. І створым яшчэ адну машынку, дзе наладзім prometheus для маніторынгу прыкладання.

Наладжвацца віртуалкі будуць з дапамогай ansible, так што перад запускам terraform пераканайцеся, што ў вас стаіць адна з апошніх версій ансібла. І ўсталюеце неабходныя ролі з 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) $

Унутры тэчкі ansible ёсць прыклад канфігурацыйнага файла .ansible.cfg, які выкарыстоўваю я. Магчыма, спатрэбіцца.

Перад тым, як ствараць віртуалкі, пераканаецеся, што ў вас запушчаны ssh-agent і дададзены ssh ключык, інакш terraform не зможа падлучыцца да створаных машынак. Я, вядома ж, натыкнуўся на багу ў os x: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Каб у вас не паўтарылася такая гісторыя, перад запускам Terraform дадайце невялікую зменную ў env:

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

У тэчцы з тэраформам ствараем неабходныя рэсурсы:

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 ...

Калі ўсё завяршылася ўдала (а так і павінна быць), то ў нас з'явяцца тры віртуальныя машыны:

  1. build - машынка для тэставання і зборкі прыкладання. Docker быў усталяваны аўтаматычна ansible'ом.
  2. monitoring – машынка для маніторынгу – на яе ўсталяваны prometheus & grafana. Лагін / пароль стандартны: admin / admin
  3. kafka - невялікая машынка з усталяванай kafka, даступная па порце 9092.

Пераканаемся, што ўсе яны на месцы:

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 |
+----------------------+------------+---------------+---------+---------------+-------------+

Рэсурсы на месцы, і адсюль можам выцягнуць іх IP-адрасы. Усюды далей я буду выкарыстоўваць ip-адрасы для падлучэння па ssh і тэсціравання прыкладання. Калі ў вас ёсць акаўнт на cloudflare, падлучаны да terraform, смела выкарыстоўвайце свежаствораныя DNS-імёны.
Дарэчы, пры стварэнні віртуалцы выдаецца ўнутраны ip і ўнутранае DNS-імя, так што звяртацца да сервераў усярэдзіне сетак можна па імёнах:

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

Гэта нам спатрэбіцца для ўказання з дадаткам endpoint'а з kafk'ай.

Збіраем дадатак

Выдатна, сервачкі ёсць, дадатак ёсць - засталося толькі яго сабраць і апублікаваць. Для зборкі будзем выкарыстоўваць звычайны docker build, а вось у якасці сховішчы выяў возьмем сэрвіс ад яндэкса – container registry. Але пра ўсё па парадку.

Капіяваны на build машынку прыкладанне, заходзім па ssh і збіраем выяву:

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

Полдела зроблена - зараз можна праверыць працаздольнасць нашага прыкладання, запусціўшы яго і накіраваўшы на 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) $

Прыкладанне адказала поспехам запісу і ўказаннем id партыцыі і афсета, у які патрапіла паведамленне. Справа за малым - стварыць registry у Яндэкс.Аблокі і закінуць туды наш вобраз (як гэта зрабіць пры дапамозе трох радкоў, апісана ў registry.tf файле). Ствараем сховішча:

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.

Для аўтэнтыфікацыі ў container registry ёсць некалькі спосабаў – з дапамогай oauth токена, iam токена або ключа сэрвіснага акаўнта. Больш падрабязна пра гэтыя спосабы - у дакументацыі https://cloud.yandex.ru/docs/container-registry/operations/authentication. Мы будзем выкарыстоўваць ключ сэрвіснага акаўнта, таму ствараем акаўнт:

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.

Цяпер засталося зрабіць для яго ключык:

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

Атрымліваем інфармацыю аб id нашага сховішча, перакідаем ключ і аўтарызуемся:

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:~$

Для загрузкі выявы ў рэестр нам спатрэбіцца ID container registry, бярэм яго з утыліты yc:

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

Пасля гэтага тэгуем нашу выяву новым імем і загружаем:

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

Можам пераканацца, што выява паспяхова загрузілася:

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

Дарэчы, калі вы ўсталюеце ўтыліту yc на машынку з linux, то можаце выкарыстоўваць каманду

yc container registry configure-docker

для наладкі докера.

Заключэнне

Мы прарабілі вялікую і цяжкую працу і ў выніку:

  1. Прыдумалі архітэктуру нашага будучага сервісу.
  2. Напісалі дадатак на golang, якое рэалізуе нашу бізнес-логіку.
  3. Сабралі яго і вылілі ў прыватны container registry.

У наступнай частцы пяройдзем да цікавага - выльем наша дадатак у production і нарэшце запусцім на яго нагрузку. Не перамыкайцеся!

Гэты матэрыял ёсць у відэазапісе адкрытага практыкума REBRAIN & Yandex.Cloud: Прымаем 10 000 запытаў у секунду на Яндэкс Воблака. https://youtu.be/cZLezUm0ekE

Калі вам цікава наведваць такія мерапрыемствы анлайн і задаваць пытанні ў рэжыме рэальнага часу, падключайцеся да каналу DevOps by REBRAIN.

Асобны дзякуй жадаем сказаць Yandex.Cloud за магчымасць правядзення такога мерпарыяція. Спасылачка на іх https://cloud.yandex.ru/prices

Калі вам патрэбен пераезд у воблака ці ёсць пытанні па вашай інфраструктуры, смела пакідайце заяўку.

PS У нас ёсць 2 бясплатных аўдыту ў месяц, магчыма, менавіта ваш праект будзе ў іх ліку.

Крыніца: habr.com

Дадаць каментар