Amazon Elastic Container Service
开发人员指南 (API Version 2014-11-13)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。请点击 Amazon AWS 入门,可查看中国地区的具体差异

Windows 容器 AWS CloudFormation 模板

下面是可让您开始使用 Windows 容器的 AWS CloudFormation 模板。有关使用 AWS CloudFormation 模板创建堆栈的更多信息,请参阅 AWS CloudFormation 用户指南 中的在 AWS CloudFormation 控制台上创建堆栈

此 AWS CloudFormation 模板提供了运行示例应用程序的 Amazon ECS 集群的参考实现。此模板需要一个具有至少两个公共子网的现有 VPC。

此模板创建一个 Amazon ECS 集群(具有可配置数量的容器实例)、一个 应用程序负载均衡器、所需的安全组配置、一个 Amazon ECS 任务定义、一个 Amazon ECS 服务和一个 Application Auto Scaling 策略(此策略允许服务缩减以响应由 应用程序负载均衡器 发出的指标)。

使用 Auto Scaling 组和关联的启动配置来配置在集群中启动的容器实例。启动配置包含容器实例的配置数据,例如卷类型和大小、实例类型、IAM 角色和 Amazon EC2 用户数据。在启动时,会在 Auto Scaling 组中的每个实例上运行用户数据以下拉、配置和运行 ECS 代理,以便实例能够注册到 ECS 集群。

您也可通过模板创建 Amazon ECS 任务定义和服务。任务定义引用了 microsoft/iis 容器映像并提供了在启动时供该映像执行的命令,以及其他参数(例如,CPU 份额以及要将日志记录信息发送到的 CloudWatch Logs 日志组)。该服务配置为在集群上运行此任务定义的一个或多个副本,并将容器与 应用程序负载均衡器 关联。还将在服务上启用 Application Auto Scaling。

此模板还会创建三个不同的 IAM 角色。第一个角色是 ECSServiceRole,它允许 Amazon ECS 代表您管理您的服务,例如,将新任务注册到 应用程序负载均衡器 中。下一个角色是 Ec2Role,它向集群中的每个 EC2 实例提供权限,并允许容器代理执行必要的操作,例如,代表您轮询 ECS API。最后,我们为 Application Auto Scaling 创建了一个角色,帮助您的服务横向扩展和缩减以代表您响应 CloudWatch 警报。

注意

包含在此模板中的 AMIID 将定期进行更新,因此,如果您使用了此模板,则应在部署和更新群集之前确认 AMIID 是否为最新。

