11 aws о ECS

Thank you for reading this post, don't forget to subscribe!

ECS — это Elastic Container Service.

Начи­на­ет­ся ECS с созда­ния ECS кла­сте­раaws_ecs_cluster в тер­ми­нах Terraform. У кла­сте­ра ника­ких осо­бых свойств, кро­ме его име­ни, нет

Зада­ча кла­сте­ра — запус­кать тас­ки (Tasks). Тас­ки — это один или несколь­ко Docker кон­тей­не­ров, запус­ка­е­мых вме­сте. Ана­лог подов в Kubernetes.

Тас­ки воз­ни­ка­ют из опи­са­ний: Task definitionsaws_ecs_task_definition в Тер­ра­фор­ме. Здесь, для каж­до­го кон­тей­не­ра тас­ка, зада­ёт­ся Docker образ, тре­бо­ва­ния по памя­ти (обя­за­тель­но) и CPU (в неко­то­рых слу­ча­ях необя­за­тель­но), режим рабо­ты сети и про­бра­сы­ва­е­мые пор­ты, под­клю­ча­е­мые тома (если нуж­но), куда будут запи­сы­вать­ся логи (то бишь, stdout), IAM роль, от име­ни кото­рой будут рабо­тать кон­тей­не­ры, ну и пере­мен­ные окружения.

Docker обра­зы хра­нят­ся в ECR — Elastic Container Registry. Хоть он и очень тес­но вза­и­мо­дей­ству­ет с ECS, это вполне само­сто­я­тель­ный сер­вис. Пол­но­цен­ный Docker Registry, кото­рый мож­но исполь­зо­вать и напря­мую. Един­ствен­ный суще­ствен­ный нюанс: паро­ли досту­па в ECR — вре­мен­ные. Их нуж­но гене­рить через AWS CLI. И они дей­ству­ют не более 12 часов.

ECS тас­ки мож­но запус­кать пооди­ноч­ке. Так посту­па­ет, напри­мер, дру­гой ама­зо­но­вый сер­вис Elastic Beanstalk. Либо мож­но запус­кать тас­ку по тай­ме­ру. Но сама по себе тас­ка — это немас­шта­би­ру­е­мый и сла­бо кон­тро­ли­ру­е­мый ресурс. Она может быть толь­ко запу­ще­на или оста­нов­ле­на, если сама не оста­но­вит­ся раньше.

Гораз­до инте­рес­нее ECS сер­ви­сыaws_ecs_service в Тер­ра­фор­ме. Сер­вис управ­ля­ет раз­вёр­ты­ва­ни­ем, мас­шта­би­ро­ва­ни­ем и обнов­ле­ни­ем тас­ков. Где и сколь­ко тас­ков под­нять. В каком поряд­ке их поды­мать при обнов­ле­нии, что­бы сер­вис все­гда был досту­пен. Где имен­но эти тас­ки запускать.

Где вооб­ще ECS запус­ка­ет кон­тей­не­ры? Есть два спо­со­ба (на самом деле боль­ше). Либо вы запус­ка­е­те свои соб­ствен­ные EC2 инстан­сы, в кото­рых уста­нов­лен Docker и ECS агент. Либо вы исполь­зу­е­те AWS Fargate.

Fargate — это вели­кая магия. Вы гово­ри­те, сколь­ко памя­ти и CPU нуж­но вашим кон­тей­не­рам (точ­нее, тас­ке), и оно маги­че­ским обра­зом запус­ка­ет­ся где-то там. Пре­крас­но, кра­си­во, но доро­го. В несколь­ко раз доро­же, чем ана­ло­гич­ные EC2 инстансы.

Fargate име­ет смысл исполь­зо­вать, если ваши ECS тас­ки рабо­та­ют не посто­ян­но. И вы не хоти­те замо­ра­чи­вать­ся с мас­шта­би­ро­ва­ни­ем EC2 инстан­сов. Напри­мер, на одном из про­ек­тов мы сде­ла­ли так, что из десят­ков сер­ви­сов посто­ян­но запу­щен толь­ко один. А осталь­ные оста­нов­ле­ны, пока в при­ло­же­ние никто не захо­дит. А вот когда кто-то захо­дит, этот глав­ный сер­вис «будит» всех осталь­ных, и через мину­ты пол­то­ры при­ло­же­ние пол­но­стью раз­вёр­ну­то, со всей функ­ци­о­наль­но­стью. Для демо окру­же­ния — самое то.

Ина­че же выгод­нее замо­ро­чить­ся с EC2. Точ­нее, с Auto Scaling Groupaws_autoscaling_group в Терраформе.

Auto Scaling Group — это шту­ка, кото­рая созда­ёт EC2 инстан­сы соглас­но Launch Configuration (aws_launch_configuration, уста­ре­ли) или Launch Template (aws_launch_template). В кон­фи­гу­ра­ции или шаб­лоне опи­са­но: EC2 инстан­сы како­го типа созда­вать, из како­го обра­за, с каки­ми пара­мет­ра­ми, и про­чее. Для рабо­ты с ECS уже есть зара­нее при­го­тов­лен­ные обра­зы Amazon Linux. Auto Scaling Group созда­ёт нуж­ное коли­че­ство инстан­сов соглас­но неко­то­рым правилам.

Рань­ше вам самим при­хо­ди­лось забо­тить­ся о том, что­бы EC2 инстан­сов в вашем ECS кла­сте­ре было доста­точ­но, что­бы запу­стить все нуж­ные тас­ки. И даже чуть боль­ше на слу­чай реде­п­лоя. Либо рука­ми зада­вать раз­мер Auto Scaling Group. Либо пытать­ся при­кру­тить умные пра­ви­ла, осно­вы­ва­ясь, напри­мер, на потреб­ле­нии памяти.

Теперь же в ECS появи­лись Capacity Providersaws_ecs_capacity_provider в Тер­ра­фор­ме. Эта шту­ка сле­дит за раз­ме­ром ваше­го ECS кла­сте­ра. Она под­клю­ча­ет­ся к Auto Scaling Group, и добав­ля­ет ещё EC2 инстан­сов, если нуж­но раз­вер­нуть боль­ше тас­ков. Или при­би­ва­ет лиш­ние EC2 инстан­сы, если на них ника­ких тас­ков не запу­ще­но. А ECS сер­ви­сы теперь раз­во­ра­чи­ва­ют­ся имен­но исполь­зуя Capacity Provider. В осо­бо хит­рых слу­ча­ях мож­но даже задей­ство­вать несколь­ко провайдеров.

Рабо­та Capacity Provider доволь­но муд­рё­на. Но оно рабо­та­ет. И рабо­та­ет пра­виль­но. Так что теперь мож­но без осо­бых про­блем добить­ся того, что­бы EC2 инстан­сов под ECS кла­стер было запу­ще­но ров­но столь­ко, сколь­ко нуж­но. Мож­но жить и без Fargate.

Сами Auto Scaling Group тоже поум­не­ли. Теперь груп­пу мож­но заста­вить созда­вать инстан­сы раз­но­го типа. Для ECS это может быть удоб­но, если у вас есть тас­ки с раз­ны­ми тре­бо­ва­ни­я­ми, напри­мер, к памя­ти. Если раз­ные тас­ки раз­ме­щать на раз­ных инстан­сах соот­вет­ству­ю­ще­го раз­ме­ра, мож­но избе­жать излиш­не­го рас­хо­до­ва­ния ресур­сов, когда у вас поло­ви­на памя­ти инстан­са ничем не заня­та. Capacity Provider такие хит­ро­сти пони­ма­ет и уме­ет (если верить документации).

Есть ещё один важ­ный ресурс, заме­шан­ный в рабо­те ECSELB — Elastic Load Balancing. aws_lb в Тер­ра­фор­ме. Лоад балан­сер, балан­си­ров­щик нагруз­ки. Как и поло­же­но, лоад балан­сер балан­си­ру­ет вхо­дя­щий сете­вой тра­фик меж­ду несколь­ки­ми бэкенд сер­ве­ра­ми: EC2 инстан­са­ми или IP адресами.

