Skip to content

Instantly share code, notes, and snippets.

@lancehudson
Created January 21, 2015 06:27
Show Gist options
  • Save lancehudson/0f78bda44b38dbb867d0 to your computer and use it in GitHub Desktop.
Save lancehudson/0f78bda44b38dbb867d0 to your computer and use it in GitHub Desktop.
CloudFormation script for Kubernetes on CoreOS on EC2
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Kubernetes on EC2",
"Mappings": {
"RegionMap": {
"eu-central-1": {"AMI": "ami-468dbd5b"},
"ap-northeast-1": {"AMI": "ami-0c05160d"},
"sa-east-1": {"AMI": "ami-23b00d3e"},
"ap-southeast-2": {"AMI": "ami-b7295c8d"},
"ap-southeast-1": {"AMI": "ami-b40f27e6"},
"us-east-1": {"AMI": "ami-3c750854"},
"us-west-2": {"AMI": "ami-bd2d728d"},
"us-west-1": {"AMI": "ami-8d534dc8"},
"eu-west-1": {"AMI": "ami-f96dec8e"}
},
"SubnetConfig" : {
"VPC" : { "CIDR" : "10.0.0.0/16" },
"Public" : { "CIDR" : "10.0.0.0/24" }
}
},
"Parameters": {
"InstanceType": {
"Description": "EC2 HVM instance type (m3.medium, etc).",
"Type": "String",
"Default": "m3.medium",
"AllowedValues": [
"m3.medium",
"m3.large",
"m3.xlarge",
"m3.2xlarge",
"c4.large",
"c4.xlarge",
"c4.2xlarge",
"c4.4xlarge",
"c4.8xlarge",
"c3.large",
"c3.xlarge",
"c3.2xlarge",
"c3.4xlarge",
"c3.8xlarge",
"i2.xlarge",
"i2.2xlarge",
"i2.4xlarge",
"i2.8xlarge",
"hs1.8xlarge",
"r3.large",
"r3.xlarge",
"r3.2xlarge",
"r3.4xlarge",
"r3.8xlarge",
"t2.micro",
"t2.small",
"t2.medium"
],
"ConstraintDescription": "Must be a valid EC2 HVM instance type."
},
"ClusterSize": {
"Description": "Number of nodes in cluster (3-12).",
"Default": "3",
"MinValue": "3",
"MaxValue": "12",
"Type": "Number"
},
"DiscoveryURL": {
"Description": "An unique etcd cluster discovery URL. Grab a new token from https://discovery.etcd.io/new",
"Type": "String"
},
"AllowSSHFrom": {
"Description": "The net block (CIDR) that SSH is available to.",
"Default": "0.0.0.0/0",
"Type": "String"
},
"KeyPair" : {
"Description": "The name of an EC2 Key Pair to allow SSH access to the instance.",
"Type": "String"
}
},
"Resources": {
"VPC" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"EnableDnsSupport" : "true",
"EnableDnsHostnames" : "true",
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]},
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"PublicSubnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Public", "CIDR" ]},
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"InternetGateway" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"GatewayToInternet" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"InternetGatewayId" : { "Ref" : "InternetGateway" }
}
},
"PublicRouteTable" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"PublicRoute" : {
"Type" : "AWS::EC2::Route",
"DependsOn" : "GatewayToInternet",
"Properties" : {
"RouteTableId" : { "Ref" : "PublicRouteTable" },
"DestinationCidrBlock" : "0.0.0.0/0",
"GatewayId" : { "Ref" : "InternetGateway" }
}
},
"PublicSubnetRouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PublicSubnet" },
"RouteTableId" : { "Ref" : "PublicRouteTable" }
}
},
"KubernetesSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Kubernetes SecurityGroup",
"VpcId" : { "Ref" : "VPC" },
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {"Ref": "AllowSSHFrom"}
},
{
"IpProtocol": "tcp",
"FromPort": "8080",
"ToPort": "8080",
"CidrIp": {"Ref": "AllowSSHFrom"}
}
]
}
},
"KubernetesIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {"Fn::GetAtt" : [ "KubernetesSecurityGroup", "GroupId" ]},
"IpProtocol": "tcp",
"FromPort": "1",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Fn::GetAtt" : [ "KubernetesSecurityGroup", "GroupId" ]
}
}
},
"KubernetesIngressUDP": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {"Fn::GetAtt" : [ "KubernetesSecurityGroup", "GroupId" ]},
"IpProtocol": "udp",
"FromPort": "1",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Fn::GetAtt" : [ "KubernetesSecurityGroup", "GroupId" ]
}
}
},
"KubernetesMasterInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": {"Fn::FindInMap" : ["RegionMap", {"Ref": "AWS::Region" }, "AMI"]},
"InstanceType": {"Ref": "InstanceType"},
"KeyName": {"Ref": "KeyPair"},
"NetworkInterfaces" : [{
"GroupSet" : [{ "Ref" : "KubernetesSecurityGroup" }],
"AssociatePublicIpAddress" : "true",
"DeviceIndex" : "0",
"DeleteOnTermination" : "true",
"SubnetId" : { "Ref" : "PublicSubnet" }
}],
"UserData": { "Fn::Base64": {"Fn::Join" : ["", [
"#cloud-config\n\n",
"---\n",
"write_files:\n",
"- path: /opt/bin/waiter.sh\n",
" owner: root\n",
" content: |\n",
" #! /usr/bin/bash\n",
" until curl http://127.0.0.1:4001/v2/machines; do sleep 2; done\n",
"runcmd:\n",
" - [ wget, -NP, /opt/bin, \"https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kubecfg\" ]\n",
" - [ wget, -NP, /opt/bin, \"https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kubectl\" ]\n",
" - [ wget, -NP, /opt/bin, \"https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kubernetes\" ]\n",
" - [ chmod, +x, /opt/bin/kubecfg ]\n",
" - [ chmod, +x, /opt/bin/kubectl ]\n",
" - [ chmod, +x, /opt/bin/kubernetes ]\n",
"coreos:\n",
" units:\n",
" - name: setup-network-environment.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Setup Network Environment\n",
" Documentation=https://github.com/kelseyhightower/setup-network-environment\n",
" Requires=network-online.target\n",
" After=network-online.target\n",
" [Service]\n",
" ExecStartPre=-/usr/bin/mkdir -p /opt/bin\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/k8s/setup-network-environment\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment\n",
" ExecStart=/opt/bin/setup-network-environment\n",
" RemainAfterExit=yes\n",
" Type=oneshot\n",
" - name: etcd.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=etcd\n",
" Requires=setup-network-environment.service\n",
" After=setup-network-environment.service\n",
" [Service]\n",
" EnvironmentFile=/etc/network-environment\n",
" User=etcd\n",
" PermissionsStartOnly=true\n",
" ExecStart=/usr/bin/etcd \\\n",
" --name $private_ipv4 \\\n",
" --addr $private_ipv4:4001 \\\n",
" --bind-addr 0.0.0.0 \\\n",
" --cluster-active-size 1 \\\n",
" --discovery \"", { "Ref": "DiscoveryURL" }, "\"\\\n",
" --data-dir /var/lib/etcd \\\n",
" --http-read-timeout 86400 \\\n",
" --peer-addr $private_ipv4:7001 \\\n",
" --snapshot true\n",
" Restart=always\n",
" RestartSec=10s\n",
" - name: fleet.socket\n",
" command: start\n",
" content: |\n",
" [Socket]\n",
" ListenStream=/var/run/fleet.sock\n",
" - name: fleet.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=fleet daemon\n",
" Wants=etcd.service\n",
" After=etcd.service\n",
" Wants=fleet.socket\n",
" After=fleet.socket\n",
" [Service]\n",
" Environment=\"FLEET_ETCD_SERVERS=http://127.0.0.1:4001\"\n",
" Environment=\"FLEET_METADATA=role=master\"\n",
" ExecStart=/usr/bin/fleetd\n",
" Restart=always\n",
" RestartSec=10s\n",
" - name: etcd-waiter.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=etcd waiter\n",
" Wants=network-online.target\n",
" Wants=etcd.service\n",
" After=etcd.service\n",
" After=network-online.target\n",
" Before=flannel.service\n",
" Before=setup-network-environment.service\n",
" [Service]\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/waiter.sh\n",
" ExecStart=/usr/bin/bash /opt/bin/waiter.sh\n",
" RemainAfterExit=true\n",
" Type=oneshot\n",
" - name: flannel.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Wants=etcd-waiter.service\n",
" After=etcd-waiter.service\n",
" Requires=etcd.service\n",
" After=etcd.service\n",
" After=network-online.target\n",
" Wants=network-online.target\n",
" Description=flannel is an etcd backed overlay network for containers\n",
" [Service]\n",
" Type=notify\n",
" ExecStartPre=-/usr/bin/mkdir -p /opt/bin\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/k8s/flanneld\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/flanneld\n",
" ExecStartPre=/usr/bin/etcdctl mk /coreos.com/network/config '{\"Network\":\"10.0.0.0/16\", \"Backend\": {\"Type\": \"vxlan\"}}'\n",
" ExecStart=/opt/bin/flanneld\n",
" - name: kube-apiserver.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes API Server\n",
" Documentation=https://github.com/GoogleCloudPlatform/kubernetes\n",
" Requires=etcd.service\n",
" After=etcd.service\n",
" [Service]\n",
" ExecStartPre=-/usr/bin/mkdir -p /opt/bin\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kube-apiserver\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-apiserver\n",
" ExecStart=/opt/bin/kube-apiserver \\\n",
" --address=0.0.0.0 \\\n",
" --port=8080 \\\n",
" --portal_net=10.0.0.0/16 \\\n",
" --etcd_servers=http://127.0.0.1:4001 \\\n",
" --public_address_override=$private_ipv4 \\\n",
" --logtostderr=true\n",
" Restart=always\n",
" RestartSec=10\n",
" - name: kube-controller-manager.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes Controller Manager\n",
" Documentation=https://github.com/GoogleCloudPlatform/kubernetes\n",
" Requires=kube-apiserver.service\n",
" After=kube-apiserver.service\n",
" [Service]\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kube-controller-manager\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-controller-manager\n",
" ExecStart=/opt/bin/kube-controller-manager \\\n",
" --master=127.0.0.1:8080 \\\n",
" --logtostderr=true\n",
" Restart=always\n",
" RestartSec=10\n",
" - name: kube-scheduler.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes Scheduler\n",
" Documentation=https://github.com/GoogleCloudPlatform/kubernetes\n",
" Requires=kube-apiserver.service\n",
" After=kube-apiserver.service\n",
" [Service]\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kube-scheduler\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-scheduler\n",
" ExecStart=/opt/bin/kube-scheduler --master=127.0.0.1:8080\n",
" Restart=always\n",
" RestartSec=10\n",
" - name: kube-register.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes Registration Service\n",
" Documentation=https://github.com/kelseyhightower/kube-register\n",
" Requires=kube-apiserver.service\n",
" After=kube-apiserver.service\n",
" Requires=fleet.service\n",
" After=fleet.service\n",
" [Service]\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/k8s/kube-register\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-register\n",
" ExecStart=/opt/bin/kube-register \\\n",
" --metadata=role=node \\\n",
" --fleet-endpoint=unix:///var/run/fleet.sock \\\n",
" --api-endpoint=http://127.0.0.1:8080\n",
" Restart=always\n",
" RestartSec=10\n",
" update:\n",
" group: stable\n",
" reboot-strategy: etcd-lock\n"
]]}
}
}
},
"KubernetesNodeLaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"DependsOn" : "VPC",
"Properties": {
"ImageId": {"Fn::FindInMap" : ["RegionMap", {"Ref": "AWS::Region" }, "AMI" ]},
"InstanceType": {"Ref": "InstanceType"},
"KeyName": {"Ref": "KeyPair"},
"SecurityGroups": [{"Ref": "KubernetesSecurityGroup"}],
"AssociatePublicIpAddress" : "true",
"UserData": { "Fn::Base64": {"Fn::Join" : ["", [
"#cloud-config\n\n",
"coreos:\n",
" units:\n",
" - name: etcd.service\n",
" mask: true\n",
" - name: fleet.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=fleet daemon\n",
" Wants=fleet.socket\n",
" After=fleet.socket\n",
" [Service]\n",
" Environment=\"FLEET_ETCD_SERVERS=http://", {"Fn::GetAtt":["KubernetesMasterInstance" , "PrivateIp"]}, ":4001\"\n",
" Environment=\"FLEET_METADATA=role=node\"\n",
" ExecStart=/usr/bin/fleetd\n",
" Restart=always\n",
" RestartSec=10s\n",
" - name: flannel.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" After=network-online.target\n",
" Wants=network-online.target\n",
" Description=flannel is an etcd backed overlay network for containers\n\n",
" [Service]\n",
" Type=notify\n",
" ExecStartPre=-/usr/bin/mkdir -p /opt/bin\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/k8s/flanneld\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/flanneld\n",
" ExecStart=/opt/bin/flanneld -etcd-endpoints http://", {"Fn::GetAtt" :["KubernetesMasterInstance" , "PrivateIp"]}, ":4001\n",
" - name: docker.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" After=flannel.service\n",
" Wants=flannel.service\n",
" Description=Docker Application Container Engine\n",
" Documentation=http://docs.docker.io\n\n",
" [Service]\n",
" EnvironmentFile=/run/flannel/subnet.env\n",
" ExecStartPre=/bin/mount --make-rprivate /\n",
" ExecStart=/usr/bin/docker -d --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} -s=overlay -H fd://\n\n",
" [Install]\n",
" WantedBy=multi-user.target\n",
" - name: setup-network-environment.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Setup Network Environment\n",
" Documentation=https://github.com/kelseyhightower/setup-network-environment\n",
" Requires=network-online.target\n",
" After=network-online.target\n\n",
" [Service]\n",
" ExecStartPre=-/usr/bin/mkdir -p /opt/bin\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/k8s/setup-network-environment\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment\n",
" ExecStart=/opt/bin/setup-network-environment\n",
" RemainAfterExit=yes\n",
" Type=oneshot\n",
" - name: kube-proxy.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes Proxy\n",
" Documentation=https://github.com/GoogleCloudPlatform/kubernetes\n",
" Requires=setup-network-environment.service\n",
" After=setup-network-environment.service\n\n",
" [Service]\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kube-proxy\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-proxy\n",
" ExecStart=/opt/bin/kube-proxy \\\n",
" --etcd_servers=http://", {"Fn::GetAtt" :["KubernetesMasterInstance" , "PrivateIp"]}, ":4001\\\n",
" --logtostderr=true\n",
" Restart=always\n",
" RestartSec=10\n",
" - name: kube-kubelet.service\n",
" command: start\n",
" content: |\n",
" [Unit]\n",
" Description=Kubernetes Kubelet\n",
" Documentation=https://github.com/GoogleCloudPlatform/kubernetes\n",
" Requires=setup-network-environment.service\n",
" After=setup-network-environment.service\n\n",
" [Service]\n",
" EnvironmentFile=/etc/network-environment\n",
" ExecStartPre=/usr/bin/wget -N -P /opt/bin https://storage.googleapis.com/kubernetes-release/release/v0.8.1/bin/linux/amd64/kubelet\n",
" ExecStartPre=/usr/bin/chmod +x /opt/bin/kubelet\n",
" ExecStart=/opt/bin/kubelet \\\n",
" --address=0.0.0.0 \\\n",
" --port=10250 \\\n",
" --hostname_override=${DEFAULT_IPV4} \\\n",
" --etcd_servers=http://", {"Fn::GetAtt" :["KubernetesMasterInstance" , "PrivateIp"]}, ":4001\\\n",
" --logtostderr=true\n",
" Restart=always\n",
" RestartSec=10\n",
" update:\n",
" group: stable\n",
" reboot-strategy: etcd-lock\n"
]]}
}
}
},
"KubernetesAutoScalingGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones" : [{ "Fn::GetAtt" : [ "PublicSubnet", "AvailabilityZone" ] }],
"VPCZoneIdentifier" : [{ "Ref" : "PublicSubnet" }],
"LaunchConfigurationName": {"Ref": "KubernetesNodeLaunchConfig"},
"MinSize": "3",
"MaxSize": "12",
"DesiredCapacity": {"Ref": "ClusterSize"}
}
}
},
"Outputs": {
"KubernetesMasterPublicIp": {
"Description": "Public Ip of the newly created Kubernetes Master instance",
"Value": {"Fn::GetAtt": ["KubernetesMasterInstance" , "PublicIp"]}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment