인프라스트럭처 코드 테스트를 통한 가치 창출

38750 단어 awsdevopscdk

가장 간단한 답은 고객의 신뢰다.
위의 화면 캡처를 통해 알 수 있듯이 배포 후 더 많은 고객의 신뢰를 얻으려면 인프라스트럭처 코드CDK Application에서 5초 이내에 신속하게 피드백을 받을 수 있습니다.
이 작은 장치에서 중요한 고객 데이터를 저장하는 것이 하나 있습니다.이러한 데이터는 언제든지 사용할 수 있어야 한다. 만약 내가 더 높은 수요를 가지고 있다면, 나는 80%의 이용률로 표를 신속하게 확대할 수 있을 것이다.이 모든 것은 다이나믹 DB에서 가능하지만, 만약 당신이 투자하지 않는다면, 이 모든 것은 실현될 수 없을 것이다.투자는 AWS 콘솔에서 수동으로 설정할 수 있으며, 더 나쁘게도 투자가 없는 상황에서 시스템 속도가 느려지거나 고객의 고소를 받을 때 설정할 수 있다.물론 고객이 그들의 서비스에 대해 불평하는 것을 더 좋아하는 회사는 없다.따라서 CDK로 코드를 작성하는 것처럼 자동화와 인프라에 투자하여 능동적으로 처리할 수 있습니다.
그러나 이 설정에서도 문제가 발생할 수 있습니다.속도를 올리고 싶을 때 오류가 발생할 수 있습니다. 생산 과정에서 길고 고통스러운 고객의 피드백이 아니라 빠른 피드백을 원합니다.이를 실현하기 위해 TDD와 CI/CD의 사용은 합리적이고 책임감이 있다.이런 상황에서 CDK는 이러한 개념에 대해 낯설지 않다. 이것은 단원 테스트를 통해 인프라 시설을 만들 때 이를 테스트할 수 있는 좋은 도구와 지원을 제공한다.
이러한 테스트의 가장 큰 가치는 단원 테스트 단계에서 탁월한 운영(OpEx) 문제를 조속히 반영할 수 있다는 데 있다.CDK 응용 프로그램에서 OpEx 문제에 따라 단원 테스트를 작성하면 생산 환경에서 서비스를 실행할 때 더욱 높은 신뢰도를 제공할 수 있습니다.이러한 믿음은 더 많은 고객 신뢰를 불러일으킬 것이다. 왜냐하면 당신은 서비스를 믿을 수 있게 운행할 수 있기 때문이다. 다행히도 고객이 발견하기 전에 문제를 발견할 수 있기 때문이다.
위의 예시 화면 캡처에서 단원 테스트는 운영 원가에 대한 나의 우려를 잘 포괄했다.이제 애플리케이션을 구축할 때마다 인프라스트럭처 코드npm run test를 간단히 실행하고 운영 환경에서 OpEx 문제가 발생하지 않도록 할 수 있습니다.조직의 기존 저장소를 스캔하여 이 점을 다른 단계로 끌어올릴 수 있습니다. 코드 단계에서 일부 로봇 프로그램을 사용해서 회사의 운영 원가 문제를 해결하지 못하면 서비스 소유자에게 알릴 수 있습니다.이 밖에 이러한 지표는 서비스 계기판을 반영하는 데 매우 유용하다.
이러한 운영 비용에 대한 우려를 말하자면 내가 과거에 참여한 사건 중 90% 이상에 가까운 사건이 경보, 감시와 보다 관찰적인 행동 항목에 관한 한두 가지가 있었다고 쉽게 말할 수 있다.이것들은 현재 코드의 일부분이 되고 관심사를 영원히 보호할 수 있다.또한 대시보드에 이러한 정보를 반영하고 보고서에 코드 변경(PR/MR/CR)을 공유하면 조직이 무엇을 가리키든지 간에 이벤트 보고서의 순환을 더욱 쉽게 완성할 수 있습니다.이런 간단한 방법을 통해 운영 원가의 측면에서 사건에 대한 장기적인 이해는 내부화되고 자동화될 수 있다.
이 점의 상업적 가치를 토론할 때, 코드를 보고 그것들을 연결합시다.다음 절에서는 코드 설정을 신속하게 정리할 것입니다. 기초 구조 코드를 위해 더 많은 테스트를 작성하는 데 영향을 주기를 바랍니다.
DynamoDB Table
샘플 설정
나는 2개 구조를 포함하는 매우 간단한 CDK 응용 프로그램 창고를 가지고 있다.하나의 창고는 모니터링(경보 주제, sns, 계기판)에 사용되고, 다른 창고는 데이터베이스에 사용된다.이 예시 코드들에 대해 나도 사용했다NestedStack.
AWS 문서에 따라 중첩된 스택은 다음과 같습니다.

