ようへいの日々精進XP

よかろうもん

JAWS-UG 福岡「また濃い目にAWSの話をしてみよう」でデモは本番で必ず失敗するという教訓を得た

追記:登壇前のルーティーン


tl;dr

久し振りの JAWS-UG でお話をさせて頂いたのと、サーバーレスアーキテクチャの実例を学んだのと、付け焼き刃のデモはだいたい本番で失敗するという教訓を得たのでメモ。

jaws-ug-kyushu.doorkeeper.jp

参加された皆さん、大変お疲れ様でした。有難うございました!


資料

月額10円から作るServerLess Website(森田さん)

SESとLambdaでメールをSlackに通知してみよう(木村さん)

Visual StudioAWS開発してみよう(藤崎さん)

Serverlessでサイト監視(安土さん)

LT:AWSで自作CGIをサーバレス実装してみた ~その2~(夏目さん)

www.slideshare.net

LT:AWS x MLB(松村さん)

www.slideshare.net

Amazon ECS & Amazon ECR 試行錯誤(かっぱ)


ハイライト

参加者の半分以上が何かしら登壇する参加型勉強会

今回、参加者(15 人位だったかな...)の半分以上が何らかの形で登壇するという全員参加型の勉強会となった。こんなに話をする人がいる勉強会って珍しいし、色々な方の多種多様な AWS への関わり方だったり、身近なトピックスを聞くことが出来てとても良い勉強会になったと思う。

サーバレスアーキテクチャ + Lambda

この 2 ワードがホットキーワードだった。このワードを聞かない発表は無かったので時流を反映した貴重な発表ばかりだった。

Serverless というフレームワークを聞いたのも初めてだったし、チャットツール全盛とはいえ、業務内でメールは未だに必要なツールであることは間違いないけど、そのメールを Lambda や SES を利用して Slack で捕捉するという発想は無かったなあ。

月額 10 円と言えば、S3 がすぐに思いつくけど、S3 以外の各種サービスの特徴を色々と抑えた上で組み合わせることにより、ちょっとした動的サイトあれば低コストで構築出来るなんて素晴らしい!

Visual Studio すげえ

この手のツールとは無縁だったけど、IDE ツールから AWS のサービスリソースが弄ることが出来るのはスゴイなあと思った。

付け焼き刃のデモは必ず失敗する

Locust のスレーブノードコンテナを ECS 上で増殖されるデモが見事に失敗したので、改めて動画でアップする。

www.youtube.com

ということで、付け焼き刃のデモは必ず失敗するので仕込みは重要ということを痛感した。


ということで...

参加された皆さん、大変お疲れ様でした!

次は何を話せるかなあ。

ecs-cli チュートリアル(2)~ ECR のコンテナイメージを利用する ~

ども、かっぱです。

tl;dr

以前から気になっていた ecs-cli から ECR のコンテナイメージをどうやって使うのか。実際にやってみたら難しくなかったけど念のためにメモっておきます。


memo

試した環境

  • 構築した環境

f:id:inokara:20160227160757p:plain

  • ecs-cli を叩く環境
i$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"

$ ecs-cli --version
ecs-cli version 0.2.1 (e7b6965)

教材

github.com

拙作の pm25.test.inokara.com で提供されている JSON データを S3 から取得してクライアントに返すだけの API サーバーっぽいの。

ECR にコンテナイメージを push するまで

#
# docker-compose build でコンテナイメージをビルドする
#
$ docker-compose build

#
# aws cli で ECR にログインする為のパスワードを取得
#
$ aws --region us-east-1 ecr get-login

#
# docker login でログイン
#
$ docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com

#
# aws cli でリポジトリを作成
#
$ aws --region us-east-1 ecr create-repository --repository-name oreno-pm25-api

#
# ビルドしたイメージにタグを付与
#
$ docker tag orenopm25api_web_1 xxxxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-pm25-api

#
# タグを付与したイメージを ECR に push
#
$ docker push xxxxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-pm25-api

以上。

docker-compose.yml

ECS 用に docker-compose.yml を作成する。

redis:
  image: redis
  cpu_shares: 100
  mem_limit: 67108864
  ports:
    - "6379"

web:
  image: xxxxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-pm25-api
  cpu_shares: 100
  mem_limit: 268435456
  volumes:
    - /tmp/nginx/:/var/log/nginx
  ports:
    - "80:80"
    - "4567:4567"
  links:
    - redis
  environment:
    - REDIS_HOST=redis

redis コンテナは Docker オフィシャルの Redis イメージを利用する。web コンテナは先ほど ECR に push したイメージを利用する。この YAML ファイルを ecs.yml という名前で保存しておく。(ファイル名は任意で OK 牧場)

ecs-cliクラスタ作成、ECS インスタンスの起動

#
# クラスタの初期設定
#
$ ecs-cli configure --region ap-northeast-1 --cluster oreno-pm25-api

#
# 実行すると以下のようなファイルが生成される
#
$ cat ~/.ecs/config
[ecs]
cluster = oreno-pm25-api
aws_profile =
region = ap-northeast-1
aws_access_key_id =
aws_secret_access_key =

#
# ECS インスタンスの起動
#
$ ecs-cli up --keypair xxxxxxxxxxxxxxxxxxx \
  --capability-iam \
  --size 1 \
  --vpc vpc-xxxxxxxx \
  --instance-type t2.micro \
  --subnets subnet-xxxxxxxx,subnet-zzzzzzzz \
  --azs ap-northeast-1a,ap-northeast-1c

(以下のように出力される)

INFO[0000] Created cluster                               cluster=oreno-pm25-api
INFO[0001] Waiting for your cluster resources to be created
INFO[0002] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0062] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0122] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0183] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0243] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0304] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS

ecs-cli compose up

準備は整ったのでコンテナを起動する。

$ ecs-cli compose -f ecs.yml up

(以下のように出力される)

ERRO[0000] Error describing task definition              error=ClientException: Unable to describe task definition.
        status code: 400, request id: 6c010388-dd17-11e5-bb49-531dd1d03f3f taskDefinitionName=ecscompose-oreno-pm25-api
INFO[0000] Using ECS task definition                     TaskDefinition=ecscompose-oreno-pm25-api:1
INFO[0000] Starting container...                         container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/redis
INFO[0000] Starting container...                         container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/web
INFO[0000] Describe ECS container status                 container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/redis desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-oreno-pm25-api:1
INFO[0000] Describe ECS container status                 container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/web desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-oreno-pm25-api:1
snip...
INFO[0097] Started container...                          container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/redis desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-oreno-pm25-api:1
INFO[0097] Started container...                          container=xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/web desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-oreno-pm25-api:1

それぞれのコンテナが起動したようだ。

ecs-cli compose ps

コンテナの状態を確認してみる。

$ ecs-cli compose -f ecs.yml ps
Name                                        State    Ports                                                 TaskDefinition
xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/redis  RUNNING  xx.xxx.x.xxx:32768->6379/tcp                          ecscompose-oreno-pm25-api:1
xxxxxxxx-0a0a-4871-a644-zzzzzzzzzz/web    RUNNING  xx.xxx.x.xxx:4567->4567/tcp, xx.xxx.x.xxx:80->80/tcp  ecscompose-oreno-pm25-api:1

おけ。どうやらコンテナは正常に起動している。

アプリケーションの確認

デプロイ済みのなんちゃってアプリケーションの動作確認。

