share facebook facebook2 twitter menu hatena pocket slack

2015.07.03 FRI

ECSで”Private Registry”を利用するCloudFormationのテンプレートを作ってみた

鈴木 宏康

WRITTEN BY鈴木 宏康

下記のドキュメントの内容をCloudFormationを使って試してみました

Private Registry Authentication

要は”Container Instance”の”/etc/ecs/ecs.config”に

ECS_ENGINE_AUTH_TYPE=docker
ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/":{"username":"my_name","password":"my_password","email":"email@example.com"}}

のように認証情報がセットされるようにします。

CloudFormationのテンプレートは、こんな感じです。

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "ProjectName": {
            "Type": "String",
            "Default": "Cloudpack"
        },
        "RoleName": {
            "Type": "String",
            "Default": "Ecs"
        },
        "KeyName": {
            "Type": "AWS::EC2::KeyPair::KeyName"
        },
        "InstanceType": {
            "Type": "String",
            "Default": "t2.micro"
        },
        "CommonSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup::Id"
        },
        "VpcId": {
            "Type": "AWS::EC2::VPC::Id"
        },
        "Az1VpcZoneIdentifier": {
            "Type": "AWS::EC2::Subnet::Id"
        },
        "Az2VpcZoneIdentifier": {
            "Type": "AWS::EC2::Subnet::Id"
        },
        "DesiredCapacity": {
            "Type": "String",
            "Default": "0"
        },
        "Username": {
            "Type": "String",
            "Default": ""
        },
        "Password": {
            "Type": "String",
            "Default": ""
        },
        "Email": {
            "Type": "String",
            "Default": ""
        }
    },
    "Mappings": {
        "RegionMapping": {
            "us-east-1": { "ImageId": "ami-5f59ac34" },
            "us-west-2": { "ImageId": "ami-c188b0f1" },
            "eu-west-1": { "ImageId": "ami-3db4ca4a" },
            "ap-northeast-1": { "ImageId": "ami-ca01d8ca" },
            "ap-southeast-2": { "ImageId": "ami-5b5d2661" }
        }
    },
    "Resources": {
        "Cluster": {
            "Type": "AWS::ECS::Cluster"
        },
        "RoleSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": { "Fn::Join" : [ "", [
                    { "Ref": "ProjectName" },
                    { "Ref": "RoleName" }
                ] ] },
                "VpcId": { "Ref": "VpcId" },
                "SecurityGroupIngress": [],
                "SecurityGroupEgress": [],
                "Tags": [ {
                    "Key": "Name",
                    "Value": { "Fn::Join" : [ "", [
                        { "Ref": "ProjectName" },
                        { "Ref": "RoleName" },
                        "Instance"
                    ] ] }
                } ]
            }
        },
        "Role": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [ {
                        "Effect": "Allow",
                        "Principal": { "Service": [ "ec2.amazonaws.com" ] },
                        "Action": [ "sts:AssumeRole" ]
                    } ]
                },
                "Path": "/",
                "Policies": [ {
                    "PolicyName": { "Fn::Join" : [ "", [
                        { "Ref": "ProjectName" },
                        "Ecs"
                    ] ] },
                    "PolicyDocument": {
                        "Version" : "2012-10-17",
                        "Statement": [ {
                            "Effect": "Allow",
                            "Action": [
                                "ecs:CreateCluster",
                                "ecs:DeregisterContainerInstance",
                                "ecs:DiscoverPollEndpoint",
                                "ecs:Poll",
                                "ecs:RegisterContainerInstance",
                                "ecs:Submit*"
                            ],
                            "Resource": [ "*" ]
                        } ]
                    }
                } ]
            }
        },
        "InstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [ {
                    "Ref": "Role"
                } ]
            }
        },
        "LaunchConfiguration": {
            "Type": "AWS::AutoScaling::LaunchConfiguration",
            "Properties": {
                "AssociatePublicIpAddress": "true",
                "KeyName": { "Ref": "KeyName" },
                "ImageId": { "Fn::FindInMap": [ "RegionMapping", { "Ref": "AWS::Region" }, "ImageId" ] },
                "InstanceType": { "Ref": "InstanceType" },
                "IamInstanceProfile": { "Ref": "InstanceProfile" },
                "SecurityGroups": [
                    { "Ref": "CommonSecurityGroup" },
                    { "Ref": "RoleSecurityGroup" }
                ],
                "UserData": { "Fn::Base64": { "Fn::Join" : [ "n", [
                    "#!/bin/bash",
                    "yum -y update",
                    "grubby --default-kernel | grep `uname -r` || reboot",
                    { "Fn::Join" : [ "", [
                        "echo ECS_CLUSTER=",
                        { "Ref": "Cluster" },
                        " >> /etc/ecs/ecs.config"
                    ] ] },
                    "echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config",
                    { "Fn::Join" : [ "", [
                        "echo ECS_ENGINE_AUTH_DATA='{"https://index.docker.io/v1/":{"username":"",
                        { "Ref": "Username" },
                        "","password":"",
                        { "Ref": "Password" },
                        "","email":"",
                        { "Ref": "Email" },
                        ""}}' >> /etc/ecs/ecs.config"
                    ] ] }
                ] ] } }
            }
        },
        "AutoScalingGroup": {
            "Type": "AWS::AutoScaling::AutoScalingGroup",
            "Properties": {
                "LaunchConfigurationName": { "Ref": "LaunchConfiguration" },
                "MinSize": "0",
                "MaxSize": "4",
                "DesiredCapacity": { "Ref": "DesiredCapacity" },
                "Cooldown": "0",
                "VPCZoneIdentifier": [
                    { "Ref" : "Az1VpcZoneIdentifier" },
                    { "Ref" : "Az2VpcZoneIdentifier" }
                ],
                "Tags": [ {
                    "Key": "Name",
                    "Value": { "Fn::Join" : [ "", [
                        { "Ref": "ProjectName" },
                        { "Ref": "RoleName" }
                    ] ] },
                    "PropagateAtLaunch": "true"
                } ]
            },
            "UpdatePolicy": {
                "AutoScalingRollingUpdate": {
                    "MaxBatchSize": "1",
                    "MinInstancesInService": "1"
                }
            }
        },
        "TaskDefinition": {
            "Type": "AWS::ECS::TaskDefinition",
            "Properties": {
                "ContainerDefinitions": [
                    {
                        "Memory": "128",
                        "Name": "nginx-public",
                        "Cpu": "128",
                        "Image": "cloudpack/nginx",
                        "Essential": "true"
                    },
                    {
                        "Memory": "128",
                        "Name": "nginx-private",
                        "Cpu": "128",
                        "Image": "cloudpack/private:nginx",
                        "Essential": "false"
                    }
                ]
            }
        },
        "Service": {
            "Type": "AWS::ECS::Service",
            "Properties": {
                "Cluster": { "Ref": "Cluster" },
                "DesiredCount": "1",
                "TaskDefinition": { "Ref": "TaskDefinition" }
            }
        }
    },
    "Outputs": {
        "Cluster": {
            "Value":  { "Ref": "Cluster" }
        },
        "Role": {
            "Value":  { "Ref": "Role" }
        },
        "RoleSecurityGroup": {
            "Value":  { "Ref": "RoleSecurityGroup" }
        }
    }
}

