🐟

[AWS Copilot] Backend Service with VPCEndpoint: 手順書

2022/02/13に公開

これは何

  • [AWS Copilot] Backend Service with VPCEndpoint の構築・削除手順書です。

AWS構成図

Figure1
Figure1:AWS構成図

リポジトリ

https://github.com/g-grass/aws-copilot-backend-without-natgateway

環境情報

OS
Mac (Mojave 10.14.6)
VSCode
バージョン: 1.64.0 (Universal)
コミット: 5554b12acf27056905806867f251c859323ff7e9
 日付: 2022-02-03T04:20:17.224Z (2 日前)
Electron: 13.5.2
Chromium: 91.0.4472.164
Node.js: 14.16.0
V8: 9.1.269.39-electron.0
OS: Darwin x64 18.7.0
aws-valut
$aws-vault --version
v6.4.0
aws-cli
$aws --version
aws-cli/2.1.21 Python/3.7.4 Darwin/18.7.0 exe/x86_64 prompt/off
aws-cdk
$node -v
v14.17.3
$npm --version
6.14.13
$cdk --version
2.8.0 (build 8a5eb49)
aws copilot
$docker --version
docker version 20.10.12, build e91ed57
$copilot -v
copilot version: v1.14.0

構築手順

1. VPCの構築

  • CDKを用いてCopilotにインポートするVPCを構築します。
command
cd aws-copilot-backend-without-natgateway/resources/cdk
cdk deploy VPCStack --profile sample_profile
result
 ✅  VPCStack

✨  Deployment time: 235.87s

Stackファイル詳細

  • VPC本体の他、各種VPCエンドポイントを定義します。 [1]
  • 今回の検証ではパブリックサブネットは不要のため、プライベートサブネットのみ構築するようにしています。
vpc-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { GatewayVpcEndpointAwsService, InterfaceVpcEndpointAwsService, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';

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

    const vpc = new Vpc(this, 'sample-vpc', {
      cidr: '10.0.0.0/16',
      subnetConfiguration: [
        {
          cidrMask: 24,
          // NATGateway無しでプライベートサブネットを構築するタイプ
          subnetType: SubnetType.PRIVATE_ISOLATED,
          name: 'private-1',
        }
      ]
    })

    vpc.addInterfaceEndpoint('cloud-watch-logs', {
      service:InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS
    })

    vpc.addInterfaceEndpoint('ecr-dkr', {
      service:InterfaceVpcEndpointAwsService.ECR_DOCKER
    })

    vpc.addInterfaceEndpoint('ecr-api', {
      service: InterfaceVpcEndpointAwsService.ECR
    })

    vpc.addGatewayEndpoint('s3', {
      service: GatewayVpcEndpointAwsService.S3
    })

    vpc.addGatewayEndpoint('dynamodb', {
      service: GatewayVpcEndpointAwsService.DYNAMODB
    })

  }
}

2. Applicationの構築 (copilot app init)

  • copilot app init を実行し、初期設定を行います。
command
cd aws-copilot-backend-without-natgateway/resources
export AWS_PROFILE=sample_profile
copilot app init
[result] app init
Application name: my-app
✔ Created the infrastructure to manage services and jobs under application my-app.

✔ The directory copilot will hold service manifests for application my-app.

Recommended follow-up action:
  - Run `copilot init` to add a new service or job to your application.

3. Environmentの構築 (copilot env init)

  • vpcIdsubnetId をAWS CLIを使って取得します。
command
cd aws-copilot-backend-without-natgateway/scripts
bash get-network-config.sh sample_profile
[result] get-network-config.sh
vpc-xxx
subnet-yyy,subnet-zzz
  • copilot env init を実行します。
  • import-vpc-idimport-private-subnets オプションを用いて先ほど作ったネットワーク環境をベースにリソースを構築するようにします。
command
copilot env init --import-vpc-id vpc-xxx --import-private-subnets subnet-yyy,subnet-zzz
[result] copilot env init
Environment name: dev
Credential source: [profile sample_profile]
Note: No existing subnets were found in VPC vpc-xxx.
If you proceed without at least two public subnets, you will not be able to deploy Load Balanced Web Services in this environment.
✔ Linked account 012345678910 and region us-east-1 to application my-app.

✔ Proposing infrastructure changes for the my-app-dev environment.
- Creating the infrastructure for the my-app-dev environment.        [create complete]  [58.0s]
  - An IAM Role for AWS CloudFormation to manage resources           [create complete]  [14.3s]
  - An ECS cluster to group your services                            [create complete]  [11.3s]
  - An IAM Role to describe resources in your environment            [create complete]  [11.9s]
  - A security group to allow your containers to talk to each other  [create complete]  [6.7s]
✔ Created environment dev in region us-east-1 under application my-app.

3. Service定義の作成 (copilot svc init)

  • copilot svc init を実行し、Service 定義を作成します。
command
cd aws-copilot-backend-without-natgateway/resources
copilot svc init
[result] copilot svc init
$copilot svc init
Note: It's best to run this command in the root of your workspace.
Service name: backend-api
Service type: Backend Service
Dockerfile: Enter custom path for your Dockerfile
Dockerfile: ../backend/api/Dockerfile
✔ Wrote the manifest for service backend-api at backend-api/manifest.yml
Your manifest contains configurations like your container size and port (:3000).

✔ Created ECR repositories for service backend-api.

Recommended follow-up actions:
  - Update your manifest backend-api/manifest.yml to change the defaults.
  - Run `copilot svc deploy --name backend-api --env test` to deploy your service to a test environment.
  • プライベートサブネットに Fargate を構築するため manifast.yml を書き換えます。
manifast.yml
# You can override any of the values defined above by environment.
#environments:
#  test:
#    count: 2               # Number of tasks to run for the "test" environment.
network:
  vpc:
    placement: 'private'
[result] tree
|--.workspace
|--backend-api
|  |--manifest.yml

4. ストレージ アドオンの追加 (copilot storage init)

  • copilot storage init を実行します。
  • 実行に成功すると DynamoDBCloudFormation テンプレートが生成されます。
command
cd aws-copilot-backend-without-natgateway/resources
copilot storage init
[result]copilot storage init
Only found one workload, defaulting to: backend-api
Storage type: DynamoDB
Storage resource name: creatures
Partition key: name
Partition key datatype: String
Sort key? No
✔ Wrote CloudFormation template at backend-api/addons/creatures.yml

Recommended follow-up actions:
  - Update backend-api's code to leverage the injected environment variable CREATURES_NAME.
    For example, in JavaScript you can write:
    ```
    const storageName = process.env.CREATURES_NAME
    ```
  - Run `copilot deploy --name backend-api` to deploy your storage resources.
  • 作成したテーブルをアプリケーションで利用したい場合は、払い出された環境変数を組み込むことで利用できます。
process.env.CREATURES_NAME
[result] tree
|--.workspace
|--backend-api
|  |--addons
|  |  |--creatures.yml #add
|  |--manifest.yml

5. カスタムリソース アドオンの追加

カスタムリソースの追加

  • CloudFormation のテンプレートを addons ディレクトリ配下に追加すると copilot のデプロイ対象として自動的に検出されます。
  • この仕組みを使って APIGateway(HTTP)を構築します。
command
cd aws-copilot-backend-without-natgateway/resources/copilot/backend-api/addons
touch apigateway.yml

カスタムパラメータの追加

  • 今回は APIGateway の統合先として copilot側で自動構築される CloudMap を使います。
  • そのため、copilot svc deploy にて生成される親Stackからパラメータ経由でARNを受け取れるようにします。
command
cd aws-copilot-backend-without-natgateway/resources/copilot/backend-api/addons
touch addons.parameters.yml
addons.parameters.yml
Parameters:
  DiscoveryServiceArn: !GetAtt DiscoveryService.Arn
apigateway.yml
Parameters:
  App:
    Type: String
    Description: Your application's name.
  Env:
    Type: String
    Description: The environment name your service, job, or workflow is being deployed to.
  Name:
    Type: String
    Description: The name of the service, job, or workflow being deployed.
  DiscoveryServiceArn: # add
    Type: String
    Description: The arn of aws cloudmap.
  • 最終的なディレクトリ構成は以下のようになります。
[result] tree
|--.workspace
|--backend-api
|  |--addons
|  |  |--addons.parameters.yml # add
|  |  |--apigateway.yml # add
|  |  |--creatures.yml
|  |--manifest.yml

6. Serviceのデプロイ (copilot svc deploy)

  • copilot svc deploy で定義したリソースをAWS環境にデプロイします。
command
cd aws-copilot-backend-without-natgateway/resources
copilot svc deploy
[result] copilot svc deploy
✔ Proposing infrastructure changes for stack my-app-dev-backend-api
- Creating the infrastructure for stack my-app-dev-backend-api                [create complete]  [388.1s]
  - An Addons CloudFormation Stack for your additional AWS resources          [create complete]  [257.5s]
    - An IAM ManagedPolicy for your service to access the creatures db        [create complete]  [14.5s]
    - An Amazon DynamoDB table for creatures                                  [create complete]  [34.2s]
  - Service discovery for your services to communicate within the VPC         [create complete]  [3.8s]
  - Update your environment's shared resources                                [create complete]  [35.8s]
  - An IAM Role for the Fargate agent to make AWS API calls on your behalf    [create complete]  [13.9s]
  - A CloudWatch log group to hold your service logs                          [create complete]  [3.8s]
  - An ECS service to run and maintain your tasks in the environment cluster  [create complete]  [89.5s]
    Deployments                                                                                   
               Revision  Rollout      Desired  Running  Failed  Pending                                   
      PRIMARY  3         [completed]  1        1        0       0                                         
  - An ECS task definition to group your containers and run them on ECS       [create complete]  [4.4s]
  - An IAM role to control permissions for the containers in your tasks       [create complete]  [15.3s]
✔ Deployed service backend-api.
Recommended follow-up action:
  - You can access your service at backend-api.dev.my-app.local:3000 with service discovery.

7. Cognitoの構築

  • CDKにて構築します。
command
cd aws-copilot-backend-without-natgateway/resources/cdk
cdk deploy CognitoStack --profile sample_profile
[result] cdk deploy CognitoStack
CognitoStack: creating CloudFormation changeset...






 ✅  CognitoStack

✨  Deployment time: 61.12s

Stack ARN:
arn:aws:cloudformation:us-east-1:012345678910:stack/CognitoStack/0ccb4520-8c16-11ec-adce-0aede6841373

✨  Total time: 70.16s

8. API実行

設定ファイルの更新

env.sh
# CognitoUser Data
readonly EMAIL=test@example.com
readonly USER_NAME=TBD

# AWS Environment
readonly REGION= #here
readonly CLIENT_ID= #here
readonly USER_POOL_ID= #here
readonly IDENTITY_POOL_ID= #here
readonly COGNITO_USER_POOL=cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}

認証ユーザの作成

command
cd aws-copilot-backend-without-natgateway/scripts
bash create-user.sh sample_profile
EMAIL:test@example.com
PASSWORD:password
USER_NAME:sample-sub

クレデンシャルの生成

command
cd aws-copilot-backend-without-natgateway/scripts
bash get-credential.sh sample_profile password
{
    "IdentityId": “xxx”,
    "Credentials": {
        "AccessKeyId": “***”,
        "SecretKey": “***”,
        "SessionToken": “***”,
        "Expiration": "2022-02-13T01:32:10+09:00"
    }
}

POST MAN経由でAPIを実行

  • APIGatewayコンソールからエンドポイントを確認します。
    API1
  • 認証モードを AWS Signature にして先ほど払い出した一時クレデンシャル情報を入力します。
    API2
  • APIを実行します。
    API3

Verification

  • データがDynamoDBに追加できていることを確認します。
    Verification

削除手順

1. Cognitoの削除

設定ファイルの更新

env.sh
# CognitoUser Data
readonly EMAIL=test@example.com
readonly USER_NAME=sample-sub # here

# AWS Environment
readonly REGION=xxx
readonly CLIENT_ID=xxx
readonly USER_POOL_ID=xxx
readonly IDENTITY_POOL_ID=${REGION}:xxx
readonly COGNITO_USER_POOL=cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}

認証ユーザの削除

command
cd aws-copilot-backend-without-natgateway/scripts
bash delete-user.sh sample_profile
[result] bash delete-user.sh
echo "USER:sample-sub is deleted."

CognitoStackの削除

command
cd aws-copilot-backend-without-natgateway/resources/cdk
cdk destroy CognitoStack --profile sample_profile
[result] cdk destory CognitoStack
Are you sure you want to delete: CognitoStack (y/n)? y
CognitoStack: destroying...



 ✅  CognitoStack: destroyed

2. Serviceの削除

command
cd aws-copilot-backend-without-natgateway/resources
copilot svc delete
[result] copilot svc delete
Only found one service, defaulting to: backend-api
Sure? Yes
✔ Deleted service backend-api from environment dev.
✔ Deleted resources of service backend-api from application my-app.

✔ Deleted service backend-api from application my-app.
Recommended follow-up action:
  - Run `copilot pipeline update` to update the corresponding pipeline if it exists.

3. Environmentの削除

command
cd aws-copilot-backend-without-natgateway/resources
copilot env delete
[result] copilot env delete
Only found one environment, defaulting to: dev
Sure? Yes
✔ Deleted environment dev from application my-app.

4. Applicationの削除

command
cd aws-copilot-backend-without-natgateway/resources
copilot app delete

5. VPCの削除

command
cd aws-copilot-backend-without-natgateway/resources/cdk
cdk destroy VPCStack --profile sample_profile
[result] cdk destroy VPCStack
Are you sure you want to delete: VPCStack (y/n)? y
VPCStack: destroying...








 ✅  VPCStack: destroyed
脚注
  1. ECRの内部処理にてS3が使われているためS3用のエンドポイントも必要です。参考記事 ↩︎

Discussion

ログインするとコメントできます