The NestedStack construct offers a way around the AWS CloudFormation 500-resource limit for stacks. A nested stack counts as only one resource in the stack that contains it, but can itself contain up to 500 resources, including additional nested stacks.

The scope of a nested stack must be a Stack or NestedStack construct. The nested stack needn’t be declared lexically inside its parent stack; it is necessary only to pass the parent stack as the first parameter (scope) when instantiating the nested stack. Aside from this restriction, defining constructs in a nested stack works exactly the same as in an ordinary stack.


CDK v2
모니터링 스택
다른 스택에서 사용할 수 있도록 전용 을 만들고 대시보드를 내보냅니다.이렇게 하면 서비스의 모든 관련 지표와 경보를 중앙 계기판에 넣을 수 있습니다.

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';

export class MonitoringStack extends cdk.NestedStack {

    public readonly dashboard: cloudwatch.Dashboard;

    public readonly alarmTopic: sns.Topic;

    constructor(scope: Construct, id: string, props: MonitoringStackProps) {
        super(scope, id, props);

        this.dashboard = new cloudwatch.Dashboard(this, 'Dashboard', {});

        this.alarmTopic = new sns.Topic(scope, 'AlarmTopic', {
            displayName: 'My Service Alarms',
        });

        const emailSubscription = new subscriptions.EmailSubscription('[email protected]');

        this.alarmTopic.addSubscription(emailSubscription);
    }
}

CloudWatch Dashboard
데이터베이스 스택
다음은 를 생성하여 5가 설정될 때 읽기와 쓰기 용량을 point in time recovery으로 설정합니다.80% 의 이용률로 책상 용량의 5배로 자동으로 확장할 수 있다.또한 스택에 생성된 CloudWatch 대시보드에 읽기 및 쓰기 용량 경고와 지표를 추가합니다.

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as cloudwatchActions from 'aws-cdk-lib/aws-cloudwatch-actions';

interface DatabaseStackProps extends cdk.NestedStackProps {
    dashboard: cloudwatch.Dashboard;
    alarmTopic: sns.Topic;
}

export class DatabaseStack extends cdk.NestedStack {

  public readonly customerOrdersTable: dynamodb.Table;

  constructor(scope: Construct, id: string, props: DatabaseStackProps) {
    super(scope, id, props);

    this.customerOrdersTable = this.setupTable(scope, props, 'CustomerOrdersTable');
  }

  private setupTable(scope: Construct, props: DatabaseStackProps, id: string): dynamodb.Table {
    //
    const table = new dynamodb.Table(scope, id, {
      partitionKey: { name: 'customerId', type: dynamodb.AttributeType.STRING },
      sortKey: { name: 'orderId', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PROVISIONED,
      readCapacity: 5,
      writeCapacity: 5,
      encryption: dynamodb.TableEncryption.DEFAULT,
      pointInTimeRecovery: true,
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
    });

    this.setupAutoScaling(scope, table);
    this.setupDashboard(scope, props, table, id);

    return table;
  }

  private setupAutoScaling(scope: Construct, table: dynamodb.Table) {

    const tableReadScaling = table.autoScaleReadCapacity({ minCapacity: 5, maxCapacity: 25 });
    tableReadScaling.scaleOnUtilization({
      targetUtilizationPercent: 80,
    });

    const tableWriteScaling = table.autoScaleWriteCapacity({ minCapacity: 5, maxCapacity: 25 });
    tableWriteScaling.scaleOnUtilization({
      targetUtilizationPercent: 80,
    });
  }



  private setupDashboard(scope: Construct, props: DatabaseStackProps, table: dynamodb.Table, tableName: string){

    const readCapacityAlarm = new cloudwatch.Alarm(scope, `${tableName}ReadCapacity`, {
      metric: table.metricConsumedReadCapacityUnits({
        period: cdk.Duration.minutes(5),
        statistic: 'sum',
      }),
      threshold: 25,
      alarmDescription: `${tableName} Table Read Capacity`,
      evaluationPeriods: 1,
    });

    readCapacityAlarm.addAlarmAction(new cloudwatchActions.SnsAction(props.alarmTopic));

    const readCapacityAlarmWidget = new cloudwatch.AlarmWidget({
      title: `${tableName} Table Read Capacity`,
      alarm: readCapacityAlarm,
    });

    const writeCapacityAlarm = new cloudwatch.Alarm(scope, `${tableName}WriteCapacity`, {
      metric: table.metricConsumedWriteCapacityUnits({
        period: cdk.Duration.minutes(5),
        statistic: 'sum',
      }),
      threshold: 25,
      alarmDescription: `${tableName} Table Write Capacity`,
      evaluationPeriods: 1,
    });

    writeCapacityAlarm.addAlarmAction(new cloudwatchActions.SnsAction(props.alarmTopic));

    const writeCapacityAlarmWidget = new cloudwatch.AlarmWidget({
      title: `${tableName} Table Write Capacity`,
      alarm: writeCapacityAlarm,
    });

    props.dashboard.addWidgets(readCapacityAlarmWidget, writeCapacityAlarmWidget);
  }
}

현재 나의 창고는 이미 설치되어 있는데, 이것이 바로 내가 그것들을 테스트하는 방식이다.나는 완전한 테스트 세트를 공유하지 않았지만, 아래에 숨겨진 중요한 운영 원가 문제를 보여 주었다.
DynamoDB Table
데이터베이스 OpEx 문제 테스트
이 간단한 설정에서, 나는 새로운 테스트 창고를 만들고, 테스트된 창고를 추가했다.하나 Jest 를 생성함으로써, 나는 단원에서 나의 CDK 설정이 나의 문제를 덮어쓰는지 테스트할 수 있다.

import * as cdk from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { MonitoringStack } from '../lib/stacks/monitoring-stack';
import { DatabaseStack } from '../lib/stacks/database-stack';
import { Stack } from 'aws-cdk-lib';

describe('Test Database Stack', () => {
    let template: Template | null;

    beforeEach(() => {
        const app = new cdk.App();

        const testStack = new Stack(app, 'TestStack');

        const monitoringStack = new MonitoringStack(testStack, 'TestMonitoringStack', {});

        new DatabaseStack(testStack, 'TestDatabaseStack', {
            dashboard: monitoringStack.dashboard,
            alarmTopic: monitoringStack.alarmTopic,
        });

        template = Template.fromStack(testStack);
    });

    afterEach(() => {
        template = null;
    });

    test('Tables have point in time recovery', () => {
        template?.hasResourceProperties('AWS::DynamoDB::Table', {
            PointInTimeRecoverySpecification: {
                PointInTimeRecoveryEnabled: true,
            },
            ProvisionedThroughput: {
                ReadCapacityUnits: 5,
                WriteCapacityUnits: 5,
            },
        });
    });

    test('Tables have READ capacity alarms', () => {
        template?.hasResourceProperties('AWS::CloudWatch::Alarm', {
            MetricName: 'ConsumedReadCapacityUnits',
            Namespace: 'AWS/DynamoDB',
        });
    });

    test('Tables have WRITE capacity alarms', () => {
        template?.hasResourceProperties('AWS::CloudWatch::Alarm', {
            MetricName: 'ConsumedWriteCapacityUnits',
            Namespace: 'AWS/DynamoDB',
        });
    });

    test('Tables have READ capacity scalable target', () => {
        template?.hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', {
            ScalableDimension: 'dynamodb:table:ReadCapacityUnits',
            ServiceNamespace: 'dynamodb',
        });
    });

    test('Tables have WRITE capacity scalable target', () => {
        template?.hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', {
            ScalableDimension: 'dynamodb:table:WriteCapacityUnits',
            ServiceNamespace: 'dynamodb',
        });
    });

    test('Tables have READ auto-scaling policy at 80% utilization', () => {
        template?.hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', {
            TargetTrackingScalingPolicyConfiguration: {
                PredefinedMetricSpecification: {
                    PredefinedMetricType: 'DynamoDBReadCapacityUtilization',
                },
                TargetValue: 80,
            },
        });
    });

    test('Tables have WRITE auto-scaling policy at 80% utilization', () => {
        template?.hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', {
            TargetTrackingScalingPolicyConfiguration: {
                PredefinedMetricSpecification: {
                    PredefinedMetricType: 'DynamoDBWriteCapacityUtilization',
                },
                TargetValue: 80,
            },
        });
    });
});

CloudFormation Template
폐막사
나는 위의 예시 코드와 전체 상하문이 당신이 기초 구조를 위해 더 많은 단원 테스트를 작성하는 데 영향을 줄 수 있기를 바랍니다.내가 아는 바에 의하면Terraform은 이러한 설정을 지원하지 않거나, 설령 지원된다 하더라도, 나는 최근의 시도에서 생산력과 도구 지원을 찾을 수 없다. 예를 들어 웹스토어나 VS코드에서 간단한 npm run test 를 실행할 수 없다.이것이 바로 내가 CDK가 AWS의 고객을 만족시키는 서비스를 구축하고 운행할 때 개발자의 신뢰와 생산력을 바꿀 것이라고 믿는 이유이다.

다음 단계는 어디로 가야 합니까?
OpEx가 왜 중요한지 자세히 알아보려면 AWS가 정성들여 디자인한 백서를 깊이 있게 이해할 수 있습니다.
  • 또한 CDK 문서에 대한 시작 자습서는 다음과 같습니다.
  • AWS Well Architected
  • CDK 문서 자체는 서비스를 어떻게 사용하는지 매우 상세하게 소개했다
  • CDK Getting Started
  • 좋은 웹페이지 즐겨찾기