Рубрики
Uncategorized

Synth CDK приложение к портативной облачной форме

Консалтинг требует, чтобы вы работали в рамках параметров клиента. У некоторых клиентов есть внутренние стандарты, … Теги с AWS, DevOps, CDK, CloudFormation.

Консалтинг требует, чтобы вы работали в рамках параметров клиента. У некоторых клиентов есть внутренние стандарты, и вы хотите, чтобы вы доставили свое приложение CDK белой марки как CloudFormation.

Назовите меня старомодным Но я не ожидаю, что Apple переписывает свои продукты в TypeScript, потому что это мой нынешний фаворит.

Помимо шутки, в консалтинге это довольно распространенный вопрос, поэтому вы должны быть готовы к этому.

По связанным примечанию, некоторые клиенты имеют ограничения на соответствие или безопасность, которые очень затрудняют доступ к AWS CLI к развертыванию с помощью CDK.

К счастью, вы можете синтезировать приложения CDK в простую старую облачную информацию, упаковать его в ковш S3 и развернуть его из веб -консоли CloudFormation.

TL; DR;

Проверьте демонстрационный проект на GitHub Анкет

Первоначальный стек продукта

Наш демонстрационный стек создаст ведро и назовит его на основе учетной записи, региона и имени клиента.

interface MyProductProps extends StackProps {
  client: string;
}
export class MyProduct extends Stack {
  constructor(scope: Construct, id: string, props: MyProductProps) {
    super(scope, id);
    const bucketName = `${props.env.account}-${props.env.region}-${props.client}`;
    new Bucket(this, 'Bucket', {
      bucketName: bucketName
    });
  }
}

Полевой поле

Обычно вы пройдете env Поле для ваших реквизитов Stack Stack

const app = new cdk.App();
new MyProduct(app, 'my-product', {
  env: {
    account: '123456879123',
    region: 'us-east-1'
  },
  client: 'foo'
});

И очень легко получить доступ к учетной записи и региону от реквизита, как это:

const bucketName = `${props.env.account}-${props.env.region}-${props.client}`;

Синтезированный шаблон будет выглядеть так:

BucketName: '123456789123-us-east-1-foo'

Это очень интуитивно понятно и отлично подходит для развертывания CDK, но Не портативно Анкет Синтезированный шаблон будет содержать значения учетной записи жесткого кода и значения региона.

Вышеупомянутые реквизиты оцениваются в синтезатор Анкет Мы хотим, чтобы значения учетной записи и региона были оценены в Время развертывания Анкет

Представление Stack.of ()

В простой облачной информации вы не будете жестко кодировать информацию об учетной записи и регионе, вы бы использовали псевдофункции, такие как: ! Ref aws:: accountId и ! Ref aws:: region которые получают оценку во время развертывания.

Давайте переписать наши параметры стека и исключать необязательные env поле.

const app = new cdk.App();
new MyProduct(app, 'my-product', {
  client: 'foo'
});

Также, Давайте переписаем наш стек, чтобы использовать Stack.of, когда Env недоступен.

export class MyProduct extends Stack {
  constructor(scope: Construct, id: string, props: MyProductProps) {
    super(scope, id);

    const stack = props.env || Stack.of(this);
    const bucketName = `${stack.account}-${stack.region}-${props.client}`;

    new Bucket(this, 'Bucket', {
      bucketName: bucketName
    });
  }
}

Если вы посмотрите на синтезированный шаблон облачной информации, результат должен выглядеть знакомо:

BucketName: !Sub '${AWS::AccountId}-${AWS::Region}-foo'

Бонус: Приведенный выше подход работает, будь то env передается или нет, поэтому мы должны использовать его по умолчанию.

Параметры облака и токены

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

export class MyProduct extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
  }

  // Separate build step from constructor to allow inheriting stack to add properties.
  protected build(props: MyProductProps){
    const stack = props.env || Stack.of(this);
    const bucketName =`${stack.account}-${stack.region}-${props.client}`;

    new Bucket(this, 'Bucket', {
      bucketName: bucketName,
    });
  }
}

export class MyPortableProduct extends MyProduct {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Add CloudFormation parameter
    const client = new CfnParameter(this, 'Client', {
      type: 'String',
      description: 'Used for naming'
    });

    // Build the base stack, using the client parameter as a string token
    this.build({
      client: client.valueAsString
    })
  }
}

Мы только что расширили наш стек продуктов, чтобы сделать его портативным, с небольшой модификацией в базовом стеке! Если бы вы синтезировали Myportablestack , ваш BucketName будет выглядеть примерно так:

BucketName: !Sub '${AWS::AccountId}-${AWS::Region}-${Client}'

Предупреждение!

ValueasString генерирует токен. Токены не представляют ваши данные, поэтому не выполняйте строковые манипуляции или условия с токенами. Я расскажу, как справиться с этим в другом посте.

Синтезирование шаблона

До сих пор мы делали наше приложение CDK Portable, но мы хотим, чтобы CDK генерировал простой шаблон облачной информации.

Создайте новый bin/product.ts файл

const app = new cdk.App();
new MyPortableProduct(app, 'my-product');

const output = app.synth();
const outStack = output.stacks[0];

const templatePath = path.resolve('./cdk.out/template.yaml')
fs.writeFileSync(templatePath, YAML.stringify(outStack.template));

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

{
  "scripts": {
    "synth:product" : "tsc && npx cdk --app 'npx ts-node --prefer-ts-exts bin/product.ts' --path-metadata false --version-reporting false synth --quiet"
  }
}

Запустите скрипт NPM Run Synth: Продукт

Ваш cdk.out/template.yaml должен выглядеть так:

Parameters:
  Client:
    Type: String
    Description: Used for naming
Resources:
  Bucket83908E77:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::Join:
          - ""
          - - Ref: AWS::AccountId
            - "-"
            - Ref: AWS::Region
            - "-"
            - Ref: Client
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain

Cloudformation Logical Ids

Если вы обновляете существующее приложение CloudFormation или SAM до CDK, вы заметите, что логический идентификатор ведра ( bucket83908e77 ) автоматически генерируется.

Если логический идентификатор наследия был Ведро Это заставило бы воссоздать ведро, если вы обновите стек.

Мы должны обновить сборка Шаг к использованию RepideLogicalid Чтобы указать наш собственный логический идентификатор.

const bucket = new Bucket(this, 'Bucket', {
  bucketName: bucketName
});
(bucket.node.defaultChild as CfnBucket).overrideLogicalId('Bucket');

Теперь шаблон имеет наш ожидаемый логический идентификатор, и мы можем обновить наш стек, не теряя наши данные.

Parameters:
  Client:
    Type: String
    Description: Used for naming
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::Join:
          - ""
          - - Ref: AWS::AccountId
            - "-"
            - Ref: AWS::Region
            - "-"
            - Ref: Client
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain

Вывод

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

Проверьте GitHub Repo Для полной настройки проекта.

Первоначально опубликовано в моем блоге

Оригинал: «https://dev.to/ibliskavka/synth-cdk-app-to-portable-cloudformation-1ndf»