AWS объявила о доступности функции преобразования кода в AWS Transform, которая переписывает отдельные вызовы Azure SDK в современных приложениях .NET, заменяя их эквивалентами AWS. В опубликованном 16 октября объявлении упоминаются преобразования Azure Functions в AWS Lambda, Azure Blob Storage в Amazon S3 и Azure Queue Storage в Amazon SQS. Преобразование Azure Cosmos DB в Amazon DynamoDB доступно в режиме предварительного просмотра.

Инженер проверяет детальную миграцию .NET-кода из Azure в AWS с хранилищем, очередями, бессерверными функциями, контролем идентификации и архитектурными проверками.

Непосредственная привлекательность понятна: команда может передать приложение, уже работающее в Azure, позволить агенту выявить поддерживаемые облачные зависимости и получить преобразованную кодовую базу вместо того, чтобы начинать переписывание отдельно для каждого сервиса. Но с операционной точки зрения важнее другое: это преобразование исходного кода, а не полноценная миграция в облако. Оно не воссоздаёт сеть Azure, не переносит данные, не воспроизводит политики идентификации и не доказывает, что после перехода приложение сохранит прежнее поведение при сбоях и работе с согласованностью данных.

Именно это различие должно определять подход платформенных и инженерных команд к оценке функции. Рассматривайте AWS Transform как ускоритель ограниченного направления модернизации, а не как разрешение сменить провайдера, просто приняв сгенерированный pull request.

Что объявила AWS

Агент модернизации .NET в AWS Transform может проверять переданный исходный код, выявлять использование Azure SDK и включать варианты преобразования в отчёт об оценке и план модернизации. До запуска преобразования команда может принять эти варианты, изменить их или отказаться от них.

Набор общедоступных сопоставлений намеренно ограничен:

  • Azure Functions можно преобразовать в функции AWS Lambda.
  • Вызовы Azure Blob Storage SDK можно преобразовать в вызовы Amazon S3 SDK.
  • Вызовы Azure Queue Storage можно преобразовать в вызовы Amazon SQS.
  • Преобразование Azure Cosmos DB в Amazon DynamoDB указано как возможность в режиме предварительного просмотра.

AWS сообщает, что функция доступна в восьми регионах: восток США (Северная Вирджиния), Азиатско-Тихоокеанский регион (Мумбаи, Токио и Сеул), Азиатско-Тихоокеанский регион (Сидней), Канада (центральный регион), а также Европа (Франкфурт и Лондон). В документации также прямо указано важное ограничение: возможность преобразует код приложения и не занимается миграцией облачной инфраструктуры.

Это ограничение — не сноска. В реальном сервисе SDK — лишь один уровень зависимости от провайдера. Функция Azure может опираться на план размещения, управляемую идентификацию, настройки приложения, приватные конечные точки, слоты развертывания, привязки к событиям, учётные записи хранения, ссылки на Key Vault, правила мониторинга и сетевые ограничения. Замена пространства имён и вызова метода оставляет людям задачу обнаружить и заново собрать все окружающие предположения.

Таким образом, функция AWS закрывает вполне конкретную часть стоимости миграции: перевод специфичного для провайдера кода приложения. Она не устраняет необходимость определить целевую архитектуру.

Почему «эквивалентный сервис» не означает эквивалентное поведение

Названия облачных сервисов создают ложное ощущение симметрии. Blob Storage и S3 — оба объектные хранилища. Azure Queue Storage и SQS — оба очередные сервисы. Azure Functions и Lambda — обе бессерверные вычислительные платформы. На уровне API такие сравнения полезны. На уровне выполнения они неполны.

Первый вопрос для команды миграции — не о том, можно ли перевести метод. Нужно понять, сохраняется ли после перевода контракт приложения.

Объектное хранилище — хороший пример. Участок кода может загружать объект, задавать метаданные, создавать временный URL, а затем рассчитывать на определённую задержку видимости, поведение при перезаписи, соглашение о контрольной сумме или модель авторизации. Целевой сервис может поддерживать аналогичную операцию, но использовать другие значения по умолчанию, заголовки, типы ошибок, механизмы жизненного цикла или наборы политик. Механически преобразованный вызов может компилироваться и при этом изменить поведение, которое наблюдают последующие системы.

Очереди создают похожую проблему. Производитель и потребитель связаны не только методом отправки. Их взаимодействие зависит от семантики доставки, тайм-аутов видимости, срока хранения, максимального размера сообщения, ожиданий по порядку, поведения очереди недоставленных сообщений, политики повторной доставки, обработки дубликатов и интервалов между повторами. Преобразование Azure Queue Storage в SQS может породить корректные вызовы AWS, но не доказывает, что потребитель останется безопасным при повторной доставке или что существующий процесс обработки проблемных сообщений продолжит работать.

Функции добавляют ещё один уровень сложности. Функция Azure может запускаться HTTP-запросом, очередью, таймером, потоком событий или привязкой, скрывающей специфическую для провайдера инфраструктуру. У Lambda есть собственные источники событий, режимы вызова, средства управления конкурентностью, ограничения по времени выполнения, упаковка развёртывания, разрешения и модель наблюдаемости. Если исходное приложение рассчитывает на долгоживущий процесс, сохранение данных в локальной файловой системе, определённый сценарий прогрева или форму запроса, создаваемую привязкой, целевой реализации потребуется проектирование, выходящее за рамки перевода SDK.

Практический вывод прост: успешная компиляция — это ранний сигнал, а не критерий приёмки миграции.

Как правильно читать отчёт об оценке

Рабочий процесс AWS Transform полезен тем, что выносит решения о преобразовании на этап до самой трансформации. Благодаря этому команда может проверить предполагаемую целевую архитектуру, а не обнаруживать все решения уже после генерации кода.

Используйте этот отчёт как инвентаризацию зависимостей с дополнительными рекомендациями.

Начните с разделения на три категории:

  1. Непосредственно поддерживаемые вызовы. Это ссылки на SDK, которые, согласно инструменту, он может преобразовать. Они подходят для автоматической трансформации, но не гарантируют автоматически корректный результат.
  2. Смежные зависимости от провайдера. Сюда входят идентификация, конфигурация, сеть, развёртывание, журналирование, трассировка, секреты, привязки событий и определения инфраструктуры. Они могут быть видны в том же репозитории, но не входят в перечисленные сопоставления сервисов.
  3. Поведение бизнес-логики. Сюда относятся идемпотентность, порядок обработки, хранение, замысел авторизации, проверка данных, процедуры восстановления и обработка ошибок, видимая пользователю. Его нельзя безопасно вывести из сопоставления сервисов один к одному.

В отчёте также следует проверить выбор целевых сервисов. AWS документирует целевые сервисы по умолчанию, но позволяет командам настраивать план, в том числе отказываться от некоторых или всех преобразований и перенаправлять сопоставление по умолчанию. Это важно, если целевая архитектура не является буквальной заменой одного сервиса другим. Например, команда может сохранить в приложении объектно-ориентированный интерфейс, добавив адаптер хранилища, или решить после измерения требований к пропускной способности и порядку обработки, что рабочую нагрузку очереди следует направить в другой интеграционный сервис.

Полезный артефакт для анализа — таблица с одной строкой на каждую специфическую для провайдера зависимость:

Зависимость Поведение источника Предлагаемая цель Что нужно подтвердить Ответственный
Загрузка blob-объекта перезапись, метаданные, хранение операция S3 согласованность и поведение политик команда хранения
Получение сообщения из очереди правила повторов и видимости поток получения SQS обработка дубликатов и ядовитых сообщений команда сервиса
Триггер функции форма события и тайм-аут вызов Lambda тайм-аут, конкурентность и повторы платформенная команда
Идентификация управляемая идентичность и области действия роль IAM и политики минимально необходимые привилегии и ротация команда безопасности

Цель здесь не в бюрократии. Такая таблица не позволяет сгенерированному diff-файлу превратиться в фактический документ архитектуры.

Что функция делает хорошо

Если приложение использует поддерживаемые Azure SDK в обычном коде .NET, прирост эффективности действительно заметен. Инструмент может находить ссылки на сервисы, предлагать план модернизации и переписывать известные шаблоны в масштабе, который в противном случае потребовал бы значительного времени разработчиков. Согласно документации AWS, он также может оставлять явные отметки там, где преобразование недоступно, включая комментарии TODO, заглушки или документ со следующими шагами.

Это особенно ценно в трёх ситуациях.

Первая — оценка портфеля. Организация с большим количеством сервисов .NET может использовать анализ, чтобы выяснить, насколько тесно каждое приложение связано с Azure. Результат помогает выстроить последовательность работ, даже если сервис ещё не готов к миграции.

Вторая — повторяющийся этап перевода. После согласования целевых контрактов и инфраструктурных шаблонов автоматические правки могут снять большой объём механической работы. Инженеры смогут больше заниматься поведением системы и меньше — изменением пространств имён, созданием клиентов и типовых форм запросов.

Третья — контролируемая ветка модернизации. Команда может запустить преобразование на копии приложения, сопоставить результат с существующими границами абстракций и использовать полученный diff, чтобы определить код, который следует изолировать до начала миграции.

Эта функция менее полезна, когда в репозитории преобладают инфраструктура как код, слабо документированные связи, пользовательские интеграции с Azure, сложные схемы доступа к данным или логика приложения, рассматривающая поведение провайдера как часть бизнес-контракта. В таких случаях анализ кода всё ещё может быть полезен, но преобразование не следует принимать за полноценный план миграции.

Проблема идентификации шире, чем изменение конструктора клиента

Миграции между провайдерами часто завершаются неудачей на границе между кодом приложения и авторизацией. Приложения Azure обычно используют управляемые идентификаторы и назначения ролей. Приложения AWS используют роли и политики IAM, а разрешения в зависимости от среды выполнения привязываются к ролям выполнения, ролям задач, профилям экземпляров или другим идентификаторам.

Преобразованный вызов SDK сам по себе не обладает полномочиями. Целевое развёртывание должно предоставить идентификатор, способный выполнять именно необходимые действия с именно необходимыми ресурсами. Это означает, что нужно сопоставить не только «может читать большой двоичный объект» с «может читать объект», но и область действия, условия, имена ресурсов, ключи шифрования, сетевой маршрут и ответственную за эксплуатацию сторону для этого доступа.

В рамках анализа миграции нужно ответить на следующие вопросы:

  • Какой идентификатор выполняет каждую функцию, рабочий процесс и задание развёртывания?
  • Какие политики ресурса и идентификатора вместе разрешают этот вызов?
  • Использует ли целевая система ключи шифрования, управляемые заказчиком, и кто может ими пользоваться?
  • Может ли рабочая нагрузка обращаться к сервису по предусмотренному сетевому маршруту?
  • Являются ли учётные данные краткосрочными и обновляются ли они без изменений в приложении?
  • Что записывается в журнал, когда проверка авторизации завершается отказом?

Именно здесь преобразование только на уровне кода может создать обманчивое ощущение завершённости. Приложение может компилироваться, тесты могут проходить с широкими разрешениями, а промышленное развёртывание всё равно завершится ошибкой, потому что реальная граница политик так и не была спроектирована. И наоборот, быстрое исправление с выдачей широкой роли может сделать миграцию «работающей», одновременно увеличив радиус поражения.

Поэтому тест безопасности должен включать запрещённые действия, попытки доступа к ресурсам разных областей и развёртывание из чистой среды. Миграция завершена не тогда, когда успешен запрос по основному сценарию, а тогда, когда целевая модель идентификации понятна и ограничена.

Перенос данных и семантика данных по-прежнему требуют участия людей

AWS Transform не переносит данные, находящиеся в Azure Blob Storage, Azure Queue Storage или Cosmos DB. Это кажется очевидным, но меняет график проекта. Преобразование кода и миграция данных могут выполняться параллельно только после того, как команда определит, как будут сосуществовать две версии.

Для объектных данных план должен включать инвентаризацию источника, оценки объёма и количества объектов, обработку метаданных и тегов, требования к шифрованию, правила хранения, журналы доступа и стратегию переключения. Копия, сохраняющая байты, но теряющая метаданные, всё равно может нарушить работу потребителей. Переключение, меняющее создание URL или семантику авторизации, может нарушить работу клиентов, даже если каждый объект был успешно перенесён.

Для очередей копирование сообщений редко бывает нейтральной операцией. Команда должна решить, следует ли старые сообщения обработать до конца, воспроизвести, отбросить или преобразовать. Повторное воспроизведение может дважды вызвать побочные эффекты. Полное опустошение очереди может увеличить окно миграции. Архитектура с двойной записью может привести к расхождению, если один провайдер примет сообщение, а другой его отклонит. Более безопасный выбор зависит от идемпотентности рабочей нагрузки и последствий для бизнеса.

Для баз данных предварительный статус переноса из Cosmos DB в DynamoDB — сигнал проявлять особую осторожность. NoSQL-системы часто различаются секционированием, индексированием, согласованностью, областью действия транзакций, языком запросов, ограничениями на элементы и поведением ленты изменений. Преобразованный слой доступа к данным не подтверждает, что целевая модель данных будет масштабироваться или возвращать те же результаты. Перед принятием решения о переключении в рабочей среде командам следует смоделировать репрезентативные шаблоны доступа и выполнить проверки качества данных.

На каждом этапе план миграции должен указывать источник истины. «Данные находятся в обоих облаках» — это не стратегия согласованности.

Тестирование должно сравнивать контракты, а не только результаты

Обычный набор модульных тестов может проверять, что преобразованный код возвращает ожидаемые значения от имитированных клиентов. Это необходимо, но недостаточно, поскольку моки обычно сохраняют абстракцию, спроектированную исходным провайдером.

Более сильный план тестирования состоит из нескольких уровней.

Контрактные тесты проверяют ожидания самого приложения: схемы сообщений, метаданные объектов, решения об авторизации, обработку повторных попыток и классификацию ошибок. Такие тесты должны выполняться с целевыми сервисами там, где их поведение имеет значение.

Дифференциальные тесты прогоняют эквивалентные рабочие нагрузки через исходную и целевую реализации и сравнивают результаты на уровне бизнес-логики. Сравнение не должно требовать идентичных ошибок провайдеров или идентификаторов запросов. Оно должно проверять то, от чего зависят пользователи, последующие сервисы и операторы.

Тесты отказоустойчивости имитируют ограничение пропускной способности, тайм-ауты, частичные записи, повторную доставку, истёкшие учётные данные, недоступные зависимости и некорректные события. Цель — выявить места, где модели сбоев исходной и целевой систем расходятся.

Эксплуатационные тесты проверяют журналы, метрики, трассировки, оповещения, панели мониторинга и инструкции по реагированию. Перенесённый сервис, который работает, но не поддаётся диагностике, не готов к промышленной эксплуатации.

Тесты безопасности подтверждают соблюдение принципа наименьших привилегий и проверяют, что рабочая нагрузка не может читать, записывать или вызывать ресурсы за пределами предусмотренной для неё границы.

Для бессерверных рабочих нагрузок включите в проверку поведение при разной степени параллелизма и холодном старте, запас по тайм-ауту, повторные попытки источника событий и откат развёртывания. Для очередей измеряйте тайм-аут видимости на основе фактического распределения времени обработки, а не выбирайте привычное значение. Для объектного хранилища проверяйте метаданные, шифрование, условные записи и URL-адреса доступа. При преобразовании базы данных воспроизводите реальные формы запросов и сравнивайте пагинацию, согласованность и обработку сбоев.

Более безопасная последовательность миграции

Команда, оценивающая новую возможность, может снизить риск, сузив масштаб первого проекта.

Выберите один сервис с понятным владельцем, ограниченным числом поддерживаемых зависимостей от провайдера и проверяемым откатом. Не начинайте с системы, которая одновременно объединяет федерацию идентификации, разветвление событий, регулируемые данные и недокументированные эксплуатационные процедуры.

До запуска преобразования создайте карту зависимостей исходной системы. Включите в неё пакеты SDK, переменные окружения, привязки, манифесты развёртывания, секреты, сетевые конечные точки, хранилища данных, очереди, планировщики и интеграции с мониторингом.

Затем определите контракты целевой системы. Решите, как приложение будет представлять хранилище, обмен сообщениями, конфигурацию, идентификацию и телеметрию. Если вызовы, специфичные для провайдера, разбросаны по бизнес-логике, до преобразования введите адаптеры или укрепите уже существующие. Это увеличит объём подготовительной работы, но упростит проверку итогового diff и удешевит будущие изменения.

Запустите оценку и проверьте каждое предложенное сопоставление. Зафиксируйте намеренные отказы от преобразования. Рассматривайте неподдерживаемые вызовы как запланированную работу, а не как уборку, которую можно оставить напоследок.

Создайте целевую инфраструктуру отдельно. Используйте роли IAM с узкими полномочиями, зашифрованные ресурсы, при необходимости — приватное подключение, журналирование, оповещения, резервные копии и средства управления развёртыванием. Не подменяйте проверку инфраструктуры сгенерированным кодом приложения.

Преобразуйте код в отдельной ветке, скомпилируйте его и запустите статический анализ. Затем протестируйте его на реальных целевых сервисах с репрезентативными данными и инъекцией сбоев. Сохраняйте исходную реализацию доступной, пока не будут подтверждены бизнес-контракты и эксплуатационные контракты миграции.

Для переключения предпочитайте обратимую последовательность: разверните сервис без передачи ему трафика, проверьте чтение, выполните неразрушающие записи, сравните телеметрию, направьте небольшой объём трафика или рабочей нагрузки и заранее определите условие отката до увеличения доли. Конкретный механизм будет различаться в зависимости от приложения, но принцип неизменен: преобразование должно сокращать механическую фазу, не сокращая фазу сбора доказательств.

Вопрос управления для платформенных команд

AWS Transform меняет экономику преобразования кода, а значит, больше организаций смогут пробовать миграцию между провайдерами небольшими командами. Это полезно, но одновременно может сдвинуть риски на более ранний этап процесса. Когда преобразование кода становится дешёвым, дефицитными ресурсами оказываются архитектурные решения и валидация.

Платформенным командам следует установить стандартный этап проверки сгенерированных миграций. Он должен требовать:

  • полной инвентаризации преобразованных и непреобразованных зависимостей от провайдеров;
  • утверждённой целевой архитектуры и модели идентификации;
  • плана миграции данных и отката;
  • тестов для специфичной для провайдера семантики и поведения при сбоях;
  • подтверждений того, что в целевой среде работают наблюдаемость и реагирование на инциденты;
  • назначенного ответственного за каждый нерешённый TODO или заглушку;
  • документированного решения для каждого сопоставления по умолчанию, которое было изменено.

Требования к такому контролю должны соответствовать масштабу задачи. Небольшой внутренний процесс, сохраняющий несекретные объекты, не нуждается в той же процедуре, что и сервис регулируемых транзакций. Но для обоих должен быть назначен ответственный и предусмотрен способ доказать приемлемость преобразованного поведения.

Главное правило — сохранять сгенерированный код пригодным для проверки. Отчёт об оценке, план модернизации, diff преобразований, результаты тестов и исключения следует хранить вместе с записью об изменениях сервиса. Если позже преобразование запустят повторно, команда должна суметь объяснить, что изменилось и почему.

За чем следить дальше

Текущее объявление охватывает ограниченный набор сопоставлений Azure с AWS, а преобразование Cosmos DB в DynamoDB пока остаётся в режиме предварительного просмотра. Это показывает, что AWS начинает с распространённых и легко распознаваемых точек перевода, не заявляя об универсальной переносимости.

Командам стоит следить за изменениями в поддерживаемых версиях .NET, появлением дополнительных сервисов Azure, обработкой инфраструктуры и тем, как инструмент сообщает о неоднозначных преобразованиях. Не менее важно наблюдать за собственными результатами тестов. Схема, которая выглядит эквивалентной в небольшом сервисе, может вести себя иначе при большем объёме, повторных попытках или более строгих политиках идентификации.

Пока практический совет таков: используйте AWS Transform там, где он особенно полезен, — для инвентаризации зависимостей и ускорения повторяющихся изменений в коде. Архитектуру, данные, идентификацию и приёмку в производственной среде оставляйте предметом явной проверки человеком. Функция помогает быстро создать ветку миграции. Но она не делает контракты двух облаков одинаковыми.

Именно это должны решить платформенные команды до одобрения первого pull request: не «преобразовал ли агент код?», а «какие доказательства показывают, что после переноса границы провайдера сервис по-прежнему работает корректно, безопасно и управляемо?»