Category: Amazon ECS


詳解: Amazon ECSのタスクネットワーク

この記事はECSのSr. Software Dev EngineerのAnirudh Aithalの寄稿です。

2017年11月14日に、AWSはコンテナにElastic Network InterfaceをアタッチできるようにするAmazon ECSのTask Networkingを発表しました。

この記事では、ECSが管理するインスタンス(コンテナインスタンスと呼ばれます)上でContainer Networking Interfaceプラグインを使って、この新しいコンテナネイティブなawsvpcネットワークモードがどのように実装されているかを詳しくご紹介したいと思います。

こちらはAmazon ECSでタスクネットワークが動作するかにdeep diveしたものです。もし自身のコンテナ化したアプリケーションでどうやってタスクネットワークを使い始めれば良いかについて学びたい時には、Amazon ECSコンテナにCloud Native Networkingが登場をご覧下さい。Cloud Native Computing Foundation (CNCF)がContainer Networking Interface (CNI)プロジェクトをホストしており、Linuxコンテナでネットワークインターフェースを設定するためのプラグインを書くための仕様やライブラリが含まれています。AWSのクラウドネイティブコンピューティングについての詳細は、Adrian CockcroftのCloud Native Computingについての投稿をご覧下さい。

コンテナインスタンスのセットアップ

コンテナインスタンス上でのタスクネットワーク有効化の詳細をご説明する前に、ECSの典型的なインスタンスがどのようになっているかを見てみましょう。

上の図は典型的なコンテナインスタンスを示しています。ECS agentは自身もコンテナとして実行されているのですが、以下のような責任を負っています:

  • EC2インスタンスをECSのバックエンドに登録
  • コンテナインスタンスに対してECSバックエンドが発生させたタスク状態の変化を、正しく適応
  • Dockerデーモンと会話しながら、コンテナの作成、開始、停止、監視
  • コンテナの状態とタスクの状態の遷移をECSバックエンドにリレー

ECS agentはその管理下のコンテナのスーパーバイザーの様に動作するので、Dockerデーモン(Dockerのデフォルトネットワークモードで設定されたコンテナ用)、又はCNIプラグイン達(ネットワークモードがawsvpcで設定されたタスク内のコンテナ)のための、ネットワーク設定をする難しさをオフロードしてくれます。

いずれの場合にも、コンテナのネットワークスタックは、ネットワークのnamespaceを通じて設定されます。ip-netns(8)のマニュアルによると「ネットワークnamespaceは論理的なネットワークスタックのコピーで、自身のルーティング、ファイアウォールルール、ネットワークデバイスを持っています。」 とあります。ネットワークnamespaceの構成によって、ホスト上で動いているプロセスやコンテナ間でのネットワークスタックの隔離を可能としてくれます。

ネットワークnamespaceとCNIプラグイン

CNIプラグインとは、CNI仕様を満たしコンテナのネットワーク接続性の設定を行う実行ファイル群です。CNIプロジェクトではプラグインの仕様を定義し、プラグインが利用するライブラリを提供することで、一貫していて信頼でき、かつ簡素なプラグイン用のインタフェースを提供してくれます。

コンテナやネットワークnamespaceを指定してプラグインを呼び出す時に、ADDコマンドでコンテナにネットワークインターフェースを追加したり、DELコマンドでそれを落としたりします。例えばリファレンスのBridgeプラグインは、ホストネットワークnamespaceの中にいるブリッジに対してホスト上の全てのコンテナを追加します。

このプラグインのモデルはECS agentの「コンテナのライフサイクルへの最小限の介入」というモデルと相性が良く、agentはコンテナのネットワーク設定の詳細について考慮する必要がなくなります。また拡張性の高いモデルなので、将来必要になった時には、agentが異なるプラグイン群を利用できるようにスイッチさせることもできます。最後に、これらプラグインは必要な時に呼び出されるだけなので、その死活監視をECS agentがする必要はありません。

ECS agentからCNIプラグインを呼び出す

ECSがElastic Network Interfaceをインスタンスにアタッチし、agentに対しそのElastic Network Interfaceをタスク内のコンテナに対してプロビジョンするようにメッセージを送った時には、(任意のネットワークデバイスを使う) そのElastic Network Interfaceはホストのグローバルデフォルトネットワークnamespaceに現れてきます。ECS agentは複数のCNIプラグインを順番に呼び出すことで、そのElastic Network Interfaceがコンテナのネットワークnamespaceに正しく設定されていることを保証してくれます。これらのプラグインはamazon-ecs-cni-pluginsのGitHubレポジトリで見ることができます。

最初に呼び出されるものはecs-eniプラグインで、Elastic Network Interfaceがコンテナのネットワークnamespaceにアタッチされ、VPCから割り当てられたIPアドレスとサブネットのゲートウェイに対するデフォルトルートが設定されていることを保証します。コンテナは更にIAMロールの認証情報を得るために、(ECS agentが提供している) 認証情報エンドポイントにHTTPリクエストできるようになる必要があります。これはその次に実行されるecs-bridgeecs-ipamプラグインによって処理されます。CNIのライブラリはこれらのプラグインの実行結果を解釈する仕組みを提供しているので、agent上で効果的にエラーをハンドリングすることができます。以下の図は、このプロセスのそれぞれのステップを図解したものです:

ネットワークスタックの設定とアプリケーションコンテナの中で実行されるコマンドのレースコンディションを避けるために、ECS agentはタスク毎にそのタスク定義内にあるコンテナを開始する前に、pauseコンテナを作成します。その後、前述のCNIプラグイン群を実行することで、pauseコンテナのネットワークnamespaceをセットアップします。それからタスクにある残りのコンテナ達を開始するので、pauseコンテナのネットワークスタックを共有します。これは、タスク内の全てのコンテナはElastic Network InterfaceのIPアドレスによって到達可能であり、かつlocalhostインタフェースを通じて互いに通信することができることを意味しています。

このセットアップ例では、1つのElastic Network Interfaceの後ろに2つのコンテナを持った1つのタスクがあります。以下のコマンドでそれらが同じネットワークスタックを持っていて、localhostインタフェースを通して互いに会話可能であることを見ていきましょう。

ホスト上で実行している最新3つのコンテナをリストする (タスクで起動した2つのコンテナと、ECS agentが追加で起動したネットワークnamespaceの設定用コンテナ):

$ docker ps -n 3 --format "{{.ID}}\t{{.Names}}\t{{.Command}}\t{{.Status}}"
7d7b7fbc30b9	ecs-front-envoy-5-envoy-sds-ecs-ce8bd9eca6dd81a8d101	"/bin/sh -c '/usr/..."	Up 3 days
dfdcb2acfc91	ecs-front-envoy-5-front-envoy-faeae686adf9c1d91000	"/bin/sh -c '/usr/..."	Up 3 days
f731f6dbb81c	ecs-front-envoy-5-internalecspause-a8e6e19e909fa9c9e901	"./pause"	Up 3 days

3つのコンテナのインタフェースをリストし、それらが同じであることを確認する:

$ for id in `docker ps -n 3 -q`; do pid=`docker inspect $id -f '{{.State.Pid}}'`; echo container $id; sudo nsenter -t $pid -n ip link show; done
container 7d7b7fbc30b9
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

container dfdcb2acfc91
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

container f731f6dbb81c
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

まとめ

以上の仕組みによって、新しいawsvpcネットワークモードを使うことができ、コンテナに対してネイティブなネットワークサポートによる利便性を享受することができます。awsvpcモードの詳しい使い方は、Amazon ECSコンテナにCloud Native Networkingが登場ECSドキュメントをご覧下さい。

GitHubのECS CNIプラグインECS Agentのレポジトリで私にフィードバック頂けると幸いです。

原文: Under the Hood: Task Networking for Amazon ECS (翻訳: SA岩永)

Amazon ECSコンテナにCloud Native Networkingが登場

この記事はECSのSr. Software Dev EngineerのAnirudh Aithalの寄稿です。

2017年11月14日に、AWSはAmazon ECSのTask Networkingを発表しました。これによって、Elastic Network Interfaceを使ったAmazon EC2のネットワーク機能をタスクに持ち込むことができるようになります。

Elastic Network InterfaceはVPC内のインスタンスにアタッチすることができる仮想的なネットワークインタフェースです。EC2の仮想マシンを起動する時には、インスタンスにネットワークの機能を提供するために自動的に1つのElastic Network Interfaceがプロビジョンされます。

タスクは実行されるコンテナの論理的なグループです。これまでは、Amazon ECSで実行されるタスクはそれが動くEC2ホストのElastic Network Interfaceを共有していました。これからは、新しいawsvpcというネットワークモードを使うことで、Elastic Network Interfaceが直接タスクにアタッチされます。

これによってネットワークの設定を簡略化することができ、VPCが持っているネットワークの全機能、隔離性、そしてセキュリティの制御を各コンテナにEC2インスタンスと同様のレベルで利用することができます。

この記事では、awsvpcモードがどのように動作し、ECSのタスクでどのようにElastic Network Interfaceを使い始めることができるかをご紹介します。

背景: EC2のElastic Network Interface

VPC内にEC2インスタンスを起動する時には、各インスタンスが互いに通信できるようにするために、追加のオーバーレイネットワークを設定する必要はありません。標準で、VPCのルーティングテーブルがインスタンスや他のエンドポイント間での通信をシームレスに実現してくれます。これは、Elastic Network Interfaceと呼ばれるVPC内の仮想的なネットワーク・インタフェースによって可能となっています。全ての起動されるEC2インスタンスは自動的に1つのElastic Network Interface(プライマリネットワークインタフェース)がアサインされます。サブネット、セキュリティグループといった全てのネットワークパラメータは、このプライマリネットワークインタフェースの属性として扱われます。

さらに、各Elastic Network Interfaceは作成時にVPCによってIPv4アドレス(プライマリIPv4アドレス)が割当られます。このプライマリアドレスはユニークでVPC内でルーティング可能なものです。これによって、VPCは実際はフラットなネットワークとなり、ネットワークトポロジを簡潔なものとしてくれます。

Elastic Network InterfaceはVPC上で多様なエンドポイントとの接続を実現するための基本的なビルディングブロックとみなすことができ、そのうえでより高レベルな抽象レイヤを構築することができます。これによってElastic Network Interfacdeは以下の機能を利用することが可能となっています:

  • VPCネイティブなIPv4アドレスとルーティング (VPC上でのインスタンス間や他のエンドポイントとの間)
  • ネットワークトラフィックの隔離
  • ACLとファイアウォールルール(セキュリティグループ)を使ったネットワークポリシーの強制
  • (サブネットのCIDRを通じた)IPv4アドレスレンジの強制

なぜawsvpcを使うのか?

以前はECSはDockerが提供する標準のネットワークの挙動が提供するネットワーク機能に依存した形でコンテナ向けのネットワークスタックを構成していました。デフォルトのBridgeネットワークモードでは、インスタンス上のコンテナ達はdocker0ブリッジを使って互いにつながっています。インスタンス外のエンドポイントと通信する時には、コンテナはこのブリッジを利用し、それが実行されているインスタンスのプライマリネットワークインタフェースを使います。コンテナは、ファイアウォールルール(セキュリティグループ)やIPアドレスは、そのプライマリElastic Network Interfaceのネットワーク属性を共有しまた依存しています。