В ECS лоад балан­сер свя­зан с сер­ви­сом. Сер­вис сооб­ща­ет балан­се­ру, где рас­по­ло­же­ны его тас­ки, и куда направ­лять тра­фик. А балан­сер сооб­ща­ет сер­ви­су, живы ли они, соглас­но настро­ен­ным health checks. Важ­но, что тут имен­но ECS сер­вис обща­ет­ся с балан­се­ром. А то ведь ещё Auto Scaling Group тоже может им рулить, а в слу­чае исполь­зо­ва­ния балан­се­ра с ECS тако­го не надо.

Elastic Load Balancing у нас есть несколь­ких типов. Опу­стим Classic Load Balancer, нын­че для ново­го раз­вёр­ты­ва­ния он вам не пона­до­бит­ся. Опу­стим Gateway Load Balancer, это экзо­ти­че­ская раз­но­вид­ность для балан­си­ров­ки тра­фи­ка к сто­рон­ним сер­ви­сам. Оста­ёт­ся ещё два.

Network Load Balancer рабо­та­ет на чет­вёр­том уровне моде­ли OSI, то есть, балан­си­ру­ет TCP или UDP. Он уме­ет слу­шать (aws_lb_listener) опре­де­лён­ный TCP или UDP порт, и перенаправлять/балансировать тра­фик на TCP/UDP порт ваше­го сер­ви­са, то, что назы­ва­ет­ся Target Group (aws_lb_target_group). Опци­аль­но он может «тер­ми­ни­ро­вать» TLS под­клю­че­ния. Здо­ро­вье ваше­го сер­ви­са про­ве­ря­ет­ся TCP или HTTP запросами.

Что­бы запря­тать за Network Load Balancer несколь­ко ваших мик­ро­сер­ви­сов, при­дёт­ся для каж­до­го выде­лить отдель­ный порт, отдель­ный listener и отдель­ную target group. Пото­му что этот балан­сер уме­ет раз­ли­чать тра­фик толь­ко по пор­там. Это­го доста­точ­но для досту­па к сер­ви­сам изнут­ри AWS. Но для внеш­не­го досту­па по един­ствен­но­му HTTPS/443 пор­ту уже мало­ва­то. Поэто­му Network Load Balancer пря­чут за API Gateway, осо­бен­но, если у вас уже есть API Gateway. Если балан­сер живёт в VPC, то для досту­па из API Gateway вам пона­до­бит­ся VPC link.

Application Load Balancer рабо­та­ет на седь­мом уровне моде­ли OSI. Он уме­ет HTTPHTTPS). Кро­ме listener и target group тут мож­но задать listener rules (aws_lb_listener_rule). Поми­мо пере­на­прав­ле­ния тра­фи­ка на target group, мож­но осу­ществ­лять аутен­ти­фи­ка­цию поль­зо­ва­те­ля или фор­ми­ро­вать ста­ти­че­ский ответ (что полез­но, напри­мер, для CORS). Мож­но выби­рать target group, а зна­чит, и кон­крет­ный сер­вис, по HTTP заго­лов­кам, пути в URL, query в URL.

При нали­чии Application Load Balancer вам, вполне воз­мож­но, уже не нужен API Gateway. Теперь вы вполне може­те спря­тать все мик­ро­сер­ви­сы за един­ствен­ной пуб­лич­ной HTTPS/443 точ­кой вхо­да. И марш­ру­ти­зи­ро­вать запро­сы на раз­ные target group по доволь­но гиб­ким пра­ви­лам. Одна­ко, помни­те, эти балан­си­ров­щи­ки всё же менее гиб­ки, чем обыч­ный Nginx. Ска­жем, они не уме­ют пере­за­пи­сы­вать URL запроса.