「”Container Instance”の”/etc/ecs/ecs.config”に認証情報を設定」は
次のようにUserDataで実現しています。

"UserData": { "Fn::Base64": { "Fn::Join" : [ "n", [
    "#!/bin/bash",
    "yum -y update",
    "grubby --default-kernel | grep `uname -r` || reboot",
    { "Fn::Join" : [ "", [
        "echo ECS_CLUSTER=",
        { "Ref": "Cluster" },
        " >> /etc/ecs/ecs.config"
    ] ] },
    "echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config",
    { "Fn::Join" : [ "", [
        "echo ECS_ENGINE_AUTH_DATA='{"https://index.docker.io/v1/":{"username":"",
        { "Ref": "Username" },
        "","password":"",
        { "Ref": "Password" },
        "","email":"",
        { "Ref": "Email" },
        ""}}' >> /etc/ecs/ecs.config"
    ] ] }
] ] } }

今回は下記”Docker Hub”のPublicなイメージとPrivateなイメージを使って
上記のテンプレートでスタックを作ってみました。

2015-06-21_16-52-48

まずはパラメータに”Docker Hub”のログイン情報を設定してスタックを作成してみます。

2015-06-21_16-20-41

ECSのクラスターができ、サービス登録したタスクが起動していることがわかります。

2015-06-21_17-22-07

実際のタスクも下記の通り、プライベートなイメージ(nginx-private)も含めて
問題ない状態になっています。

2015-06-21_17-19-48

次にパラメータに”Docker Hub”のログイン情報を設定せずにスタックを作成してみます。

2015-06-21_16-27-29

こちらもサービス登録したタスクが起動している状態になりましたが、

2015-06-21_17-22-45

タスクの状況を確認すると、プライベートなイメージ(nginx-private)の方は
イメージが見つからないというエラーになっていることがわかります。
(パブリックなイメージ”nginx-public”は問題ありません)

2015-06-21_17-15-30

元記事はこちら

ECSで”Private Registry”を利用するCloudFormationのテンプレートを作ってみた

鈴木 宏康

鈴木 宏康

愛知県生まれ。東京工業大学大学院修士課程修了。在学時より、ベンチャー企業でインターネットに関する業務に携わり、現在はクラウド(主にAmazon Web Services)上での開発・運用を軸とした事業の、業務の中心として活躍。