🔖

AWS CDKを使ってLightsail Containerにカスタムドメインを設定する方法

2023/02/04に公開

はじめに

プロジェクトのセットアップについては別記事で書いているので本記事では割愛。

証明書の発行

Stackの定義

最低限必要な情報としては以下の通り。

import * as cdk from "aws-cdk-lib";

export class CdkExampleStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new cdk.aws_lightsail.CfnCertificate(this, "cdk-example-certificate", {
      certificateName: "cdk-example-certificate",
      domainName: "cdk-example.com",
    });
  }
}

cdk-example-certificateは一意なIDとしての指定になるため正直なんでもいい。
第3引数のプロパティにsubjectAlternativeNamesを指定することで他のサブドメインを含めることも可能。
指定できる各プロパティの詳細は公式のCloudFormationのドキュメントを見た方が早い。

Stackのデプロイ

次は定義したStackをcliでdeployをする。 コマンドは以下の通り。

cdk deploy --profile ${用意したprofile名}

実行後に特にエラーらしき出力が無ければ正常に終わっている。
これでlightsail上に証明書の用意ができたが、コンソール上からは証明書を確認することができない。 ただし、AWS CLIでは確認ができるので以下コマンドで証明書の情報を確認する。

aws lightsail get-certificates --certificate-name cdk-example-certificate --profile ${用意したprofile名} \
| jq '.certificates[].certificateDetail.domainValidationRecords'

正常に終了すればACMで証明書を発行した時と同様にDNSに登録するためのレコードが取得できる。
取得したレコードをDNSに登録して認証が通れば証明書の作業は完了になる。

証明書とコンテナサービスの繋ぎ込み

コンテナサービスの作成

証明書の使用するためのコンテナサービスを作成する。
証明書の定義をしているCdkExampleStackクラス内に以下のようにコンテナサービスの定義を追加する。

    new cdk.aws_lightsail.CfnContainer(this, 'cdk-example-container', {
      power: 'nano',
      scale: 1,
      serviceName: 'cdk-example-container',
      containerServiceDeployment: {
        containers: [{
          containerName: 'cdk-example-container',
          image: 'public.ecr.aws/nginx/nginx:stable',
          ports: [
            {
              port: '80',
              protocol: 'HTTP'
            }
          ],
        }],
        publicEndpoint: {
          containerName: 'cdk-example-container',
          containerPort: 80,
          healthCheckConfig: {
            healthyThreshold: 2,
            unhealthyThreshold: 2,
            timeoutSeconds: 2,
            intervalSeconds: 5,
            path: '/',
            successCodes: "200-499"
          }
        }
      }
    });

CfnContainerクラスの第2引数はIDになるので任意の値を設定すれば良い。
第3引数で設定しているserviceNameプロパティはサービスの名前になる。
コンテナ自体の名前はcontainerServiceDeploymentプロパティ内で定義しているcontainerscontainerNameが該当する。
この名前は外部へ公開するためにロードバランサーから疎通するコンテナを指定するために利用する。

ここでdiffを取ると以下のように作成対象として出てくる。

Resources
[+] AWS::Lightsail::Container cdk-example-container cdkexamplecontainer 

きちんとdiffの対象として出てきたら証明書の作成時同様にStackのデプロイを行う。

デプロイが完了するとLightsailダッシュボードのコンテナタブでサービスの存在が確認できる。
このデプロイがLBからのヘルスチェックが通らないと完了しないため時間がかかるが、存在が確認できた段階で一応サービスの詳細ページには移動ができる。
詳細ページにアクセスするとデプロイといったタブが並んでいる中にカスタムドメインというタブがあるのが確認できる。
このタブに移動すると証明書をアタッチというテキストがあり、サービスのデプロイが終わっていればそれをクリックすると先ほど作成した証明書があるのが確認できる。
もしも無い場合は証明書をアタッチの下にある保留中の証明書で確認ができる。

サービスへの証明書の設定

サービスに証明書を設定する場合はpublicDomainNamesプロパティを設定する。
設定内容例は以下の内容を参照。

      publicDomainNames: [{
        certificateName: 'cdk-example-certificate',
        domainNames: ['cdk-example.com']
      }]

certificateNameに利用する先ほど作成した証明書のcertificateNamedomainNamesには証明書で利用できるドメインを設定する。

設定内容の共通化などをすると最終的なスタック定義は以下のようになる。

export class CdkExampleStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const certificate = new cdk.aws_lightsail.CfnCertificate(this, "cdk-example-certificate", {
      certificateName: "cdk-example-certificate",
      domainName: "cdk-example.com",
    });

    new cdk.aws_lightsail.CfnContainer(this, 'cdk-example-container', {
      power: 'nano',
      scale: 1,
      serviceName: 'cdk-example-container',
      publicDomainNames: [{
        certificateName: certificate.certificateName,
        domainNames: [certificate.domainName]
      }],
      containerServiceDeployment: {
        containers: [{
          containerName: 'cdk-example-container',
          image: 'public.ecr.aws/nginx/nginx:stable',
          ports: [
            {
              port: '80',
              protocol: 'HTTP'
            }
          ],
        }],
        publicEndpoint: {
          containerName: 'cdk-example-container',
          containerPort: 80,
          healthCheckConfig: {
            healthyThreshold: 2,
            unhealthyThreshold: 2,
            timeoutSeconds: 2,
            intervalSeconds: 5,
            path: '/',
            successCodes: "200-499"
          }
        }
      }
    });
  }
}

このスタックでdiffを作成すると以下のような結果が取得できる。

Resources
[~] AWS::Lightsail::Container cdk-example-container cdkexamplecontainer 
 └─ [+] PublicDomainNames
     └─ [{"CertificateName":"cdk-example-certificate","DomainNames":["cdk-example.com"]}]

diffの結果も特に問題が無ければStackのデプロイを行う。
デプロイが正常に完了したら以下のコマンドで取得したパブリックエンドポイントのドメインをDNSに設定を行い、アクセスができれば完了になる。

aws lightsail get-container-services --profile ${用意したprofile名} \
--service-name cdk-example-container \
--query 'containerServices[0].url'

さいごに

DNSの繋ぎ込みについてはRoute53を使ってる場合にはCDKで定義してレコード作成されるようにしたい。

GitHubで編集を提案
株式会社D2C ID

Discussion