LoginSignup
8
4

More than 1 year has passed since last update.

AWS CDKで独自ドメインホスティング環境構築を自動化してみた

Last updated at Posted at 2022-03-21

img

AWS CDKで独自ドメインホスティング環境構築を自動化してみました :tada:


以前の記事内容をAWS CDKで実現する方法をためしてみました!


今回の作成したテンプレートをGitHubで公開したのでぜひご利用ください!

/lib/unique-domain-hosting-stack.ts

import { Stack, StackProps, RemovalPolicy, CfnOutput } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
import * as route53 from 'aws-cdk-lib/aws-route53';
import * as targets from 'aws-cdk-lib/aws-route53-targets';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';

export class UniqueDomainHostingStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    // ドメイン名取得
    const domainName = this.node.tryGetContext('domainName');
    // 擬似パラメータ取得
    const {
      accountId,
      region,
    } = new cdk.ScopedAws(this);
    // ホストゾーンID取得
    const hostedZoneId = route53.HostedZone.fromLookup(this, 'HostedZoneId', {
      domainName: domainName
    });
    // Certificate Manager設定
    const certificateManagerCertificate = new acm.DnsValidatedCertificate(this, 'CertificateManagerCertificate', {
      // ドメイン指定
      domainName: domainName,
      // ホストゾーンID指定
      hostedZone: hostedZoneId,
      // リージョン指定 (CloudFront固定)
      region: 'us-east-1',
      // 検証方法指定
      validation: acm.CertificateValidation.fromDns(),
    });
    // S3バケット作成
    const s3Bucket = new s3.Bucket(this, 'S3Bucket', {
      // バケット名指定
      bucketName: `${domainName}-${region}-${accountId}`,
      // ブロックパブリックアクセスをすべてON
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      // リソース削除時にバケット削除
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });
    // CloudFrontOAI設定
    const cloudFrontOAI = new cloudfront.OriginAccessIdentity(this, 'CloudFrontOriginAccessIdentityy', {
      comment: 'Unique Domain Hosting Environment',
    })
    // CloudFront設定
    const cloudFrontDistribution = new cloudfront.Distribution(this, 'CloudFrontDistribution', {
      // ドメイン指定
      domainNames: [domainName],
      // キャッシュビヘイビア設定
      defaultBehavior: {
        // オリジンID指定
        origin: new origins.S3Origin(s3Bucket, {
          originAccessIdentity: cloudFrontOAI
        }),
        // 自動圧縮有無指定
        compress: true,
        // HTTPメソッド指定
        allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD,
        cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD,
        // ビューアプロトコルポリシー指定
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        // キャッシュポリシー指定 (CachingOptimized)
        cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
      },
      // SPA対応設定
      errorResponses: [
        {
          httpStatus: 403,
          responsePagePath: '/index.html',
          responseHttpStatus: 200,
          ttl: cdk.Duration.minutes(0),
        },
        {
          httpStatus: 404,
          responsePagePath: '/index.html',
          responseHttpStatus: 200,
          ttl: cdk.Duration.minutes(0),
        },
      ],
      // 料金クラス指定
      priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
      // ディストリビューション有効無効指定
      enabled: true,
      // SSL証明書設定
      certificate: certificateManagerCertificate,
      // セキュリティポリシー指定
      minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
      // HTTPバージョン指定
      httpVersion: cloudfront.HttpVersion.HTTP2,
      // ルートURL指定
      defaultRootObject: 'index.html',
      // IPv6有無指定
      enableIpv6: true,
    })
    // Route53レコード設定
    new route53.ARecord(this, 'Route53RecordSet', {
      // ドメイン指定
      recordName: domainName,
      // ホストゾーンID指定
      zone: hostedZoneId,
      // エイリアスターゲット設定
      target: route53.RecordTarget.fromAlias(
        new targets.CloudFrontTarget(cloudFrontDistribution)
      ),
    });
    // S3バケットにデプロイ
    new s3deploy.BucketDeployment(this, 'S3BucketDeploy', {
      // 対象ディレクトリ指定
      sources: [s3deploy.Source.asset('./dist')],
      // S3バケット指定
      destinationBucket: s3Bucket,
      // CloudFront指定
      distribution: cloudFrontDistribution,
      distributionPaths: ['/*'],
    });
    // デプロイ先URL表示
    new CfnOutput(this, 'DeployURL', {
      value: `https://${domainName}`,
    })
  }
}

/bin/unique-domain-hosting.ts

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { UniqueDomainHostingStack } from '../lib/unique-domain-hosting-stack';

const app = new cdk.App();
new UniqueDomainHostingStack(app, 'UniqueDomainHostingStack', {
  // アカウント情報設定
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION
  },
});

cdk.json

{
  "app": "npx ts-node --prefer-ts-exts bin/unique-domain-hosting.ts",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ],
    "domainName": "ドメイン名設定"
  }
}

package.json

{
  "name": "unique-domain-hosting",
  "version": "0.1.0",
  "bin": {
    "unique-domain-hosting": "bin/unique-domain-hosting.js"
  },
 "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "keywords": [],
  "author": "Yasunori Kirimoto",
  "license": "ISC",
  "devDependencies": {
    "@types/jest": "^26.0.10",
    "@types/node": "10.17.27",
    "jest": "^26.4.2",
    "ts-jest": "^26.2.0",
    "aws-cdk": "2.15.0",
    "ts-node": "^9.0.0",
    "typescript": "~3.9.7"
  },
  "dependencies": {
    "aws-cdk-lib": "2.15.0",
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.16"
  }
}

事前準備

img


実行環境

  • node v16.10.0
  • npm v7.24.0

構築の流れ

  1. 各ファイル配置と設定ファイル更新
  2. 独自ドメインホスティング環境を自動デプロイ

各ファイル配置と設定ファイル更新

はじめに、各ファイル配置と設定ファイルを更新します。

aws-cdk-templates-showcase」リポジトリ内の「unique-domain-hosting」ディレクトリをそのまま利用するか任意の場所にコピーします。
img

「cdk.json」にAmazon Route 53で取得した独自ドメイン名を設定します。

"domainName": "ドメイン名設定"

「dist」ディレクトリにデプロイしたいアプリケーションファイル一式をコピーします。
img


独自ドメインホスティング環境を自動デプロイ

最後に、独自ドメインホスティング環境を自動デプロイします。

パッケージをインストールします。

npm install

デプロイ前に初回のみ下記コマンドを実行します。リージョンを変更した時にも実行します。

cdk bootstrap

img

プロジェクトをデプロイします。

cdk deploy

img

スタックが作成されたのを確認。各サービスも自動作成されているのを確認できます。
img

独自ドメインにアクセスするとデプロイしたWebSiteが表示されます。
img


AWS CDKを利用することで、独自ドメインホスティング等のさまざまなリソース構築を自動化することが可能です。今回は、ACMを固定リージョンで作成やCloudFront用のS3バケットポリシー自動生成やデプロイしたいアプリケーションをコード内で定義する等がコード量も少なく実装可能でした。各機能定義は、AWS CloudFormationと同様にドキュメントで学習する必要はありますが、すごく将来性を感じるツールで構築するのが楽しいです :bulb:

今後も色々と自動化していければと思います!


AWS CDKについて、他にも記事を書いています。よろしければぜひ :bow:
tags - AWS CDK

やってみたシリーズ :grinning:
tags - Try



book

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4