В настрой­ках лоад­ба­лан­се­ра есть инте­рес­ный пара­метр cross zone load balancing. Как вы помни­те, в каж­дом реги­оне AWS есть availability zones, зоны доступ­но­сти. Балан­сер может пере­на­прав­лять тра­фик, то есть иметь свой ENI (Elastic Network Interface), в несколь­ких availability zones. Вхо­дя­щий тра­фик рас­пре­де­ля­ет­ся, по умол­ча­нию слу­чай­но и рав­но­мер­но, меж­ду все­ми зона­ми, где у балан­се­ра есть интер­фей­сы. С дру­гой сто­ро­ны, EC2 инстан­сы в ECS кла­сте­ре тоже могут быть запу­ще­ны в раз­ных availability zones. В зави­си­мо­сти от настро­ек Auto Scaling Group. И, если вы спе­ци­аль­но не оза­бо­ти­тесь раз­ме­стить по тас­ке ECS сер­ви­са в каж­дой зоне, вполне может так ока­зать­ся, что в какой-то зоне не ока­жет­ся ваше­го сер­ви­са. В такой ситу­а­ции вам нуж­но вклю­чить cross zone load balancing, что­бы ENI балан­се­ра из одной availability zone мог бы обра­щать­ся к пор­ту ECS сер­ви­са в любой дру­гой availability zone. Ина­че могут быть стран­ные задерж­ки и поте­ри тра­фи­ка. Для Application Load Balancer cross zone load balancing по умол­ча­нию вклю­чен, а вот для Network Load Balancer — выключен.

В ECS вы заво­ди­те кла­сте­ры. В кла­сте­ре запус­ка­ют­ся тас­ки, по опре­де­ле­нию в Task Definition, где, поми­мо про­че­го, ука­зан Docker образ, кото­рый запускать.

Для посто­ян­но запу­щен­ных сер­ви­сов удоб­но созда­вать ECS service. Он сам созда­ёт тас­ки для запус­ка сво­их экзем­пля­ров. И зани­ма­ет­ся реде­п­ло­ем сво­их новых вер­сий (новых вер­сий Task Definition).

Тас­ки запус­ка­ют­ся на EC2 инстан­сах (или в Fargate). На этих инстан­сах запу­щен Docker и ECS агент. Для это­го есть уже гото­вые AMI обра­зы Amazon Linux. Агент под­клю­ча­ет­ся к ECS кла­сте­ру и так полу­ча­ет ука­за­ния, что там в Docker запускать.

Коли­че­ством и типом EC2 инстан­сов управ­ля­ет Auto Scaling Group. Инстан­сы созда­ют­ся по Launch template (или Launch configuration). В ECS есть Capacity Provider, кото­рый управ­ля­ет Auto Scaling Group, что­бы все­гда было доста­точ­но инстан­сов для запус­ка необ­хо­ди­мых задач. В ECS сер­ви­се нуж­но ука­зать, каким Capacity Provider поль­зо­вать­ся для раз­ме­ще­ния тасков.

Кста­ти, на один ECS кла­стер вполне мож­но пове­сить несколь­ко Capacity Provider и несколь­ко Auto Scaling Group. И раз­ме­щать ваши сервисы/таски по раз­ным хит­рым правилам.

Сете­вой тра­фик на сер­ви­сы направ­ля­ет Load Balancer. У него есть фрон­тенд часть — Listener, где ука­за­но, какой про­то­кол на каком пор­ту слу­шать, и TLS сер­ти­фи­кат, если надо. И бэкенд часть — Target Group, кото­рая сле­дит за все­ми тас­ка­ми сер­ви­са и их здоровьем.

Network Load Balancer уме­ет толь­ко TCP или UDP. Хотя heath checks может делать по HTTP. Application Load Balancer уме­ет HTTP/HTTPS. В нём мож­но задач слож­ные пра­ви­ла направ­ле­ния тра­фи­ка, и мно­го чего другого.

И напо­сле­док. Если есть воз­мож­ность не исполь­зо­вать Elastic Beanstalk, не исполь­зуй­те. Хоть сна­ру­жи этот сер­вис и пыта­ет­ся казать­ся про­стым и дру­же­люб­ным, под капо­том там те же Auto Scaling Group, Load Balancer и наш ECS. Когда воз­ник­нет необ­хо­ди­мость в этом разо­брать­ся и тон­ко настро­ить, всё рав­но ока­жет­ся, что про­ще рабо­тать с ECS напрямую.