これは、Dockerによって割当られたIPアドレス(ローカルスコープのアドレスプールから割当られます)を使ってもこれらのコンテナに到達できないことと、細かいNetwork ACLやファイアウォールルールを強制できないことを意味します。代わりに、VPCからはインスタンスのプライマリElastic Network InterfaceのIPアドレスと、マップされたホスト側のポート番号(静的か動的なポートマッピング)の組み合わせによって、コンテナに到達することができます。また、1つのElastic Network Interfaceが複数のコンテナで共有されているので、各コンテナに最適なネットワークポリシーを簡単に作成することが難しくなっています。

awsvpcネットワークモードでは、タスク毎にElastic Network Interfaceをプロビジョンすることによって、これらの課題を解決しています。従って、コンテナ達はこれらのリソースを共有もせず干渉することももはやありません。これによって、以下のことが可能となります:

  • 複数のコンテナのコピーを同じインスタンス上で同じコンテナポートを使っていても、ポートマッピングの様なことをせずに実行することができ、アプリケーションの構成を簡素化できます。
  • 共有ブリッジで帯域が干渉することがないので、アプリケーションのネットワークパフォーマンスを向上させられます。
  • 各Amazon ECS タスクにセキュリティグループのルールを紐付けることで、コンテナ化したアプリケーションに緻密なアクセス制御を強制することができるので、アプリケーションのセキュリティを向上できます。

タスク内のコンテナにセキュリティグループを紐付けることで、送信元のポートとIPアドレスで受け付けるネットワークトラフィックを制限することができます。例えば、インスタンスにはSSHアクセスを許可するが、コンテナにはそれを許可しないということが可能です。あるいは、HTTPのトラフィックを80番ポートでコンテナは受付可能とするポリシーを強制するが、インスタンスではブロックするといったことができます。このようなセキュリティグループのルールを強制することによって、インスタンスもコンテナも攻撃にさらされる範囲を限りなく狭めることができます。

ECSはタスクのためにプロビジョンされるElastic Network Interfaceのライフサイクルを管理しており、オンデマンドで作成し、タスクが停止したら削除します。EC2インスタンスを起動する時と全く同じプロパティをタスクに指定することができます。こうしたタスクの中にあるコンテナは以下のような特徴を持ちます:

  • Elastic Network InterfaceのIPアドレスとDNS名で到達可能
  • Application Load BalancerとNetwork Load BalancerにIPターゲットとして登録可能
  • VPC Flow Logで観測可能
  • セキュリティグループでアクセス制御可能

これはまた、全く同じタスク定義から複数のタスクを同じインスタンス上で実行するときに、ポートの衝突を心配する必要をなくしてくれます。Bridgeネットワークモードの時にはあった、共有のdocker0ブリッジでのポートの変換や帯域の干渉が不要となるので、より高いパフォーマンスを得ることもできます。

始めてみよう

まだECSクラスタを持っていなければ、クラスタ作成ウィザードを使って1つ作成することができます。この記事ではawsvpc-demoをクラスタ名として使います。また、コマンドラインの手順を行うのであれば、最新バージョンのAWS CLISDKをインストールしていることを確認してください。

タスク定義を登録する

タスクネットワークの為にタスク定義で変更する必要がある唯一のものは、ネットワークモードのパラメータをawsvpcにするだけです。ECSコンソールでは、この値はNetwork Modeに入力します。

もしこのタスク定義のコンテナをECSサービスへ登録しようと思っている場合には、コンテナポートをタスク定義で指定します。この例ではNGINXコンテナは80番ポートを開放するように指定しています:

これでnginx-awsvpcという名前のタスク定義が作成され、ネットワークモードがawsvpcに設定されています。以下のコマンド群は、コマンドラインでタスク定義を登録する方法を示しています:

$ cat nginx-awsvpc.json
{
        "family": "nginx-awsvpc",
        "networkMode": "awsvpc",
        "containerDefinitions": [
            {
                "name": "nginx",
                "image": "nginx:latest",
                "cpu": 100,
                "memory": 512,
                "essential": true,
                "portMappings": [
                  {
                    "containerPort": 80,
                    "protocol": "tcp"
                  }
                ]
            }
        ]
}

$ aws ecs register-task-definition --cli-input-json file://./nginx-awsvpc.json

タスクを実行する

このタスク定義でタスクを実行するために、Amazon ECSコンソールのクラスタ画面に行き、Run new taskを選択します。nginx-awsvpcのタスク定義を指定します。次に、このタスクを実行するサブネットの集合を指定します。これらサブネットの少なくとも1つにはECSに登録されたインスタンスが必要です。そうしないと、ECSはElatic Network Interfaceをアタッチする候補を見つけることができません。

コンソールを使うと、Cluster VPCの値を選ぶことで、サブネットの候補を絞り込むことができます:

次に、タスクのセキュリティグループを選択します。この例では、新しいセキュリティグループを作成し、80番ポートの内向きのみを許可します。もしくは、既に作成済のセキュリティグループを選択することもできます。

次に、Run Taskをクリックしてタスクを実行します。

これで実行中のタスクができました。タスクの詳細画面をみると、Elastic Network Interfaceが割り当てられていることと、そのElatic Network Interfaceに紐付いたIPアドレスを確認することができます:

コマンドラインを使って同じことができます:

$ aws ecs run-task --cluster awsvpc-ecs-demo --network-configuration "awsvpcConfiguration={subnets=["subnet-c070009b"],securityGroups=["sg-9effe8e4"]}" nginx-awsvpc $ aws ecs describe-tasks --cluster awsvpc-ecs-demo --task $ECS_TASK_ARN --query tasks[0]
{
    "taskArn": "arn:aws:ecs:us-west-2:xx..x:task/f5xx-...",
    "group": "family:nginx-awsvpc",
    "attachments": [
        {
            "status": "ATTACHED",
            "type": "ElasticNetworkInterface",
            "id": "xx..",
            "details": [
                {
                    "name": "subnetId",
                    "value": "subnet-c070009b"
                },
                {
                    "name": "networkInterfaceId",
                    "value": "eni-b0aaa4b2"
                },
                {
                    "name": "macAddress",
                    "value": "0a:47:e4:7a:2b:02"
                },
                {
                    "name": "privateIPv4Address",
                    "value": "10.0.0.35"
                }
            ]
        }
    ],
    ...
    "desiredStatus": "RUNNING",
    "taskDefinitionArn": "arn:aws:ecs:us-west-2:xx..x:task-definition/nginx-awsvpc:2",
    "containers": [
        {
            "containerArn": "arn:aws:ecs:us-west-2:xx..x:container/62xx-...",
            "taskArn": "arn:aws:ecs:us-west-2:xx..x:task/f5x-...",
            "name": "nginx",
            "networkBindings": [],
            "lastStatus": "RUNNING",
            "networkInterfaces": [
                {
                    "privateIpv4Address": "10.0.0.35",
                    "attachmentId": "xx.."
                }
            ]
        }
    ]
}

awsvpcのタスクの詳細を見ると、Elastic Network Interfaceの詳細についてはattachmentsオブジェクトとして値が返ってきます。containersオブジェクトの中でもこの情報を見ることができます。例:

$ aws ecs describe-tasks --cluster awsvpc-ecs-demo --task $ECS_TASK_ARN --query tasks[0].containers[0].networkInterfaces[0].privateIpv4Address
"10.0.0.35"

まとめ

nginxコンテナはVPC上で10.0.0.35というIPv4アドレスでアクセスすることが可能です。80番ポートでリクエストを受け付けるために、インスタンスのセキュリティグループを編集する必要はありませんので、インスタンスのセキュリティを向上できます。また、アプリケーションの改修を全くせずに、80番ポート以外の全てのポートがブロックされていることも保証できるので、ネットワーク上でタスクの管理が簡単になります。Elastic Network InterfaceのAPI操作はECSが全て面倒を見てくれるので、何もする必要がありません。

タスクネットワークの機能に関するより詳しい情報はECSのドキュメントをご覧下さい。この新しいネットワークモードがインスタンス上でどのように実装されているかの詳細は、詳説: Amazon ECSのタスクネットワークをご覧下さい。

原文: Introducing Cloud Native Networking for Amazon ECS Containers (翻訳: SA岩永)

コンテナやサーバレスアプリのデプロイツールとしてのAWS CloudFormation

SA岩永です。AWS上にシステムを構築する際に、アプリケーションのデプロイをどのように行うか?については多様なやり方が考えられますが、今日はAWS CloudFormationを使ったデプロイをご紹介したいと思います。CloudFormationはインフラ構築のツールとして考えられている方も多いと思いますが、最近は特にAmazon ECSAWS LambdaといったComputeサービスへのアプリケーションデプロイツールとしての活用が進んでいます。AWSのリソースはAWS Command Line Interface (CLI)やSDK等での操作が可能なので自作のツール等を使われるのはもちろん1つの選択肢ですが、もしCloudFormationを検討されたことのない方は、ぜひこの投稿を参考にして頂けるとありがたいです。

デプロイツールとしてのCloudFormationのメリット

最初に結論をまとめておきます。CloudFormationを使ったデプロイには以下の様なメリットがあります。

  • デプロイツール自体のインストールが不要、YAML/JSONを書くだけ、ブラウザからでもデプロイ可能
  • 宣言的にデプロイが定義・実行できる
  • アプリケーションに関連する他のAWSリソースも合わせて管理可能

現在お使いのデプロイツールで、逆に上記の様な観点で困ったことのある方は、この投稿をじっくり読んで頂くと良いと思います。

デプロイツール自体のインストールが不要、YAML/JSONを書くだけ、ブラウザからでもデプロイ可能

例えばCLIで行う様なデプロイツールの場合、そのツール自体のインストール等が必要になりますが、CloudFormationであればブラウザからテンプレートを指定するだけでデプロイできます。CloudFormationの一番のメリットはここです。アプリケーションの構成を記述したYAML or JSONのテンプレートファイルを用意するだけで、すぐにデプロイが可能です。

CloudFormationも実態はAWSのAPIを実行しながらリソースを作成・更新しますが、CloudFormationの場合にはAPIの実行そのものをCloudFormationのサービス側でやってくれます。例えばECSのデプロイで新しいTask Definitionを作成した後でそれを指定してServiceを更新するという依存関係のある2回のAPI操作を順番に実行する必要がありますが、CloudFormationに1回命令を送るだけで後のAPI操作はCloudFormationのサービスが代わりにやってくれます。なので、デプロイが終わるまで実行プロセスが待っている必要もないですし、複数人の排他的実行も実現できますし、さらに現在の状態と過去の履歴というデータの保存までもやってくれます。

もちろん、CloudFormation自体もAWSのサービスなので、CLI/SDKでの操作は可能です。もしもデプロイをCLIで実行して終わるまで待ちたい、ということであれば、aws cloudformation deployというコマンドを使うと更新が終わるまでポーリングしながら待ってくれます。この場合に必要なものはAWS CLIのインストールのみなので、そこまでハードルの高いものではありません。

宣言的にデプロイが定義・実行できる

