diff --git a/docs/01-infrastructure-aws.md b/docs/01-infrastructure-aws.md new file mode 100644 index 0000000..a70c2da --- /dev/null +++ b/docs/01-infrastructure-aws.md @@ -0,0 +1,396 @@ +# AWS Cloud Infrastructure Provisioning + +Kubernetes can be installed just about anywhere physical or virtual machines can be run. In this lab we are going to focus on [Amazon EC2](https://aws.amazon.com) (IaaS). + +This lab will walk you through provisioning the compute instances required for running a H/A Kubernetes cluster. A total of 9 virtual machines will be created. + +After completing this guide you should have the following compute instances: + +``` +``` + +```` +```` + +> All machines will be provisioned with fixed private IP addresses to simplify the bootstrap process. + +To make our Kubernetes control plane remotely accessible, a public IP address will be provisioned and assigned to a Load Balancer that will sit in front of the 3 Kubernetes controllers. + +## Create a Custom Network + +``` +VPC_ID=$(aws ec2 create-vpc \ + --cidr-block 10.240.0.0/16 | \ + jq -r '.Vpc.VpcId') +``` + +``` +aws ec2 modify-vpc-attribute \ + --vpc-id ${VPC_ID} \ + --enable-dns-support '{"Value": true}' +``` + +``` +aws ec2 modify-vpc-attribute \ + --vpc-id ${VPC_ID} \ + --enable-dns-hostnames '{"Value": true}' +``` + +``` +DHCP_OPTION_SET_ID=$(aws ec2 create-dhcp-options \ + --dhcp-configuration "Key=domain-name,Values=us-west-2.compute.internal" \ + "Key=domain-name-servers,Values=AmazonProvidedDNS" | \ + jq -r '.DhcpOptions.DhcpOptionsId') +``` + +``` +aws ec2 associate-dhcp-options \ + --dhcp-options-id ${DHCP_OPTION_SET_ID} \ + --vpc-id ${VPC_ID} +``` + +Create a subnet for the Kubernetes cluster: + +``` +SUBNET_ID=$(aws ec2 create-subnet \ + --vpc-id ${VPC_ID} \ + --cidr-block 10.240.0.0/24 | \ + jq -r '.Subnet.SubnetId') +``` + +Create an internet gateway + +``` +INTERNET_GATEWAY_ID=$(aws ec2 create-internet-gateway | \ + jq -r '.InternetGateway.InternetGatewayId') +``` + +``` +aws ec2 attach-internet-gateway \ + --internet-gateway-id ${INTERNET_GATEWAY_ID} \ + --vpc-id ${VPC_ID} +``` + +### Route Table + +``` +ROUTE_TABLE_ID=$(aws ec2 create-route-table \ + --vpc-id ${VPC_ID} | \ + jq -r '.RouteTable.RouteTableId') +``` + +``` +aws ec2 associate-route-table \ + --route-table-id ${ROUTE_TABLE_ID} \ + --subnet-id ${SUBNET_ID} +``` + +``` +aws ec2 create-route \ + --route-table-id ${ROUTE_TABLE_ID} \ + --destination-cidr-block 0.0.0.0/0 \ + --gateway-id ${INTERNET_GATEWAY_ID} +``` + +### Firewall Rules + +``` +SECURITY_GROUP_ID=$(aws ec2 create-security-group \ + --group-name kubernetes \ + --description "Kubernetes security group" \ + --vpc-id ${VPC_ID} | \ + jq -r '.GroupId') +``` + +``` +aws ec2 authorize-security-group-ingress \ + --group-id ${SECURITY_GROUP_ID} \ + --protocol all +``` + +``` +aws ec2 authorize-security-group-ingress \ + --group-id ${SECURITY_GROUP_ID} \ + --protocol tcp \ + --port 22 \ + --cidr 0.0.0.0/0 +``` + +``` +aws ec2 authorize-security-group-ingress \ + --group-id ${SECURITY_GROUP_ID} \ + --protocol tcp \ + --port 443 \ + --cidr 0.0.0.0/0 +``` + +## Create the Kubernetes Public IP Address + +Create a public IP address that will be used by remote clients to connect to the Kubernetes control plane: + +``` +KUBERNETES_PUBLIC_IP=$(aws ec2 allocate-address \ + --domain vpc | \ + jq -r '.PublicIp') +``` + +## Provision Virtual Machines + +All the VMs in this lab will be provisioned using Ubuntu 16.04 mainly because it runs a newish Linux Kernel that has good support for Docker. + +### Create Instance IAM Policies + +``` +cat > kubernetes-iam-role.json <<'EOF' +{ + "Version": "2012-10-17", + "Statement": [ + {"Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole"} + ] +} +EOF +``` + +``` +aws iam create-role \ + --role-name kubernetes \ + --assume-role-policy-document file://kubernetes-iam-role.json +``` + +``` +cat > kubernetes-iam-policy.json <<'EOF' +{ + "Version": "2012-10-17", + "Statement": [ + {"Effect": "Allow", "Action": ["ec2:*"], "Resource": ["*"]}, + {"Effect": "Allow", "Action": ["elasticloadbalancing:*"], "Resource": ["*"]}, + {"Effect": "Allow", "Action": ["route53:*"], "Resource": ["*"]}, + {"Effect": "Allow", "Action": ["ecr:*"], "Resource": "*"} + ] +} +EOF +``` + +``` +aws iam put-role-policy \ + --role-name kubernetes \ + --policy-name kubernetes \ + --policy-document file://kubernetes-iam-policy.json +``` + +``` +aws iam create-instance-profile \ + --instance-profile-name kubernetes +``` + +``` +aws iam add-role-to-instance-profile \ + --instance-profile-name kubernetes \ + --role-name kubernetes +``` + +### Chosing an Image + +Use the [Ubuntu Amazon EC2 AMI Locator](https://cloud-images.ubuntu.com/locator/ec2/) to find the right image-id for your zone. This guide assumes the `us-west-2` zone. + +``` +IMAGE_ID="ami-746aba14" +``` + +### Generate A SSH Key Pair + +``` +aws ec2 create-key-pair --key-name kubernetes | \ + jq -r '.KeyMaterial' > ~/.ssh/kubernetes_the_hard_way +``` + +``` +chmod 600 ~/.ssh/kubernetes_the_hard_way +``` + +``` +ssh-add ~/.ssh/kubernetes_the_hard_way +``` + +### etcd + +``` +ETCD_0_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.10 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${ETCD_0_INSTANCE_ID} \ + --tags Key=Name,Value=etcd0 +``` + +``` +ETCD_1_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.11 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${ETCD_1_INSTANCE_ID} \ + --tags Key=Name,Value=etcd1 +``` + +``` +ETCD_2_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.12 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${ETCD_2_INSTANCE_ID} \ + --tags Key=Name,Value=etcd2 +``` + +### Kubernetes Controllers + +``` +CONTROLLER_0_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.20 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${CONTROLLER_0_INSTANCE_ID} \ + --tags Key=Name,Value=controller0 +``` + +``` +CONTROLLER_1_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.21 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${CONTROLLER_1_INSTANCE_ID} \ + --tags Key=Name,Value=controller1 +``` + +``` +CONTROLLER_2_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.22 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${CONTROLLER_2_INSTANCE_ID} \ + --tags Key=Name,Value=controller2 +``` + +### Kubernetes Workers + +``` +WORKER_0_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.30 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${WORKER_0_INSTANCE_ID} \ + --tags Key=Name,Value=worker0 +``` + +``` +WORKER_1_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.31 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${WORKER_1_INSTANCE_ID} \ + --tags Key=Name,Value=worker1 +``` + +``` +WORKER_2_INSTANCE_ID=$(aws ec2 run-instances \ + --associate-public-ip-address \ + --iam-instance-profile 'Name=kubernetes' \ + --image-id ${IMAGE_ID} \ + --count 1 \ + --key-name kubernetes \ + --security-group-ids ${SECURITY_GROUP_ID} \ + --instance-type t2.small \ + --private-ip-address 10.240.0.32 \ + --subnet-id ${SUBNET_ID} | \ + jq -r '.Instances[].InstanceId') +``` + +``` +aws ec2 create-tags \ + --resources ${CONTROLLER_2_INSTANCE_ID} \ + --tags Key=Name,Value=worker2 +```