{ "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "KeyName": { "Type": "AWS::EC2::KeyPair::KeyName", "Description": "Name of an existing EC2 key pair to enable SSH access to the ECS instances." }, "VpcId": { "Type": "AWS::EC2::VPC::Id", "Description": "Select a default VPC ID." }, "SubnetID": { "Type": "List<AWS::EC2::Subnet::Id>", "Description": "Select a default subnet ID in your selected VPC." }, "DesiredCapacity": { "Type": "Number", "Default": "1", "Description": "Number of instances to launch in your ECS cluster." }, "MaxSize": { "Type": "Number", "Default": "1", "Description": "Maximum number of instances that can be launched in your ECS cluster." }, "InstanceType": { "Description": "EC2 instance type", "Type": "String", "Default": "t2.micro", "AllowedValues": [ "t2.micro", "t2.small", "t2.medium", "t2.large", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge" ], "ConstraintDescription": "Please choose a valid instance type." } }, "Mappings": { "AWSRegionToAMI": { "ap-south-1": { "AMIID": "ami-df97e8b0" }, "eu-west-2": { "AMIID": "ami-a84254cc" }, "eu-west-1": { "AMIID": "ami-0d839d6b" }, "ap-northeast-2": { "AMIID": "ami-13b06f7d" }, "ap-northeast-1": { "AMIID": "ami-ba707bdd" }, "sa-east-1": { "AMIID": "ami-7a147f16" }, "ca-central-1": { "AMIID": "ami-58df603c" }, "ap-southeast-1": { "AMIID": "ami-0f2cae6c" }, "ap-southeast-2": { "AMIID": "ami-52e9f831" }, "eu-central-1": { "AMIID": "ami-a8d671c7" }, "us-east-1": { "AMIID": "ami-bd5b7dab" }, "us-east-2": { "AMIID": "ami-c086a0a5" }, "us-west-1": { "AMIID": "ami-ec28058c" }, "us-west-2": { "AMIID": "ami-3c4b4145" } } }, "Resources": { "EcsSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "ECS Security Group", "VpcId": { "Ref": "VpcId" } } }, "EcsSecurityGroupHTTPinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": { "Ref": "EcsSecurityGroup" }, "IpProtocol": "tcp", "FromPort": "80", "ToPort": "80", "CidrIp": "0.0.0.0/0" } }, "EcsSecurityGroupRDPinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": { "Ref": "EcsSecurityGroup" }, "IpProtocol": "tcp", "FromPort": "3389", "ToPort": "3389", "CidrIp": "0.0.0.0/0" } }, "EcsSecurityGroupALBports": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": { "Ref": "EcsSecurityGroup" }, "IpProtocol": "tcp", "FromPort": "31000", "ToPort": "61000", "SourceSecurityGroupId": { "Ref": "EcsSecurityGroup" } } }, "ECSCluster": { "Type": "AWS::ECS::Cluster" }, "CloudwatchLogsGroup": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": { "Fn::Join": [ "-", [ "ECSLogGroup", { "Ref": "AWS::StackName" } ] ] }, "RetentionInDays": 14 } }, "taskdefinition": { "Type": "AWS::ECS::TaskDefinition", "Properties": { "ContainerDefinitions": [ { "Name": "windows_sample_app", "Cpu": "100", "Essential": "true", "Image": "microsoft/iis", "Memory": "500", "EntryPoint": [ "powershell", "-Command" ], "Command": [ "New-Item -Path C:\\inetpub\\wwwroot\\index.html -Type file -Value '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p>'; C:\\ServiceMonitor.exe w3svc" ], "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-group": { "Ref": "CloudwatchLogsGroup" }, "awslogs-region": { "Ref": "AWS::Region" }, "awslogs-stream-prefix": "ecs-windows-sample-app" } }, "PortMappings": [ { "ContainerPort": 80 } ] } ] } }, "ECSALB": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { "Name": "ECSALB", "Scheme": "internet-facing", "LoadBalancerAttributes": [ { "Key": "idle_timeout.timeout_seconds", "Value": "30" } ], "Subnets": { "Ref": "SubnetID" }, "SecurityGroups": [ { "Ref": "EcsSecurityGroup" } ] } }, "ALBListener": { "Type": "AWS::ElasticLoadBalancingV2::Listener", "DependsOn": "ECSServiceRole", "Properties": { "DefaultActions": [ { "Type": "forward", "TargetGroupArn": { "Ref": "ECSTargetGroup" } } ], "LoadBalancerArn": { "Ref": "ECSALB" }, "Port": "80", "Protocol": "HTTP" } }, "ECSALBListenerRule": { "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", "DependsOn": "ALBListener", "Properties": { "Actions": [ { "Type": "forward", "TargetGroupArn": { "Ref": "ECSTargetGroup" } } ], "Conditions": [ { "Field": "path-pattern", "Values": [ "/" ] } ], "ListenerArn": { "Ref": "ALBListener" }, "Priority": 1 } }, "ECSTargetGroup": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "DependsOn": "ECSALB", "Properties": { "HealthCheckIntervalSeconds": 10, "HealthCheckPath": "/", "HealthCheckProtocol": "HTTP", "HealthCheckTimeoutSeconds": 5, "HealthyThresholdCount": 2, "Name": "ECSTargetGroup", "Port": 80, "Protocol": "HTTP", "UnhealthyThresholdCount": 2, "VpcId": { "Ref": "VpcId" } } }, "ECSAutoScalingGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "VPCZoneIdentifier": { "Ref": "SubnetID" }, "LaunchConfigurationName": { "Ref": "ContainerInstances" }, "MinSize": "1", "MaxSize": { "Ref": "MaxSize" }, "DesiredCapacity": { "Ref": "DesiredCapacity" } }, "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "UpdatePolicy": { "AutoScalingRollingUpdate": { "MinInstancesInService": "1", "MaxBatchSize": "1", "PauseTime": "PT15M", "WaitOnResourceSignals": "true" } } }, "ContainerInstances": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Metadata": { "AWS::CloudFormation::Init": { "config": { "files": { "c:\\cfn\\cfn-hup.conf": { "content": { "Fn::Join": [ "", [ "[main]\n", "stack=", { "Ref": "AWS::StackId" }, "\n", "region=", { "Ref": "AWS::Region" }, "\n" ] ] } }, "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf": { "content": { "Fn::Join": [ "", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.ContainerInstances.Metadata.AWS::CloudFormation::Init\n", "action=cfn-init.exe -v -s ", { "Ref": "AWS::StackId" }, " -r ContainerInstances", " --region ", { "Ref": "AWS::Region" }, "\n" ] ] } } }, "services": { "windows": { "cfn-hup": { "enabled": "true", "ensureRunning": "true", "files": [ "c:\\cfn\\cfn-hup.conf", "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf" ] } } } } } }, "Properties": { "ImageId": { "Fn::FindInMap": [ "AWSRegionToAMI", { "Ref": "AWS::Region" }, "AMIID" ] }, "SecurityGroups": [ { "Ref": "EcsSecurityGroup" } ], "InstanceType": { "Ref": "InstanceType" }, "IamInstanceProfile": { "Ref": "EC2InstanceProfile" }, "KeyName": { "Ref": "KeyName" }, "BlockDeviceMappings": [ { "DeviceName": "/dev/sda1", "Ebs": { "VolumeSize": "100", "VolumeType": "gp2" } } ], "AssociatePublicIpAddress": "true", "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "<powershell> \n", " # Set agent env variables for the Machine context (durable)\n", " [Environment]::SetEnvironmentVariable(\"ECS_CLUSTER\", \"", { "Ref": "ECSCluster" }, "\"", ", \"Machine\")", "\n", "$agentVersion = 'v1.14.1';", "$agentZipUri = \"https://s3.amazonaws.com/amazon-ecs-agent/ecs-agent-windows-$agentVersion.zip\";", "$agentZipMD5Uri = \"$agentZipUri.md5\";", "$ecsExeDir = \"$env:ProgramFiles\\Amazon\\ECS\";", "$zipFile = \"$env:TEMP\\ecs-agent.zip\";", "echo \"log\" >> c:\\windows\\temp\\log1.txt;", "echo $zipFile >> c:\\windows\\temp\\log1.txt;", "echo $ecsExeDir >> c:\\windows\\temp\\log1.txt;", "$md5File = \"$env:TEMP\\ecs-agent.zip.md5\";", "Invoke-RestMethod -OutFile $zipFile -Uri $agentZipUri;", "Invoke-RestMethod -OutFile $md5File -Uri $agentZipMD5Uri;", "$expectedMD5 = (Get-Content $md5File);", "$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider;", "$actualMD5 = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($zipFile))).replace(\"-\", \"\");", "if($expectedMD5 -ne $actualMD5) {", "echo \"Download does not match hash.\";", "echo \"Expected: $expectedMD5 - Got: $actualMD5\";", "exit 1;", "};", "Expand-Archive -Path $zipFile -DestinationPath $ecsExeDir -Force;", "$jobname = \"ECS-Agent-Init\";", "$script = \"cd '$ecsExeDir'; .\\amazon-ecs-agent.ps1\";", "$repeat = (New-TimeSpan -Minutes 1);", "$jobpath = $env:LOCALAPPDATA + \"\\Microsoft\\Windows\\PowerShell\\ScheduledJobs\\$jobname\\ScheduledJobDefinition.xml;\"", "if($(Test-Path -Path $jobpath)) {", "echo \"Job definition already present\";", "exit 0;", "}", "$scriptblock = [scriptblock]::Create(\"$script\");", "$trigger = New-JobTrigger -At (Get-Date).Date -RepeatIndefinitely -RepetitionInterval $repeat -Once;", "$options = New-ScheduledJobOption -RunElevated -ContinueIfGoingOnBattery -StartIfOnBattery;", "Register-ScheduledJob -Name $jobname -ScriptBlock $scriptblock -Trigger $trigger -ScheduledJobOption $options -RunNow;", "Add-JobTrigger -Name $jobname -Trigger (New-JobTrigger -AtStartup -RandomDelay 00:1:00);", "echo $scriptblock >> c:\\windows\\temp\\log1.txt;", "echo $trigger >> c:\\windows\\temp\\log1.txt;", "echo $options >> c:\\windows\\temp\\log1.txt;", "# end of script\n", " cfn-init.exe -v -s ", { "Ref": "AWS::StackId" }, " -r ContainerInstances", " --region ", { "Ref": "AWS::Region" }, "\n", " cfn-signal.exe -e $lastexitcode --stack ", { "Ref": "AWS::StackName" }, " --resource ECSAutoScalingGroup ", " --region ", { "Ref": "AWS::Region" }, "; \n", " </powershell>\n", "<persist>true</persist>" ] ] } } } }, "service": { "Type": "AWS::ECS::Service", "DependsOn": "ALBListener", "Properties": { "Cluster": { "Ref": "ECSCluster" }, "DesiredCount": "1", "LoadBalancers": [ { "ContainerName": "windows_sample_app", "ContainerPort": "80", "TargetGroupArn": { "Ref": "ECSTargetGroup" } } ], "Role": { "Ref": "ECSServiceRole" }, "TaskDefinition": { "Ref": "taskdefinition" } } }, "ECSServiceRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ecs.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": [ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets", "ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress" ], "Resource": "*" } ] } } ] } }, "ServiceScalingTarget": { "Type": "AWS::ApplicationAutoScaling::ScalableTarget", "DependsOn": "service", "Properties": { "MaxCapacity": 2, "MinCapacity": 1, "ResourceId": { "Fn::Join": [ "", [ "service/", { "Ref": "ECSCluster" }, "/", { "Fn::GetAtt": [ "service", "Name" ] } ] ] }, "RoleARN": { "Fn::GetAtt": [ "AutoscalingRole", "Arn" ] }, "ScalableDimension": "ecs:service:DesiredCount", "ServiceNamespace": "ecs" } }, "ServiceScalingPolicy": { "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", "Properties": { "PolicyName": "AStepPolicy", "PolicyType": "StepScaling", "ScalingTargetId": { "Ref": "ServiceScalingTarget" }, "StepScalingPolicyConfiguration": { "AdjustmentType": "PercentChangeInCapacity", "Cooldown": 60, "MetricAggregationType": "Average", "StepAdjustments": [ { "MetricIntervalLowerBound": 0, "ScalingAdjustment": 200 } ] } } }, "ALB500sAlarmScaleUp": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "EvaluationPeriods": "1", "Statistic": "Average", "Threshold": "10", "AlarmDescription": "Alarm if our ALB generates too many HTTP 500s.", "Period": "60", "AlarmActions": [ { "Ref": "ServiceScalingPolicy" } ], "Namespace": "AWS/ApplicationELB", "Dimensions": [ { "Name": "ECSService", "Value": { "Ref": "service" } } ], "ComparisonOperator": "GreaterThanThreshold", "MetricName": "HTTPCode_ELB_5XX_Count" } }, "EC2Role": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:StartTelemetrySession", "ecs:Submit*", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } } ] } }, "AutoscalingRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "application-autoscaling.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "service-autoscaling", "PolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": [ "application-autoscaling:*", "cloudwatch:DescribeAlarms", "cloudwatch:PutMetricAlarm", "ecs:DescribeServices", "ecs:UpdateService" ], "Resource": "*" } ] } } ] } }, "EC2InstanceProfile": { "Type": "AWS::IAM::InstanceProfile", "Properties": { "Path": "/", "Roles": [ { "Ref": "EC2Role" } ] } } }, "Outputs": { "ecsservice": { "Value": { "Ref": "service" } }, "ecscluster": { "Value": { "Ref": "ECSCluster" } }, "ECSALB": { "Description": "Your ALB DNS URL", "Value": { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "ECSALB", "DNSName" ] } ] ] } }, "taskdef": { "Value": { "Ref": "taskdefinition" } } } }