AWSのAPIを利用しながらデプロイツールを自作する場合には、リソースの作成順序に気を払いながら、かつ途中で失敗した場合のエラーハンドリング等も考慮しつつ手続き的に実装する必要があります。これはシンプルな構成であればそこまで難しくはないのですが、対応したい機能が徐々に増えてくるとだんだんと実装が複雑化してきてしまいます。

CloudFormationで使うテンプレートは、手続きを記述するのではなく、希望する状態を宣言的に定義するものです。そのため、複雑な構成であっても簡潔さを保って記述することができますし、多くのケースで各リソース間の依存関係も自動で判断されるので、実行順序を考えて記述する必要もありません。もちろん、テンプレートにはパラメータを設定することも可能なので、例えばECSであれば新しく作成したコンテナイメージ名をパラメータにしておくと、デプロイはそのパラメータを更新するだけで済みます。

アプリケーションに関連する他のAWSリソースも合わせて管理可能

ECSやLambdaは、それ単体だけで利用するケースよりも、他のAWSのサービスも合わせて利用されることが多いと思います。例えば、AWS Identity and Access Management (IAM)のRoleは良く使われますし、データベースとしてAmazon DynamoDBを使ったり、ECSのコンテナへの負荷分散にElastic Load Balancingを使うことは非常に多く、場合によってはアプリケーションのデプロイ時にそれらのリソースの更新も行いたいケースもあります。

CloudFormationでは他のリソースも合わせて定義して操作させられるので、そういったケースに非常に強力なツールとなります。アプリケーションと同じテンプレートで作成することもできますし、昨年リリースされたCross Stack Referenceという機能を使うと、先に作成しておいたリソースをアプリケーション側から参照するといった使い方もできます。

CloudFormationを使ったECSのデプロイ例

こちらは、ECSへの継続的デプロイメントについて紹介した以下のブログをご参照頂くのが良いです。

ブログで紹介されている構成では、GitHubへのコードのpushをトリガーにして、イメージのビルドからECSのServiceの更新まで一貫したものを紹介していますが、Service更新部分はCloudFormationテンプレートを使って実施しています。また、AWS CodePipelineがデプロイ方式としてCloudFormationに対応しているので、簡単に設定することが可能です。

参考のために、Task DefinitionとServiceとIAM Roleを定義するYAMLテンプレート例を貼り付けておきます。

https://github.com/awslabs/ecs-refarch-continuous-deployment/blob/master/templates/service.yaml

Resources:
  ECSServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument: |
        {
            "Statement": [{
                "Effect": "Allow",
                "Principal": { "Service": [ "ecs.amazonaws.com" ]},
                "Action": [ "sts:AssumeRole" ]
            }]
        }
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole

  Service:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref Cluster
      Role: !Ref ECSServiceRole
      DesiredCount: !Ref DesiredCount
      TaskDefinition: !Ref TaskDefinition
      LoadBalancers:
        - ContainerName: simple-app
          ContainerPort: 80
          TargetGroupArn: !Ref TargetGroup

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub ${AWS::StackName}-simple-app
      ContainerDefinitions:
        - Name: simple-app
          Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repository}:${Tag}
          EntryPoint:
            - /usr/sbin/apache2
            - -D
            - FOREGROUND
          Essential: true
          Memory: 128
          MountPoints:
            - SourceVolume: my-vol
              ContainerPath: /var/www/my-vol
          PortMappings:
            - ContainerPort: 80
          Environment:
            - Name: Tag
              Value: !Ref Tag
        - Name: busybox
          Image: busybox
          EntryPoint:
            - sh
            - -c
          Essential: false
          Memory: 128
          VolumesFrom:
            - SourceContainer: simple-app
          Command:
            - /bin/sh -c "while true; do /bin/date > /var/www/my-vol/date; sleep 1; done"
      Volumes:
        - Name: my-vol

CloudFormationを使ったLambdaのデプロイ例

Lambdaの構成管理およびデプロイには、AWS Serverless Application Model (SAM)を使うことができます。これはCloudFormationの拡張表記であり、例えば以下のようなテンプレートを書くと簡単にAmazon API GatewayとLambda Functionをデプロイ(初回は構築含む)をすることができます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Outputs the time
Resources:
  TimeFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      CodeUri: ./
      Events:
        MyTimeApi:
          Type: Api
          Properties:
            Path: /TimeResource
            Method: GET

Lambdaのデプロイを行う際、多くのケースでは依存ライブラリ等もまとめたzipファイルを作成し、Amazon Simple Storage Service (S3)にアップロードした上でFunctionを更新することになります。AWS SAMを使っているとこれをAWS CLIを使って簡単に実現できます。実装例は以下のドキュメントに詳しく紹介されています。

まとめ

この投稿では、AWS CloudFormationをコンテナやサーバレスアプリケーションをデプロイするためのツールとしてご紹介しました。多くの実際のユースケースで利用可能なものですのでご参考にして頂ければ幸いです。サーバレスアプリのデリバリパイプラインまで含めた実装を実際にご覧になりたい場合には、AWS CodeStarで作成されるプロジェクトも参考になるかと思いますので合わせてご参考頂ければと思います。

EC2 Container ServiceのBlue/Greenデプロイメント

この投稿と付随するコードの作成には、下記3名による多大な貢献がありました。

Jeremy Cowan
Solutions Architect
Anuj Sharma
DevOps Cloud Architect
Peter Dalbhanjan
Solutions Architect

コンテナ化されていないトラディショナルな環境にソフトウェアアップデートを展開するのは難しく、リスクを伴います。デプロイパッケージまたはスクリプトを記述するときは、ターゲットマシンが特定の状態にあると仮定する必要があります。ステージング環境が本番環境の正確なミラーイメージでない場合、デプロイは失敗する可能性があります。デプロイが失敗すると、アプリケーションの最後の正常なバージョンを再デプロイするまでサービス停止が起きることがあります。あなたが運用管理者だとしたら、サービス停止があると夜間に起きていなければいけないでしょう。

リリース内容の審査が終わるまでユーザーに新しいバージョンをさらすことなく、本番環境でテストをおこないたいと考えているお客様が増えています。人によっては、新機能が多くの人たちに公開される前に少数の顧客に対してのみ公開し、フィードバックを集めることもあるでしょう。これは、カナリア分析またはカナリアテストと呼ばれる手法です。この記事では、Application Load Balancerstarget groupsを使用してBlue/Greenとカナリアデプロイを実装するパターンを紹介します。

もし実際にこのアプローチを試したい場合、オープンソースのコードとAWS CloudFormationテンプレートをecs-blue-green-deployment GitHubリポジトリに公開しています。
このワークフローでは、サービスをECSクラスタにデプロイする自動化されたCI / CDパイプラインが構築され、コードの最新バージョンを本番環境に昇格する準備が整ったらターゲットグループをスワップする制御されたプロセスが提供されます。環境は3つのステップで簡単に設定でき、Blue/Greenのスワップが動作することを確認できます。ぜひ試してみてフィードバックを送ってください!

 

Blue/Greenの利点

Blue/Greenデプロイメントは、ソフトウェア更新を低リスクでおこなうことができるイミュータブルデプロイメントの1つのパターンです。現在の実行中の “Blue”バージョンのアプリケーションと新しい “Green”バージョンのアプリケーションを別々の環境で作成することで、リスクが軽減されます。

このデプロイメント方法では、アプリケーションの現在の実行中のバージョンに影響を与えずに、Greenの環境で機能をテストすることができます。Greenバージョンが正常に動作していることが確認できたら、DNSを変更して古いBlue環境から新しい環境にトラフィックを徐々にルーティングすることができます。この方法に従うことで、ほぼゼロダウンタイムで機能更新とロールバックをおこなうことができます。

2つの異なる環境感でトラフィックをシフトする典型的なBlue/Greenデプロイメント

このように運用中のBlue環境に素早くトラフィックを戻すことできることは、Blue/Greenデプロイメントの主要メリットの1つです。Blue/Greenデプロイメントでは、デプロイメントプロセスのどのタイミングでもBlue環境にロールバックすることが可能です。ダウンタイムはGreen環境に問題があることを認識してから、Blue環境にトラフィックを切り戻すまでの時間に制限されます。さらに、停止の影響はすべてのトラフィックではなく、Green環境に振り分けられたトラフィックに限定されます。デプロイエラーの規模が縮小されると、全体的なデプロイのリスクも低下します。

コンテナでBlue/Greenをシンプルに実現する

複数環境の管理およびプロビジョニングの複雑さとコストのために、従来のオンプレミスでのソフトウェア更新にはBlue/Greenデプロイメントはあまり導入されていませんでした。代わりに、アプリケーションはin-placeでアップグレードされていました。

このアプローチは有効でしたが、障害時のロールバックの迅速性などいくつかの欠陥がありました。ロールバックには通常、以前のバージョンのアプリケーションの再デプロイメントをおこなっていましたが、再デプロイメントは良くないリリースがあった場合の停止時間を長期化させる可能性があります。

コンテナは、簡単にパッケージ化でき、環境間を移動しても一貫して動作するため、Blue/Greenデプロイメントの導入を容易にします。この一貫性のひとつの要因は、コンテナのもつ不変性です。コンテナの設定を変更するには、In-Placeでソフトウェアを更新するのではなく、Dockerfileを更新してコンテナを再構築、再デプロイする必要があります。

コンテナは、アプリケーションのプロセスと名前空間の分離も提供します。これにより、複数のバージョンのアプリケーションを同じDockerホスト上で競合することなく並行して実行できます。仮想マシンに比べてサイズが小さいため、ホストあたりにVMに比べて多くのコンテナを詰め込むことができます。これにより、コンピューティングリソースをより効率的に使用できるようになり、Blue/Greenデプロイメントのコストを削減できます。

Amazon ECSのフルマネージド更新

Amazon EC2 Container Service (ECS) は、既存のAmazon ECSサービスを更新すると、ローリングアップデートを実行します。ローリングアップデートでは、現在実行中のバージョンのコンテナを最新バージョンに置き換えます。ローリングアップデート中にAmazon ECSがサービスに追加または削除するコンテナの数は、サービスのデプロイ時に許可される健全なタスクの最小数と最大数を調整することによって制御されます。

最新バージョンのコンテナイメージを利用するようにサービスのタスク定義を更新すると、Amazon ECSによってコンテナの古いバージョンが自動的に最新バージョンに置き換えられます。デプロイメント中、Amazon ECSは現在実行中のバージョンから接続を切断し、新しいコンテナがオンラインになるとApplication Load Balancer に登録します。

Target groups

ターゲットグループは、同じApplication Load Balancerの背後に複数のサービスを実行できるようにする論理構造です。これは、ターゲットグループごとにリスナーを持つことで実現されています。

Application Load Balancerを前に置くECSサービスを作成する時は、サービスのターゲットグループを指定する必要があります。通常はECSサービスごとにターゲットグループを作成しますが、ここでご紹介するアプローチでは、BlueのサービスとGreenのサービスの2つのターゲットグループを作成します。Blueサービスと同じパスを使用してGreenサービスをテストできるように、ターゲットグループごとに異なるリスナーポートを使用しています。

