LoginSignup
4
2

AWS CDK で Infrastructure as Code する: SpringBoot編2

Last updated at Posted at 2023-10-11

こんにちは。ただいまAWS CDK絶賛勉強中です。

のつづきです。前回まででDockerイメージが作成できたので、そのイメージを使ってECSを起動していきます。

ちなみに、前回作ったDockerイメージはこれでした。

$ docker images
REPOSITORY                        TAG              IMAGE ID       CREATED      SIZE
myorg/spring-boot-sample-tomcat   0.1.1-SNAPSHOT   cdcd3af69190   3 days ago   363MB
$

前提条件

などを終えておくこと。

作る環境

こんなかんじになります。

env

やってみる

Dockerイメージを格納する、ECRの作成

まずは自前のDockerイメージを格納するリポジトリAmazon ECR( Amazon Elastic Container Registry ) を作成します。ECRはAWS CDKでも作れますが、今回はさくっとコマンドラインから。リポジトリ名はspring-boot-sample-tomcatとします。

$ aws ecr create-repository \
    --repository-name spring-boot-sample-tomcat \
    --image-scanning-configuration scanOnPush=true \
    --region ap-northeast-1
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:xxxxx:repository/spring-boot-sample-tomcat",
        "registryId": "xxxxx",
        "repositoryName": "spring-boot-sample-tomcat",
        "repositoryUri": "xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/spring-boot-sample-tomcat",
        "createdAt": "2023-10-09T11:32:52+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

できたようです。AWSのコンソール画面でみても

VYsRsNs

うん、できていそうです。

参考 AWS CLI での Amazon ECR の使用

ECRへアップロード

つづいて作成したECRへ、先のDockerイメージをアップロードします。アップロードにはECRへのログインなど多少の前準備が必要ですので、順番にやっていきます。

あらためてイメージの確認。

$ docker images
REPOSITORY                        TAG              IMAGE ID       CREATED      SIZE
myorg/spring-boot-sample-tomcat   0.1.1-SNAPSHOT   cdcd3af69190   4 days ago   363MB

アップロードしたいのはこのイメージ(IMAGE ID: cdcd3af69190)でした。

まずはAWSのECRにログインしておきます。

$ ECR_REPOSITORY_NAME=spring-boot-sample-tomcat ← 先ほど作成したECRのリポジトリ名
$ version=0.1.1-SNAPSHOT ← バージョンはTAG名

$ AWS_REGION_NAME=ap-northeast-1
$ AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
↑ 使用しているプロファイルのアカウントIDを取得している

$ aws ecr --region ${AWS_REGION_NAME} get-login-password | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/xxx/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
$

つづいて、先のイメージにタグをつけます。

$ REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME}
$ docker image tag cdcd3af69190 ${REPOSITORY_URI}:${version}
↑ cdcd3af69190 というのは先ほど確認した IMAGE IDです

$ docker images
REPOSITORY                                                                    TAG              IMAGE ID       CREATED      SIZE
xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/spring-boot-sample-tomcat   0.1.1-SNAPSHOT   cdcd3af69190   4 days ago   363MB
myorg/spring-boot-sample-tomcat                                               0.1.1-SNAPSHOT   cdcd3af69190   4 days ago   363MB

おなじIMAGE IDのイメージに、タグ(ようするに別名)をつけることができました。

最後にイメージをアップロード( docker image push )します。

$ docker image push ${REPOSITORY_URI}:${version}
The push refers to repository [xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/spring-boot-sample-tomcat]
7e1014d42cd2: Pushed
34f7184834b2: Pushed
5836ece05bfd: Pushed
72e830a4dff5: Pushed
0.1.1-SNAPSHOT: digest: sha256:37e2111ef45a00373393b766bd920d1648d5900448738b2434387566c4e3aef7 size: 1163
$

できたようです。画面でも見てみましょう。

yNgUftj

よさそうですね。
以上でECR関連の作業は完了です。

CDKのソースコード を取得

さてSpringBootのDockerイメージをECRにアップロードできたので、次はECSサービスがそれを使用する設定をしていきます。

いままで通り CDK を用いるので、前回(nginxをECSサービス化したとき) のCDKのソースコードを取得しておきます。

$ git clone -b ecs_first_nginx https://github.com/masatomix/cdk-samples.git
$ 

前回のECSサービスを削除

さてコードを修正する前に、前回作成したnginxのECSサービスが別のタスク定義を参照していて競合するため、まずはECSサービス関連を削除します。CDKで

$ cd cdk-samples
cdk-samples$ yarn cdk destroy ECSServiceStack ECSServiceELBStack
....
cdk-samples$ 

って削除すればOK。

タスク定義等の書き換え

さてECSが使用するDockerイメージを差し替えるためのソースコードの変更箇所ですが、

  • image名としてnginxのイメージを指定していた箇所を、ECRのURLに変更
  • コンテナのポート番号を80 → 8080へ変更(nginxとSpringBootはデフォで使用するポートがちがう)
  • ヘルスチェックのURLを変更

などがあります。具体的には以下の通り。

lib/AppTaskdefinitionStack.ts
import { App, ScopedAws, Stack, StackProps } from 'aws-cdk-lib'
import { ContainerInfo, getProfile } from './Utils'
import { CfnTaskDefinition } from 'aws-cdk-lib/aws-ecs'
import { CfnRole } from 'aws-cdk-lib/aws-iam'

type AppTaskdefinitionStackProps = StackProps & {
  ecsTaskRole: CfnRole
  ecsTaskExecutionRole: CfnRole
  containerInfo: ContainerInfo
}

export class AppTaskdefinitionStack extends Stack {
  public readonly taskDef: CfnTaskDefinition
  constructor(scope: App, id: string, props: AppTaskdefinitionStackProps) {
    super(scope, id, props)
    const p = getProfile(this)
    const { accountId, region } = new ScopedAws(this)

    this.taskDef = new CfnTaskDefinition(this, 'ECSTaskDefinition', {
      family: `${props.containerInfo.name}-taskdefinition${p.name}`,
      containerDefinitions: [
        {
          essential: true,
          // image: 'nginx',
ココ      image: `${accountId}.dkr.ecr.${region}.amazonaws.com/spring-boot-sample-tomcat:0.1.1-SNAPSHOT`,
          name: props.containerInfo.name,
          logConfiguration: {
            logDriver: 'awslogs',
            options: {
              'awslogs-create-group': 'true',
              'awslogs-group': `/ecs/app-taskdefinition${p.name}`,
              'awslogs-region': `${region}`,
              'awslogs-stream-prefix': 'ecs',
            },
          },
          memoryReservation: 100,
          portMappings: [
            {
              containerPort: props.containerInfo.port,
              hostPort: props.containerInfo.port,
              protocol: 'tcp',
            },
          ],
        },
      ],
      taskRoleArn: props.ecsTaskRole.attrArn,
      executionRoleArn: props.ecsTaskExecutionRole.attrArn,
      networkMode: 'awsvpc',
      requiresCompatibilities: ['FARGATE'],
      cpu: '256',
      memory: '512',
    })
  }
}

bin/cdk-samples.ts
#!/usr/bin/env node
import 'source-map-support/register'
import * as cdk from 'aws-cdk-lib'
import { VPCStack } from '../lib/VPCStack'
import { ELBStack } from '../lib/ELBStack'
import { ClusterStack } from '../lib/ClusterStack'
import { ECSRoleStack } from '../lib/ECSRoleStack'
import { ECSServiceStack } from '../lib/ECSServiceStack'
import { BastionStack } from '../lib/BastionStack'
import { ECSSecurityGroupStack } from '../lib/ECSSecurityGroupStack'
import { ECSServiceELBStack } from '../lib/ECSServiceELBStack'
import { AppTaskdefinitionStack } from '../lib/AppTaskdefinitionStack'
import { ContainerInfo, ServiceInfo } from '../lib/Utils'

const main = () => {
  const app = new cdk.App()

  const vpcStack = new VPCStack(app, 'VPCStack')

  const sgStack = new ECSSecurityGroupStack(app, 'ECSSecurityGroupStack', { vpc: vpcStack.vpc })
  const clusterStack = new ClusterStack(app, 'ClusterStack')
  const ecsRoleStack = new ECSRoleStack(app, 'ECSRoleStack')

  const elbStack = new ELBStack(app, 'ELBStack', {
    subnets: vpcStack.publicSubnets,
    elbSecuriyGroup: sgStack.ELBSecurityGroup,
  })

  const serviceInfo: ServiceInfo = {
    serviceName: 'app-service',
    listenerPort: 8080,
    testListenerPort: 9080,
  }

  const containerInfo: ContainerInfo = {
    name: 'app',
    // port: 80,
    // healthCheckPath: '/',
ココ port: 8080, // コンテナが利用するポート番号 が8080
ココ healthCheckPath: '/actuator/health', // ヘルスチェックもURLが異なる
  }

  const serviceStackELB = new ECSServiceELBStack(app, 'ECSServiceELBStack', {
    loadbalancer: elbStack.loadbalancer,
    vpc: vpcStack.vpc,
    containerInfo,
    serviceInfo,
  })

  const appTaskdefinition = new AppTaskdefinitionStack(app, 'AppTaskdefinitionStack', {
    ecsTaskRole: ecsRoleStack.ecsTaskRole,
    ecsTaskExecutionRole: ecsRoleStack.ecsTaskExecutionRole,
    containerInfo,
  })

  const serviceStack = new ECSServiceStack(app, 'AppServiceStack', {
    cluster: clusterStack.cluster,
    subnets: vpcStack.privateSubnets, // ECSを配置するネットはPrivate Subnet
    taskDef: appTaskdefinition.taskDef,
    ecsSecurityGroup: sgStack.ECSSecurityGroup,
    targetGroup: serviceStackELB.targetGroup,
    containerInfo,
    serviceInfo,
  })
}

main()

CDKを実行する

ではCDKを実行します。いつもどおり

cdk-samples$ yarn cdk deploy --all

でOK。おわったらURLを確認してアクセスしてみます。

$ aws elbv2 describe-load-balancers \
--query "LoadBalancers[*].[LoadBalancerName,DNSName]" \
--output table
---------------------------------------------------------------------------------------------------------------------
|                                               DescribeLoadBalancers                                               |
+---------------------------------+---------------------------------------------------------------------------------+
|  ............                   |  xx.elb.ap-northeast-1.amazonaws.com                                            |
|  app-ELB-dev-20230827           |  app-ELB-dev-20230827-1197243654.ap-northeast-1.elb.amazonaws.com               |
+---------------------------------+---------------------------------------------------------------------------------+
$ 

URLがわかったので、さきほどのヘルスチェックのURLにアクセスしてみましょう。

$ curl http://app-ELB-dev-20230827-1197243654.ap-northeast-1.elb.amazonaws.com:8080/actuator/health -i 
HTTP/1.1 200
Date: Mon, 09 Oct 2023 16:03:32 GMT
Content-Type: application/vnd.spring-boot.actuator.v3+json
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: AWSALB=oxq+VQxZTBSHBSgxLHBN2oiz1zRR69Qc2bPpyjCEdISbun1MGNh5YeJS/PqBdUtMyJUAb9HSmwyObePK/lNgblon9o0knhmgEw/AEuNaUAV8s0d82+6aw2s0zjfd; Expires=Mon, 16 Oct 2023 16:03:32 GMT; Path=/
Set-Cookie: AWSALBCORS=oxq+VQxZTBSHBSgxLHBN2oiz1zRR69Qc2bPpyjCEdISbun1MGNh5YeJS/PqBdUtMyJUAb9HSmwyObePK/lNgblon9o0knhmgEw/AEuNaUAV8s0d82+6aw2s0zjfd; Expires=Mon, 16 Oct 2023 16:03:32 GMT; Path=/; SameSite=None

{"status":"UP"}
$

SpringBootアプリが動いていそうです!

以上で、ECRに独自にアップロードしたSpringBootのイメージを用いて、ECSサービスを動かすことができました。

おつかれさまでした。

関連リンク

4
2
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
4
2