$ curl -s 'xx.xxx.x.xxx/json?date=20160224&station_code=40202010' | jq .
{
  "time_series": {
    "24": 3,
    "23": 3,
    "22": 1,
    "21": 7,
    "20": 9,
    "19": 15,
    "18": 13,
    "17": 17,
    "08": 13,
    "07": 21,
    "06": 20,
    "05": 18,
    "04": 15,
    "03": 17,
    "02": 21,
    "01": 20,
    "09": 11,
    "10": 14,
    "11": 17,
    "12": 21,
    "13": 24,
    "14": 23,
    "15": 22,
    "16": 19
  },
  "check_date": "20160224",
  "check_station_code": "40202010",
  "check_station": "国設大牟田"
}

一応、それっぽい JSON のレスポンスが得られた。

後片付け

$ ecs-cli down --force
INFO[0001] Waiting for your cluster resources to be deleted
INFO[0001] Cloudformation stack status                   stackStatus=DELETE_IN_PROGRESS
INFO[0062] Cloudformation stack status                   stackStatus=DELETE_IN_PROGRESS
INFO[0122] Deleted cluster                               cluster=oreno-pm25-api

ecs-cli down --force で一発。


以上

ecs-cli から ECR が使えたのはなんでだろう

ECS インスタンスの起動時に --capability-iam を付与することで以下の IAM ポリシーがコンテナインスタンスに付与されている為に利用できるのかしら。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:Submit*",
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage"
      ],
      "Resource": "*"
    }
  ]
}

なるほど。

ちなみに、上記のポリシーは Managed Policy の AmazonEC2ContainerServiceforEC2Role で適用される。

思ったより簡単だったけど...

  • ECR は東京リージョンにいつくるだんろう...
  • pm25.test.inokara.com をちゃんと作り直したい

手作業で構築した AWS リソースの管理には awspec が良いと思ったのでメモ

tl;dr

手作業で構築した AWS リソースの管理には以前から気になっていた awspec が良いと思ったのでメモ。

二台、三台のインスタンスなら...とうっかりと手作業で構築したインスタンスや、どんな設定で作ったか判らないけど、なんとなく利用されている S3 Bucket の管理をどうしようかなと思っていたら awspec の generate コマンドがリソース情報を生成してくれるので試してみた。


参考

github.com

qiita.com


memo

インストール

$ cat Gemfile
source "https://rubygems.org"

gem 'awspec'
gem 'rake'

$ bundle

初期化

$ bundle exec awspec init
 + spec/
 + spec/spec_helper.rb
 + Rakefile
 + spec/.gitignore
 + .rspec

awspec generate

以下のようにサポートされているリソースであれば各リソースの情報を利用してテストを生成してくれるという有り難い機能。

$ bundle exec awspec generate
Commands:
  awspec generate cloudwatch_alarm                    # Generate cloudwatch_alarm spec
  awspec generate directconnect                       # Generate directconnect spec
  awspec generate ebs                                 # Generate attached ebs spec
  awspec generate ec2 [vpc_id]                        # Generate ec2 spec from VPC ID (or VPC "Name" tag)
  awspec generate elb [vpc_id]                        # Generate elb spec from VPC ID (or VPC "Name" tag)
  awspec generate help [COMMAND]                      # Describe subcommands or one specific subcommand
  awspec generate iam_policy                          # Generate attached iam_policy spec
  awspec generate nat_gateway [vpc_id]                # Generate nat_gateway spec from VPC ID (or VPC "Name" tag)
  awspec generate network_acl [vpc_id]                # Generate network_acl spec from VPC ID (or VPC "Name" tag)
  awspec generate rds [vpc_id]                        # Generate rds spec from VPC ID (or VPC "Name" tag)
  awspec generate route53_hosted_zone [example.com.]  # Generate route53_hosted_zone spec from Domain name
  awspec generate route_table [vpc_id]                # Generate route_table spec from VPC ID (or VPC "Name" tag)
  awspec generate s3_bucket [backet_name]             # Generate s3_bucket spec from S3 bucket name. if NO args, Generate all.
  awspec generate security_group [vpc_id]             # Generate security_group spec from VPC ID (or VPC "Name" tag)
  awspec generate subnet [vpc_id]                     # Generate subnet spec from VPC ID (or VPC "Name" tag)
  awspec generate vpc [vpc_id]                        # Generate vpc spec from VPC ID (or VPC "Name" tag)

Options:
  [--profile=PROFILE] 

EC2 の情報を生成する

以下のように generate コマンドを利用して vpc-xxxxxxxx 内の EC2 情報を生成してみる。

$ echo "require 'spec_helper'" > spec/ec2_spec.rb
$ bundle exec awspec generate ec2 vpc-xxxxxxxx >> spec/ec2_spec.rb

以下のような内容が出力される。

require 'spec_helper'
describe ec2('oreno-instance01') do
  it { should exist }
  it { should be_stopped }
  its(:instance_id) { should eq 'i-xxxxxxxxx' }
  its(:image_id) { should eq 'ami-xxxxxxxx' }
  its(:private_dns_name) { should eq 'ip-10-0-x-xxx.ap-northeast-1.compute.internal' }
  its(:public_dns_name) { should eq '' }
  its(:instance_type) { should eq 't1.micro' }
  its(:private_ip_address) { should eq '10.0.x.xxx' }
  it { should have_security_group('test') }
  it { should belong_to_vpc('vpc-xxxxxxxx') }
  it { should belong_to_subnet('subnet-xxxxxxxxxxx') }
  it { should have_ebs('vol-xxxxxxxxxx') }
end

生成された情報を元にテストしてみる。

$ bundle exec rake spec

以下のように出力される。

f:id:inokara:20160221112941p:plain

おお。

このバケットってどんな設定だっけ

S3 バケットの設定も生成しておく。

$ echo "require 'spec_helper'" > spec/s3_bucket_spec.rb
$ bundle exec awspec generate s3 inokara-sandbox >> spec/s3_bucket_spec.rb

以下のように生成される。

$ cat spec/s3_bucket_spec.rb 
require 'spec_helper'
describe s3_bucket('inokara-sandbox') do
  it { should exist }
  its(:acl_owner) { should eq 'xxxxxxxxx' }
  its(:acl_grants_count) { should eq 1 }
  it { should have_acl_grant(grantee: 'xxxxxxxx', permission: 'FULL_CONTROL') }
end

テストしてみる。

f:id:inokara:20160221120110p:plain

VPC の設定も見てみよう

VPC の設定も生成しておく。

$ echo "require 'spec_helper'" > spec/vpc_spec.rb
$ bundle exec awspec generate vpc vpc-xxxxxxxx >> spec/vpc_spec.rb

以下のように生成される。

$ cat spec/vpc_spec.rb 
require 'spec_helper'
describe vpc('vpc-xxxxxxxxx') do
  it { should exist }
  it { should be_available }
  its(:vpc_id) { should eq 'vpc-xxxxxxxxx' }
  its(:cidr_block) { should eq '10.0.0.0/16' }
  it { should have_route_table('rtb-xxxxxxxxx') }
  it { should have_route_table('rtb-xxxxxxxxx') }
  it { should have_network_acl('acl-xxxxxxxxx') }
end

テストしてみる。

f:id:inokara:20160221120122p:plain


最後に

generate がとても有り難い

手作業で構築した AWS リソースは generate コマンドを利用してリソースをコードに吐き出すことでテキストベースで管理出来るのが嬉しい。手で修正を加えたら generate で吐き出すような運用をすれば良さそう。(generate で吐き出すのを忘れる可能性が...)

ということで

構築前にテストを書いて、構築後のチェックで利用という側面もあると思うが、手作業で構築したリソースの資産管理として awspec を使っていきたいと思った。

以上。

Windows Server 上の各種ログを CloudWatch Logs に送信するメモ

ども、初老丸です。

tl;dr

Windows Server 上のイベントログや IIS のログって CloudWatch Logs にどうやって送るのかしらと思って調べて試したメモ。


参考


メモ

構成図

f:id:inokara:20160211003810p:plain

ざっくり手順

  1. 適切なポリシーを EC2 にアタッチ済みの IAM role にアタッチする(既に IAM role がアタッチされている前提)
  2. EC2Config サービスにて CloudWatch Logs integration を有効にする
  3. AWS.EC2.Windows.CloudWatch.json を修正
  4. EC2Config サービスの再起動

以下のようなポリシーを EC2 にアタッチ済みの IAM role にアタッチする

  • AmazonEC2RoleforSSM
  • CloudWatch Logs に対する以下のポリシー(Managed Policy の CloudWatchFullAccess でも良いと思う)
{
    "Version": "2012-10-17",
    "Statement": [[f:id:inokara:20160210231534p:plain]
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*"
            ]
        }
    ]
}

EC2Config サービスの設定変更

スタートメニューから All apps に遷移して EC2ConfigService Setting を起動する。

f:id:inokara:20160210231348p:plain

起動したら Enable CloudWatch Logs integration をチェックする。

f:id:inokara:20160210231534p:plain

チェックして Apply 又は OK でウィンドウを閉じる。

AWS.EC2.Windows.CloudWatch.json の修正

C:\Program Files\Amazon\Ec2ConfigService\Settings\AWS.EC2.Windows.CloudWatch.json を適当なエディタで開いて修正する。今回の要件を改めて整理すると...

  • IIS のログを取得する
  • IIS のログを 2 つのログストリームに転送する

この要件を満たす設定は以下の通り。(ポイントは // でコメントを付ける)

(snip)
             // IIS の Log の転送定義
             // 
             // - TimestampFormat を IIS のログに合わせて定義する
             // - Encoding を定義する
             //
            {
                "Id": "IISLog",
                "FullName": "AWS.EC2.Windows.CloudWatch.IisLog.IisLogInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "LogDirectoryPath": "C:\\inetpub\\logs\\LogFiles\\W3SVC1",
                    "TimestampFormat": "yyyy-MM-dd HH:mm:ss",
                    "Encoding": "UTF-8"
                }
            },
(snip)
             // 転送先定義
             //
             // - IAM role が適用されていなければ AccessKey や SecretKey を適宜設定する
             // - CloudWatch Logs の Region を定義
             // - LogGroup と Log Stream を定義する
             //
            {
                "Id": "CloudWatchLogs",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "ap-northeast-1",
                    "LogGroup": "Default-Log-Group",
                    "LogStream": "{instance_id}"
                }
            },

            // 転送先定義
             //
             // - IAM role が適用されていなければ AccessKey や SecretKey を適宜設定する
             // - CloudWatch Logs の Region を定義
             // - LogGroup と Log Stream を定義する
             //
            {
                "Id": "CloudWatchLogs02",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "ap-northeast-1",
                    "LogGroup": "Default-Log-Group",
                    "LogStream": "{instance_id}-02"
                }
            },
(snip)

そして... このエージェントが収集したログをどこに(LogGroup / LogStream)転送するかを以下のように Flow セクションで定義する。 Flow セクション自体は CloudWatch Logs だけではなく CloudWatch でも収集したパフォーマンスカウンタのメトリクスをどこの Namespace に転送するかも定義する。

        "Flows": {
            "Flows": 
            [
                "IISLog, (CloudWatchLogs, CloudWatchLogs02)"
            ]
        }

上記の定義だと、ID: IISLog に定義されたログは ID: CloudWatchLogsID: CloudWatchLogs02 に定義された転送先に転送するということ。

少しわかりづらいので図示。

f:id:inokara:20160211003742p:plain

うむ...これでもわかり辛い。

EC2Config サービスの再起動

そして、EC2Config サービスを再起動する。

#
# 一旦、サービスを確認
#
C:\Users\Administrator>sc query | find "DISP"

(snip)

DISPLAY_NAME: Diagnostic Policy Service
DISPLAY_NAME: Ec2Config
DISPLAY_NAME: Windows Event Log

(snip)

DISPLAY_NAME: Windows Remote Management (WS-Management)
C:\Users\Administrator>

#
# Ec2Config を停止
#
C:\Users\Administrator>sc stop Ec2Config

SERVICE_NAME: Ec2Config
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 3  STOP_PENDING
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

#
# Ec2Config を開始
#
C:\Users\Administrator>sc start Ec2Config

SERVICE_NAME: Ec2Config
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 3888
        FLAGS              :

C:\Users\Administrator>

ちなみに、上記の操作はコマンドプロンプトにて実施すること。

適当にアクセスすると...

以下のように適当にアクセスして IIS にログを吐かせる。

$  curl -s -I win01-xxxxxxxxxx.ap-northeast-1.elb.amazonaws.com

しばらくすると...

f:id:inokara:20160210235241p:plain

ふむ。

ひとまずは目的達成。


以上

Windows Server 上の各種ログを CloudWatch Logs に転送する雰囲気はつかめた気がする。気がするだけかも。

(超メモ)Elastic Beanstalk で ECR の Docker イメージをデプロイするメモ

ども、かっぱです。

tl;dr

aws.typepad.com

とのことでちっくと試してみました。


メモ

引き続き教材は

github.com

引き続き Worker Tire で Cron っぽいやつをやってみます。

ひとまずは ECR に build して push

$ aws --region us-east-1 ecr create-repository --repository-name oreno-sinatra-worker
  • ECR にログインする
$ aws ecr get-login --region us-east-1
$ docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(ホントはもっと長い)xxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com
  • build する
$ docker build --no-cache=true -t oreno-sinatra-worker .
  • tag を付ける
$ docker tag -f oreno-sinatra-worker:latest xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-sinatra-worker:latest
  • push する
$ docker push xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-sinatra-worker:latest
  • push されていることを確認
$ aws --region us-east-1 ecr list-images --repository-name oreno-sinatra-worker
{
    "imageIds": [
        {
            "imageTag": "latest",
            "imageDigest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
    ]
}

Elastic Beanstalk インスタンスに適用する IAM role にポリシーを追加(1)

以下のように Elastic Beanstalk インスタンスに適用されている IAM role にマネージドポリシー(AmazonEC2ContainerRegistryReadOnly)を追加する。

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": [
            "ecr:GetAuthorizationToken",
            "ecr:BatchCheckLayerAvailability",
            "ecr:GetDownloadUrlForLayer",
            "ecr:GetRepositoryPolicy",
            "ecr:DescribeRepositories",
            "ecr:ListImages",
            "ecr:BatchGetImage"
        ],
        "Resource": "*"
    }]
}

マネージドポリシーを適用することで、今後の機能追加等で IAM ポリシーをイチイチいじる必要が無いのが嬉しい。

ECR へのログイン情報を S3 バケットにアップしておく

Elastic Beanstalk で Docker イメージを利用する際に、Docker Hub やプライベートリポジトリからイメージを取得してくることになりますが、認証情報を S3 バケットに置いておく必要があります。もちろん、ECR も同じ事が言えるので、先ほど ECR のリポジトリにログインした際に利用した認証情報を S3 バケットに保存しておきましょう。

尚、ログインの際に利用した認証情報は ~/.docker/config.json に格納されています。

$ cat ~/.docker/config.json
{
        "auths": {
                "https://xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com": {
                        "auth": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(ホントはもっと長い)xxxxxxxxxxxxxxxxxxxx",
                        "email": "none"
                }
        }

上記のファイルを S3 Bucket にアップロードしておきます。

#
# S3 Bucket を作成する
#
$ aws --region ap-northeast-1 s3 mb s3://oreno-docker-auth

#
# S3 Bucket に認証情報をアップする
#
$ aws --region ap-northeast-1 s3 cp ~/.docker/config.json s3://oreno-docker-auth/oreno-docker-auth.txt

Beanstalk インスタンスに適用する IAM role にポリシーを追加(2)

上記で作成したバケットへのアクセスも許可する必要があるので IAM role にポリシーを追加します。こちらもマネージドポリシーの AmazonS3ReadOnlyAccess をアタッチしておきました。実運用を想定する場合には適切なポリシーを与えるように検討したいところです。

Dockerrun.aws.json を修正

今回は Docker イメージを利用する為、以下のように AuthenticationImage を追記しました。

{
  "AWSEBDockerrunVersion": "1",
  "Authentication": {
    "Bucket": "oreno-docker-auth",
    "Key": "oreno-docker-auth.txt"
  },
  "Image": {
    "Name": "xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-sinatra-worker:latest",
    "Update": "true"
  },
  "Ports": [
    {
      "ContainerPort": "4567"
    }
  ],
  "Volumes": [
    {
      "HostDirectory": "/tmp",
      "ContainerDirectory": "/tmp"
    }
  ],
  "Logging": "/var/log/nginx"
}

Authentication には ECR にログインする為の認証情報を保存している Bucket とファイル名(キー)、そして Image には ECR のリポジトリを定義しています。

eb create

後は以下のように eb create を実行します。

$ eb create --tier worker --instance_profile ${Insance_Profile_Name}

しばし待ちましょ。

確認

  • 各種ログの確認

eb ssh でログインして各種ログを確認してみます。

#
# /tmp/docker_build.log を確認
#
$ cat /tmp/docker_build.log
Sending build context to Docker daemon 14.34 kB
Sending build context to Docker daemon
Step 0 : FROM xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-sinatra-worker:latest
 ---> 45afb86977eb
Step 1 : EXPOSE 4567
 ---> Running in 215ae90196d6
 ---> aa4a2596cf6f
Removing intermediate container 215ae90196d6
Successfully built aa4a2596cf6f

#
# /tmp/docker_pull.log を確認
#
$ cat /tmp/docker_pull.log

(snip)

45afb86977eb: Pull complete
Remote Digest:
Digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Status: Downloaded newer image for xxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-sinatra-worker:latest
  • Woker アプリケーションのログを確認

eb ssh でログインして Worker アプリケーションのログを確認してみます。

[ec2-user@ip-10-134-164-40 tmp]$ tail /tmp/sinatra.log
I, [2016-01-16T10:00:00.014747 #8]  INFO -- : bar
I, [2016-01-16T10:02:42.844395 #8]  INFO -- : bar
I, [2016-01-16T10:05:33.582870 #8]  INFO -- : bar
I, [2016-01-16T10:05:59.486555 #8]  INFO -- : bar
I, [2016-01-16T10:06:59.511213 #8]  INFO -- : bar
I, [2016-01-16T10:07:59.553031 #8]  INFO -- : bar
I, [2016-01-16T10:08:59.519486 #8]  INFO -- : bar
I, [2016-01-16T10:09:59.543144 #8]  INFO -- : bar
I, [2016-01-16T10:10:59.513466 #8]  INFO -- : bar
I, [2016-01-16T10:11:59.514448 #8]  INFO -- : bar

一応、一分毎に Worker アプリケーションにアクセスが発生していることがわかります。しめしめ。


終わり

ということで、Elastic Beanstalk から ECR のコンテナイメージを利用することが出来ました。ギョームで使うことは多分無いと思いますが東京リージョンでのサービス開始が待ち遠しです。

(ショロカレ 23 日目)Amazon ECR をもう一時間使ってみた(aws-cli による操作と ECS との連携を試す)

「初老丸の独り Advent calendar 2015」の二十三日目の記事です。

追記

コンテナインスタンスに付ける IAM role のポリシーを Amazon Managed Policy に変更した。

inokara.hateblo.jp

助言を頂いた @riywo さん、有難う御座いました!


tl;dr

inokara.hateblo.jp

では、触ってみただけだったので、少しうんちくを参考資料などから拝借する。


うんちくとか

なんぼ?

Amazon ECR って利用するのになんぼくらいするの?(現在はヴァージニア料金)

  • ストレージ使用料 0.10 USD/GB/月
  • Amazon ECR からのデータ転送量が発生

お楽しみの無料枠は...

  • 500MB/月
  • 翌月繰り越しは出来ないとの(携帯電話みたい)

ECR の特徴

こちらからの抜粋。

ECS との連携

  • ECS で稼働しているコンテナイメージを管理することが出来る
  • タスク定義で ECR を指定してイメージを取得することが出来る

Docker 互換

  • Docker Registry HTTP API V2 がサポートされている
  • Docker コマンド(push / pull / list / tag 等)が利用可能

高可用性、耐久性

  • コンテナイメージは S3 に保存される

共有

  • リポジトリ内で AWS のリソースタグが利用可能
  • リソースレベルのアクセス制限によりアカウントを越えてコンテナイメージを共有することが可能

アクセスコントロール

  • IAM によってコンテナイメージへのアクセス制限を設けることが出来る

暗号化

  • コンテナイメージの送受信は HTTPS 経由で行われる
  • 保存されたイメージは Amazon S3 のサーバー側で自動的に暗号化される

モニタリング

  • CloudWatch を利用してモニタリングされる
  • コンテナイメージサイズ、ストレージ、データ転送などのリソース消費状況を確認することが出来る

制限事項

こちらを抜粋。

以下は申請により変更が可能(と思われる)。

Resource Default Limit
1 アカウントあたりの最大リポジトリ 1,000
1 リポジトリあたりの最大イメージ数 500

以下は変更不可。

Resource Default Limit
1 イメージあたりの最大 layer 数 127 (this is the current Docker limit)
最大 layer part サイズ 10 MiB
最小 layer part サイズ 5 MiB (except the final layer part in an upload)
最大 layer parts 1,000 MiB

もう一時間くらい

awscli と docker コマンドだけで操作してみる

$ aws --region us-east-1 ecr create-repository --repository-name oreno-docker-repo
{
    "repository": {
        "registryId": "xxxxxxxxxxxxx",
        "repositoryName": "oreno-docker-repo",
        "repositoryArn": "arn:aws:ecr:us-east-1:xxxxxxxxxxxxx:repository/oreno-docker-repo"
    }
}
$ aws --region us-east-1 ecr describe-repositories
{
    "repositories": [
        {
            "registryId": "xxxxxxxxxxxxx0",
            "repositoryName": "oreno-docker-repo",
            "repositoryArn": "arn:aws:ecr:us-east-1:xxxxxxxxxxxxx:repository/oreno-docker-repo"
        },
        {
            "registryId": "xxxxxxxxxxxxx",
            "repositoryName": "oreno-registory",
            "repositoryArn": "arn:aws:ecr:us-east-1:xxxxxxxxxxxxx:repository/oreno-registory"
        }
    ]
}
$ aws --region us-east-1 ecr list-images --repository-name oreno-registory
{
    "imageIds": [
        {
            "imageTag": "latest",
            "imageDigest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
    ]
}
  • ECR にログインする為の情報を取得(docker login する為の情報を取得)
$ aws --region us-east-1 ecr get-login

以下のようにログイン情報が出力される。

docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com
  • docker login を利用して ECR にログインする
$ docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com

以下のように出力される。

WARNING: login credentials saved in ${HOME}/.docker/config.json
Login Succeeded

尚、${HOME}/.docker/config.json の中身は以下の通り。

$ cat /home/vagrant/.docker/config.json
{
        "auths": {
                "https://xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com": {
                        "auth": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                        "email": "none"
                }
        }
}
  • docker build でオリジナルコンテナをビルド
$ docker build -t inokappa/oreno-jenkins .
$ docker tag inokappa/oreno-jenkins xxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo
$ docker push xxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo

The push refers to a repository [xxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo] (len: 1)
0d3bf9ffe6f6: Pushed
4bb741cb567f: Pushing 1.024 kB

(snip)

3375effa7f2a: Pushed
latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 24325
  • イメージを確認
$ aws --region us-east-1 ecr list-images --repository-name oreno-docker-repo
{
    "imageIds": [
        {
            "imageTag": "latest",
            "imageDigest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
    ]
}
  • docker run してみる
#
# docker run
#
$ docker run --name jenkins -d -p 8080 xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo
Unable to find image 'xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo:latest' locally
latest: Pulling from oreno-docker-repo
Digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Status: Downloaded newer image for xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo:latest
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#
# docker ps
#
$ docker ps
CONTAINER ID        IMAGE                                                            COMMAND                  CREATED             STATUS              PORTS                     NAMES
aa3ef49191c9        xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo   "/usr/bin/java -jar /"   46 seconds ago      Up 45 seconds       0.0.0.0:32772->8080/tcp   jenkins

#
# Jenkins コンテナを確認
# 
$ curl -s localhost:32772/api/json | jq .
{
  "views": [
    {
      "url": "http://localhost:32772/",
      "name": "All"
    }
  ],
  "useSecurity": false,
  "useCrumbs": false,
  "unlabeledLoad": {},
  "slaveAgentPort": 0,
  "quietingDown": false,
  "primaryView": {
    "url": "http://localhost:32772/",
    "name": "All"
  },
  "assignedLabels": [
    {}
  ],
  "mode": "NORMAL",
  "nodeDescription": "the master Jenkins node",
  "nodeName": "",
  "numExecutors": 2,
  "description": null,
  "jobs": [],
  "overallLoad": {}
}

ECS との連携を試してみる

やっと本番

以下のように ECS と ECR の連携をしてみる。

f:id:inokara:20151223024101p:plain

教材はいつものように。

github.com

ドキュメントによると ECR との連携については以下の条件を満たす必要がありそう。

  • ECS Container agent のバージョンは 1.7 以上
  • latest バージョンの Amazon ECS-optimized AMI で起動したコンテナインスタンス

但し、今回は Docker 1.9 をインストールした Ubuntu 14.04 で試すことにした。

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"

$ sudo docker version
sudo: unable to resolve host ip-10-0-0-93
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64
$ 

ECS コンテナインスタンスに付与する IAM ポリシー

以下をコンテナインスタンスに付与する IAM role に追加する。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        }
    ]
}

terraform のテンプレートは以下のように

terraform のテンプレートは以下のように修正する。

#
# Create ECS cluster
#
resource "aws_ecs_cluster" "oreno-cluster" {
  name = "oreno-cluster"
}

#
# Define task
#
resource "aws_ecs_task_definition" "sample01" {
  family = "sample01"
  container_definitions = <<EOS
[
  {
    "environment": [],
    "name": "oreno-jenkins",
    "image": "xxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo",
    "cpu": 0,
    "memory": 256,
    "portMappings": [
      {
          "containerPort": 8080,
          "hostPort": 8080
      }
    ],
    "command": [
    ],
    "essential": true
  }
]
EOS
}
#
# Define Service(as container start)
#
resource "aws_ecs_service" "sample01" {
  name = "sample01"
  cluster = "${aws_ecs_cluster.oreno-cluster.id}"
  task_definition = "${aws_ecs_task_definition.sample01.arn}"
  desired_count = 1
}

コンテナイメージを指定する際に ECR のリポジトリを指定する。

apply

apply すると以下のように。

$ make tf-apply

(snip)

Outputs:

  CloudWatch Logs Log Group Name = docker-logging
  EC2 IP address                 = xxx.xxx.xxx.xxx
  EC2 Instance ID                = i-xxxxxxxx
  ECS Cluster Name               = oreno-cluster

terraform apply で適用する。

確認

マネジメントコンソールの Task Definitions にて確認。

f:id:inokara:20151223021010p:plain

そして...暫くすると Task に登録された Jenkins コンテナが起動しているはずなので確認する。

$ curl -s xx.xx.xxx.xx:8080/api/json | jq .
{
  "views": [
    {
      "url": "http://xx.xx.xxx.xx:8080/",
      "name": "All"
    }
  ],
  "useSecurity": false,
  "useCrumbs": false,
  "unlabeledLoad": {},
  "slaveAgentPort": 0,
  "quietingDown": false,
  "primaryView": {
    "url": "http://xx.xx.xxx.xx:8080/",
    "name": "All"
  },
  "assignedLabels": [
    {}
  ],
  "mode": "NORMAL",
  "nodeDescription": "the master Jenkins node",
  "nodeName": "",
  "numExecutors": 2,
  "description": null,
  "jobs": [],
  "overallLoad": {}
}

念のため、ECS Container Agent のログを見てみる。

$ sudo docker logs ecs-agent

(snip)

2015-12-22T16:56:40Z [INFO] Creating container module="TaskEngine" task="sample01:3 arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/4a5bf09f-cc8e-4908-b351-d2451201a051, Status: (NONE->RUNNING) Containers: [oreno-jenkins (PULLED->RUNNING),]" container="oreno-jenkins(xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo:latest) (PULLED->RUNNING)"
2015-12-22T16:56:40Z [INFO] Created container name mapping for task sample01:3 arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/4a5bf09f-cc8e-4908-b351-d2451201a051, Status: (NONE->RUNNING) Containers: [oreno-jenkins (PULLED->RUNNING),] - oreno-jenkins(xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo:latest) (PULLED->RUNNING) -> ecs-sample01-3-oreno-jenkins-ead1bcfd81ba9fe91400

ECR から docker pull してきているのがなんとなく判る。


以上

ECR と ECS の連携を試してみた。ポイントは IAM Policy を適切に付与すること。ここだけ気をつければ簡単に連携を試すことが出来ると思う。

以上。

(ショロカレ 21 日目)ずっと待ってた Amazon ECR を一瞬、使ってみた

「初老丸の独り Advent calendar 2015」の二十一日目の記事です。

tl;dr

ずっと待ってた Amazon EC2 Container Registory Service が来た!ので、ドキュメントを全く読まずに恐縮ですが触ってみた。(後ほど、いろいろと追記していくか別記事に書く)

aws.typepad.com

うれしい。クリスマスプレゼンツや。


使ってみた!

マネジメントコンソールからポチポチとリポジトリを作る

現時点では東京リージョンには来ていなかったのでヴァージニアで試すことにした。

f:id:inokara:20151222091419p:plain

ECS クラスタを作成するか ECR を作るかの選択肢。

f:id:inokara:20151222091426p:plain

リポジトリ名を入力する。

f:id:inokara:20151222091435p:plain

ビルドしてプッシュするまでの手順が丁寧に紹介されている。

f:id:inokara:20151222091445p:plain

完成。

aws-cli のバージョンアップ

事前に aws-cli のバージョンを上げておく必要があるので注意。

$ aws --version
aws-cli/1.9.15 Python/2.7.6 Linux/3.13.0-55-generic botocore/1.3.15

ECR 関連のオプションは以下の通り。

  • batch-check-layer-availability
  • batch-delete-image
  • batch-get-image
  • complete-layer-upload
  • create-repository
  • delete-repository
  • delete-repository-policy
  • describe-repositories
  • get-authorization-token
  • get-download-url-for-layer
  • get-login
  • get-repository-policy
  • initiate-layer-upload
  • list-images
  • put-image
  • set-repository-policy
  • upload-layer-part

ビルドしてポイ

まずは、ECS 連携ではなくて、手元の Docker イメージを push するだけを試す。

以下のように docker login コマンドを取得する。

$ aws ecr get-login --region us-east-1

以下のように出力される。

docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com

出力されたコマンドを利用してログインする。

$ docker login -u AWS -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -e none https://xxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com

以下のように出力されてログイン完了。

WARNING: login credentials saved in /path/to/.docker/config.json
Login Succeeded

適宜ビルドする。

$ docker build --no-cache=true -t oreno-registory .

tag を付ける。

$ docker tag oreno-es-index-snapshot:latest xxxxxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-registory:latest

あとは push する。

$ docker push xxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-registory:latest
The push refers to a repository [xxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-registory] (len: 1)
43737a875786: Pushed
b370b48fdda0: Pushed
b272a22d11f5: Pushed
c761a8960a2c: Pushed
e3c74b06a9ef: Pushed
60e97b91fc80: Pushed
b794e346bfef: Pushed

(snip)

5822f840e16b: Pushed
1565e86129b8: Pushed
latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 46605

プッシュ完了。

f:id:inokara:20151222092533p:plain

とっても簡単。


ということで

ずっと待ってた!

だけに年内に触れて嬉しい。

ぱっと触った感じだと

ふつうの Docker Registory と遜色無い。

権限などの設定

以下のように権限も設定できる。

f:id:inokara:20151222093523p:plain

ドキュメント

docs.aws.amazon.com

引き続き、さわっていく。

(ショロカレ 18 日目)t2.nano は僕の欲求を満たしてくれるのか

自転車操業になりつつある「初老丸の独り Advent calendar 2015」の十八日目の記事です。

tl;dr

先日、EC2 インスタンスの t2 ブラザーズに新しい弟が増えた。その名は t2.nano(ナノ)。五男なナノは最もスペックは低い位置づけだが個人的にはコストを抑えられるという点でとても有り難い発表ナノ。

aws.typepad.com

え、そうなの?

ということで、t2.nano がどの程度の実力なのか自分がやりたいことが出来るのか目線で試してみることにした。

尚、上記のブログ記事がとても参考になった。以下の内容はほぼ上記の記事を自分なりに纏めたものになるので、詳細については上記の記事を参照されたし。


え、そうなの?

t2.nano のスペック

  • 1vCPU
  • 512MB メモリ
  • 最大2つの ENI をサポート
  • 30 CPU クレジット

t2.nano ってなんぼ?

  • t2.micro の半額
  • $0.0100/時間(東京リージョン/オンデマンド)
  • $7.30/月(東京リージョン/オンデマンド)

想定されるユースケース

t2.nanoはトラフィックの少ないウェブサイト、マイクロサービス、開発・テスト環境に使われることを想定していますし、費用効果を計測する車両にも使えると期待しています。さらに、トレーニングや教育用途もあります。

こちらの記事の抜粋。

僕の欲求

で、ナノでやってみたいのは以下のような内容ナノ。

三番目の諸々については具体的な何かというよりも、いつでもお小遣いを気にすることが出来るという点では既に欲求は満たされている気がしている。


やってみる

ECS のコンテナインスタンス

いつも使っている教材を利用して t2.nano な ECS コンテナインスタンスを起動してみた。

  • cpuinfo
$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 63
model name      : Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz
stepping        : 2
microcode       : 0x2b
cpu MHz         : 2400.028
cache size      : 30720 KB

(snip)

cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:
  • meminfo
$ cat /proc/meminfo
MemTotal:         500212 kB
MemFree:           99000 kB
Buffers:            8928 kB
Cached:           297356 kB
SwapCached:            0 kB

(snip)

Hugepagesize:       2048 kB
DirectMap4k:       53248 kB
DirectMap2M:      602112 kB
$ curl http://169.254.169.254/latest/meta-data/instance-type
t2.nano
  • Docker Engine
$ sudo docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS                        NAMES
aa24c40078d5        amazon/amazon-ecs-agent:latest   "/agent"            3 minutes ago       Up 3 minutes        127.0.0.1:51678->51678/tcp   ecs-agent

$ sudo docker version
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Docker Engine は起動していることを確認。

  • ECS からはどんな風に見えているのか
$ make OUTPUT=json ECS_CLUSTER=oreno-cluster ECS_ARN=705afbd9-d078-48bc-82c
8-3b2aafc83cbe ecs-describe-container-instances
{
    "failures": [],
    "containerInstances": [
        {
            "status": "ACTIVE",
            "registeredResources": [
                {
                    "integerValue": 1024,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "CPU",
                    "doubleValue": 0.0
                },
                {
                    "integerValue": 488,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "MEMORY",
                    "doubleValue": 0.0
                },

(snip)

            ],
            "versionInfo": {
                "agentVersion": "1.7.0",
                "agentHash": "191dbd5",
                "dockerVersion": "DockerVersion: 1.9.1"
            }
        }
    ]
}
  • ECS container agent はどの位のリソースを使っているのか

docker stats コマンドで確認してみる。

$ sudo docker stats --no-stream=true ecs-agent
CONTAINER           CPU %               MEM USAGE / LIMIT    MEM %               NET I/O               BLOCK I/O
ecs-agent           0.06%               12.5 MB / 512.2 MB   2.44%               27.78 kB / 27.86 kB   9.056 MB / 4.096 kB

ECS container agent 自体が t2.nano 搭載メモリ一杯、一杯にメモリを使用できる状態で起動しているのはちょっと注意が必要。

やっぱりメモリが見た目で心もとないけど、ひとまず Docker Engine 動いているから欲求は満たされそうナノ。

Rundeck を動かす

  • インストール
$ wget http://dl.bintray.com/rundeck/rundeck-deb/rundeck-2.6.2-1-GA.deb
$ sudo apt-get install openjdk-7-jdk
$ sudo dpkg -i rundeck-2.6.2-1-GA.deb
  • 設定
$ cd /etc/rundeck
$ sudo diff -u rundeck-config.properties.bk rundeck-config.properties
--- rundeck-config.properties.bk        2015-12-17 14:30:22.943200999 +0000
+++ rundeck-config.properties   2015-12-17 14:30:51.663200999 +0000
@@ -5,6 +5,6 @@
 #rss.enabled if set to true enables RSS feeds that are public (non-authenticated)
 rss.enabled=false
 # change hostname here
-grails.serverURL=http://localhost:4440
+grails.serverURL=http://xxx.xxx.xxx.xxx:4440


$ sudo diff -u framework.properties.original framework.properties
--- framework.properties.original       2015-12-17 14:30:01.995200999 +0000
+++ framework.properties        2015-12-17 14:32:52.923200999 +0000
@@ -8,10 +8,10 @@
 framework.server.name = localhost


 framework.server.hostname = localhost
 framework.server.port = 4440
-framework.server.url = http://localhost:4440
+framework.server.url = http://xxx.xxx.xxx.xxx:4440
  • 起動

満を持して起動。

$ sudo service rundeckd start

ブラウザでアクセスすると...

f:id:inokara:20151217234439p:plain

キタ━━━━(゚∀゚)━━━━!!

  • 残念でした...

ところが...ログインしつつ rundeck のログを見ると...

2015-12-17 14:39:14.157:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:4440
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000d4777000, 20123648, 0) failed; error='Cannot allocate memory' (errno=12)

予想はしていたもののメモリ不足を訴えるログが。「メモリ不足ナノ」。

ドキュメントのインストール要件には含まれていないようだけど...JVM の割り当てメモリを見てみると...

$ sudo cat /etc/rundeck/profile | grep Xmx
RDECK_JVM="$RDECK_JVM -Xmx1024m -Xms256m -XX:MaxPermSize=256m -server"

おお、すでに搭載メモリを超える容量で最大ヒープサイズの確保が行われるようだ。-Xmx のサイズを調整すればもしかして...

$ sudo diff -u profile.original profile
--- profile.original    2015-12-17 14:58:17.931200999 +0000
+++ profile     2015-12-17 14:58:32.531200999 +0000
@@ -36,7 +36,7 @@
 #
 # Set min/max heap size
 #
-RDECK_JVM="$RDECK_JVM -Xmx1024m -Xms256m -XX:MaxPermSize=256m -server"
+RDECK_JVM="$RDECK_JVM -Xmx256m -Xms256m -XX:MaxPermSize=256m -server"
 #
 # SSL Configuration - Uncomment the following to enable.  Check SSL.properties for details.
 #

ヒープサイズを控えめにするとメモリ不足のエラーは出なくなることが確認できた。

  • だが...

使い物になるのか(ちゃんと JOB が動くのか)否かは適当な JOB を動かして長期的に見ていきたい。


ということで

一応

自分の欲求は満たしてくれそうナノ。

きっと

Docker Engine と Rundeck を同時に動かすのはしんどいかもしれないけど、ちょっとした検証や低負荷で長時間動かしておくにはおススメ出来るインスタンスタイプではないかと思うナノ。(その気になればバーストもするし)

(ショロカレ 17 日目)Amazon ECS の個人的な疑問を紐解いていくメモ(3)~ ECS で Docker の CloudWatch Logs Logging Driver を利用する

自転車操業になりつつある「初老丸の独り Advent calendar 2015」の十七日目の記事です。

追記(2016/01/20)

ECS 上の Docker コンテナから CloudWatch Logs を利用する場合には以下の点に注意が必要です。

  • Task Definition での定義はサポートしていない
  • docker run 時のオプションで指定することで利用は可能

コメントにて id:NewGyu さんよりご指摘頂きました。id:NewGyu さん、コメント有難うございました。

現時点ではTask Definitionにawslogsを指定すると「awslogsなぞ知らん」と言われてしまい使えないようです。

ただ、ECSAgentにそれっぽいプルリクが来ているので近日使えるようになりそうな気配です。
https://github.com/aws/amazon-ecs-agent/pull/251

上記の通り、ECS Agent に Logging Driver として CloudWatch Logs を利用出来るようにするプルリクがあるようです(Stream 名(デフォルトは Container ID))について検討が必要な点があるようです)ので、近いうちに Task Definition で指定が可能になると思います。


tl;dr

Amazon ECS で個人的な疑問を紐解いていきたい。


今日の疑問

疑問

  • Docker の Logging Driver で CloudWatch Logs が使えるとのことですが、ECS でも使えますでしょか

答え

  • 少々お待ち下さい、ECS から直接利用するにはもう少し時間がかかりそうです(2016/01/20)
  • 安心してください、もちろん使えますよ

以下のようにドキュメントにも記載されいる。

docs.docker.com

ポイントとしては Credentials だと思う。(後ほど)

ちなみに Logging Driver とは

個人的な認識だがコンテナのログを以下のようなミドルウェアに出力することができるようになるオプション。

  • json-file
  • syslog
  • journald
  • gelf
  • fluentd
  • awslogs(CloudWatch Logs)

journaldgelf は生まれて初めて聞いた。

ドキュメントを読むと、Docker Engine を起動する際、Docker コンテナを起動する際にオプションとして Logging Driver を指定できるようだ。

以下、Docker Engine 起動時のオプション。(ドキュメントより抜粋)

$ docker daemon --log-driver=json-file --log-opt labels=foo --log-opt env=foo,fizz

以下、コンテナ起動時のオプション。(ドキュメントより抜粋)

$ docker run --log-driver=syslog --log-opt syslog-address=tcp://192.168.0.42:123

ECS で Logging Driver CloudWatch Logs 試す

教材

引き続き、教材は以下の教材を利用する。

github.com

まずは Credential

以下のような IAM Policy をコンテナインスタンスに適用する必要がある。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

教材の terraform/iam.tf を以下のように修正する。

$ git diff iam.tf
diff --git a/terraform/iam.tf b/terraform/iam.tf
index 3734e62..8811f67 100644
--- a/terraform/iam.tf
+++ b/terraform/iam.tf
@@ -50,6 +50,14 @@ resource "aws_iam_role_policy" "ecs_iam_role" {
       ],
       "Effect": "Allow",
       "Resource": "*"
+    },
+    {
+      "Action": [
+        "logs:CreateLogStream",
+        "logs:PutLogEvents"
+      ],
+      "Effect": "Allow",
+      "Resource": "*"
     }
   ]
 }

次に CloudWatch Logs の Log Group を作っておく

これも教材に追加。

$ cat cwlog.tf
#
# Create CloudWatch Logs Log Group
#
resource "aws_cloudwatch_log_group" "oreno_cw_log" {
  name = "docker-logging"
}

terraform apply

あとは terraform apply するだけ。(教材では make tf-apply

$ make tf-apply

(snip)

Outputs:

  CloudWatch Logs Log Group Name = docker-logging
  EC2 IP address                 = xxx.xxx.xxx.xxx
  EC2 Instance ID                = i-xxxxxxxx
  ECS Cluster Name               = oreno-cluster

hello-world

コンテナインスタンスにログインして hello-world してみる。

$ docker run \
> --log-driver=awslogs \
> --log-opt awslogs-region=ap-northeast-1 \
> --log-opt awslogs-group=docker-logging \
> hello-world

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/userguide/

以下のようにログが出力されている。

f:id:inokara:20151217093900p:plain

Log Stream 名を指定しなければ上記のようにコンテナ ID が Log Stream 名となる。

f:id:inokara:20151217094006p:plain

おお簡単。

CloudWatch Logs Logging Driver について

ドキュメントより抜粋。

  • Docker Engine のオプションとして
$ docker daemon --log-driver=awslogs
  • コンテナの起動時にオプションとして
$ docker run --log-driver=awslogs
  • awslogs-region オプション

リージョンを指定する。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1...
  • awslogs-group オプション

Log Group を指定する。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1 --log-opt awslogs-group=docker-logging ...

Log Group は事前に作成しておく必要があるので注意。

  • awslogs-stream オプション

Log Stream を指定する。これは必須ではない。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1 --log-opt awslogs-group=docker-logging --log-opt=awslogs-stream=foo ...

指定しない場合にはコンテナ ID が Log Stream 名を指定する。

Log Stream 名については以下のような注意書きがある。

Log streams within a given log group should only be used by one container at a time. Using the same log stream for multiple containers concurrently can cause reduced logging performance.

同一の Log Stream に複数のコンテナからのログを送るとログの収集パフォーマンスに影響を及ぼす...(という解釈)。


以上

疑問は...

解けました。

もう少し...

Log Driver については触れていきたいと思う。

(ショロカレ 16 日目)Amazon ECS の個人的な疑問を紐解いていくメモ(2)~ ECS Container agent が始めからインストールされている環境を作る

自転車操業になりつつある「初老丸の独り Advent calendar 2015」の十六日目の記事です。

tl;dr

前の記事でやり残した宿題をひとつずつ片づける。

今回は...

  • Docker と ECS container agent をインストールするまでを自動化(出来るはず)

を試す。


作業にあたって

どこが自動化できそうか

  • Docker のインストール
  • ECS container agent のインストール

戦略

  • AMI を作る
  • EC2 起動時に User Data を利用する

EC2 の User Data をやってみる

参考

stormcat.hatenablog.com

引き続き、上記の記事を参考にさせていただく。有難うございます。

教材

github.com

引き続き、上記の教材を利用する。

User Data のスクリプト

すごく雑だが...以下のようなスクリプトを作ってみる。

#!/usr/bin/env bash

apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-engine
mkdir -p /var/log/ecs
mkdir -p /var/lib/ecs/data

docker run --name ecs-agent \
--detach=true \
--restart=on-failure:10 \
--volume=/var/run/docker.sock:/var/run/docker.sock \
--volume=/var/log/ecs/:/log \
--volume=/var/lib/ecs/data:/data \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
--volume=/var/run/docker/execdriver/native:/var/lib/docker/execdriver/native:ro \
--publish=127.0.0.1:51678:51678 \
--env=ECS_LOGFILE=/log/ecs-agent.log \
--env=ECS_LOGLEVEL=info \
--env=ECS_DATADIR=/data \
--env=ECS_CLUSTER=oreno-cluster \
amazon/amazon-ecs-agent:latest

terraform で一発構築

する為に、以下のように EC2 構築用の terraform テンプレートに組み込んでみる。

#
# AWS Launch EC2 instance
#
resource "aws_instance" "oreno_tf_test" {
  count = 1
  instance_type = "${var.instance_type}"
  ami = "${lookup(var.aws_amis, var.region)}"
  subnet_id = "${var.subnet}"
  associate_public_ip_address = true
  vpc_security_group_ids = ["${var.securiy_group}"]
  iam_instance_profile = "${aws_iam_role_policy.ecs_iam_role.name}"
  key_name = "${var.ssh_key_name}"
  tags = {
    Name = "${lookup(var.tag_names, count.index)}"
  }
  user_data = <<EOT
#!/usr/bin/env bash
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-engine
mkdir -p /var/log/ecs
mkdir -p /var/lib/ecs/data

docker run --name ecs-agent \
--detach=true \
--restart=on-failure:10 \
--volume=/var/run/docker.sock:/var/run/docker.sock \
--volume=/var/log/ecs/:/log \
--volume=/var/lib/ecs/data:/data \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
--volume=/var/run/docker/execdriver/native:/var/lib/docker/execdriver/native:ro \
--publish=127.0.0.1:51678:51678 \
--env=ECS_LOGFILE=/log/ecs-agent.log \
--env=ECS_LOGLEVEL=info \
--env=ECS_DATADIR=/data \
--env=ECS_CLUSTER="${aws_ecs_cluster.oreno_ecs_cluster.name}" \
amazon/amazon-ecs-agent:latest
EOT
}

若干、力技っぽいけど...これで試してみる。

構築

$ cd oreno-ecs/terraform
$ make

Makefile for ECS

Usage: make [task]

Tasks:
tf-plan                         ....... Execute terraform plan
tf-apply                        ....... Execute terraform apply
tf-destroy                      ....... Execute terraform destroy

#
# terraform plan
#
$ make tf-plan
Refreshing Terraform state prior to plan...

(snip)

Plan: 5 to add, 0 to change, 0 to destroy.

#
# terraform apply
#
$ make tf-apply

(snip)

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

Outputs:

  EC2 IP address   = xxx.xxx.xxx.xxx
  EC2 Instance ID  = i-xxxxxxxx
  ECS Cluster Name = oreno-cluster

確認

$ oreno-ecs/ecs-cli
$ make

Makefile for ECS

Usage: make [task]

Tasks:
ecs-up                          ....... ECS Cluster up
ecs-list                        ....... list up ECS Clusters. Require environment variable 'OUTPUT'
ecs-list-container-instances    ....... list up ECS Container instances. Require environment variable 'OUTPUT' and 'ECS_CLUSTER'
ecs-describe-container-instances....... describe ECS Container instances. Require environment variable 'OUTPUT' and 'ECS_CLUSTER' and 'ECS_ARN'

#
# ECS Cluster の一覧を確認
#
$ make OUTPUT=text ecs-list
CLUSTERARNS     arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxxx:cluster/oreno-cluster

#
# ECS Cluster Container Instance の一覧を確認
#
$ make OUTPUT=text ECS_CLUSTER=oreno-cluster ecs-list-container-instances
CONTAINERINSTANCEARNS   arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxxxxx:container-instance/b7ed2bdf-0ee9-4c1e-9ff2-c3aa066abbcb

#
# ECS Cluster Container Instance の詳細を確認
#
$ make OUTPUT=text ECS_CLUSTER=oreno-cluster ECS_ARN=b7ed2bdf-0ee9-4c1e-9ff2-c3aa066abbcb ecs-describe-container-instances
CONTAINERINSTANCES      True    arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxxxxx:container-instance/b7ed2bdf-0ee9-4c1e-9ff2-c3aa066abbcb i-xxxxxxxx 0       0       ACTIVE
ATTRIBUTES      com.amazonaws.ecs.capability.privileged-container
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.17
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.18
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.19
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.20
ATTRIBUTES      com.amazonaws.ecs.capability.logging-driver.json-file
ATTRIBUTES      com.amazonaws.ecs.capability.ecr-auth
REGISTEREDRESOURCES     0.0     1024    0       CPU     INTEGER
REGISTEREDRESOURCES     0.0     992     0       MEMORY  INTEGER
REGISTEREDRESOURCES     0.0     0       0       PORTS   STRINGSET
STRINGSETVALUE  22
STRINGSETVALUE  2376
STRINGSETVALUE  2375
STRINGSETVALUE  51678
REGISTEREDRESOURCES     0.0     0       0       PORTS_UDP       STRINGSET
REMAININGRESOURCES      0.0     1024    0       CPU     INTEGER
REMAININGRESOURCES      0.0     992     0       MEMORY  INTEGER
REMAININGRESOURCES      0.0     0       0       PORTS   STRINGSET
STRINGSETVALUE  22
STRINGSETVALUE  2376
STRINGSETVALUE  2375
STRINGSETVALUE  51678
REMAININGRESOURCES      0.0     0       0       PORTS_UDP       STRINGSET
VERSIONINFO     191dbd5 1.7.0   DockerVersion: 1.9.1

とりあえず構築できたっぽいが、一応、マネジメントコンソールからも確認してみる。

f:id:inokara:20151216231226p:plain

セットアップ出来た。


ひとまずは

ひとまずは Docker Engine と ECS container agent のインストールすることが出来たので、ひとまずは目的達成ということで。

最新の Docker Engine を使うという前提であれば User Data で諸々実行するの方が良いような気がする。