├── .gitignore ├── README.md ├── nodes.json └── rancher.json /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | shots/ 3 | data.txt 4 | .DS_Store 5 | *.swp 6 | public/ 7 | *.rdb 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Setting up Rancher on AWS 2 | ============================ 3 | 4 | 5 | This guide is designed for those who want a hassle free setup of Rancher using RancherOS on AWS using Cloudformation templates. These are provided as as close to "Ready to use" as possible, with the exception that the Rancher Server is not HA, only single instance. 6 | 7 | # Stack information 8 | 9 | The stacks are very customisable, including an RDS instance for database storage of the Rancher Server, a single EC2 instance for Rancher Server and several instances for the Rancher nodes. 10 | 11 | ### Create MySQL and Rancher Server Instance 12 | 13 | Create these resources by uploading the rancher template. If the Rancher server goes down, all your data will be stored in MySQL. You can select the instance type you want as well as other parameters around RDS, or you can use the defaults. 14 | 15 | The Rancher Server instance will run on top of RancherOS. Once completed, the Rancher server will be available at the load balancer URL found in the Load Balancer section in the EC2 Console. 16 | 17 | If running RancherOS is not an option, you will need to chance the UserData section to remove the Rancher specific start up options. 18 | 19 | ### Create Rancher Node Instances 20 | 21 | Create the Rancher Nodes. If you are going to use the load balancer URL rather than a domain you own, visit that in your browser, otherwise you can use a domain you own via a service such as Route53. 22 | 23 | When you first visit Rancher, it will ask you to set up authentication, probably via Github, set this up as prompted and then visit the infrastructure tab. 24 | 25 | Click add custom node and copy the URL. 26 | 27 | Upload the nodes template and add in your Rancher Server URL without any of the docker commands. This should connect your nodes to your Rancher Server. 28 | -------------------------------------------------------------------------------- /nodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Parameters": { 4 | "MinSize": { 5 | "Type": "String", 6 | "Description": "The minimum number of instances", 7 | "Default": 3 8 | }, 9 | "MaxSize": { 10 | "Type": "String", 11 | "Description": "The maximum number of instances", 12 | "Default": 5 13 | }, 14 | "InstanceType": { 15 | "Type": "String", 16 | "Description": "The size of the instances", 17 | "Default": "t2.small" 18 | }, 19 | "ImageId": { 20 | "Type": "String", 21 | "Default": "ami-997b1eea" 22 | }, 23 | "KeyName": { 24 | "Type": "AWS::EC2::KeyPair::KeyName" 25 | }, 26 | "CPUAlarmHighEvalPeriods": { 27 | "Type": "String", 28 | "Default": "1" 29 | }, 30 | "CPUAlarmHighThreshold": { 31 | "Type": "String", 32 | "Default": "80" 33 | }, 34 | "CPUAlarmLowThreshold": { 35 | "Type": "String", 36 | "Default": "60" 37 | }, 38 | "CPUAlarmLowEvalPeriods": { 39 | "Type": "String", 40 | "Default": "5" 41 | }, 42 | "AlarmPeriod": { 43 | "Type": "String", 44 | "Default": "60" 45 | }, 46 | "RancherServerURL": { 47 | "Type": "String" 48 | }, 49 | "VpcId": { 50 | "Type": "AWS::EC2::VPC::Id", 51 | "Default": "vpc-" 52 | }, 53 | "PublicSubnets": { 54 | "Type": "List", 55 | "Default": "subnet-" 56 | } 57 | }, 58 | "Resources": { 59 | "ComponentAutoScalingGroup": { 60 | "Type": "AWS::AutoScaling::AutoScalingGroup", 61 | "UpdatePolicy": { 62 | "AutoScalingRollingUpdate": { 63 | "MinInstancesInService": 1, 64 | "MaxBatchSize": 1, 65 | "PauseTime": "PT0S" 66 | } 67 | }, 68 | "Properties": { 69 | "VPCZoneIdentifier" : { "Ref" : "PublicSubnets" }, 70 | "Tags": [ 71 | { 72 | "Value": "rancher", 73 | "PropagateAtLaunch": true, 74 | "Key": "Project" 75 | }, 76 | { 77 | "Value": "rancher-node", 78 | "PropagateAtLaunch": true, 79 | "Key": "Name" 80 | }, 81 | { 82 | "Value": "rancher-node", 83 | "PropagateAtLaunch": true, 84 | "Key": "Component" 85 | } 86 | ], 87 | "MinSize": { 88 | "Ref": "MinSize" 89 | }, 90 | "MaxSize": { 91 | "Ref": "MaxSize" 92 | }, 93 | "LaunchConfigurationName": { 94 | "Ref": "ComponentLaunchConfiguration" 95 | }, 96 | "AvailabilityZones": { 97 | "Fn::GetAZs": "" 98 | } 99 | } 100 | }, 101 | "ComponentLaunchConfiguration": { 102 | "Type": "AWS::AutoScaling::LaunchConfiguration", 103 | "Properties": { 104 | "KeyName": { 105 | "Ref": "KeyName" 106 | }, 107 | "SecurityGroups": [ 108 | { 109 | "Ref": "ComponentSecurityGroup" 110 | } 111 | ], 112 | "InstanceType": { 113 | "Ref": "InstanceType" 114 | }, 115 | "ImageId": { 116 | "Ref": "ImageId" 117 | }, 118 | "UserData": { 119 | "Fn::Base64": { 120 | "Fn::Join": [ 121 | "", 122 | [ 123 | "#cloud-config\n", 124 | "rancher:\n", 125 | " services:\n", 126 | " register:\n", 127 | " priviledged: true\n", 128 | " volumes:\n", 129 | " - /var/run/docker.sock:/var/run/docker.sock\n", 130 | " image: rancher/agent\n", 131 | " command:\n", 132 | { 133 | "Fn::Join": [ 134 | "", 135 | [ 136 | " - ", 137 | { 138 | "Ref": "RancherServerURL" 139 | } 140 | ] 141 | ] 142 | } 143 | ] 144 | ] 145 | } 146 | } 147 | } 148 | }, 149 | "ComponentScaleUpPolicy": { 150 | "Type": "AWS::AutoScaling::ScalingPolicy", 151 | "Properties": { 152 | "AutoScalingGroupName": { 153 | "Ref": "ComponentAutoScalingGroup" 154 | }, 155 | "AdjustmentType": "ChangeInCapacity", 156 | "Cooldown": 240, 157 | "ScalingAdjustment": 1 158 | } 159 | }, 160 | "ComponentScaleDownPolicy": { 161 | "Type": "AWS::AutoScaling::ScalingPolicy", 162 | "Properties": { 163 | "AutoScalingGroupName": { 164 | "Ref": "ComponentAutoScalingGroup" 165 | }, 166 | "AdjustmentType": "ChangeInCapacity", 167 | "Cooldown": 60, 168 | "ScalingAdjustment": -1 169 | } 170 | }, 171 | "CPUAlarmHigh": { 172 | "Type": "AWS::CloudWatch::Alarm", 173 | "Properties": { 174 | "AlarmDescription": "Scale-up if CPU > 80% for 1 minutes", 175 | "Threshold": { 176 | "Ref": "CPUAlarmHighThreshold" 177 | }, 178 | "AlarmActions": [ 179 | { 180 | "Ref": "ComponentScaleUpPolicy" 181 | } 182 | ], 183 | "ComparisonOperator": "GreaterThanThreshold", 184 | "EvaluationPeriods": { 185 | "Ref": "CPUAlarmHighEvalPeriods" 186 | }, 187 | "MetricName": "CPUUtilization", 188 | "Namespace": "AWS/EC2", 189 | "Statistic": "Average", 190 | "Period": { 191 | "Ref": "AlarmPeriod" 192 | }, 193 | "Dimensions": [ 194 | { 195 | "Name": "AutoScalingGroupName", 196 | "Value": { 197 | "Ref": "ComponentAutoScalingGroup" 198 | } 199 | } 200 | ] 201 | } 202 | }, 203 | "CPUAlarmLow": { 204 | "Type": "AWS::CloudWatch::Alarm", 205 | "Properties": { 206 | "AlarmDescription": "Scale-down if CPU < 60% for 5 minutes", 207 | "Threshold": { 208 | "Ref": "CPUAlarmLowThreshold" 209 | }, 210 | "AlarmActions": [ 211 | { 212 | "Ref": "ComponentScaleDownPolicy" 213 | } 214 | ], 215 | "ComparisonOperator": "LessThanThreshold", 216 | "EvaluationPeriods": { 217 | "Ref": "CPUAlarmLowEvalPeriods" 218 | }, 219 | "MetricName": "CPUUtilization", 220 | "Namespace": "AWS/EC2", 221 | "Statistic": "Average", 222 | "Period": { 223 | "Ref": "AlarmPeriod" 224 | }, 225 | "Dimensions": [ 226 | { 227 | "Name": "AutoScalingGroupName", 228 | "Value": { 229 | "Ref": "ComponentAutoScalingGroup" 230 | } 231 | } 232 | ] 233 | } 234 | }, 235 | "ComponentSecurityGroup": { 236 | "Type": "AWS::EC2::SecurityGroup", 237 | "Properties": { 238 | "SecurityGroupIngress": [ 239 | { 240 | "FromPort": 0, 241 | "ToPort": 0, 242 | "IpProtocol": "-1", 243 | "CidrIp": "0.0.0.0/0" 244 | } 245 | ], 246 | "VpcId": { 247 | "Ref": "VpcId" 248 | }, 249 | "GroupDescription": "A component security group allowing access to the outside world" 250 | } 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /rancher.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Parameters": { 4 | "HealthCheckGracePeriod": { 5 | "Type": "String", 6 | "Description": "The length of time in seconds after a new EC2 instance comes into service that Auto Scaling starts checking its health.", 7 | "Default": 600 8 | }, 9 | "InstanceType": { 10 | "Type": "String", 11 | "Description": "The size of the instances", 12 | "Default": "t2.medium" 13 | }, 14 | "ImageId": { 15 | "Type": "String", 16 | "Default": "ami-997b1eea" 17 | }, 18 | "KeyName": { 19 | "Type": "AWS::EC2::KeyPair::KeyName" 20 | }, 21 | "VpcId": { 22 | "Type": "AWS::EC2::VPC::Id", 23 | "Default": "vpc-" 24 | }, 25 | "PublicSubnets": { 26 | "Type": "List", 27 | "Default": "subnet-" 28 | }, 29 | "ELBConnectionDraining": { 30 | "Type": "String", 31 | "Description": "Connection draining ensures that the load balancer completes serving all in-flight requests made to a registered instance when the instance is deregistered or becomes unhealthy", 32 | "Default": 30 33 | }, 34 | "AllocatedStorage": { 35 | "Type": "String", 36 | "Default": "5", 37 | "Description": "Disk space, default 5GB" 38 | }, 39 | "BackupRetentionPeriod": { 40 | "Type": "String", 41 | "Default": "7", 42 | "Description": "Number of days" 43 | }, 44 | "DBInstanceClass": { 45 | "Type": "String", 46 | "Default": "db.t2.medium" 47 | }, 48 | "DBInstanceIdentifier": { 49 | "Type": "String", 50 | "Default": "rancher-master" 51 | }, 52 | "DBName": { 53 | "Type": "String", 54 | "Default": "rancher" 55 | }, 56 | "MasterUsername": { 57 | "Type": "String", 58 | "MinLength": "1", 59 | "MaxLength": "16", 60 | "AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*", 61 | "Description": "Username for database access" 62 | }, 63 | "MasterUserPassword": { 64 | "NoEcho": true, 65 | "Type": "String", 66 | "Description": "Password for database access - minimum 8 characters", 67 | "MinLength": "8", 68 | "MaxLength": "41", 69 | "AllowedPattern": "[a-zA-Z0-9]*", 70 | "ConstraintDescription": "must contain 8 alphanumeric characters." 71 | }, 72 | "MultiAZ": { 73 | "Type": "String", 74 | "Default": true, 75 | "Description": "Provides enhanced availablily for RDS" 76 | }, 77 | "Port": { 78 | "Type": "String", 79 | "Default": "3306", 80 | "Description": "Standard Port for MySQL" 81 | }, 82 | "PubliclyAccessible": { 83 | "Type": "String", 84 | "Default": false, 85 | "Description": "Determines if the MySQL instance can be connected to outside of you VPC" 86 | }, 87 | "StorageType": { 88 | "Type": "String", 89 | "Default": "gp2", 90 | "Description": "Disk type for RDS" 91 | } 92 | }, 93 | "Resources": { 94 | "ComponentAutoScalingGroup": { 95 | "Type": "AWS::AutoScaling::AutoScalingGroup", 96 | "UpdatePolicy": { 97 | "AutoScalingRollingUpdate": { 98 | "MinInstancesInService": 1, 99 | "MaxBatchSize": 1, 100 | "PauseTime": "PT0S" 101 | } 102 | }, 103 | "Properties": { 104 | "VPCZoneIdentifier" : { "Ref" : "PublicSubnets" }, 105 | "Tags": [ 106 | { 107 | "Value": "rancher", 108 | "PropagateAtLaunch": true, 109 | "Key": "Project" 110 | }, 111 | { 112 | "Value": "rancher-server", 113 | "PropagateAtLaunch": true, 114 | "Key": "Name" 115 | }, 116 | { 117 | "Value": "rancher-server", 118 | "PropagateAtLaunch": true, 119 | "Key": "Component" 120 | } 121 | ], 122 | "LoadBalancerNames": [ 123 | { 124 | "Ref": "ComponentElasticLoadBalancer" 125 | } 126 | ], 127 | "MinSize": 1, 128 | "MaxSize": 2, 129 | "LaunchConfigurationName": { 130 | "Ref": "ComponentLaunchConfiguration" 131 | }, 132 | "AvailabilityZones": { 133 | "Fn::GetAZs": "" 134 | }, 135 | "HealthCheckType": "ELB", 136 | "HealthCheckGracePeriod": { 137 | "Ref": "HealthCheckGracePeriod" 138 | } 139 | }, 140 | "DependsOn": "ServiceComponentRDS" 141 | }, 142 | "ComponentLaunchConfiguration": { 143 | "Type": "AWS::AutoScaling::LaunchConfiguration", 144 | "Properties": { 145 | "KeyName": { 146 | "Ref": "KeyName" 147 | }, 148 | "SecurityGroups": [ 149 | { 150 | "Ref": "ComponentSecurityGroup" 151 | }, 152 | { 153 | "Ref": "RDSComponentSecurityGroup" 154 | } 155 | ], 156 | "InstanceType": { 157 | "Ref": "InstanceType" 158 | }, 159 | "ImageId": { 160 | "Ref": "ImageId" 161 | }, 162 | "UserData": { 163 | "Fn::Base64": { 164 | "Fn::Join": [ 165 | "", 166 | [ 167 | "#cloud-config\n", 168 | "rancher:\n", 169 | " services:\n", 170 | " rancher-server:\n", 171 | " image: rancher/server\n", 172 | " ports:\n", 173 | " - 8080:8080\n", 174 | " restart: always\n", 175 | " environment:\n", 176 | { 177 | "Fn::Join": [ 178 | "", 179 | [ 180 | " - CATTLE_DB_CATTLE_MYSQL_HOST=", 181 | { 182 | "Fn::GetAtt": [ 183 | "ServiceComponentRDS", 184 | "Endpoint.Address" 185 | ] 186 | }, 187 | "\n" 188 | ] 189 | ] 190 | }, 191 | { 192 | "Fn::Join": [ 193 | "", 194 | [ 195 | " - CATTLE_DB_CATTLE_MYSQL_PORT=", 196 | { 197 | "Fn::GetAtt": [ 198 | "ServiceComponentRDS", 199 | "Endpoint.Port" 200 | ] 201 | }, 202 | "\n" 203 | ] 204 | ] 205 | }, 206 | { 207 | "Fn::Join": [ 208 | "", 209 | [ 210 | " - CATTLE_DB_CATTLE_MYSQL_NAME=", 211 | { 212 | "Ref": "DBName" 213 | }, 214 | "\n" 215 | ] 216 | ] 217 | }, 218 | { 219 | "Fn::Join": [ 220 | "", 221 | [ 222 | " - CATTLE_DB_CATTLE_USERNAME=", 223 | { 224 | "Ref": "MasterUsername" 225 | }, 226 | "\n" 227 | ] 228 | ] 229 | }, 230 | { 231 | "Fn::Join": [ 232 | "", 233 | [ 234 | " - CATTLE_DB_CATTLE_PASSWORD=", 235 | { 236 | "Ref": "MasterUserPassword" 237 | }, 238 | "\n" 239 | ] 240 | ] 241 | } 242 | ] 243 | ] 244 | } 245 | } 246 | } 247 | }, 248 | "LoadBalancerSecurityGroup": { 249 | "Type": "AWS::EC2::SecurityGroup", 250 | "Properties": { 251 | "SecurityGroupIngress": [ 252 | { 253 | "ToPort": 80, 254 | "IpProtocol": "tcp", 255 | "FromPort": 80, 256 | "CidrIp": "0.0.0.0/0" 257 | } 258 | ], 259 | "VpcId": { 260 | "Ref": "VpcId" 261 | }, 262 | "GroupDescription": "An ELB group allowing access only to from the corresponding component" 263 | } 264 | }, 265 | "ComponentSecurityGroup": { 266 | "Type": "AWS::EC2::SecurityGroup", 267 | "Properties": { 268 | "SecurityGroupIngress": [ 269 | { 270 | "FromPort": 8080, 271 | "ToPort": 8080, 272 | "IpProtocol": "tcp", 273 | "SourceSecurityGroupId": { 274 | "Ref": "LoadBalancerSecurityGroup" 275 | } 276 | }, 277 | { 278 | "FromPort": 4500, 279 | "ToPort": 4500, 280 | "IpProtocol": "udp", 281 | "CidrIp": "0.0.0.0/0" 282 | }, 283 | { 284 | "FromPort": 22, 285 | "ToPort": 22, 286 | "IpProtocol": "tcp", 287 | "CidrIp": "0.0.0.0/0" 288 | }, 289 | { 290 | "FromPort": 500, 291 | "ToPort": 500, 292 | "IpProtocol": "udp", 293 | "CidrIp": "0.0.0.0/0" 294 | } 295 | ], 296 | "VpcId": { 297 | "Ref": "VpcId" 298 | }, 299 | "GroupDescription": "A component security group allowing access only from the corresponding ELB" 300 | } 301 | }, 302 | "ComponentElasticLoadBalancer": { 303 | "Type": "AWS::ElasticLoadBalancing::LoadBalancer", 304 | "Properties": { 305 | "CrossZone": true, 306 | "Subnets": { 307 | "Ref": "PublicSubnets" 308 | }, 309 | "Listeners": [ 310 | { 311 | "InstancePort": 8080, 312 | "LoadBalancerPort": 80, 313 | "Protocol": "tcp", 314 | "InstanceProtocol": "tcp" 315 | } 316 | ], 317 | "SecurityGroups": [ 318 | { 319 | "Ref": "LoadBalancerSecurityGroup" 320 | } 321 | ], 322 | "Policies": [ 323 | { 324 | "PolicyName": "EnableProxyProtocol", 325 | "InstancePorts": [ 326 | "8080" 327 | ], 328 | "PolicyType": "ProxyProtocolPolicyType", 329 | "Attributes": [ 330 | { 331 | "Name": "ProxyProtocol", 332 | "Value": "true" 333 | } 334 | ] 335 | } 336 | ], 337 | "HealthCheck": { 338 | "HealthyThreshold": 3, 339 | "Interval": 15, 340 | "Target": "HTTP:8080/ping", 341 | "Timeout": 10, 342 | "UnhealthyThreshold": 8 343 | }, 344 | "ConnectionDrainingPolicy": { 345 | "Enabled": true, 346 | "Timeout": { 347 | "Ref": "ELBConnectionDraining" 348 | } 349 | } 350 | } 351 | }, 352 | "ServiceComponentRDS": { 353 | "Type": "AWS::RDS::DBInstance", 354 | "Properties": { 355 | "AllocatedStorage": { 356 | "Ref": "AllocatedStorage" 357 | }, 358 | "BackupRetentionPeriod": { 359 | "Ref": "BackupRetentionPeriod" 360 | }, 361 | "DBInstanceClass": { 362 | "Ref": "DBInstanceClass" 363 | }, 364 | "DBInstanceIdentifier": { 365 | "Ref": "DBInstanceIdentifier" 366 | }, 367 | "DBName": { 368 | "Ref": "DBName" 369 | }, 370 | "Engine": "MySQL", 371 | "MasterUsername": { 372 | "Ref": "MasterUsername" 373 | }, 374 | "MasterUserPassword": { 375 | "Ref": "MasterUserPassword" 376 | }, 377 | "MultiAZ": { 378 | "Ref": "MultiAZ" 379 | }, 380 | "Port": { 381 | "Ref": "Port" 382 | }, 383 | "PubliclyAccessible": { 384 | "Ref": "PubliclyAccessible" 385 | }, 386 | "StorageType": { 387 | "Ref": "StorageType" 388 | }, 389 | "VPCSecurityGroups": [ 390 | { 391 | "Ref": "RancherRDSSecurityGroup" 392 | } 393 | ], 394 | "DBSubnetGroupName": { 395 | "Ref": "ServiceSubnetRDS" 396 | } 397 | } 398 | }, 399 | "ServiceSubnetRDS": { 400 | "Type": "AWS::RDS::DBSubnetGroup", 401 | "Properties": { 402 | "DBSubnetGroupDescription": "VPC access", 403 | "SubnetIds": { 404 | "Ref": "PublicSubnets" 405 | } 406 | } 407 | }, 408 | "RDSComponentSecurityGroup": { 409 | "Type": "AWS::EC2::SecurityGroup", 410 | "Properties": { 411 | "VpcId": { 412 | "Ref": "VpcId" 413 | }, 414 | "GroupDescription": "Component security group for RDS" 415 | } 416 | }, 417 | "RancherRDSSecurityGroup": { 418 | "Type": "AWS::EC2::SecurityGroup", 419 | "Properties": { 420 | "SecurityGroupIngress": [ 421 | { 422 | "ToPort": "3306", 423 | "IpProtocol": "tcp", 424 | "FromPort": "3306", 425 | "SourceSecurityGroupId": { 426 | "Ref": "RDSComponentSecurityGroup" 427 | } 428 | } 429 | ], 430 | "VpcId": { 431 | "Ref": "VpcId" 432 | }, 433 | "GroupDescription": "RDS security group" 434 | } 435 | } 436 | }, 437 | "Outputs": { 438 | "WebsiteURL": { 439 | "Value": { 440 | "Fn::Join": [ 441 | "", 442 | [ 443 | "http://", 444 | { 445 | "Fn::GetAtt": [ 446 | "ComponentElasticLoadBalancer", 447 | "DNSName" 448 | ] 449 | } 450 | ] 451 | ] 452 | }, 453 | "Description": "URL for newly created rancher application" 454 | } 455 | } 456 | } 457 | --------------------------------------------------------------------------------