【アップデート】AWS Copilot CLIを使ってARMベース(AWS Graviton2)のFargateを起動する

2021.11.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンサル部のとばち(@toda_kk)です。

ARMベースのアーキテクチャであるAWS Graviton2に、Fargateが対応しました!

同時に、Amazon ECSのデプロイツールであるAWS Copilot CLIでもFargateのGraviton2対応をサポートしました!

Copilot CLIについて

そもそもAWS Copilot CLIって何? という方は、過去の記事をご参考ください。

すぐに始められるようなサンプルなども用意しています。

Copilot CLIのインストールとバージョンアップグレード

新たに v1.13.0 がリリースされています。macOSの場合は、Homebrewを使ってインストールできます。

Homebrewを使ったインストール

$ brew install aws/tap/copilot-cli

LinuxやWIndowsなど、Homebrew以外の方法でインストールする場合は下記ページをご参照ください。

すでにHomebrewでインストールしている場合は、バージョンアップグレードしましょう。

Homebrewを使ったバージョンアップグレード

$ brew upgrade copilot-cli

中の人によるデモ動画

AWSの中の人(@realadamjkeller)によるデモ動画も投稿されています。5分もない動画なので、さくっと動きを確認できるかと思います。

動画の内容に従って、PythonファイルとDockerfileを用意しておきます。Flaskを利用しているため、事前にインストールしておく必要があります。

Flaskのインストール

$ pip install flask

app.py

#!/usr/bin/env python3

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def index():
    return f'{{ "OS_Architecture": "{os.uname().machine}" }}'

if __name__ == '__main__':
    app().run(host='0.0.0.0')

Dockerfile

FROM python:3.8

EXPOSE 5000

WORKDIR /

COPY ./app.py /app.py

RUN pip install flask

CMD ["flask", "run", "--host", "0.0.0.0"]

まずはIntelベースのFargateを起動してみる

では、実際にCopilot CLIを使ってECS環境を構築し、Fargateを起動してみます。

copilot initコマンドを実行し、対話プロンプトに従って必要な内容を入力していきます。

  • Application name: fargate-arm-demo
  • Workload type: Load Balanced Web Service
  • Service name: os-arch
  • Dockerfile: ./Dockerfile

Copilot CLIを使ったデプロイ(実行結果は一部抜粋)

$ copilot init
Note: It's best to run this command in the root of your Git repository.
Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with a containerized application on AWS. An application is a collection of
containerized services that operate together.

Note: Looks like you're creating an application using credentials set by environment variables.
Copilot will store your application metadata in this account.
We recommend using credentials from named profiles. To learn more:
https://aws.github.io/copilot-cli/docs/credentials/

Application name: fargate-arm-demo
Workload type: Load Balanced Web Service
Service name: os-arch
Dockerfile: ./Dockerfile
Ok great, we'll set up a Load Balanced Web Service named os-arch in application fargate-arm-demo listening on port 5000.

✔ Created the infrastructure to manage services and jobs under application fargate-arm-demo..

✔ The directory copilot will hold service manifests for application fargate-arm-demo.

✔ Wrote the manifest for service os-arch at copilot/os-arch/manifest.yml
Your manifest contains configurations like your container size and port (:5000).

✔ Created ECR repositories for service os-arch..

All right, you're all set for local development.
Deploy: Yes

✔ Linked account 123456789012 and region ap-northeast-1 to application fargate-arm-demo..

✔ Proposing infrastructure changes for the fargate-arm-demo-test environment.
- Creating the infrastructure for the fargate-arm-demo-test environment.  [create complete]  [94.2s]
  - An IAM Role for AWS CloudFormation to manage resources                [create complete]  [29.0s]
  - An ECS cluster to group your services                                 [create complete]  [9.3s]
  - An IAM Role to describe resources in your environment                 [create complete]  [27.2s]
  - A security group to allow your containers to talk to each other       [create complete]  [5.5s]
  - An Internet Gateway to connect to the public internet                 [create complete]  [18.1s]
  - Private subnet 1 for resources with no internet access                [create complete]  [15.5s]
  - Private subnet 2 for resources with no internet access                [create complete]  [15.5s]
  - Public subnet 1 for resources that can access the internet            [create complete]  [15.5s]
  - Public subnet 2 for resources that can access the internet            [create complete]  [15.5s]
  - A Virtual Private Cloud to control networking of your AWS resources   [create complete]  [18.1s]
✔ Created environment test in region ap-northeast-1 under application fargate-arm-demo.
Environment test is already on the latest version v1.7.0, skip upgrade.
[+] Building 45.5s (9/9) FINISHED
 => [1/4] FROM docker.io/library/python:3.8@sha256:68bddbf6e88c9c88d3238e13f02edf1884fc349a0964fad4b3d44f2425791ac7                   34.5s
 => [2/4] COPY ./app.py /app.py                                                                                                        0.3s
 => [3/4] RUN pip install flask                                                                                                        4.0s
 => => naming to 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch                                            0.0s
Login Succeeded
Using default tag: latest
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch]
✔ Proposing infrastructure changes for stack fargate-arm-demo-test-os-arch
- Creating the infrastructure for stack fargate-arm-demo-test-os-arch             [create complete]  [331.6s]
  - Service discovery for your services to communicate within the VPC             [create complete]  [3.8s]
  - Update your environment's shared resources                                    [update complete]  [152.6s]
    - A security group for your load balancer allowing HTTP and HTTPS traffic     [create complete]  [5.4s]
    - An Application Load Balancer to distribute public traffic to your services  [create complete]  [123.2s]
  - An IAM Role for the Fargate agent to make AWS API calls on your behalf        [create complete]  [26.4s]
  - 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]  [76.3s]
    Deployments
               Revision  Rollout      Desired  Running  Failed  Pending
      PRIMARY  1         [completed]  1        1        0       0
  - A target group to connect the load balancer to your service                   [create complete]  [3.8s]
  - An ECS task definition to group your containers and run them on ECS           [create complete]  [5.1s]
  - An IAM role to control permissions for the containers in your tasks           [create complete]  [30.0s]
✔ Deployed service os-arch.
Recommended follow-up action:
  - You can access your service at http://farga-Publi-XXXXXXXXXXX-0000000000.ap-northeast-1.elb.amazonaws.com over the internet.

実行が完了すると、ECSリソースと共に、必要なVPCやALBといったリソースがいっしょに作成されています。

末尾に表示されるALBのエンドポイントから、作成したECSサービス/タスクにアクセスできます。デフォルトの状態なので、 "OS_Architecture" はIntelベースのアーキテクチャであることを示しています。

また、copilot initの実行後はCopilot Serviceの設定ファイルとなるcopilot/os-arch/manifest.ymlが生成されています。

copilot/os-arch/manifest.yml

# The manifest for the "os-arch" service.
# Read the full specification for the "Load Balanced Web Service" type at:
#  https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/

# Your service name will be used in naming your resources like log groups, ECS services, etc.
name: os-arch
type: Load Balanced Web Service

# Distribute traffic to your service.
http:
  # Requests to this path will be forwarded to your service.
  # To match all requests you can use the "/" path.
  path: '/'
  # You can specify a custom health check path. The default is "/".
  # healthcheck: '/'

# Configuration for your containers and service.
image:
  # Docker build arguments. For additional overrides: https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/#image-build
  build: Dockerfile
  # Port exposed through your container to route traffic to it.
  port: 5000

cpu: 256       # Number of CPU units for the task.
memory: 512    # Amount of memory in MiB used by the task.
count: 1       # Number of tasks that should be running in your service.
exec: true     # Enable running commands in your container.

# Optional fields for more advanced use-cases.
#
#variables:                    # Pass environment variables as key value pairs.
#  LOG_LEVEL: info

#secrets:                      # Pass secrets from AWS Systems Manager (SSM) Parameter Store.
#  GITHUB_TOKEN: GITHUB_TOKEN  # The key is the name of the environment variable, the value is the name of the SSM parameter.

# You can override any of the values defined above by environment.
#environments:
#  test:
#    count: 2               # Number of tasks to run for the "test" environment.

この設定を反映させるような形で、AWSリソース上の実態としてECSタスク定義が作成されます。

fargate-arm-demo-test-os-arch:1

{
  "ipcMode": null,
  "executionRoleArn": "arn:aws:iam::123456789012:role/fargate-arm-demo-test-os-arch-ExecutionRole-1PLWRL6LCP2B",
  "containerDefinitions": [
    {
      "dnsSearchDomains": [],
      "environmentFiles": [],
      "logConfiguration": {
        "logDriver": "awslogs",
        "secretOptions": [],
        "options": {
          "awslogs-group": "/copilot/fargate-arm-demo-test-os-arch",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "copilot"
        }
      },
      "entryPoint": [],
      "portMappings": [
        {
          "hostPort": 5000,
          "protocol": "tcp",
          "containerPort": 5000
        }
      ],
      "command": [],
      "linuxParameters": null,
      "cpu": 0,
      "environment": [
        {
          "name": "COPILOT_APPLICATION_NAME",
          "value": "fargate-arm-demo"
        },
        {
          "name": "COPILOT_ENVIRONMENT_NAME",
          "value": "test"
        },
        {
          "name": "COPILOT_LB_DNS",
          "value": "farga-Publi-XXXXXXXXXXX-0000000000.ap-northeast-1.elb.amazonaws.com"
        },
        {
          "name": "COPILOT_SERVICE_DISCOVERY_ENDPOINT",
          "value": "test.fargate-arm-demo.local"
        },
        {
          "name": "COPILOT_SERVICE_NAME",
          "value": "os-arch"
        }
      ],
      "resourceRequirements": null,
      "ulimits": [],
      "dnsServers": [],
      "mountPoints": [],
      "workingDirectory": null,
      "secrets": [],
      "dockerSecurityOptions": [],
      "memory": null,
      "memoryReservation": null,
      "volumesFrom": [],
      "stopTimeout": null,
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch@sha256:3d5f4c94d1d5f3619e573d2550cb5afecf20741f65daf8ad7b9f55b46a755006",
      "startTimeout": null,
      "firelensConfiguration": null,
      "dependsOn": null,
      "disableNetworking": null,
      "interactive": null,
      "healthCheck": null,
      "essential": true,
      "links": [],
      "hostname": null,
      "extraHosts": [],
      "pseudoTerminal": null,
      "user": null,
      "readonlyRootFilesystem": null,
      "dockerLabels": {},
      "systemControls": [],
      "privileged": null,
      "name": "os-arch"
    }
  ],
  "placementConstraints": [],
  "memory": "512",
  "taskRoleArn": "arn:aws:iam::123456789012:role/fargate-arm-demo-test-os-arch-TaskRole-1321J1VIS5NFT",
  "compatibilities": [
    "EC2",
    "FARGATE"
  ],
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/fargate-arm-demo-test-os-arch:1",
  "family": "fargate-arm-demo-test-os-arch",
  "requiresAttributes": [...],
  "pidMode": null,
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "networkMode": "awsvpc",
  "runtimePlatform": null,
  "cpu": "256",
  "revision": 1,
  "status": "ACTIVE",
  "inferenceAccelerators": null,
  "proxyConfiguration": null,
  "volumes": []
}

Copilot CLIでARMベースのFargateを起動する

続いて、ARMベースのFargateを起動するように設定を変更してみます。

具体的には、先ほど確認したmanifest.ymlファイルを更新した上で、copilot svc deployコマンドを実行します。

copilot/os-arch/manifest.yml

# The manifest for the "os-arch" service.
# Read the full specification for the "Load Balanced Web Service" type at:
#  https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/

# Your service name will be used in naming your resources like log groups, ECS services, etc.
name: os-arch
type: Load Balanced Web Service

# Distribute traffic to your service.
http:
  # Requests to this path will be forwarded to your service.
  # To match all requests you can use the "/" path.
  path: '/'
  # You can specify a custom health check path. The default is "/".
  # healthcheck: '/'

# Configuration for your containers and service.
image:
  # Docker build arguments. For additional overrides: https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/#image-build
  build: Dockerfile
  # Port exposed through your container to route traffic to it.
  port: 5000

cpu: 256       # Number of CPU units for the task.
memory: 512    # Amount of memory in MiB used by the task.
count: 1       # Number of tasks that should be running in your service.
exec: true     # Enable running commands in your container.
platform: linux/arm64 # この行を追加する

# Optional fields for more advanced use-cases.
#
#variables:                    # Pass environment variables as key value pairs.
#  LOG_LEVEL: info

#secrets:                      # Pass secrets from AWS Systems Manager (SSM) Parameter Store.
#  GITHUB_TOKEN: GITHUB_TOKEN  # The key is the name of the environment variable, the value is the name of the SSM parameter.

# You can override any of the values defined above by environment.
#environments:
#  test:
#    count: 2               # Number of tasks to run for the "test" environment.

platform: linux/arm64の行を追加します。ちなみにこの項目は、デフォルトではlinux/x86_64となります。

Serviceの更新(実行結果は一部抜粋)

$ copilot svc deploy
Only found one service, defaulting to: os-arch
Only found one environment, defaulting to: test
Environment test is already on the latest version v1.7.0, skip upgrade.
Building your container image: docker build -t 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch --platform linux/arm64 /Users/tobachi/work/sample-arm-container -f /Users/tobachi/work/sample-arm-container/Dockerfile
[+] Building 62.4s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                                                   0.0s
 => => transferring dockerfile: 37B                                                                                                    0.0s
 => [internal] load .dockerignore                                                                                                      0.0s
 => => transferring context: 2B                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/python:3.8                                                                          3.4s
 => [internal] load build context                                                                                                      0.0s
 => => transferring context: 28B                                                                                                       0.0s
 => [1/4] FROM docker.io/library/python:3.8@sha256:68bddbf6e88c9c88d3238e13f02edf1884fc349a0964fad4b3d44f2425791ac7                   35.4s
 => [2/4] COPY ./app.py /app.py                                                                                                        0.4s
 => [3/4] RUN pip install flask                                                                                                       22.8s
 => => naming to 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch                                            0.0s
Login Succeeded
Using default tag: latest
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch]
✔ Proposing infrastructure changes for stack fargate-arm-demo-test-os-arch
- Updating the infrastructure for stack fargate-arm-demo-test-os-arch         [update complete]  [281.6s]
  - An ECS service to run and maintain your tasks in the environment cluster  [update complete]  [251.6s]
    Deployments
               Revision  Rollout      Desired  Running  Failed  Pending
      PRIMARY  2         [completed]  1        1        0       0
  - An ECS task definition to group your containers and run them on ECS       [delete complete]  [3.6s]
✔ Deployed service os-arch.
Recommended follow-up action:
  - You can access your service at http://farga-Publi-XXXXXXXXXXX-0000000000.ap-northeast-1.elb.amazonaws.com over the internet.

copilot svc deployコマンドを実行することで、実態としてはまずコンテナイメージのビルドのためにdocker buildコマンドが実行されるのですが、その際に自動で--platformフラグが追加されています。

Copilot CLIを利用する上では、dockerコマンドを意識することなくコンテナイメージのベースとなるアーキテクチャを指定することができるわけです。

先ほどと同じようにALBのエンドポイントにアクセスしてみると、 "OS_Architecture" はArmベースのアーキテクチャであることを示しており、Graviton2で起動していることがわかります。

そして、manifest.ymlの内容はECSタスク定義にも反映され、runtimePlatformの項目が更新されています。

{
  "ipcMode": null,
  "executionRoleArn": "arn:aws:iam::123456789012:role/fargate-arm-demo-test-os-arch-ExecutionRole-1PLWRL6LCP2B",
  "containerDefinitions": [
    {
      "dnsSearchDomains": [],
      "environmentFiles": [],
      "logConfiguration": {
        "logDriver": "awslogs",
        "secretOptions": [],
        "options": {
          "awslogs-group": "/copilot/fargate-arm-demo-test-os-arch",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "copilot"
        }
      },
      "entryPoint": [],
      "portMappings": [
        {
          "hostPort": 5000,
          "protocol": "tcp",
          "containerPort": 5000
        }
      ],
      "command": [],
      "linuxParameters": null,
      "cpu": 0,
      "environment": [
        {
          "name": "COPILOT_APPLICATION_NAME",
          "value": "fargate-arm-demo"
        },
        {
          "name": "COPILOT_ENVIRONMENT_NAME",
          "value": "test"
        },
        {
          "name": "COPILOT_LB_DNS",
          "value": "farga-Publi-XXXXXXXXXXX-0000000000.ap-northeast-1.elb.amazonaws.com"
        },
        {
          "name": "COPILOT_SERVICE_DISCOVERY_ENDPOINT",
          "value": "test.fargate-arm-demo.local"
        },
        {
          "name": "COPILOT_SERVICE_NAME",
          "value": "os-arch"
        }
      ],
      "resourceRequirements": null,
      "ulimits": [],
      "dnsServers": [],
      "mountPoints": [],
      "workingDirectory": null,
      "secrets": [],
      "dockerSecurityOptions": [],
      "memory": null,
      "memoryReservation": null,
      "volumesFrom": [],
      "stopTimeout": null,
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fargate-arm-demo/os-arch@sha256:0c6b2ede1cd7699c0dd2bbf3d973054146aaf67632d366cded7e90e595c2b56f",
      "startTimeout": null,
      "firelensConfiguration": null,
      "dependsOn": null,
      "disableNetworking": null,
      "interactive": null,
      "healthCheck": null,
      "essential": true,
      "links": [],
      "hostname": null,
      "extraHosts": [],
      "pseudoTerminal": null,
      "user": null,
      "readonlyRootFilesystem": null,
      "dockerLabels": {},
      "systemControls": [],
      "privileged": null,
      "name": "os-arch"
    }
  ],
  "placementConstraints": [],
  "memory": "512",
  "taskRoleArn": "arn:aws:iam::123456789012:role/fargate-arm-demo-test-os-arch-TaskRole-1321J1VIS5NFT",
  "compatibilities": [
    "EC2",
    "FARGATE"
  ],
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/fargate-arm-demo-test-os-arch:2",
  "family": "fargate-arm-demo-test-os-arch",
  "requiresAttributes": [...],
  "pidMode": null,
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "networkMode": "awsvpc",
  "runtimePlatform": {
    "operatingSystemFamily": "LINUX",
    "cpuArchitecture": "ARM64"
  },
  "cpu": "256",
  "revision": 2,
  "status": "ACTIVE",
  "inferenceAccelerators": null,
  "proxyConfiguration": null,
  "volumes": []
}

クリーンアップ

今回の検証で構築した環境を削除する際は、下記のコマンドを実行すれば済みます。

クリーンアップ

$ copilot service delete
$ copilot app delete

Copilot CLIで実行環境の設定が容易になる

Fargateではつい先日、Windowsコンテナの起動もサポートされるようになりました。

Copilot CLIからWindowsコンテナを利用する際も、アーキテクチャと同じようにplatformの項目として設定すれば対応できます。

こうしたアップデートはCopilot CLIにも即日反映されており、ECSそのものの利便性が高まると共に、AWS公式ツールとしての存在感も徐々に増してきているのかなと感じています。

ECSの概念を良い感じに抽象化してわかりやすくしてくれるツールだと思うので、より便利に、使いやすくなっていくことを期待しています!

以上、コンサル部のとばち(@toda_kk)でした。