🤖

AWS CDK + AWS Lightsail Container + Wordpressの環境を作る

2022/09/23に公開

はじめに

AWS CDKとは

正式名称はAWS Cloud Development Kitでライブラリを通してCloudFormationを利用するためのツールだ。
terraformはproviderを通してリソースを直接管理しますが、こちらはCloudFormationを通してリソースを管理ができる。
terraformでやるか、CDKを使って使い慣れた言語でリソースを管理するかは個人の嗜好の範疇だと思いますが、AWS ChatBotなどterraformのAWS providerでサポートがまだのリソースについてはCDKで管理をした方が良いと考える。

AWS Lightsailとは

決まったマシンパワーのリソースを決まった月額料金で利用するためのバンドルサービスだ。
データ転送量など一部の料金については超過してしまった場合にはその分が課金対象となる。
また、lightsailの料金ページを見るとわかりますが、コンテナサービスを利用した料金は仮想サーバを利用するよりも割高になっている。

Lightsailのコンテナサービスを採用した理由

まずLightsailを使おうの前にOSのサポート期限の問題があった。
Amazon Linuxを使っていたのでセキュリティサポート自体は2023年6月30日までと告知されてはいたものの、OSのサポート期限を気にするのは嫌だよねということでコンテナサービスを採用するに至った。
その上でECSでやるのか、Lightsailでやるのかの話があり、実施予定のスケジュールを考えるとECSを一からキャッチアップするよりは裏でECSが動いてそうなLightsailの方が早いよねということでLightsailに決まった。

terraformではなくCDKの理由

個人的にはterraformの方が好きなのだが、実施時期(この時は4月〜5月で対応するスケジュールだった)ではterraformの方ではコンテナサービスの管理ができなかった。
なので、単純にlightsailサービス全体をterraform以外で管理ができるCDKを使うことになった。
これを書いている2022年9月20日時点はterraformでも作成ができるようになったらしい。

今回の記事で作成する構成

この記事で作成する環境は以下の通り。

環境周りの情報

  • node.js
    • バージョン: 16.17.0
  • AWS CDK
    • バージョン: 2.42.1
  • AWS Profile
    • (あまりよくないけど)AdministratorAccess権限があるもの

実際に作成

CDKプロジェクトの作成

CDKのインストール

まずは公式のドキュメントに沿ってCDKをインストールをする。

npm install -g aws-cdk

これでcdkコマンドが実行できるようになったはず。

CDKプロジェクトの初期化

これも公式のドキュメントに沿って行う。
ただし、プロジェクト名はcdk-example、使う言語はTypeScriptにする。

mkdir cdk-example
cd cdk-example
cdk init app --language typescript

作成が終わると以下のような構造のプロジェクトになっているはず。
node_modulesや.gitなどのプロジェクトに依存しないものは構造から省いている。

.
├── .gitignore
├── .npmignore
├── README.md
├── bin
│   └── cdk-example.ts
├── cdk.json
├── jest.config.js
├── lib
│   └── cdk-example-stack.ts
├── package-lock.json
├── package.json
├── test
│   └── cdk-example.test.ts
└── tsconfig.json

続いてCloudFormationのStackが作成できるように以下を実施。

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

無事に終わると以下のような出力結果になる。

CDKToolkit: creating CloudFormation changeset...
 ✅  Environment aws://${アカウントID}/us-east-1 bootstrapped.

これでリソースが作成できるようになる。

データベースの作成

Stackの定義

まずはlib/cdk-example-stack.tsの中身を以下のように書き換えをする。

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.CfnDatabase(this, 'cdk-example-database', {
      masterDatabaseName: 'cdk_example_database',
      masterUsername: 'user',
      relationalDatabaseBlueprintId: 'mysql_5_7',
      relationalDatabaseBundleId: 'micro_2_0',
      relationalDatabaseName: 'cdk-example-database',
    });
  }
}

プロパティの細かい説明は公式のドキュメントを参照してもらうことにして、補足した方がいいものについてはここで補足する。
データベースのパスワードもプロパティとして設定できるが今回は対応しない。

プロパティの補足説明
relationalDatabaseBlueprintId

作成するデータベースに使うシステムの種類とバージョン。
設定する値は以下のコマンドで取得できたblueprintIdを使用する。

aws lightsail get-relational-database-blueprints --profile ${用意したprofile名}
relationalDatabaseBundleId

利用するプラン。
設定する値は以下のコマンドで取得できたbundleIdを使用する。

aws lightsail get-relational-database-bundles --profile ${用意したprofile名}

注意点としてだが、高可用性(Multi-AZ)のデータベースを作成するにはmicro_ha_2_0のようにhaがついたものを利用するが、CloudFormation経由では作成ができない。
ドキュメントにもなく、AWSに問い合わせたが再現性のある問題で調査するとなり以降は音沙汰無し。
記事執筆時点で3ヶ月は経っているけども対応される日は来るのか。

relationalDatabaseName

masterDatabaseNameと混同しやすいがrelationalDatabaseNameはリソースの名前であり、データベースの名前では無いので注意。

Stackのデプロイ

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

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

実行が完了するまでに少し時間がかかるが、コンソール上でも進捗が見れる。
完了すればコンソールから作成したリソースにアクセスしてデータベースに接続するためのパスワードを確認できるようになる。

コンテナサービスの作成とデプロイ

まずはlib/cdk-example-stack.tsをコピーしてlib/cdk-example-container-stack.tsを作成する。
内容は以下の通り。

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

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

    new cdk.aws_lightsail.CfnContainer(this, 'cdk-example-container', {
      power: 'nano',
      scale: 1,
      serviceName: 'cdk-example-container',
      containerServiceDeployment: {
        containers: [{
          containerName: 'cdk-example-container',
          image: 'wordpress:6',
          ports: [
            {
              port: '80',
              protocol: 'HTTP'
            }
          ],
          environment: [
            {
              variable: 'WORDPRESS_DB_HOST',
              value: '' // 自分で作成したDBのホスト
            },
            {
              variable: 'WORDPRESS_DB_USER',
              value: 'user'
            },
            {
              variable: 'WORDPRESS_DB_PASSWORD',
              value: '' // 自分で作成したDBのパスワード
            },
            {
              variable: 'WORDPRESS_DB_NAME',
              value: 'cdk_example_database'
            },
          ]
        }],
        publicEndpoint: {
          containerName: 'cdk-example-container',
          containerPort: 80,
          healthCheckConfig: {
            healthyThreshold: 2,
            unhealthyThreshold: 2,
            timeoutSeconds: 2,
            intervalSeconds: 5,
            path: '/',
            successCodes: "200-499"
          }
        }
      }
    });
  }
}

今回使用するイメージはDockerHubにある公式のイメージを使用する。
プロパティの細かい説明は公式のドキュメントを参照してもらうことにして、補足した方がいいものについてはここで補足する。

プロパティの補足説明
power

利用するプラン。
設定する値は以下のコマンドで取得できたnameを使用する。

aws lightsail get-container-service-powers --profile ${用意したprofile名}

定義したStackをデプロイ対象に登録

前段のStackの定義をするだけではCDKでのデプロイには含まれない。
含めるにはbin/cdk-example.tsを修正する必要がある。
ファイルを開くと以下のようになっているはず。

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

const app = new cdk.App();
new CdkExampleStack(app, 'CdkExampleStack', {
    // コメント省略
});

これを

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkExampleStack } from '../lib/cdk-example-stack';
import {CdkExampleContainerStack} from "../lib/cdk-example-container-stack";

const app = new cdk.App();
new CdkExampleStack(app, 'CdkExampleStack', {
  // コメント省略
});
new CdkExampleContainerStack(app, 'CdkExampleContainerStack', {});

こうする。

やったこととしては、
先ほど作成したStackをインポートしてCDKでデプロイできるように登録をしている。
Stackで渡している第二引数はCloudFormation上で確認できるStack名になる。

Stackのデプロイ

複数のStackのデプロイになるので、証明書の時とは少しコマンドが変わる。
具体的には--allオプションを追加することになり、以下のようになる。

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

デプロイ後の確認

無事データベースとの接続もできて正常にデプロイできると以下のようにコンソールで確認ができる。

今サービスで稼働中のバージョンについてはステータスが有効になっていて、使われなくなったものについては無効になっている。
失敗と表示されているものは、コンテナがうまく起動しなかったり、ヘルスチェックに失敗したもの。

この状態でコンテナサービスに割り当てられたFQDNにアクセスをしてWordPressのセットアップ画面(サイト名や管理者アカウントの作成をする画面)が表示されれば完了になる。

まとめ

IaCで管理できるようにしたことで複数の環境が同じ設定で作りやすくなった。
同じコードで開発用、本番用のStackを作るにはcontextオプションで情報を渡したりで分けることができる。これについては別記事にしたい。
また、データベースについては本番環境で利用することを考えると高可用性での設定で使いたいので、もしそうする場合はCDK管理外のリソースができてしまうことは注意が必要になる。

今回はCDKのみで作成をしたが、CDK for TerraformがGAになったようなので、そっちも使ってみたい。

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

Discussion