Skip to content

Commit 1fb74d3

Browse files
authored
Merge pull request aws-samples#326 from buzzsurfr/master
Automated IDE Deployment
2 parents 4c295c7 + 771fe3c commit 1fb74d3

File tree

4 files changed

+838
-0
lines changed

4 files changed

+838
-0
lines changed

cloud9-development/readme.adoc

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,102 @@ The workshop repo has configuration files that are used to create Kubernetes res
8484
$ git clone https://github.com/aws-samples/aws-workshop-for-kubernetes
8585

8686
At this point, you should have everything you need to complete any of the section of the this workshop using your Cloud9 Environment.
87+
88+
=== Automated Deployment using CloudFormation
89+
90+
You can also use a CloudFormation template to create the Kubernetes Development Environment. These templates will create the Cloud9 IDE with IAM Role as well as the kops state store bucket.
91+
92+
To launch the template in your account, you will need to download one of the following:
93+
94+
* To use an existing Subnet, download link:templates/lab-ide-novpc.template[lab-ide-novpc.template]
95+
* To use a new VPC/Subnet, download link:templates/lab-ide-vpc.template[lab-ide-vpc.template]
96+
97+
==== Option 1: Console
98+
99+
1. Log into the AWS CloudFormation Console by visiting https://console.aws.amazon.com/cloudformation/home
100+
101+
2. Click on **Create Stack**.
102+
103+
3. Under **Choose a Template**, click to *Upload a template to Amazon S3* and upload the file you downloaded earlier.
104+
105+
4. Click **Next**.
106+
107+
5. Specify a `Stack Name` and optionally a `SubnetId`. Click **Next**.
108+
109+
6. Scroll down to the bottom and click **Next**.
110+
111+
7. Under **Capabilities**, acknowledge that CloudFormation will create IAM resources, and click **Create**.
112+
113+
8. Wait until the stack you just launched has a status of `CREATE_COMPLETE` (you may need to refresh), then check the box next to the new stack and select the **Outputs** tab. This will show the URL to the Cloud9 IDE (`LabIdeUrl`). Click the URL to go into your IDE.
114+
115+
9. Download the build script: link:scripts/lab-ide-build.sh[lab-ide-build.sh].
116+
117+
10. Copy the contents of the build script and paste into the *Terminal* window in the IDE (near the bottom).
118+
119+
At this point, you should have everything you need to complete any of the section of the this workshop using your Cloud9 Environment.
120+
121+
==== Option 2: CLI
122+
123+
Get a list of existing public subnets.
124+
125+
.Command
126+
[source,bash]
127+
----
128+
aws ec2 describe-subnets --query 'Subnets[?MapPublicIpOnLaunch==`true`].SubnetId'
129+
----
130+
131+
.Output
132+
[source,output]
133+
----
134+
[
135+
"subnet-1234abcd",
136+
"subnet-5678ef12",
137+
...
138+
]
139+
----
140+
141+
Launch the CloudFormation stack, substituting a SubnetId for `<SubnetId>`.
142+
143+
.Command
144+
[source,bash]
145+
----
146+
aws cloudformation create-stack --stack-name "LabIDE" --template-body file://lab-ide-novpc.template --capabilities CAPABILITY_NAMED_IAM --parameters ParameterKey=SubnetId,ParameterValue=<SubnetId>
147+
----
148+
149+
If you are using the link:templates/lab-ide-vpc.template[lab-ide-vpc.template], launch the stack using:
150+
151+
.Command
152+
[source,bash]
153+
----
154+
aws cloudformation create-stack --stack-name "LabIDE" --template-body file://lab-ide-vpc.template --capabilities CAPABILITY_NAMED_IAM
155+
----
156+
157+
Once launched, occasionally poll the status of the stack.
158+
159+
.Command
160+
[source,bash]
161+
----
162+
aws cloudformation describe-stacks --stack-name LabIDE --query "Stacks[0].StackStatus" --output text
163+
----
164+
165+
When this changes from `CREATE_IN_PROGRESS` to `CREATE_COMPLETE`, get the URL of the Cloud9 IDE.
166+
167+
.Command
168+
[source,bash]
169+
----
170+
aws cloudformation describe-stacks --stack-name LabIDE --query 'Stacks[0].Outputs[?OutputKey==`LabIdeUrl`].OutputValue' --output text
171+
----
172+
173+
.Output
174+
[source,output]
175+
----
176+
https://console.aws.amazon.com/cloud9/ide/<EnvironmentId>
177+
----
178+
179+
Launch the IDE by copying the URL into your browser.
180+
181+
Download the build script: link:scripts/lab-ide-build.sh[lab-ide-build.sh].
182+
183+
Copy the contents of the build script and paste into the *Terminal* window in the IDE (near the bottom).
184+
185+
At this point, you should have everything you need to complete any of the section of the this workshop using your Cloud9 Environment.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# IDE-Build script
2+
#title lab-ide-build.sh
3+
#description This script will make a header for a bash script.
4+
5+
#date 2018-01-19
6+
#version 0.1
7+
#usage curl -sSL https://s3.amazonaws.com/lab-ide-theomazonian/lab-ide-build.sh | bash -s stable
8+
#notes Install Vim and Emacs to use this script.
9+
#==============================================================================
10+
11+
# Install jq
12+
sudo yum -y install jq
13+
14+
# Install kubectl
15+
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
16+
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
17+
source <(kubectl completion bash)
18+
19+
# Install kops
20+
curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
21+
chmod +x kops-linux-amd64
22+
sudo mv kops-linux-amd64 /usr/local/bin/kops
23+
24+
# Configure AWS CLI
25+
availability_zone=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
26+
export AWS_DEFAULT_REGION=${availability_zone%?}
27+
28+
# Lab-specific configuration
29+
export AWS_AVAILABILITY_ZONES="$(aws ec2 describe-availability-zones --query 'AvailabilityZones[].ZoneName' --output text | awk -v OFS="," '$1=$1')"
30+
export AWS_INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
31+
aws ec2 describe-instances --instance-ids $AWS_INSTANCE_ID > /tmp/instance.json
32+
export AWS_STACK_NAME=$(jq -r '.Reservations[0].Instances[0]|(.Tags[]|select(.Key=="aws:cloudformation:stack-name")|.Value)' /tmp/instance.json)
33+
export AWS_ENVIRONMENT=$(jq -r '.Reservations[0].Instances[0]|(.Tags[]|select(.Key=="aws:cloud9:environment")|.Value)' /tmp/instance.json)
34+
export AWS_MASTER_STACK=${AWS_STACK_NAME%$AWS_ENVIRONMENT}
35+
export AWS_MASTER_STACK=${AWS_MASTER_STACK%?}
36+
export AWS_MASTER_STACK=${AWS_MASTER_STACK#aws-cloud9-}
37+
export KOPS_STATE_STORE=s3://$(aws cloudformation describe-stack-resource --stack-name $AWS_MASTER_STACK --logical-resource-id "KopsStateStore" | jq -r '.StackResourceDetail.PhysicalResourceId')
38+
39+
# Persist lab variables
40+
echo "AWS_AVAILABILITY_ZONES=$AWS_AVAILABILITY_ZONES" >> ~/.bash_profile
41+
echo "KOPS_STATE_STORE=$KOPS_STATE_STORE" >> ~/.bash_profile
42+
echo "export AWS_AVAILABILITY_ZONES KOPS_STATE_STORE" >> ~/.bash_profile
43+
44+
# Download lab Repository
45+
git clone https://github.com/aws-samples/aws-workshop-for-kubernetes
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
{
2+
"AWSTemplateFormatVersion": "2010-09-09",
3+
"Description": "Lab IDE using existing Subnet for container workshop v0.4",
4+
"Metadata": {},
5+
"Parameters": {
6+
"SubnetId": {
7+
"Description": "Public Subnet for the Lab IDE.",
8+
"Type": "AWS::EC2::Subnet::Id",
9+
"Default": ""
10+
}
11+
},
12+
"Mappings": {},
13+
"Conditions": {},
14+
"Resources": {
15+
"LabIDE": {
16+
"Description": "-",
17+
"Type": "AWS::Cloud9::EnvironmentEC2",
18+
"Properties": {
19+
"Description": "Lab IDE for container workshop",
20+
"AutomaticStopTimeMinutes": 60,
21+
"InstanceType": "t2.micro",
22+
"Name": {
23+
"Ref": "AWS::StackName"
24+
},
25+
"SubnetId": {
26+
"Ref": "SubnetId"
27+
}
28+
}
29+
},
30+
"KopsStateStore": {
31+
"Description": "-",
32+
"Type": "AWS::S3::Bucket",
33+
"Properties": {
34+
"VersioningConfiguration": {
35+
"Status": "Enabled"
36+
}
37+
}
38+
},
39+
"LabIdeRole": {
40+
"Type": "AWS::IAM::Role",
41+
"Properties": {
42+
"AssumeRolePolicyDocument": {
43+
"Version": "2012-10-17",
44+
"Statement": [
45+
{
46+
"Effect": "Allow",
47+
"Principal": {
48+
"Service": [
49+
"ec2.amazonaws.com"
50+
]
51+
},
52+
"Action": [
53+
"sts:AssumeRole"
54+
]
55+
}
56+
]
57+
},
58+
"ManagedPolicyArns": [
59+
"arn:aws:iam::aws:policy/AmazonEC2FullAccess",
60+
"arn:aws:iam::aws:policy/AmazonRoute53FullAccess",
61+
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
62+
"arn:aws:iam::aws:policy/IAMFullAccess",
63+
"arn:aws:iam::aws:policy/AmazonVPCFullAccess"
64+
],
65+
"Path": "/"
66+
}
67+
},
68+
"LabIdeInstanceProfile": {
69+
"Type": "AWS::IAM::InstanceProfile",
70+
"Properties": {
71+
"Path": "/",
72+
"Roles": [
73+
{
74+
"Ref": "LabIdeRole"
75+
}
76+
]
77+
}
78+
},
79+
"AddRoleToInstance": {
80+
"Description": "Add LabIdeRole to Cloud9 IDE Instance",
81+
"Type": "Custom::AddRoleToInstance",
82+
"DependsOn": ["AddRoleToInstanceFunction"],
83+
"Properties": {
84+
"ServiceToken": {
85+
"Fn::GetAtt": [
86+
"AddRoleToInstanceFunction",
87+
"Arn"
88+
]
89+
},
90+
"Region": {
91+
"Ref": "AWS::Region"
92+
},
93+
"StackName": {
94+
"Ref": "AWS::StackName"
95+
},
96+
"EnvironmentId": {
97+
"Ref": "LabIDE"
98+
},
99+
"LabIdeInstanceProfileName": {
100+
"Ref": "LabIdeInstanceProfile"
101+
},
102+
"LabIdeInstanceProfileArn": {
103+
"Fn::GetAtt": [
104+
"LabIdeInstanceProfile",
105+
"Arn"
106+
]
107+
}
108+
}
109+
},
110+
"AddRoleToInstanceFunction": {
111+
"Type": "AWS::Lambda::Function",
112+
"Properties": {
113+
"Code": {
114+
"ZipFile": {
115+
"Fn::Join": [
116+
"\n",
117+
[
118+
"import boto3",
119+
"import time",
120+
"import traceback",
121+
"import cfnresponse",
122+
"",
123+
"def handler(event, context):",
124+
" responseData = {}",
125+
" ",
126+
" # Immediately respond on Delete (no work to be done)",
127+
" if event['RequestType'] == 'Delete':",
128+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
129+
" ",
130+
" try:",
131+
" # Open AWS clients",
132+
" ec2 = boto3.client('ec2')",
133+
" ",
134+
" # Get the InstanceId of the Cloud9 IDE",
135+
" instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0]",
136+
" ",
137+
" # Create the IamInstanceProfile request object",
138+
" iam_instance_profile = {",
139+
" 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'],",
140+
" 'Name': event['ResourceProperties']['LabIdeInstanceProfileName']",
141+
" }",
142+
" ",
143+
" # Wait for Instance to become ready before adding Role",
144+
" instance_state = instance['State']['Name']",
145+
" while instance_state != 'running':",
146+
" time.sleep(5)",
147+
" instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']])",
148+
" ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId'])",
149+
" ",
150+
" responseData = {'Success': 'Role added to instance'+instance['InstanceId']+'.'}",
151+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
152+
" except Exception as e:",
153+
" responseData = {'Error': traceback.format_exc(e)}",
154+
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')"
155+
]
156+
]
157+
}
158+
},
159+
"Handler": "index.handler",
160+
"Role": {
161+
"Fn::GetAtt": [
162+
"LambdaExecutionRole",
163+
"Arn"
164+
]
165+
},
166+
"Runtime": "python2.7",
167+
"Timeout": "30"
168+
}
169+
},
170+
"LambdaExecutionRole": {
171+
"Type": "AWS::IAM::Role",
172+
"Properties": {
173+
"AssumeRolePolicyDocument": {
174+
"Version": "2012-10-17",
175+
"Statement": [
176+
{
177+
"Effect": "Allow",
178+
"Principal": {
179+
"Service": [
180+
"lambda.amazonaws.com"
181+
]
182+
},
183+
"Action": [
184+
"sts:AssumeRole"
185+
]
186+
}
187+
]
188+
},
189+
"Path": "/",
190+
"Policies": [
191+
{
192+
"PolicyName": "root",
193+
"PolicyDocument": {
194+
"Version": "2012-10-17",
195+
"Statement": [
196+
{
197+
"Effect": "Allow",
198+
"Action": [
199+
"logs:CreateLogGroup",
200+
"logs:CreateLogStream",
201+
"logs:PutLogEvents"
202+
],
203+
"Resource": "arn:aws:logs:*:*:*"
204+
},
205+
{
206+
"Effect": "Allow",
207+
"Action": [
208+
"cloudformation:DescribeStacks",
209+
"cloudformation:DescribeStackEvents",
210+
"cloudformation:DescribeStackResource",
211+
"cloudformation:DescribeStackResources",
212+
"ec2:DescribeInstances",
213+
"ec2:AssociateIamInstanceProfile",
214+
"ec2:ReplaceIamInstanceProfileAssociation",
215+
"iam:ListInstanceProfiles",
216+
"iam:PassRole"
217+
],
218+
"Resource": "*"
219+
}
220+
]
221+
}
222+
}
223+
]
224+
}
225+
}
226+
},
227+
"Outputs": {
228+
"LabIdeUrl": {
229+
"Value": {
230+
"Fn::Join": [
231+
"",
232+
[
233+
"https://console.aws.amazon.com/cloud9/ide/",
234+
{
235+
"Ref": "LabIDE"
236+
}
237+
]
238+
]
239+
}
240+
}
241+
}
242+
}

0 commit comments

Comments
 (0)