Есть 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, а просто переходы между пунктами меню не помогали.
Саппорт передал в команду разработки — пофиксят.
Собственно, на этом приключения завершились.