Skip to content

Instantly share code, notes, and snippets.

@mbabineau
Last active July 3, 2018 13:34
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mbabineau/11387941 to your computer and use it in GitHub Desktop.
Save mbabineau/11387941 to your computer and use it in GitHub Desktop.
Docker Registry CloudFormation template (better version here: https://github.com/mbabineau/cloudformation-docker-registry)
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Launches a Docker Registry.",
"Parameters" : {
"InstanceType" : {
"Description" : "EC2 instance type",
"Type" : "String",
"Default" : "m1.small",
"AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","m3.xlarge","m3.2xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
"ConstraintDescription" : "must be a valid EC2 instance type."
},
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"Type" : "String"
},
"DockerAmi" : {
"Description" : "Docker-capable AMI to use for the registry servers",
"Type" : "String"
},
"ClientSecurityGroup" : {
"Description" : "Name of the security group from which clients may access the registry",
"Type" : "String"
},
"DnsPrefix" : {
"Description" : "Prefix for the registry's DNS record (<prefix>.<zone>)",
"Type": "String",
"Default": "docker"
},
"DnsZone" : {
"Description" : "Route53-hosted zone to use for the registry's DNS record (<prefix>.<zone>) (e.g., 'mycompany.com')",
"Type": "String"
},
"RegistryImage" : {
"Description" : "Name of the Docker Registry image to use (format: 'registry:port/repository:version'",
"Type" : "String",
"Default" : "samalba/docker-registry"
},
"S3Bucket" : {
"Description" : "Bucket to use for Docker images (e.g., 'mycompany-docker')",
"Type" : "String",
},
"ClusterSize": {
"Description" : "Number of Docker Registry servers to run",
"Type" : "Number",
"Default" : 1
},
"AdminLocation" : {
"Description" : "IP address range that can be used to manage the instance and the registry",
"Type": "String",
"MinLength": "9",
"MaxLength": "18",
"Default": "0.0.0.0/0",
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
"ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
}
},
"Resources" : {
"IAMUser" : {
"Type" : "AWS::IAM::User",
"Properties" : {
"Policies" : [{
"PolicyName" : "S3Access",
"PolicyDocument" : {
"Statement": [{
"Effect" : "Allow",
"Action" : "s3:*",
"Resource" : { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref" : "S3Bucket"} , "/*"]]}
}]
}
},
{
"PolicyName" : "IAMAccess",
"PolicyDocument" : {
"Statement" : [{
"Effect" : "Allow",
"NotAction" : "iam:*",
"Resource" : "*"
}]
}
}]
}
},
"HostKeys" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : {
"UserName" : { "Ref" : "IAMUser" }
}
},
"ServerGroup" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : { "Fn::GetAZs" : "" },
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MinSize" : "1",
"MaxSize" : "1",
"DesiredCapacity" : "1",
"LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ],
"VPCZoneIdentifier" : { "Ref" : "Subnets" }
}
},
"LaunchConfig" : {
"Type" : "AWS::AutoScaling::LaunchConfiguration",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config": {
"files" : {
"/opt/docker-registry/config.yml" : {
"content" : { "Fn::Join" : ["\n", [
"prod:",
" loglevel: warn",
" storage: s3",
" s3_access_key: {{access_key}}",
" s3_secret_key: {{secret_key}}",
" s3_bucket: {{s3_bucket}}",
" boto_bucket: {{s3_bucket}}",
" storage_path: /srv/docker",
" secret_key: {{magic_string}}"
]]},
"context" : {
"access_key" : { "Ref" : "HostKeys" },
"secret_key" : { "Fn::GetAtt" : ["HostKeys", "SecretAccessKey"]},
"s3_bucket" : { "Ref" : "S3Bucket"},
"magic_string": "fL3YHeP1cmCHH5FWm1PKaO7cdo0VXkabAgiSEestXYZDgAiQcDCsTiWpOaukB1e9"
},
"mode" : "000700",
"owner" : "root",
"group" : "root"
}
}
}
}
},
"Properties" : {
"KeyName" : { "Ref" : "KeyName" },
"ImageId" : { "Ref" : "DockerAmi" },
"SecurityGroups" : [ { "Ref" : "ServerSecurityGroup" } ],
"AssociatePublicIpAddress": "true",
"InstanceType" : { "Ref" : "InstanceType" },
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bash -ex\n",
"# Helper function\n",
"function error_exit\n",
"{\n",
" cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandle" }, "'\n",
" exit 1\n",
"}\n",
"cfn-init -s ", { "Ref" : "AWS::StackName" }, " -r LaunchConfig ",
" --access-key ", { "Ref" : "HostKeys" },
" --secret-key ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]},
" --region ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
"# Post-cfn work\n",
"sudo docker run -d",
" -p 5000:5000",
" -v /opt/docker-registry:/registry-conf",
" -e DOCKER_REGISTRY_CONFIG=/registry-conf/config.yml",
" -e SETTINGS_FLAVOR=prod",
" ", { "Ref": "RegistryImage" }, "|| error_exit 'Failed to launch Docker container'\n",
"# All is well so signal success\n",
"cfn-signal -e 0 -r \"Stack setup complete\" '", { "Ref" : "WaitHandle" }, "'\n",
"#EOF"
]]}}
}
},
"ServerSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable SSH and Registry access",
"VpcId" : { "Ref" : "VpcId" },
"SecurityGroupIngress" :
[ { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "AdminLocation"} },
{ "IpProtocol" : "tcp", "FromPort" : "5000", "ToPort" : "5000", "SourceSecurityGroupId" : { "Ref" : "LbSecurityGroup"} }]
}
},
"LbSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable Registry access",
"VpcId" : { "Ref" : "VpcId" },
"SecurityGroupIngress" :
[ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : { "Ref" : "AdminLocation"} },
{ "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupId" : { "Ref" : "ClientSecurityGroup"} } ]
}
},
"ElasticLoadBalancer" : {
"Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties" : {
"SecurityGroups": [{ "Ref": "LbSecurityGroup" }],
"Subnets": { "Ref": "Subnets" },
"Listeners" : [ {
"LoadBalancerPort" : "80",
"InstancePort" : "5000",
"Protocol" : "HTTP"
} ],
"HealthCheck" : {
"Target" : "HTTP:5000/",
"HealthyThreshold" : "3",
"UnhealthyThreshold" : "5",
"Interval" : "30",
"Timeout" : "5"
}
}
},
"DnsRecord" : {
"Type" : "AWS::Route53::RecordSet",
"Properties" : {
"HostedZoneName" : { "Fn::Join" : [ "", [{"Ref" : "DnsZone"}, "." ]]},
"Comment" : "Docker Registry",
"Name" : { "Fn::Join" : [ "", [{"Ref" : "DnsPrefix"}, ".", {"Ref" : "DnsZone"}, "."]]},
"Type" : "CNAME",
"TTL" : "900",
"ResourceRecords" : [ { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ] } ]
}
},
"WaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
}
},
"Outputs" : {
"DnsAddress" : {
"Description" : "Docker Registry",
"Value" : { "Ref" : "DnsRecord" }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment