Есть AWS Glue job, которая должна загрузить данные в AWS S3 в другом регионе.
Джоба падает с ошибкой:
ERROR [Executor task launch worker for task 39] executor.Executor (Logging.scala:logError(91)): Exception in task 6.1 in stage 2.0 (TID 39)
com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to projectname-dwh.s3.eu-west-1.amazonaws.com:443 [projectname-dwh.s3.eu-west-1.amazonaws.com/52.218.112.104] failed: connect timed out
Причину искал долго, потому что во-первых – изначально пошёл искать не в том направлении, во-вторых – не слишком обращал внимания на документацию, в третих – столкнулся с “забавными” багами AWS Console.
Но – всё-таки всё завелось.
Поехали.
Содержание
“Решение” первое – неправильное (не верьте Google!)
Что мы делаем, когда встречаем какую-то ошибку? Гуглим.
Гуглим по запросу “aws glue s3 timeout“, находим обсуждение>>> на форуме тех. поддержки AWS, в котором автор размышляет о SecurityGroup, в которой не разрешён доступ кот AWS S3.
В принципе – выглядит достаточно логично.
“Виновата” SecurityGroup?
Проверяем используемый AWS Glue Connection:
Он настроен на VPC нашего AWS Aurora RDS-кластера, в подсети subnet-04bb24f7a349d36de которого AWS Glue создаёт свой Elastic Network Interface, к которому подключает SecurityGroup sg-08bed0e10707da5e6.
Проверяем исходящие правила этой SecurityGroup:
Outbound открыт по всем портам и на все адреса, окей.
А Inboud правила – нет, потому что SecurityGroup сервера баз данных, подключение к которой, разумеется, ограничено:
Значит, сейчас всё выглядит так, что когда AWS Glue пытается подключиться к AWS S3 – исходящий запрос уходит к корзине projectname-dwh.s3.eu-west-1.amazonaws.com/52.218.112.104, а обратно поступить не может.
Логично? Вроде бы да.
Варианты решения:
- разрешить входящий с IP 52.218.112.104, который есть в логе, и который вроде как принадлежит корзине projectname-dwh.s3.eu-west-1.amazonaws.com – но статичен ли он? Сильно сомневаюсь, что S3 оперирует статичными адресами, тем не менее – можно попробовать
- создать отдельную SecurityGroup в той же VPC, в этой SG разрешим весь входящий и исходящий трафик + доступ к самой себе (требования AWS Glue – немного документации всё-таки читать приходилось), и переключим коннекшен на эту SG – но насколько решение такое секьюрно? Попробуем, если сработает – потом подумаем над безопасностью.
Попробуем для начала открыть 52.218.112.104 (на скрине – привычка замазывать IP 🙂 ):
Перезапускаем джобу – и она снова падает:
ERROR [Executor task launch worker for task 25] executor.Executor (Logging.scala:logError(91)): Exception in task 14.1 in stage 2.0 (TID 25)
com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to projectname-dwh.s3.eu-west-1.amazonaws.com:443 [projectname-dwh.s3.eu-west-1.amazonaws.com/52.218.97.131] failed: connect timed out
Теперь адрес 52.218.97.131.
В общем-то – логично, что там не статичный IP.
Тогда – создаём отдельную SecurityGroup в той же VPC, в Inbound и Outbound рулах – разрешаем весь трафик.
Далее – редактируем сам Connection в AWS Glue, и меняем SecurityGroup на только что созданную:
Запукаем ещё раз, ждём.
Иииии…
ERROR [Executor task launch worker for task 16] executor.Executor (Logging.scala:logError(91)): Exception in task 14.0 in stage 2.0 (TID 16)
com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to projectname-dwh.s3.eu-west-1.amazonaws.com:443 [projectname-dwh.s3.eu-west-1.amazonaws.com/52.218.112.48] failed: connect timed out
WTF? А почему?
Возвращаемся к нашему Connection, проверяем – а там старая SecurityGroup… Но мы ведь только что её меняли?!?
Невозможно изменить SecurityGroup в AWS Glue Connection?
Пробуем ещё раз:
- редактируем Connection – ставим новую SecurityGroup
- жмём Next, потом Finish
- снова редактируем Connection – а там старая SecurityGroup
What?!?
Окей, пробуем отключить коннекшен от джобы – может, не хочет применяться, пока коннекшен активен?
Редактируем коннекшен ещё раз – и снова та же х*%?ня.
Пишем тикет в Tech Support, ждём.
Через несколько дней из дома зашёл проверить что и как – а там у нашего Connection уже новая SecurityGroup…
Хм… Ну, ОК, подумал я – может, саппорт что-то втихаря подфиксил.
Решение второе – правильное (RTFM!)
Но проблема осталась – джоба по-прежнему фейлится с ошибкой “connect timed out“, даже если к Connection подключена SecurityGroup, которая разрешает всё.
К решению подтолкнул всё тот же саппорт, который намекнул глянуть в сторону не SecurityGroup – а VPC и настроек сети.
Итак, наш Connection использует подсеть subnet-04bb24f7a349d36de, глянем её Route Table:
Вроде бы правильно?
У нас есть Internet Gateway, есть маршрут в сеть 0.0.0.0/0 через него, есть VPC endpoint для S3:
AWS VPC Endpoints
Читаем за VPC ендпоинты в документации>>>, и чешим репу – ну вроде ж всё правильно? Ендпоин для S3 создан, маршрут к нему в таблице маршрутизации есть – он создаётся автоматически при создании ендпоинта (вот тут-то и проблема: создавал бы руками – обратил бы внимание раньше):
Вот как должно работать:
Т.е. запросы от нашего AWS Glue Connection ENI должны идти через этот VPC S3 Endpoint, согласно маршруту, прописанному в таблице маршрутизации.
Но не работает.
И вот тут до меня дошло.
Смотрим внимательнее на маршрут:
А корзина где? projectname-dwh.s3.eu-west-1.amazonaws.com – Европа.
AWS Glue и cross-region AWS S3 Connections
Что можно сделать? Прочитать, б%;*ь, документацию по кросс-регион коннекшенам для AWS Glue – https://aws.amazon.com/ru/blogs/big-data/create-cross-account-and-cross-region-aws-glue-connections.
Которая говорит использовать NAT Gateway.
Только тогда надо создать отдельную подсеть, что бы роут в 0.0.0.0/0 слать через этот NAT Gateway, так как сейчас таблица маршрутизации этой подсети шлёт трафик через Internet Gateway, но её трогать нельзя, т.к. кластер баз данных.
Итак, что надо настроить:
- приватная подсеть в VPC нашей Aurora
- для подсети роут в 0.0.0.0/0 укажем через NAT GW
- AWS Glue Connection сделаем в этой приватной подсети, навешиваем SecurityGroup с self-allow
- и используем существующую публичную сеть в VPC Aurora, в которой создадим NAT Gateway
- для этой подсети роут в 0.0.0.0 через Internet Gateway
- NAT GW в этой публичной подсети будет ходить через IGW в мир, к S3 в Европе
Вроде так?
Делаем.
С сетями у меня плохо – используем ipcalc
, считаем 3 сети по 62 доступных хоста (2 уже есть, и существующие подсети уже разбиты так – не будем менять):
[simterm]
$ ipcalc 10.0.18.0/24 -s 62 62 62 | grep Network Network: 10.0.18.0/24 00001010.00000000.00010010. 00000000 Network: 10.0.18.0/26 00001010.00000000.00010010.00 000000 Network: 10.0.18.64/26 00001010.00000000.00010010.01 000000 Network: 10.0.18.128/26 00001010.00000000.00010010.10 000000
[/simterm]
10.0.18.0/26 и 10.0.18.64/26 у нас уже есть
Создаём новую подсеть:
Создаём NAT Gateway в существующей публичной подсети:
RouteTable для новой, приватной, подсети уже есть – создаётся сама при создании подсети:
Редактируем её – указываем маршрут в 0.0.0.0/0 через созданный ранее NAT GW:
Редактируем AWS Glue Connection – задаём использование новой, приватной, подсети:
Сохраняем изменения, и…
&^$&$*%!!!
Невозможно изменить Subnet в AWS Glue Connection?
Ничего не сохраняется – повторяется история с SecurityGroup, когда мы её обновляли – а она оставалась прежней.
Причину нашли позже, а пока я просто создал новый Connection:
Меняем Connection в настройках самой джобы:
Запускаем джобу.
Ждём.
И всё работает.
Твою ж мать…
Невозможно изменить […] в AWS Glue Connection – причина и “решение”
На самом деле – всё менялось. Т.е. изменения применяются – они просто не отображаются в AWS Console, пока не перезагрузишь страницу через F5, а просто переходы между пунктами меню не помогали.
Саппорт передал в команду разработки – пофиксят.
Собственно, на этом приключения завершились.