この構成では、Greenサービスに切り替える準備が整うまで、両方の環境を並行して実行できます。セキュリティグループルールや配置制約を使用して、社内ネットワーク上のテスターからにのみGreenバージョンへのアクセスを制限することも可能です。たとえば、サービスのGreenバージョンを、企業ネットワークからアクセス可能なインスタンスでのみ実行するように設定することができます。

切り替え

古いBlueサービスを新しいGreenサービスに置き換える準備ができたら、ModifyListener APIを呼び出して、対象のターゲットグループのリスナールールを入れ替えます。変更は即座に反映されます。その後、Greenサービスはポート80のリスナーを使用してターゲットグループで実行され、Greenサービスはポート8080のリスナーを使用してターゲットグループで実行されています。下の図は、このアプローチを示しています。

シナリオ

2つのサービスが定義されており、それぞれのターゲットグループが同じApplication Load Balancerに登録され、異なるポートで待機しています。 2つのターゲットグループ間でリスナールールを入れ替えることでデプロイが完了します。

Blueサービスへのリクエストはポート80リスナーを持つターゲットグループに向けられ、Greenサービスへのリクエストはポート8080リスナーを持つターゲットグループに向けられています。

テストの後で、Application Load Balancerでリスナールールをスワップし、Greenサービスにトラフィックを送信することで、デプロイメントを完了します。

留意事項

このアプローチを使用する際に注意すべきポイントがいくつかあります。

  • アプリケーションコードが完全にステートレスである必要があります。ステート情報はコンテナの外部に格納してください。
  • コネクションドレイニングはグレースフルには実行されません。ターゲットグループのスワップは突然実行されます。そのため、実行時間が長いトランザクションがあるサービスの場合は注意が必要です。
  • カナリアデプロイメントは実行できません。この方法では、サービスの異なるバージョン間をすばやく切り替えることができますが、本番トラフィックの一部をカナリアに流したり、サービスがクラスタ全体に展開される速度を制御したりすることはできません。

カナリアテスト

標準のAmazon ECSデプロイを使用したデプロイメント方法では、ローリングデプロイメントに伴う重労働の多くが自動化されますが、問題を発見した場合にデプロイメントを途中で中断することはできません。ロールバックしたい場合は、最後の正常なコンテナバージョンにサービスのタスク定義を更新し、Amazon ECSがクラスタ全体にデプロイを実行するのを待つ必要があります。最新のバージョンでテスト中に発見されなかった問題のある変更が導入されてしまった場合、このロールバック方法では遅すぎる可能性があります。

カナリアテストでは、Green環境が期待どおりに動作していないことがわかった場合、Blue環境に影響はありません。トラフィックを元の環境に戻すことができるため、問題のある操作やダウンタイムを最小限に抑え、影響範囲を制限します。

このタイプのデプロイメントは、一部分のユーザーに新しい機能を公開して広く利用できるようにする前にフィードバックを得るA/Bテストに特に役立ちます。

カナリアスタイルのデプロイメントでは、同じターゲットグループにBlueサービスとGreenサービスを配備します。この方法はスワップ方式ほど高速ではありませんが、各サービスのタスク数を調整することで、コンテナの交換レートを制御することができます。さらに、BlueとGreenのサービスのタスク数をそれぞれ調整することでロールバックすることができます。上記のスワップアプローチとは異なり、コンテナへの接続はグレースフルに終了します。我々はAmazon ECSのカナリアスタイルのデプロイメントについてのブログも投稿する計画を立てています。

まとめ

AWSでは、Amazon ECS、Application Load Balancer、およびターゲットグループを使用して、Blue/Greenデプロイメントの操作が可能になります。 ecs-blue-green-deployment GitHubリポジトリに公開されているコードをお客様のユースケースに合わせてカスタマイズすることをお勧めします。

より詳細に興味がある場合、 Blue/Green Deployments on AWSおよびPracticing Continuous Integration and Continuous Delivery on AWSというホワイトペーパーをお読みください。 ご質問やご提案がありましたら、ぜひご意見をお寄せください。あなたのフィードバックを楽しみにしています。

(翻訳はSA千葉が担当しました。原文はこちら)

AWS Summit Tokyo 2017でのAmazon EC2 Container Service (ECS) 関連セッションまとめ

5月末〜6月頭に開催されたAWS Summit Tokyo 2017において、Amazon ECSを実際にご利用頂いているお客様からの導入事例セッションとAWSからのTechセッションを合わせると、なんと11ものAmazon ECS関連セッションが行われました。Summit全体で130以上のセッションがありましたので、その中で10%程度がAmazon ECS関連だったということになります。Amazon ECSは、2015年4月にGA(東京リージョン含む)して以来、着実にお客様に導入を頂き、スタートアップからエンタープライズまで、新規システムだけでなくオンプレからの移行でも利用される標準的なサービスとなってきたことの表れかと思います。

この投稿では、それらのセッションを一気に見返せる様に情報を集約してお届けしたいと思います。これらの情報をご覧になって、Amazon ECSの利用をぜひご検討下さいませ。


導入事例トラック

  • ナビタイムサービスにおける、Amazon ECS を活用したシステム移行 ~『乗換NAVITIME』での移行事例 ~ 資料
  • [リコー] サービス全断はダメ、ゼッタイ。途切れないテレビ会議システムを目指して 〜AWS を最大限活用して可用性を高める秘策〜 資料 動画
  • クックパッドの機械学習を支える基盤のつくりかた 資料 動画
  • Amazon ECS と SpotFleet を活用した低コストでスケーラブルなジョブワーカーシステム (※株式会社インティメート・マージャー様事例) 資料 動画
  • [Intelligence] オンプレから移行するので、Amazon ECS でコンテナ化と Terraform でインフラコード化した話 資料
  • DAU 100 万人突破! 急成長を支える Shadowverse のインフラ技術 資料
  • DMM における会員基盤プラットフォームへのAWS導入から活用事例の紹介 資料 動画
  • [ABEJA] IoT / Bigdata / AI 時代におけるスケーラブルな Deep Learning 実行基盤と応用 動画
  • Amazon ECS の進化、DevOps と Microservices の実践 (※フラー株式会社様事例)  動画
  • [CyberZ] OPENREC.tvにおけるライブ動画およびメッセージ配信基盤のリプレース全貌 資料 動画

AWS Techトラック

  • AWS のコンテナ管理入門(Amazon EC2 Container Service)資料 動画
  • C# 開発者必見、Docker コンテナへの継続的デプロイメント on AWS ~CodeCommit, CodeBuild, CodePipeline, CloudFormation, ECR, ECS を活用した CI/CD ~ 資料 動画

その他

  • Running Container-Enabled Microservices on AWS – ブートキャンプ (特別有償トレーニング)
    • 5時間で、コンテナ対応のアプリケーションの管理およびスケーリングについて詳細かつ実践に説明する、エキスパートレベルのトレーニングブートキャンプを実施しました。

最後に、直近のAmazon ECSのアップデートをまとめてご紹介します。

Amazon ECSについてより詳しく学びたい方は、日本語化されたドキュメントAWS Black Belt Online Seminarの資料等をご確認下さい。

SA岩永

Amazon EC2 スポットインスタンスを利用した Amazon ECSクラスターの起動

この記事は気前よく次の方から寄贈されました。

Chad Schmutzer, Solutions Architect Shawn O'Conner, Enterprise Solutions Architect
Chad Schmutzer
Solutions Architect
Shawn O’Connor
Solutions Architect

 

本日、Amazon EC2 Container Service(Amazon ECS)が、ECSコンソール上から直接 Amazon EC2 Spot Instances上に ECSクラスターを起動させる機能をサポートする事を発表しました。

スポットインスタンスを利用すると、Amazon EC2の余剰コンピュートキャパシティに入札することが出来ます。スポットインスタンスは通常、オンデマンドインスタンスよりも50-90%安い価格です。スポットインスタンス上でECSクラスターを起動することで、既存のコンテナ化されたワークロードの実行コストを削減したり、同じ予算を維持しながら、コンピュートキャパシティを2倍から10倍に増やすことが可能です。もしくは、その両方を実現することもできます!

スポットインスタンスを利用する場合、インスタンス時間あたりに支払う価格を指定します。現在のスポットプライスを上回る価格で入札している間、スポットインスタンスは起動します。スポットプライスの上昇によりインスタンスが回収された場合、インスタンスが実行された分の時間は請求されません。

ECSコンソールはスポットインスタンスをデプロイするために、 Spot Fleetを利用します。Spot Fleetは、利用者にとって最も良い価格となる様にスポットインスタンスを起動し、コンテナ化したアプリケーションの為にリクエストしたターゲットキャパシティ(インスタンスやvCPUの数で表現される)をデプロイしようします。スポットプライスや、空き容量の変化によってスポットインスタンスが回収された場合、Spot Fleetはターゲットキャパシティを維持しようとします。

コンテナはSpot Fleetが大きくなる多様なリソースプールに適してします。Spot Fleetを利用すると複数のスポットインスタンスプール(インスタンスタイプとアベイラビリティゾーンの組み合わせ)に渡ってキャパシティをプロビジョニング出来き、アプリケーションの可用性を向上させ、時間経過と共に運用コストを削減できます。ECSが提供する拡張性と柔軟性を備えたコンテナ配置システムとSpot Fleetとの組み合わせはコンテナ化されたワークロードを効率的にデプロイし、わずかなコストであらゆる規模のクラスタを容易に管理できます。

従来は、スポットインスタン上へのECSクラスタのデプロイは手動で行われてました。この記事では、ECSコンソール上からのSpot Fleetとの新しいインテグレーションによって、高い可用性とスケーラビリティをどの様に実現し、コンテナ化したワークロードをどの様にコストを削減するのかを紹介します。また、AWS CloudFormationを利用し、スポットインスタンス上にECSクラスターを構築する方法も紹介します。

 

スポットインスタンスで実行するECSクラスタの作成

AWS マネージメントコンソールを利用してECSクラスタを作成することが可能です。

  1. Amazon ECSコンソールを開きます。 https://console.aws.amazon.com/ecs/
  2. ナビゲーションパネル上でClustersを選択します。
  3. Clustersページでは、Create Clusterを選択します。
  4. Cluster nameに名前を入力します。
  5. インスタンス設定では、プロビジョニングモデルとしてSpotを選択します。

ECS Create Cluster - Spot Fleet

配置戦略の選択

2つの利用可能なSpet Fleet配置戦略はDiversified戦略かLower price戦略です。

ECS Spot Allocation Strategies

Spot Fleetで選択した配置戦略は、利用可能なスポットインスタンスプールからSpot Fleetをどの様に満たすかを決定します。diversified戦略を使用すると、スポットインスタンスは全てのプールにわたって分散されます。lowest price戦略を選択した場合、リクエストで指定された最低価格のプールから取得されます。

各インスタンスタイプ(各インスタンスファミリ内のインスタンスサイズ、例えばc4.4xlarge)、各アベイラビリティゾーン、各リージョンで、キャパシティで別れたプールであり、別々のスポットマーケットであることに注意してください。可能な限り異なったインスタンスタイプとアベイラビリティゾーンにまたがって多様にすることで、fleetの可用性を向上することができます。また、時間の経過とともにスポットプライスが上昇することに対しての反応を低くすることができます。

Spot Fleet Market

Spot Fleetに利用するインスタンスタイプを6種類まで選択可能です。この例では、m3,m4,c3,c4,r3,そしてr4のxlargeを選択しています。

Spot Instance Selection

インスタンスの為に入札価格を入力する必要があります。一般的には、オンデマンドインスタンス価格かそれに近い価格で入札するが良い出発点です。そのスポットプールのインスタンスタイプに支払うつもりがある最大価格が入札価格になります。スポット価格が入札価格と同じ、または下回っている間、スポット価格を支払います。低い価格での入札はコストを低減させ、高い価格での入札はインスタンスの中断の確率を下げます。

クラスターに所属するインスタンスの数を設定します。Spot Fleetはリクエストで特定されたターゲットキャパシティを満たす様にスポットインスタンスを起動しようとします。

最新のECS最適化AMIがSpot Fleetがインスタンス時に使用されます。

ストレージとネットワークの設定を行います。多様性と高可用性を実現する為に、複数のアベイラビリティゾーンとなる様にsubnetを選択する様にします。singleのSpot Fleetでは、同じアベイラビリティゾーンにある複数のサブネットを選択する事はできません。

ECSコンテナエージェントがECSのAPIをコールします。エージェントが実行されるコンテナインスタンスはに、エージェントの所有者を知るためにecsInstanceRole IAMポリシーとロールが必要です。

Spot Fleetを利用するマネージドコンピュート環境を作成した場合、入札、起動、インスタンスの終了するためのSpot Fleet権限を付与したロールを作成しなくてはなりません。このロールはECSコンソールから作成できます。

ECSコンソールでの作用はこれだけです!Spot Instance上で稼働するるECSクラスターを起動する為に作成を選択してください。

スポットインスタンス上で稼働するECSクラスターのデプロイにAWS CloudFormationを利用する

リファレンスアーキテクチャとなるAWS CloudFormationテンプレートを公開しています。このテンプレートはCloudFormationスタックの起動や、スポットインスタンス上でのECSクラスタのデプロイがどれくらい簡単をデモンストレーションします。

CloudFormationテンプレートには 以前投稿したSpotインスタンスの終了通知スクリプトだけではなく、いくつかの追加のロギングやその他のサンプル機能が含まれています。Amazon EC2 Spot Instance GitHub上のレポジトリからCloudFormationテンプレートを見つけることができます。

環境に応じてカスタマイズを実施して試してみてください!

Spot Fleet Architecture

終了のハンドリング

スポットインスタンスでは、指定した価格以上を支払う必要はありません。もしスポット価格があるインスタンスで入札を上回った場合、そのインスタンスは自動的に終了されます。

スポットインスタンスの終了を防ぐための最も良い方法は、コンテナ化されたアプリケーションをフォールトトレラントなアーキテクチャにすることです。加えて、スポットインスタンスの終了通知機能を利用することもできます。それはEC2がスポットインスタンスを終了する前に2分間の警告を提供します。

この警告は、インスタンスメタデータ内の項目を使用して、スポットインスタンス上のアプリケーションで使用可能になります。コンソールを利用してスポットインスタンス上にECSクラスターをデプロイした場合、AWSはインスタンス終了通知を5秒毎に確認するスクリプトをインストールします。通知を検知した場合、スクリプトはコンテナインスタンスの状態をDRAININGにただちにに更新します。

簡略したバージョンのスポットインスタンス終了通知は次の様になります。

#!/bin/bash

while sleep 5; do
  if [ -z $(curl -Isf http://169.254.169.254/latest/meta-data/spot/termination-time) ]; then
    /bin/false
  else
    ECS_CLUSTER=$(curl -s http://localhost:51678/v1/metadata | jq .Cluster | tr -d \")
    CONTAINER_INSTANCE=$(curl -s http://localhost:51678/v1/metadata \
      | jq .ContainerInstanceArn | tr -d \")
    aws ecs update-container-instances-state --cluster $ECS_CLUSTER \
      --container-instances $CONTAINER_INSTANCE --status DRAINING
  fi
done

コンテナインスタンスをDRAININGにセットすると、ECSによって、新しいタスクのコンテナインスタンスへの配置がスケジュールされなくなります。リソースが利用可能な場合、代替サービスタスクはクラスター内の別のコンテナインスタンスで開始されます。コンテナインスタンスのドレイニングにより、クラスタ内のタスクに影響を与えない様にクラスターからコンテナインスタンスを削除することができます。PENDING状態にあるコンテナインスタンス上のサービスタスクは直ちに停止します。

コンテナインスタンス上でRUNNING状態にあるサービスタスクは停止し、サービスデプロイ設定パラメータであるminimumHealthyPercentとmaximumPercentに従い、再配置されます。

実際のスポットインスタンス上のECS

どの様にお客様がスポットインスタンス上でECSクラスターをすでに起動しているか知りたいですか?Mapboxにいる友人はこの様にしています。

Mapboxはカスタムマップをデザインし、公開するためのプラットフォームです。同社はマップを作成する為に1日に1億マイルを超えるセンサーデータの収集と実行するバッチプロセッシングアーキテクチャー全体の実行にECSを利用しています。彼らはスポットインスタンスを使用したECSを利用することでバッチプロセッシングアーキテクチャを最適化しています。

Mapboxプラットフォームは5000を超えるアプリケーションを起動し、各月で2億ユーザ以上に達しようとしています。それらのバックエンドはECS上で動いていて、1日あたり13億リクエスト以上を処理しています。Mapbox社の最近のECSへのマイグレーションについてより学びたい場合は、同社のブログである、We Switched to Amazon ECS, and You Won’t Believe What Happened Next. を読んでください。そして、フォローアップ記事である、 Caches to Cashでは、EC2のコストを50-90%節約しながら、同社がスポットインスタンス上でどの様にプラットフォーム全体を動かしているのかを学んでください。

結論

スポットインスタンスを利用してスケールし、コスト効率よくコンテナ化したアプリケーションを動かす事について、私たちと同じ様に読者の方も興奮している事を願います。さらなる情報については、次のページを確認してください。

コメントや提案があるかたは下記よりコメントをください。

原文:Powering your Amazon ECS Cluster with Amazon EC2 Spot Instances(翻訳:SA浅野)
 

Amazon EC2 Container Service – リリースに関する要約、お客様事例、コードについて

今回は、去年 Amazon EC2 Container Service に追加したいくつかの機能に関する概要と、お客様事例やコードについてご紹介します。このサービスは EC2 インスタンスのマネージド型クラスターの範囲内で Docker コンテナをいくつでも実行しやすくします。また、同サービスはコンソールAPICloudFormationCLIPowerShell のサポートも備えています。簡単にアクセスできるように、Linux や Windows Docker イメージを EC2 Container Registry に保存できます。

リリースの要約
それでは ECS の最新機能と、その使用方法を説明したブログをいくつか見てみましょう:「アプリケーションの負荷分散 (Application Load Balancing)」- 去年は「アプリケーションロードバランサー (application load balancer)」のサポートを追加しました。この高性能なロードバランシングオプションはアプリケーションレベルで実行され、コンテンツベースのルーティングルールで定義することができます。ダイナミックポートをサポートし、複数のサービスでの共有が可能なため、コンテナ内でマイクロサービスを実行しやすくなります。詳細については「サービスロードバランシング (Service Load Balancing)」をご覧ください。

タスクで使用する IAM ロール – ECS タスクに IAM ロールを割り当てることでインフラストラクチャを安全にできます。これにより、各タスクごとに細かく設定しアクセス許可を付与できるので、各タスクが必要とするアクセス許可を割り当てることが可能です。詳しくは「タスクで使用する IAM ロール (IAM Roles for Tasks)」をご覧ください。

サービス Auto Scaling – 需要の変化に応じるため、サービス (タスク) のスケールダウンやスケールアップに関するスケーリングポリシーを定義できます。お客様は必要なタスクの最小数および最大数を選択し、1 つまたはそれ以上のスケーリングポリシーを作成するのみです。あとはサービス Auto Scaling で処理されます。この機能を活用するには「サービス Auto Scaling (Service Auto Scaling)」をご覧ください。

Blox – コンテナベース環境の Scheduling は、インスタンスにタスクを割り当てる際のプロセスです。ECS は 3 つのオプションを提供します: 自動 (すでに組み込まれている サービススケジューラー)、手動 (RunTask 関数を使用)、カスタム (ご自分で提供するスケジューラーを使用)。Blox は one-task-per-host タイプをサポートするオープンソーススケジューラーです。今後、他のタイプにも対応する可能性も充分にあります。これはクラスターの状態を監視し、モニタリングエージェントやログコレクター、その他のデーモンスタイルのタスクを実行するのに適しています。

Windows – Linux コンテナをサポートする ECS をリリースしたほか Windows Server 2016 Base with Containers の実行もサポートするようになりました。

コンテナインスタンスのドレイン – クラスターをスケールダウンしたりシステムを更新するために、実行中のクラスターからインスタンスを削除することが必要な場合も時にはあるでしょう。インスタンスの状態をより管理しやすくするため、今年始めに一連のライフサイクルフックを追加しました。ライフサイクルフックと Lambda 関数を使用して、新しい作業にスケジュールを設定することなく、インスタンスから既存の作業のドレインプロセスを自動化する方法については「Amazon ECS でコンテナインスタンスのドレインを自動化する (How to Automate Container Instance Draining in Amazon ECS)」をご覧ください。

コードを使用した CI/CD パイプライン* – コンテナはソフトウェアの導入を簡素化し、CI/CD (継続的インテグレーション / 継続的デプロイメント) パイプラインにとって理想的なターゲットです。過去に公開したブログ「AWS CodePipeline、AWS CodeBuild、Amazon ECR、AWS CloudFormation を使用し Amazon ECS で行う継続的デプロイメント (Continuous Deployment to Amazon ECS using AWS CodePipeline, AWS CodeBuild, Amazon ECR, and AWS CloudFormation)」では、複数の AWS サービスを使用して CI/CD パイプラインを構築し動作させる方法について説明しています。

CloudWatch Logs の統合 – このリリースでは、一元管理と分析に使用する CloudWatch Logs にログ情報を送信するタスクを実行するコンテナ設定が可能になりました。Amazon ECS コンテナエージェントをインストールし awslogs ログドライバーを有効にするだけです。CloudWatch Events – タスクの状態またはコンテナインスタンスが変更すると、ECS は CloudWatch Events を生成します。こうしたイベントは Lambda 関数を使用してクラスターの状態を監視できるようにします。Elasticsearch クラスターでイベントをキャプチャし保存する方法については「Amazon ECS Event Stream でクラスターの状態を監視する (Monitor Cluster State with Amazon ECS Event Stream)」をご覧ください。

タスク配置のポリシー – このリリースでは、クラスター内のコンテナインスタンスでタスク配置における細かな管理設定を提供しました。クラスター制約、カスタム制約 (場所、インスタンスタイプ、AMI、属性)、配置戦略 (スプレッドまたはビンパック) を含むポリシーを作成し、コードを作成することなく使用できるようにします。詳細については「Amazon ECS タスク配置のポリシー (Introducing Amazon ECS Task Placement Policies)」をご覧ください。

EC2 Container Service の実行
金融サービス、ホスピタリティ企業、家電メーカーなど様々な分野における大規模なエンタープライズから急成長中のスタートアップ企業まで、AWS をご利用のお客様は Amazon ECS を使用して独自のマイクロサービスアプリケーションを本稼働環境で使用しています。Capital One、Expedia、Okta、Riot Games、Viacom といった企業は Amazon ECS に依存しています。

Mapbox は、カスタムマップを設計し公開するプラットフォームです。同企業は ECS を使用してバッチ処理のアーキテクチャをサポートし、マップのサポートに使用する 1 億マイルのセンサーデータを毎日収集し処理しています。スポットインスタンスを使用して ECS でバッチ処理アーキテクチャの最適化も行います。Mapbox のプラットフォームは 5,000 件以上のアプリをサポートし、毎月 2 億人以上のユーザーをターゲットにしています。そのバックエンドは ECS で実行され、毎日 13 億件のリクエストに対応しています。同社が最近行った ECS への移行に関する詳細は「Amazon ECS に切り替えるメリット (We Switched to Amazon ECS, and You Won’t Believe What Happened Next)」をご覧ください。

旅行会社の Expedia は、マイクロサービスアーキテクチャで同社のバックエンドを設計しました。Docker の普及に伴い、スピードのあるデプロイメントや環境の可搬性に Docker を取り入れることにしました。ALB から IAM ロール、VPC の統合まで、優れた統合性を備えているため、すべてのコンテナ調整に ECS を使用することにしました。これにより、既存の AWS インフラストラクチャで ECS がとても使いやすくなりました。ECS により、デプロイやコンテナ化されたアプリケーションの負担を軽減できるようになりました。Expedia はすべてのアプリケーションのうち 75% を ECS の AWS で実行し、毎時間 40 億件のリクエストを処理できるようにしています。詳しくは Kuldeep Chowhan のブログ「Amazon ECS を使用して本稼働環境で Expedia が何百件ものアプリケーションを実行している方法 (How Expedia Runs Hundreds of Applications in Production Using Amazon ECS)」をご覧ください。

Realtor.com は住宅の購入販売において現在売りに出されている不動産物件の包括的なデータベースを提供しています。同社が AWS に移行してから ECS を使用することでサポートビジネスが成長し、現在では毎月の閲覧者数が 5,000 万人を超え、ピーク時には毎秒 250,000 件のリクエストが記録されています。ECS は同社がクラウドインフラストラクチャの使用率を高めながら、よりすばやくコードをデプロイすることをサポートしています。同社が ECS、Kinesis、その他の AWS サービスをどのように活用しているかは「Realtor.com の導入事例 (Realtor.com Case Study)」をご覧ください。Instacart は、食品同日配送サービスのサポートに ECS をどのように利用しているのか説明しています:

Capital One は、ECS を使用してオペレーションやインフラストラクチャの管理を自動化しているのか説明しています:

Code Clever の開発者は ECS を独自の作業ベースに使用しています。例: Rack はオープンソースの PaaS (Platform as a Service) です。これは分離されている VPC で実行するインフラストラクチャの自動化に集中し、セキュリティにはシングルテナントで構築されたサービスを使用します。

Empire もオープンソース PaaS です。Heroku のようなワークフローを提供し、マイクロサービスに重点を置いた小規模および中規模のスタートアップ企業をターゲットにしています。Cloud Container Cluster Visualizer (c3vis) は、ECS クラスター内でリソースの使用率を可視化します:

今後もお楽しみに!
この他にも ECS の新機能を構築中です、乞うご期待ください!

Jeff;

AWS Batch上で深層学習

同僚のKiuk ChungがAWS Batchを使って深層学習をするという素晴らしい記事を書いてくれました。


GPUインスタンスは当然のように深層学習とペアになりますが、それはそのニューラルネットワークのアルゴリズムがGPUインスタンスの超並列処理能力を活かすことができるからです。AWSではg2やp2といったGPUインスタンスを提供しており、お客様はスケーラブルなGPUワークロードを実行することができます。AWS Batchを使うことでそのスケーラビリティをもっと効率よく使うことができます。(訳注: 丁度GTC 2017のKeynoteにて次期NVIDIA GPUであるV100に関する情報も発表されましたのでご参考頂ければ幸いです: AWS and NVIDIA Expand Deep Learning Partnership at GTC 2017)

AWS Batchは皆さんの代わりに下回りの計算リソースを管理してくれるので、リソース管理のオーバーヘッド無しにモデリングすることに集中できます。AWS Batchにおける計算環境 (すなわちクラスタ)とは、皆さんのアカウント内のインスタンスのプールであり、AWS Batchはジョブの数に応じてインスタンスを起動したり削除したりしながらそれを動的にスケールしてくれます。これによって無駄なインスタンスを最小化でき、コストを最適化することができます。

さらに、AWS Batchは登録されたジョブが適切なインスタンスに配置されるように確実にスケジュールしてくれるので、ジョブのライフサイクルが管理されます。お客様独自のAMI利用の機能追加によって、AWS Batchの利用者はGPUが必要とされるジョブのためにもこの弾力性や利便性を活用することができるようになりました。

この記事ではGPUベースの深層学習ワークロードをAWS Batch上でどのように動かせばよいかをお見せします。Apache MXNetを使ってMNISTデータセットから手書きの数字を認識するための、畳み込みニューラルネットワーク(LeNetアーキテクチャ)の学習をとして使います。

MXNetのジョブをAWS Batchで実行する

Apache MXNetは機能が豊富で、柔軟にプログラムが書け、高いスケーラビリティをもった深層学習フレームワークで、畳み込みニューラルネットワーク (CNNs)やlong short-term memory networks (LSTMs)を含む最新の深層モデルをサポートしています。

AWS Batchでジョブを実行するには3つのステップがあります:

  • カスタムAMIを作成
  • AWS Batchのリソースを作成
  • 学習ジョブを登録

カスタムAMIを作成

まず、NVIDIAドライバとAmazon ECSエージェントを含むAMIを作成するところから始めます。AWS Batchでは、計算環境を作成する時にimage_idを指定することで特定のAMIからインスタンスを起動させることができます。GPUが必要なジョブを実行しようとしているので、NVIDIAドライバが含まれたAMIが必要となります。

Launch Stackを選択して、あなたのアカウント上でus-east-1にCloudFromationテンプレートを起動します: 

下にある様に、CloudFormationスタックのOutputsタブの中にあるAMIという値をメモしておきます。次のセクションで計算環境を作成する時にこれをimage_idの値として使います。

または、AWS BatchのドキュメンテーションのGPU有効なAMIを作成するに従っても良いです。

AWS Batchのリソースを作成

AMIを作成したら、以下のリソースを作成します:

計算環境は、同じまたは異なるインスタンスタイプのインスタンス(計算リソース)の集合です。ここでは、p2.xlargeのインスタンスを使ったマネージド計算環境を作成します。imageIdには、前のセクションで作成したAMIを指定します。

そうしたら、ジョブキューを作成します。AWS Batchでは、ジョブは計算環境の順序付きリストに紐付いたジョブキューに登録されます。順位が優先の計算環境が埋まってしまったら、ジョブは次の順位の計算環境へと漏れていきます。今回の例ではジョブキューには1つの計算環境のみ紐付けます。

最後に、ジョブの仕様のテンプレートとなるジョブ定義を作成します。Amazon ECSに馴染みのある方には、これはタスク定義と似たようなものですと言えばお分かりでしょう。ホスト上のNVIDIAドライバが含まれるディレクトリをコンテナの/usr/local/nvidia上にマウントします。またコンテナのプロパティでprivilegedフラグを設定する必要もあります。

以下のコードは前述のAWS Batchのリソースを作成してくれます。より詳しい情報は、AWS Batchユーザガイドをご覧ください。

git clone https://github.com/awslabs/aws-batch-helpers
cd aws-batch-helpers/gpu-example

python create-batch-entities.py\
 --subnets <subnet1,subnet2,…>\
 --security-groups <sg1,sg2,…>\
 --key-pair <ec2-key-pair>\
 --instance-role <instance-role>\
 --image-id <custom-AMI-image-id>\
 --service-role <service-role-arn> 

学習ジョブの登録

ここまできたら、手書き数字の認識のための畳み込みニューラルネットワークモデルを学習するジョブを登録します。Amazon ECSのタスクの様に、AWS BatchではジョブはDockerコンテナ内のコマンドとして実行されます。MXNetを深層学習ライブラリとして使うためには、MXNetが含まれたDockerイメージが必要になります。ここではmxnet/python:gpuを利用します。

submit-job.pyスクリプトはジョブを登録し、CloudWatch Logsから出力をtailしてくれます。

# cd aws-batch-helpers/gpu-example
python submit-job.py --wait

下のような出力を見ることができると思います:

Submitted job [train_imagenet - e1bccebc-76d9-4cd1-885b-667ef93eb1f5] to the job queue [gpu_queue]
Job [train_imagenet - e1bccebc-76d9-4cd1-885b-667ef93eb1f5] is RUNNING.
Output [train_imagenet/e1bccebc-76d9-4cd1-885b-667ef93eb1f5/12030dd3-0734-42bf-a3d1-d99118b401eb]:
 ================================================================================

[2017-04-25T19:02:57.076Z] INFO:root:Epoch[0] Batch [100]	Speed: 15554.63 samples/sec Train-accuracy=0.861077
[2017-04-25T19:02:57.428Z] INFO:root:Epoch[0] Batch [200]	Speed: 18224.89 samples/sec Train-accuracy=0.954688
[2017-04-25T19:02:57.755Z] INFO:root:Epoch[0] Batch [300]	Speed: 19551.42 samples/sec Train-accuracy=0.965313
[2017-04-25T19:02:58.080Z] INFO:root:Epoch[0] Batch [400]	Speed: 19697.65 samples/sec Train-accuracy=0.969531
[2017-04-25T19:02:58.405Z] INFO:root:Epoch[0] Batch [500]	Speed: 19705.82 samples/sec Train-accuracy=0.968281
[2017-04-25T19:02:58.734Z] INFO:root:Epoch[0] Batch [600]	Speed: 19486.54 samples/sec Train-accuracy=0.971719
[2017-04-25T19:02:59.058Z] INFO:root:Epoch[0] Batch [700]	Speed: 19735.59 samples/sec Train-accuracy=0.973281
[2017-04-25T19:02:59.384Z] INFO:root:Epoch[0] Batch [800]	Speed: 19631.17 samples/sec Train-accuracy=0.976562
[2017-04-25T19:02:59.713Z] INFO:root:Epoch[0] Batch [900]	Speed: 19490.74 samples/sec Train-accuracy=0.979062
[2017-04-25T19:02:59.834Z] INFO:root:Epoch[0] Train-accuracy=0.976774
[2017-04-25T19:02:59.834Z] INFO:root:Epoch[0] Time cost=3.190
[2017-04-25T19:02:59.850Z] INFO:root:Saved checkpoint to "/mnt/model/mnist-0001.params"
[2017-04-25T19:03:00.079Z] INFO:root:Epoch[0] Validation-accuracy=0.969148

================================================================================
Job [train_imagenet - e1bccebc-76d9-4cd1-885b-667ef93eb1f5] SUCCEEDED

実際には、学習されたモデル情報をAmazon S3に保存することで後続の予測ジョブが学習したモデルを使って予測を生成できるように、ジョブのコマンドを修正したくなると思います。Amazon S3のオブジェクトをジョブからどのように参照するかについては、Creating a Simple “Fetch & Runb” AWS Batch Jobの記事をご覧ください。

まとめ

この記事では、MXNetを深層学習のライブラリとして使いながらAWS Batch上でGPU有効なジョブを実行する例をお見せしました。AWS Batchはご自身のワークロードのために最も最適なアルゴリズムを実装することに集中できるだけの基礎的な部分を提供してくれます。登録したジョブのライフサイクルを管理し、指定した範囲内でジョブの要求に合わせて動的にインフラを最適化することが可能です。コスト最適なやり方でAWSが提供する計算用インスタンスの水平スケーラビリティの利点を簡単に活かすことができます。

MXNetは、一方で、自身の深層学習アルゴリズムを実装し始めるために必要な、高度に最適化されスケーラブルなビルディングブロックを豊富に提供しています。これによって巨大なニューラルネットワークモデルを必要とする問題を解決するだけでなく、Amazon EC2の無制限の計算リソースをつなげることで繰り返しの時間を削減することもできます。

AWS Batchが皆さんの代わりにリソースを管理してくれるので、ハイパーパラメータの最適化のために数十、数百の検索を並列で実行して、問題に最適なモデルパラータを探すといったワークロードの実装を簡単に行うことができます。さらに、ジョブはDockerコンテナの中で実行されるので、必要に応じて最適なツールとライブラリを選択し、Dockerイメージをビルドし、好きなイメージを使ってジョブを登録することができます。

ご自身の手でこれを試してみることをおすすめします。そして感想をぜひ教えて下さい!

原文: Deep Learning on AWS Batch (翻訳: SA岩永)

AWSでの疎結合データセットの適合、検索、分析

あなたは刺激的な仮説を思いつきました。そして今、あなたは、それを証明する(あるいは反論する)ためにできるだけ多くのデータを見つけて分析したいと思っています。適用可能な多くのデータセットがありますが、それらは異なる人によって異なる時間に作成され、共通の標準形式に準拠していません。異なるものを意味する変数に対して同じ名前を、同じものを意味する変数に対して異なる名前を使用しています。異なる測定単位と異なるカテゴリを使用しています。あるものは他のものより多くの変数を持っています。そして、それらはすべてデータ品質の問題を抱えています(例えば、日時が間違っている、地理座標が間違っているなど)。
最初に、これらのデータセットを適合させ、同じことを意味する変数を識別し、これらの変数が同じ名前と単位を持つことを確認する方法が必要です。無効なデータでレコードをクリーンアップまたは削除する必要もあります。
データセットが適合したら、データを検索して、興味のあるデータセットを見つける必要があります。それらのすべてにあなたの仮説に関連するレコードがあるわけではありませんので、いくつかの重要な変数に絞り込んでデータセットを絞り込み、十分に一致するレコードが含まれていることを確認する必要があります。
関心のあるデータセットを特定したら、そのデータにカスタム分析を実行して仮説を証明し、美しいビジュアライゼーションを作成して世界と共有することができます。
このブログ記事では、これらの問題を解決する方法を示すサンプルアプリケーションについて説明します。サンプルアプリケーションをインストールすると、次のようになります。

  • 異なる3つのデータセットを適合させて索引付けし、検索可能にします。
  • 事前分析を行い、関連するデータセットを見つけるために、データセットを検索するための、データ駆動のカスタマイズ可能なUIを提示します。
  • Amazon AthenaAmazon QuickSightとの統合により、カスタム解析やビジュアライゼーションが可能です

(more…)

タスクIAMロールとパラメータストアを利用したAmazon ECSアプリケーションの秘密情報管理

同僚のStas Vonholskyが、Amazon ECSアプリケーションの秘密情報管理に関する素晴らしいブログを寄稿してくれました。

—–

コンテナ化されたアプリケーションとマイクロサービス指向のアーキテクチャが普及するにつれて、アプリケーションデータベースにアクセスするためのパスワードなどの秘密情報を管理することは、より困難かつ重要になっています。

いくつか課題の例を挙げます:

  • dev、test、prodなどのさまざまなアクセスパターンをコンテナ環境全体でサポートしたい
  • ホストレベルではなくコンテナ/アプリケーションレベルで秘密情報へのアクセスを隔離したい
  • サービスとしても、他サービスのクライアントとしても、アクセスが必要である疎結合なサービスが複数存在する

この記事では、Amazon ECS上で動作するコンテナアプリケーションの秘密情報管理をサポートする、新しくリリースされた機能に焦点を当てています。同僚のMatthew McCleanもAWSセキュリティブログに、S3とDockerを使用してECSベースのアプリケーションの秘密情報を管理する方法についての素晴らしい記事を公開しています。この記事では、コンテナパラメータ変数を使って秘密情報を受け渡し/保存する際の制限について説明しています。

多くの秘密情報管理ツールは、次のような機能を提供しています。

  • 高セキュアなストレージシステム
  • 集中管理機能
  • セキュアな認証と認証メカニズム
  • 鍵管理および暗号化プロバイダとの統合
  • アクセスのための安全な導入メカニズム
  • 監査
  • 秘密情報のローテーションと失効

Amazon EC2 Systems Manager パラメータストア

パラメータストアは、Amazon EC2 Systems Managerの1機能です。秘密情報のための集中化/暗号化されたデータストアを提供し、Run CommandやステートマネージャーなどのSystems Managerの他の機能と組み合わせることで多くの利点をもたらします。このサービスはフルマネージドで、高い可用性・セキュリティを持っています。

System Manager API、AWS CLI、およびAWS SDKを使用してパラメータストアにアクセスできるため、汎用の秘密情報管理ストアとして使用することができます。秘密情報は簡単にローテートしたり取り消したりすることができます。パラメータストアはAWS Key Management Service (KMS)と統合されているため、デフォルトまたはカスタムのKMSキーを使用して特定のパラメータを暗号化できます。 KMSキーをインポートすることで、独自のキーを使用して機密データを暗号化することも可能です。

パラメータストアへのアクセスはIAMポリシーによって実現にされ、リソースレベルのアクセス許可をサポートします。特定のパラメータまたは名前空間にアクセス権を持つIAMポリシーを使用して、これらのパラメータへのアクセスを制限することができます。 CloudTrailログを有効にすると、パラメータへのアクセスを記録することも可能です。

Amazon S3も上記の機能の多くを持つので、集約秘密情報ストアの実装にも使用できますが、パラメータストアにはさらに次のような利点があります。

  • アプリケーションライフサイクルのさまざまなステージをサポートするためのネームスペースを簡単に作成できる
  • インスタンスまたはコンテナからKMSキーにアクセスし、ローカルメモリ内で復号化を実行することで、アプリケーションからパラメータの暗号化を抽象化するKMS統合機能を提供する
  • パラメータの変更履歴を保管できる
  • 他の多くのアプリケーションで使用されるS3とは別に制御できる
  • 複数システムを実装する際のオーバーヘッドを削減する構成情報ストアとなる
  • 使用料がかからない

注:本記事の公開時点では、Systems ManagerはVPCプライベートエンドポイント機能をサポートしていません。プライベートVPCからのパラメータストアエンドポイントへのより厳密なアクセスを強制するには、限られたIPアドレスセットからのみにアクセスを制限するIAMポリシーConditionとともに、Elastic IPアドレスを持つNATゲートウェイを使用します。

タスクIAMロール

Amazon ECSタスク用のIAMロールを使用すると、タスク内のコンテナが使用するIAMロールを指定することができます。 AWSサービスと対話するアプリケーションは、AWSクレデンシャルでAPIリクエストに署名する必要があります。ECSタスクIAMロールは、Amazon EC2インスタンスプロファイルがEC2インスタンスにクレデンシャルを提供するのと同じように、コンテナアプリケーションのクレデンシャルを管理する方法を提供します。

AWSクレデンシャルを作成してコンテナに配布したり、EC2インスタンスロールを使用する代わりに、IAMロールをECSタスク定義またはRunTask API操作に関連付けることができます。詳細については、IAM Roles for Tasksを参照してください。

タスク用のIAMロールを利用することで、集約パラメータストアを使用してアプリケーションまたはコンテナを安全に導入および認証することができます。秘密情報管理機能へのアクセスには、次のような機能が含まれている必要があります。

  • 使用されたクレデンシャルのTTL制限
  • きめ細やかな認可ポリシー
  • リクエストを追跡するためのIDのログ保存
  • デプロイされたコンテナまたはタスクと関連するアクセス権との間をマッピングできるスケジューラの統合サポート

タスクIAMロールは、ロールが定義されているコンテナ内からのみロールクレデンシャルにアクセスできるため、これらのユースケースをうまくサポートします。このロールは一時的なクレデンシャルを提供し、これらは自動的にローテーションされます。IAMポリシーは、送信元インスタンス、送信元IPアドレス、時刻などのオプション条件をサポートされています。

ソースとなるIAMロールは、一意のAmazonリソースネームに基いてCloudTrailログで識別でき、アクセス許可はいつでもIAM APIまたはコンソールで取り消すことができます。パラメータストアはリソースレベルの権限をサポートするため、特定のキーと名前空間へのアクセスを制限するポリシーを作成できます。

動的な環境の関連付け

多くの場合、環境を移動する際にもコンテナイメージは変更されず、イミュータブルなデプロイメントと結果再現性を保証します。変更されうるものは構成情報、この文脈では具体的には秘密情報です。たとえば、データベースとそのパスワードは、ステージング環境と本番環境で異なる場合があります。正しい秘密情報を取得するためにどのようにアプリケーションを指定すればよいでしょうか?

1つのオプションは、環境変数として環境タイプをコンテナに渡すことです。次に、アプリケーションは環境タイプ(prod、testなど)を相対キーパスに連結し、関連する秘密情報を取得します。ほとんどの場合、この方法では多数の独立したECSタスク定義が生まれてしまいます。

IAMロールは、“environment type”などの単一のCloudFormationパラメータで、パラメータストア、KMSキーおよび環境プロパティへのアクセスを提供します。

このアプローチを利用することで、一般的なCloudFormationテンプレートに基づいた単一のタスク定義をサポートすることができます。

ウォークスルー:タスクIAMロールを使用してパラメータストアリソースに安全にアクセスする

このウォークスルーはNorth Virginiaリージョン(us-east-1)向けに構成されています。同じリージョンを使って試すことをお勧めします。

Step 1: KMSキーとパラメータを作成する

最初に、既定のセキュリティポリシーを使用して、いくつかのパラメータを暗号化するためのKMSキーを作成します。

  • prod-app1  –  app1の秘密情報を暗号化するために使用されます
  • license-key  – ライセンス関連の秘密情報を暗号化するために使用されます
aws kms create-key --description prod-app1 --region us-east-1
aws kms create-key --description license-code --region us-east-1

両方のコマンドの出力のKeyIdプロパティを確認してください。ウォークスルー全体でKMSキーを識別するために使用します。

次のコマンドで、パラメータストアに3つのパラメータを作成します。

  • prod.app1.db-pass(prod-app1 KMSキーで暗号化)
  • general.license-code(license-key KMSキーで暗号化)
  • prod.app2.user-name(暗号化されていない標準文字列として保存)
aws ssm put-parameter --name prod.app1.db-pass --value "AAAAAAAAAAA" --type SecureString --key-id "<key-id-for-prod-app1-key>" --region us-east-1
aws ssm put-parameter --name general.license-code --value "CCCCCCCCCCC" --type SecureString --key-id "<key-id-for-license-code-key>" --region us-east-1
aws ssm put-parameter --name prod.app2.user-name --value "BBBBBBBBBBB" --type String --region us-east-1

Step 2: IAMロールとポリシーを作成する

ここで、後で作成するECSタスクと関連付けるロールとIAMポリシーを作成します。

IAMロールの信頼ポリシーは、ecs-tasksエンティティがロールを引き受けることを許可する必要があります。

{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Sid": "",
       "Effect": "Allow",
       "Principal": {
         "Service": "ecs-tasks.amazonaws.com"
       },
       "Action": "sts:AssumeRole"
     }
   ]
 }

上記のポリシーを、ecs-tasks-trust-policy.jsonという名前のファイルとしてローカルディレクトリに保存します。

aws iam create-role --role-name prod-app1 --assume-role-policy-document file://ecs-tasks-trust-policy.json

次のポリシーはロールにアタッチされ、後でapp1コンテナに関連付けられます。 prod.app1.*という名前空間パラメータおよびライセンスコードパラメータへのアクセスと、prod.app1.db-passパラメータを復号化するために必要な暗号化キーへのアクセスが許可されています。名前空間リソースのパーミッション構造は、さまざまな階層を構築するのに便利です(環境、アプリケーションなどに基づいています)。

次のポリシーの<key-id-for-prod-app1-key>を関連するKMSキーのキーIDに、<account-id>をあなたのアカウントIDに置き換えてください。

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Effect": "Allow",
             "Action": [
                 "ssm:DescribeParameters"
             ],
             "Resource": "*"
         },
         {
             "Sid": "Stmt1482841904000",
             "Effect": "Allow",
             "Action": [
                 "ssm:GetParameters"
             ],
             "Resource": [
                 "arn:aws:ssm:us-east-1:<account-id>:parameter/prod.app1.*",
                 "arn:aws:ssm:us-east-1:<account-id>:parameter/general.license-code"
             ]
         },
         {
             "Sid": "Stmt1482841948000",
             "Effect": "Allow",
             "Action": [
                 "kms:Decrypt"
             ],
             "Resource": [
                 "arn:aws:kms:us-east-1:<account-id>:key/<key-id-for-prod-app1-key>"
             ]
         }
     ]
 }

上記のポリシーを、app1-secret-access.jsonという名前のファイルとしてローカルディレクトリに保存します。

aws iam create-policy --policy-name prod-app1 --policy-document file://app1-secret-access.json

次のコマンドの<account-id>はあなたのアカウントIDに置き換えてください:

aws iam attach-role-policy --role-name prod-app1 --policy-arn "arn:aws:iam::<account-id>:policy/prod-app1"

Step 3:S3バケットにテストスクリプトを追加する

以下のスクリプトファイルを作成し、access-test.shという名前をつけてアカウントのS3バケットに追加します。オブジェクトがパブリックアクセス可能であることを確認し、オブジェクトリンクを書き留めておいてください。

例えば、https://s3-eu-west-1.amazonaws.com/my-new-blog-bucket/access-test.shのようになります。

#!/bin/bash
#This is simple bash script that is used to test access to the EC2 Parameter store.
# Install the AWS CLI
apt-get -y install python2.7 curl
curl -O https://bootstrap.pypa.io/get-pip.py
python2.7 get-pip.py
pip install awscli
# Getting region
EC2_AVAIL_ZONE=`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`
EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\([0-9][0-9]*\)[a-z]*\$:\\1:'`"
# Trying to retrieve parameters from the EC2 Parameter Store
APP1_WITH_ENCRYPTION=`aws ssm get-parameters --names prod.app1.db-pass --with-decryption --region $EC2_REGION --output text 2>&1`
APP1_WITHOUT_ENCRYPTION=`aws ssm get-parameters --names prod.app1.db-pass --no-with-decryption --region $EC2_REGION --output text 2>&1`
LICENSE_WITH_ENCRYPTION=`aws ssm get-parameters --names general.license-code --with-decryption --region $EC2_REGION --output text 2>&1`
LICENSE_WITHOUT_ENCRYPTION=`aws ssm get-parameters --names general.license-code --no-with-decryption --region $EC2_REGION --output text 2>&1`
APP2_WITHOUT_ENCRYPTION=`aws ssm get-parameters --names prod.app2.user-name --no-with-decryption --region $EC2_REGION --output text 2>&1`
# The nginx server is started after the script is invoked, preparing folder for HTML.
if [ ! -d /usr/share/nginx/html/ ]; then
mkdir -p /usr/share/nginx/html/;
fi
chmod 755 /usr/share/nginx/html/
# Creating an HTML file to be accessed at http://<public-instance-DNS-name>/ecs.html
cat > /usr/share/nginx/html/ecs.html <<EOF
<!DOCTYPE html>
<html>
<head>
<title>App1</title>
<style>
body {padding: 20px;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
code {white-space: pre-wrap;}
result {background: hsl(220, 80%, 90%);}
</style>
</head>
<body>
<h1>Hi there!</h1>
<p style="padding-bottom: 0.8cm;">Following are the results of different access attempts as expirienced by "App1".</p>
<p><b>Access to prod.app1.db-pass:</b><br/>
<pre><code>aws ssm get-parameters --names prod.app1.db-pass --with-decryption</code><br/>
<code><result>$APP1_WITH_ENCRYPTION</result></code><br/>
<code>aws ssm get-parameters --names prod.app1.db-pass --no-with-decryption</code><br/>
<code><result>$APP1_WITHOUT_ENCRYPTION</result></code></pre><br/>
</p>
<p><b>Access to general.license-code:</b><br/>
<pre><code>aws ssm get-parameters --names general.license-code --with-decryption</code><br/>
<code><result>$LICENSE_WITH_ENCRYPTION</result></code><br/>
<code>aws ssm get-parameters --names general.license-code --no-with-decryption</code><br/>
<code><result>$LICENSE_WITHOUT_ENCRYPTION</result></code></pre><br/>
</p>
<p><b>Access to prod.app2.user-name:</b><br/>
<pre><code>aws ssm get-parameters --names prod.app2.user-name --no-with-decryption</code><br/>
<code><result>$APP2_WITHOUT_ENCRYPTION</result></code><br/>
</p>
<p><em>Thanks for visiting</em></p>
</body>
</html>
EOF

Step 4:テストクラスタを作成する

最新のECS AMIとECSエージェントを持つ新しいECSテストクラスタを作成することをお勧めします。次のフィールド値を使用します。

  • クラスタ名:access-test
  • EC2インスタンスタイプ:t2.micro
  • インスタンス数:1
  • キーペア:インスタンスにSSHして実行中のコンテナを操作したい場合を除き、EC2キーペアは必要ありません。
  • VPC:デフォルトVPCを選択します。わからない場合は、Amazon VPCコンソールで172.31.0.0/16のIPレンジのVPCのIDを探してください。
  • サブネット:デフォルトVPC内のサブネットを選択します。
  • セキュリティグループ:CIDRブロック0.0.0.0/0からのポート80のインバウンドアクセス用の新しいセキュリティグループを作成します。

他のフィールドはデフォルト設定のままにします。

パブリックNGINXコンテナとapp1用に作成したロールに依存するシンプルなタスク定義を作成します。利用可能なコンテナリソースやポートマッピングなどのプロパティを指定します。commandオプションは、コンテナにテストスクリプトのダウンロードおよび実行に利用されます。このテストスクリプトはAWS CLIをコンテナにインストールし、いくつかのget-parameterコマンドを実行し、結果を含むHTMLファイルを作成します。

次のコマンドの<account-id>はアカウントIDに、<your-S3-URI>はStep 3で作成したS3オブジェクトのリンクに置き換えてください。

aws ecs register-task-definition --family access-test --task-role-arn "arn:aws:iam::<account-id>:role/prod-app1" --container-definitions name="access-test",image="nginx",portMappings="[{containerPort=80,hostPort=80,protocol=tcp}]",readonlyRootFilesystem=false,cpu=512,memory=490,essential=true,entryPoint="sh,-c",command="\"/bin/sh -c \\\"apt-get update ; apt-get -y install curl ; curl -O <your-S3-URI> ; chmod +x access-test.sh ; ./access-test.sh ; nginx -g 'daemon off;'\\\"\"" --region us-east-1
aws ecs run-task --cluster access-test --task-definition access-test --count 1 --region us-east-1

アクセスの確認

タスクが実行状態になったら、インスタンスのパブリックDNS名を確認し、次のページに移動します。

http://<ec2-instance-public-DNS-name>/ecs.html

コンテナからアクセステストを実行した結果が表示されます。

テスト結果がすぐに表示されない場合は、数秒待ってからページを更新してください。

ポート80のインバウンドトラフィックがインスタンスにアタッチされたセキュリティグループで許可されていることを確認してください。

静的HTMLページに表示される結果は、コンテナから次のコマンドを実行する場合と同じものになります。

prod.app1.key1

aws ssm get-parameters --names prod.app1.db-pass --with-decryption --region us-east-1
aws ssm get-parameters --names prod.app1.db-pass --no-with-decryption --region us-east-1

必要なKMSキーとパラメータにアクセスできるポリシーがあるため、この2つのコマンドはどちらも実行可能なはずです。

general.license-code

aws ssm get-parameters --names general.license-code --no-with-decryption --region us-east-1
aws ssm get-parameters --names general.license-code --with-decryption --region us-east-1

“no-with-decryption”パラメータを持つ最初のコマンドだけが動作するはずです。指定したポリシーでは、パラメータストアのパラメータへのアクセスは許可されていますが、KMSキーへのアクセスは許可されていません。 2番目のコマンドは、アクセス拒否エラーで失敗するはずです。

prod.app2.user-name

aws ssm get-parameters --names prod.app2.user-name –no-with-decryption --region us-east-1

prod.app2の名前空間に関連付けられている権限がないため、このコマンドはアクセス拒否エラーで失敗するはずです。

仕上げ

料金が発生しないように、すべてのリソース(KMSキーやEC2インスタンスなど)を削除することを忘れないでください。

まとめ

集約秘密情報管理は、コンテナ化された環境のセキュリティにとって重要な機能です。

ユーザーは、パラメータストアとタスクIAMロールを使用することで、アプリケーションが必要なキーのみにアクセスすることができるKMSキーと統合されたアクセスレイヤーおよび集約秘密情報ストアを構築することができます。

秘密情報管理レイヤはパラメータストア、Amazon S3、Amazon DynamoDB、またはVaultやKeyWhizなど、どんなソリューションで実装されている場合でも、秘密情報の管理・アクセスのプロセスに不可欠なものです。

(翻訳はSA千葉が担当しました。原文はこちらです。)