eks_cli 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +666 -0
- data/README.md +52 -0
- data/bin/eks +3 -0
- data/eks_cli.gemspec +31 -0
- data/lib/assets/default_storage_class.yaml +10 -0
- data/lib/assets/nodegroup_cf_template.yaml +305 -0
- data/lib/assets/nvidia_device_plugin.yaml +38 -0
- data/lib/eks_cli/cli.rb +161 -0
- data/lib/eks_cli/cloudformation/client.rb +11 -0
- data/lib/eks_cli/cloudformation/stack.rb +113 -0
- data/lib/eks_cli/cloudformation/vpc.rb +33 -0
- data/lib/eks_cli/config.rb +117 -0
- data/lib/eks_cli/ec2/security_group.rb +53 -0
- data/lib/eks_cli/eks/client.rb +11 -0
- data/lib/eks_cli/eks/cluster.rb +61 -0
- data/lib/eks_cli/iam/client.rb +84 -0
- data/lib/eks_cli/k8s/auth.rb +53 -0
- data/lib/eks_cli/k8s/client.rb +95 -0
- data/lib/eks_cli/k8s/configmap_builder.rb +30 -0
- data/lib/eks_cli/log.rb +26 -0
- data/lib/eks_cli/nodegroup.rb +118 -0
- data/lib/eks_cli/route53/client.rb +67 -0
- data/lib/eks_cli/vpc/client.rb +112 -0
- data/lib/eks_cli.rb +5 -0
- metadata +183 -0
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# EKS-CLI
|
2
|
+
|
3
|
+
EKS cluster bootstrap with batteries included
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
$ gem install eks_cli
|
9
|
+
$ eks bootstrap us-west-2 --cluster-name=My-EKS-Cluster
|
10
|
+
$ eks create-cluster-vpc --cluster-name=My-EKS-Cluster
|
11
|
+
$ eks create-cluster-security-group --cluster-name My-EKS-Cluster --open-ports=22
|
12
|
+
$ eks create-nodegroup --cluster-name My-EKS-Cluster --group-name nodes --ssh-key-name my-ssh-key --min 1 --max 3
|
13
|
+
$ eks create-nodegroup --cluster-name My-EKS-Cluster --group-name other-nodes --ssh-key-name my-ssh-key --min 3 --max 3 --instance-type m5.2xlarge
|
14
|
+
$ eks create-nodegroup --all --cluster-name My-EKS-Cluster --yes
|
15
|
+
```
|
16
|
+
|
17
|
+
## Extra Stuff
|
18
|
+
|
19
|
+
### Setting IAM policies to be attached to EKS nodes
|
20
|
+
|
21
|
+
`$ eks set-iam-policies --cluster-name=My-EKS-Cluster --policies=AmazonS3FullAccess AmazonDynamoDBFullAccess`
|
22
|
+
|
23
|
+
Makes sure all nodegroup instances are attached with the above policies once created
|
24
|
+
|
25
|
+
### Routing Route53 hostnames to Kubernetes service
|
26
|
+
|
27
|
+
`$ eks update-dns my-cool-service.my-company.com cool-service --route53-hosted-zone-id=XXXXX --elb-hosted-zone-id=XXXXXX --cluster-name=My-EKS-Cluster`
|
28
|
+
|
29
|
+
Takes the ELB endpoint from `cool-service` and puts it as an alias record of `my-cool-service.my-company.com`
|
30
|
+
|
31
|
+
### Enabling GPU
|
32
|
+
|
33
|
+
`$ eks enable-gpu --cluster-name EKS-Staging`
|
34
|
+
|
35
|
+
Installs the nvidia device plugin required to have your GPUs exposed
|
36
|
+
|
37
|
+
*Assumptions*:
|
38
|
+
|
39
|
+
1. You have a nodegroup using [EKS GPU AMI](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html)
|
40
|
+
2. This nodegroup uses a GPU instance (p2.x / p3.x etc)
|
41
|
+
|
42
|
+
### Adding Dockerhub Secrets
|
43
|
+
|
44
|
+
`$ eks set-docker-registry-credentials <dockerhub-user> <dockerhub-email> <dockerhub-password> --cluster-name My-EKS-Cluster`
|
45
|
+
|
46
|
+
Adds your dockerhub credentials as a secret and attaches it to the default serviceaccount imagePullSecrets
|
47
|
+
|
48
|
+
### Creating Default Storage Class
|
49
|
+
|
50
|
+
`$ eks create-default-storage-class --cluster-name My-EKS-Cluster`
|
51
|
+
|
52
|
+
Creates a standard gp2 default storage class named gp2
|
data/bin/eks
ADDED
data/eks_cli.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'eks_cli'
|
7
|
+
s.version = '0.1.0'
|
8
|
+
s.date = '2018-11-18'
|
9
|
+
s.summary = "Make EKS great again!"
|
10
|
+
s.description = "A utility to manage and create EKS (Kubernetes) cluster on Amazon Web Services"
|
11
|
+
s.authors = ["Erez Rabih"]
|
12
|
+
s.email = 'erez.rabih@gmail.com'
|
13
|
+
s.homepage =
|
14
|
+
'https://github.com/nanit/eks_cli'
|
15
|
+
s.license = 'MIT'
|
16
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
s.bindir = "bin"
|
20
|
+
s.executables = ["eks"]
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.add_dependency 'thor'
|
23
|
+
s.add_dependency 'aws-sdk-iam'
|
24
|
+
s.add_dependency 'aws-sdk-eks'
|
25
|
+
s.add_dependency 'aws-sdk-ec2'
|
26
|
+
s.add_dependency 'aws-sdk-cloudformation'
|
27
|
+
s.add_dependency 'aws-sdk-route53'
|
28
|
+
s.add_dependency 'activesupport'
|
29
|
+
s.add_dependency 'kubeclient'
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,305 @@
|
|
1
|
+
---
|
2
|
+
AWSTemplateFormatVersion: '2010-09-09'
|
3
|
+
Description: 'Amazon EKS - Node Group - Released 2018-08-30'
|
4
|
+
|
5
|
+
Parameters:
|
6
|
+
|
7
|
+
KeyName:
|
8
|
+
Description: The EC2 Key Pair to allow SSH access to the instances
|
9
|
+
Type: AWS::EC2::KeyPair::KeyName
|
10
|
+
|
11
|
+
NodeImageId:
|
12
|
+
Type: AWS::EC2::Image::Id
|
13
|
+
Description: AMI id for the node instances.
|
14
|
+
|
15
|
+
NodeInstanceType:
|
16
|
+
Description: EC2 instance type for the node instances
|
17
|
+
Type: String
|
18
|
+
Default: t2.medium
|
19
|
+
AllowedValues:
|
20
|
+
- t2.small
|
21
|
+
- t2.medium
|
22
|
+
- t2.large
|
23
|
+
- t2.xlarge
|
24
|
+
- t2.2xlarge
|
25
|
+
- m3.medium
|
26
|
+
- m3.large
|
27
|
+
- m3.xlarge
|
28
|
+
- m3.2xlarge
|
29
|
+
- m4.large
|
30
|
+
- m4.xlarge
|
31
|
+
- m4.2xlarge
|
32
|
+
- m4.4xlarge
|
33
|
+
- m4.10xlarge
|
34
|
+
- m5.large
|
35
|
+
- m5.xlarge
|
36
|
+
- m5.2xlarge
|
37
|
+
- m5.4xlarge
|
38
|
+
- m5.12xlarge
|
39
|
+
- m5.24xlarge
|
40
|
+
- c4.large
|
41
|
+
- c4.xlarge
|
42
|
+
- c4.2xlarge
|
43
|
+
- c4.4xlarge
|
44
|
+
- c4.8xlarge
|
45
|
+
- c5.large
|
46
|
+
- c5.xlarge
|
47
|
+
- c5.2xlarge
|
48
|
+
- c5.4xlarge
|
49
|
+
- c5.9xlarge
|
50
|
+
- c5.18xlarge
|
51
|
+
- i3.large
|
52
|
+
- i3.xlarge
|
53
|
+
- i3.2xlarge
|
54
|
+
- i3.4xlarge
|
55
|
+
- i3.8xlarge
|
56
|
+
- i3.16xlarge
|
57
|
+
- r3.xlarge
|
58
|
+
- r3.2xlarge
|
59
|
+
- r3.4xlarge
|
60
|
+
- r3.8xlarge
|
61
|
+
- r4.large
|
62
|
+
- r4.xlarge
|
63
|
+
- r4.2xlarge
|
64
|
+
- r4.4xlarge
|
65
|
+
- r4.8xlarge
|
66
|
+
- r4.16xlarge
|
67
|
+
- x1.16xlarge
|
68
|
+
- x1.32xlarge
|
69
|
+
- p2.xlarge
|
70
|
+
- p2.8xlarge
|
71
|
+
- p2.16xlarge
|
72
|
+
- p3.2xlarge
|
73
|
+
- p3.8xlarge
|
74
|
+
- p3.16xlarge
|
75
|
+
ConstraintDescription: Must be a valid EC2 instance type
|
76
|
+
|
77
|
+
NodeAutoScalingGroupMinSize:
|
78
|
+
Type: Number
|
79
|
+
Description: Minimum size of Node Group ASG.
|
80
|
+
Default: 1
|
81
|
+
|
82
|
+
NodeAutoScalingGroupMaxSize:
|
83
|
+
Type: Number
|
84
|
+
Description: Maximum size of Node Group ASG.
|
85
|
+
Default: 3
|
86
|
+
|
87
|
+
NodeVolumeSize:
|
88
|
+
Type: Number
|
89
|
+
Description: Node volume size
|
90
|
+
Default: 20
|
91
|
+
|
92
|
+
ClusterName:
|
93
|
+
Description: The cluster name provided when the cluster was created. If it is incorrect, nodes will not be able to join the cluster.
|
94
|
+
Type: String
|
95
|
+
|
96
|
+
BootstrapArguments:
|
97
|
+
Description: Arguments to pass to the bootstrap script. See files/bootstrap.sh in https://github.com/awslabs/amazon-eks-ami
|
98
|
+
Default: ""
|
99
|
+
Type: String
|
100
|
+
|
101
|
+
NodeGroupName:
|
102
|
+
Description: Unique identifier for the Node Group.
|
103
|
+
Type: String
|
104
|
+
|
105
|
+
ClusterControlPlaneSecurityGroup:
|
106
|
+
Description: The security group of the cluster control plane.
|
107
|
+
Type: AWS::EC2::SecurityGroup::Id
|
108
|
+
|
109
|
+
VpcId:
|
110
|
+
Description: The VPC of the worker instances
|
111
|
+
Type: AWS::EC2::VPC::Id
|
112
|
+
|
113
|
+
Subnets:
|
114
|
+
Description: The subnets where workers can be created.
|
115
|
+
Type: List<AWS::EC2::Subnet::Id>
|
116
|
+
|
117
|
+
ClusterSecurityGroup:
|
118
|
+
Description: Security group ID for in-cluster communication between node groups
|
119
|
+
Type: AWS::EC2::SecurityGroup::Id
|
120
|
+
|
121
|
+
Metadata:
|
122
|
+
AWS::CloudFormation::Interface:
|
123
|
+
ParameterGroups:
|
124
|
+
-
|
125
|
+
Label:
|
126
|
+
default: "EKS Cluster"
|
127
|
+
Parameters:
|
128
|
+
- ClusterName
|
129
|
+
- ClusterControlPlaneSecurityGroup
|
130
|
+
-
|
131
|
+
Label:
|
132
|
+
default: "Worker Node Configuration"
|
133
|
+
Parameters:
|
134
|
+
- NodeGroupName
|
135
|
+
- NodeAutoScalingGroupMinSize
|
136
|
+
- NodeAutoScalingGroupMaxSize
|
137
|
+
- NodeInstanceType
|
138
|
+
- NodeImageId
|
139
|
+
- NodeVolumeSize
|
140
|
+
- KeyName
|
141
|
+
- BootstrapArguments
|
142
|
+
-
|
143
|
+
Label:
|
144
|
+
default: "Worker Network Configuration"
|
145
|
+
Parameters:
|
146
|
+
- VpcId
|
147
|
+
- Subnets
|
148
|
+
|
149
|
+
Resources:
|
150
|
+
|
151
|
+
NodeInstanceProfile:
|
152
|
+
Type: AWS::IAM::InstanceProfile
|
153
|
+
Properties:
|
154
|
+
Path: "/"
|
155
|
+
Roles:
|
156
|
+
- !Ref NodeInstanceRole
|
157
|
+
|
158
|
+
NodeInstanceRole:
|
159
|
+
Type: AWS::IAM::Role
|
160
|
+
Properties:
|
161
|
+
AssumeRolePolicyDocument:
|
162
|
+
Version: '2012-10-17'
|
163
|
+
Statement:
|
164
|
+
- Effect: Allow
|
165
|
+
Principal:
|
166
|
+
Service:
|
167
|
+
- ec2.amazonaws.com
|
168
|
+
Action:
|
169
|
+
- sts:AssumeRole
|
170
|
+
Path: "/"
|
171
|
+
ManagedPolicyArns:
|
172
|
+
- arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
|
173
|
+
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
|
174
|
+
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
|
175
|
+
|
176
|
+
NodeSecurityGroup:
|
177
|
+
Type: AWS::EC2::SecurityGroup
|
178
|
+
Properties:
|
179
|
+
GroupDescription: Security group for all nodes in the cluster
|
180
|
+
VpcId:
|
181
|
+
!Ref VpcId
|
182
|
+
Tags:
|
183
|
+
- Key: !Sub "kubernetes.io/cluster/${ClusterName}"
|
184
|
+
Value: 'owned'
|
185
|
+
|
186
|
+
NodeSecurityGroupIngress:
|
187
|
+
Type: AWS::EC2::SecurityGroupIngress
|
188
|
+
DependsOn: NodeSecurityGroup
|
189
|
+
Properties:
|
190
|
+
Description: Allow node to communicate with each other
|
191
|
+
GroupId: !Ref NodeSecurityGroup
|
192
|
+
SourceSecurityGroupId: !Ref NodeSecurityGroup
|
193
|
+
IpProtocol: '-1'
|
194
|
+
FromPort: 0
|
195
|
+
ToPort: 65535
|
196
|
+
|
197
|
+
NodeSecurityGroupFromControlPlaneIngress:
|
198
|
+
Type: AWS::EC2::SecurityGroupIngress
|
199
|
+
DependsOn: NodeSecurityGroup
|
200
|
+
Properties:
|
201
|
+
Description: Allow worker Kubelets and pods to receive communication from the cluster control plane
|
202
|
+
GroupId: !Ref NodeSecurityGroup
|
203
|
+
SourceSecurityGroupId: !Ref ClusterControlPlaneSecurityGroup
|
204
|
+
IpProtocol: tcp
|
205
|
+
FromPort: 1025
|
206
|
+
ToPort: 65535
|
207
|
+
|
208
|
+
ControlPlaneEgressToNodeSecurityGroup:
|
209
|
+
Type: AWS::EC2::SecurityGroupEgress
|
210
|
+
DependsOn: NodeSecurityGroup
|
211
|
+
Properties:
|
212
|
+
Description: Allow the cluster control plane to communicate with worker Kubelet and pods
|
213
|
+
GroupId: !Ref ClusterControlPlaneSecurityGroup
|
214
|
+
DestinationSecurityGroupId: !Ref NodeSecurityGroup
|
215
|
+
IpProtocol: tcp
|
216
|
+
FromPort: 1025
|
217
|
+
ToPort: 65535
|
218
|
+
|
219
|
+
NodeSecurityGroupFromControlPlaneOn443Ingress:
|
220
|
+
Type: AWS::EC2::SecurityGroupIngress
|
221
|
+
DependsOn: NodeSecurityGroup
|
222
|
+
Properties:
|
223
|
+
Description: Allow pods running extension API servers on port 443 to receive communication from cluster control plane
|
224
|
+
GroupId: !Ref NodeSecurityGroup
|
225
|
+
SourceSecurityGroupId: !Ref ClusterControlPlaneSecurityGroup
|
226
|
+
IpProtocol: tcp
|
227
|
+
FromPort: 443
|
228
|
+
ToPort: 443
|
229
|
+
|
230
|
+
ControlPlaneEgressToNodeSecurityGroupOn443:
|
231
|
+
Type: AWS::EC2::SecurityGroupEgress
|
232
|
+
DependsOn: NodeSecurityGroup
|
233
|
+
Properties:
|
234
|
+
Description: Allow the cluster control plane to communicate with pods running extension API servers on port 443
|
235
|
+
GroupId: !Ref ClusterControlPlaneSecurityGroup
|
236
|
+
DestinationSecurityGroupId: !Ref NodeSecurityGroup
|
237
|
+
IpProtocol: tcp
|
238
|
+
FromPort: 443
|
239
|
+
ToPort: 443
|
240
|
+
|
241
|
+
ClusterControlPlaneSecurityGroupIngress:
|
242
|
+
Type: AWS::EC2::SecurityGroupIngress
|
243
|
+
DependsOn: NodeSecurityGroup
|
244
|
+
Properties:
|
245
|
+
Description: Allow pods to communicate with the cluster API Server
|
246
|
+
GroupId: !Ref ClusterControlPlaneSecurityGroup
|
247
|
+
SourceSecurityGroupId: !Ref NodeSecurityGroup
|
248
|
+
IpProtocol: tcp
|
249
|
+
ToPort: 443
|
250
|
+
FromPort: 443
|
251
|
+
|
252
|
+
NodeGroup:
|
253
|
+
Type: AWS::AutoScaling::AutoScalingGroup
|
254
|
+
Properties:
|
255
|
+
DesiredCapacity: !Ref NodeAutoScalingGroupMaxSize
|
256
|
+
LaunchConfigurationName: !Ref NodeLaunchConfig
|
257
|
+
MinSize: !Ref NodeAutoScalingGroupMinSize
|
258
|
+
MaxSize: !Ref NodeAutoScalingGroupMaxSize
|
259
|
+
VPCZoneIdentifier:
|
260
|
+
!Ref Subnets
|
261
|
+
Tags:
|
262
|
+
- Key: Name
|
263
|
+
Value: !Sub "${ClusterName}-${NodeGroupName}-Node"
|
264
|
+
PropagateAtLaunch: 'true'
|
265
|
+
- Key: !Sub 'kubernetes.io/cluster/${ClusterName}'
|
266
|
+
Value: 'owned'
|
267
|
+
PropagateAtLaunch: 'true'
|
268
|
+
UpdatePolicy:
|
269
|
+
AutoScalingRollingUpdate:
|
270
|
+
MinInstancesInService: '1'
|
271
|
+
MaxBatchSize: '1'
|
272
|
+
|
273
|
+
NodeLaunchConfig:
|
274
|
+
Type: AWS::AutoScaling::LaunchConfiguration
|
275
|
+
Properties:
|
276
|
+
AssociatePublicIpAddress: 'true'
|
277
|
+
IamInstanceProfile: !Ref NodeInstanceProfile
|
278
|
+
ImageId: !Ref NodeImageId
|
279
|
+
InstanceType: !Ref NodeInstanceType
|
280
|
+
KeyName: !Ref KeyName
|
281
|
+
SecurityGroups:
|
282
|
+
- !Ref NodeSecurityGroup
|
283
|
+
- !Ref ClusterSecurityGroup
|
284
|
+
BlockDeviceMappings:
|
285
|
+
- DeviceName: /dev/xvda
|
286
|
+
Ebs:
|
287
|
+
VolumeSize: !Ref NodeVolumeSize
|
288
|
+
VolumeType: gp2
|
289
|
+
DeleteOnTermination: true
|
290
|
+
UserData:
|
291
|
+
Fn::Base64:
|
292
|
+
!Sub |
|
293
|
+
#!/bin/bash
|
294
|
+
set -o xtrace
|
295
|
+
/etc/eks/bootstrap.sh ${ClusterName} ${BootstrapArguments}
|
296
|
+
/opt/aws/bin/cfn-signal --exit-code $? \
|
297
|
+
--stack ${AWS::StackName} \
|
298
|
+
--resource NodeGroup \
|
299
|
+
--region ${AWS::Region}
|
300
|
+
|
301
|
+
Outputs:
|
302
|
+
NodeInstanceRole:
|
303
|
+
Description: The node instance role
|
304
|
+
Value: !GetAtt NodeInstanceRole.Arn
|
305
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
apiVersion: apps/v1
|
2
|
+
kind: DaemonSet
|
3
|
+
metadata:
|
4
|
+
name: nvidia-device-plugin-daemonset
|
5
|
+
namespace: kube-system
|
6
|
+
spec:
|
7
|
+
selector:
|
8
|
+
matchLabels:
|
9
|
+
name: nvidia-device-plugin-ds
|
10
|
+
template:
|
11
|
+
metadata:
|
12
|
+
# Mark this pod as a critical add-on; when enabled, the critical add-on scheduler
|
13
|
+
# reserves resources for critical add-on pods so that they can be rescheduled after
|
14
|
+
# a failure. This annotation works in tandem with the toleration below.
|
15
|
+
annotations:
|
16
|
+
scheduler.alpha.kubernetes.io/critical-pod: ""
|
17
|
+
labels:
|
18
|
+
name: nvidia-device-plugin-ds
|
19
|
+
spec:
|
20
|
+
tolerations:
|
21
|
+
# Allow this pod to be rescheduled while the node is in "critical add-ons only" mode.
|
22
|
+
# This, along with the annotation above marks this pod as a critical add-on.
|
23
|
+
- key: CriticalAddonsOnly
|
24
|
+
operator: Exists
|
25
|
+
containers:
|
26
|
+
- image: nvidia/k8s-device-plugin:1.10
|
27
|
+
name: nvidia-device-plugin-ctr
|
28
|
+
securityContext:
|
29
|
+
allowPrivilegeEscalation: false
|
30
|
+
capabilities:
|
31
|
+
drop: ["ALL"]
|
32
|
+
volumeMounts:
|
33
|
+
- name: device-plugin
|
34
|
+
mountPath: /var/lib/kubelet/device-plugins
|
35
|
+
volumes:
|
36
|
+
- name: device-plugin
|
37
|
+
hostPath:
|
38
|
+
path: /var/lib/kubelet/device-plugins
|
data/lib/eks_cli/cli.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
autoload :JSON, 'json'
|
4
|
+
|
5
|
+
module EksCli
|
6
|
+
|
7
|
+
autoload :Config, 'config'
|
8
|
+
autoload :NodeGroup, 'nodegroup'
|
9
|
+
module CloudFormation
|
10
|
+
autoload :Stack, 'cloudformation/stack'
|
11
|
+
autoload :VPC, 'cloudformation/vpc'
|
12
|
+
end
|
13
|
+
module EKS
|
14
|
+
autoload :Cluster, 'eks/cluster'
|
15
|
+
end
|
16
|
+
module K8s
|
17
|
+
autoload :Auth, 'k8s/auth'
|
18
|
+
autoload :Client, 'k8s/client'
|
19
|
+
end
|
20
|
+
module EC2
|
21
|
+
autoload :SecurityGroup, 'ec2/security_group'
|
22
|
+
end
|
23
|
+
module IAM
|
24
|
+
autoload :Client, 'iam/client'
|
25
|
+
end
|
26
|
+
module Route53
|
27
|
+
autoload :Client, 'route53/client'
|
28
|
+
end
|
29
|
+
module VPC
|
30
|
+
autoload :Client, 'vpc/client'
|
31
|
+
end
|
32
|
+
|
33
|
+
class Cli < Thor
|
34
|
+
|
35
|
+
class_option :cluster_name, required: true, aliases: :c
|
36
|
+
|
37
|
+
desc "bootstrap REGION", "bootstrap cluster configuration"
|
38
|
+
def bootstrap(region)
|
39
|
+
role = IAM::Client.new(cluster_name).create_eks_role
|
40
|
+
Config[cluster_name].bootstrap({region: region, eks_role_arn: role.arn})
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "show-config", "print cluster configuration"
|
44
|
+
option :group_name, desc: "group name to show configuration for"
|
45
|
+
def show_config
|
46
|
+
if options[:group_name]
|
47
|
+
puts JSON.pretty_generate(Config[cluster_name].for_group(options[:group_name]))
|
48
|
+
else
|
49
|
+
puts JSON.pretty_generate(Config[cluster_name].read_from_disk)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "create-cluster-vpc", "creates a vpc according to aws cloudformation template"
|
54
|
+
def create_cluster_vpc
|
55
|
+
cfg = CloudFormation::VPC.create(cluster_name)
|
56
|
+
Config[cluster_name].write(cfg)
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "create-eks-cluster", "create EKS cluster on AWS"
|
60
|
+
def create_eks_cluster
|
61
|
+
cluster = EKS::Cluster.new(cluster_name).create
|
62
|
+
cluster.await
|
63
|
+
Config[cluster_name].write({cluster_arn: cluster.arn})
|
64
|
+
cluster.update_kubeconfig
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "enable-gpu", "installs nvidia plugin as a daemonset on the cluster"
|
68
|
+
def enable_gpu
|
69
|
+
K8s::Client.new(cluster_name).enable_gpu
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "set-docker-registry-credentials USERNAME PASSWORD EMAIL", "sets docker registry credentials"
|
73
|
+
def set_docker_registry_credentials(username, password, email)
|
74
|
+
K8s::Client.new(cluster_name).set_docker_registry_credentials(username, password, email)
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "create-default-storage-class", "creates default storage class on a new k8s cluster"
|
78
|
+
def create_default_storage_class
|
79
|
+
K8s::Client.new(cluster_name).create_default_storage_class
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "create-nodegroup", "creates all nodegroups on environment"
|
83
|
+
option :all, type: :boolean, default: false, desc: "create all nodegroups. must be used in conjunction with --yes"
|
84
|
+
option :group_name, type: :string, desc: "create a specific nodegroup. can't be used with --all"
|
85
|
+
option :ami, desc: "AMI for the nodegroup"
|
86
|
+
option :instance_type, desc: "EC2 instance type (m5.xlarge etc...)"
|
87
|
+
option :num_subnets, type: :numeric, desc: "Number of subnets (AZs) to spread the nodegroup across"
|
88
|
+
option :ssh_key_name, desc: "Name of the default SSH key for the nodes"
|
89
|
+
option :taints, desc: "Kubernetes taints to put on the nodes for example \"dedicated=critical:NoSchedule\""
|
90
|
+
option :min, type: :numeric, desc: "Minimum number of nodes on the nodegroup"
|
91
|
+
option :max, type: :numeric, desc: "Maximum number of nodes on the nodegroup"
|
92
|
+
option :yes, type: :boolean, default: false, desc: "Perform nodegroup creation"
|
93
|
+
def create_nodegroup
|
94
|
+
Config[cluster_name].update_nodegroup(options) unless options[:all]
|
95
|
+
if options[:yes]
|
96
|
+
cf_stacks = nodegroups.map {|ng| ng.create(wait_for_completion: false)}
|
97
|
+
CloudFormation::Stack.await(cf_stacks)
|
98
|
+
cf_stacks.each {|s| IAM::Client.new(cluster_name).attach_node_policies(s.node_instance_role_name)}
|
99
|
+
K8s::Auth.new(cluster_name).update
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
desc "delete-nodegroup", "deletes cloudformation stack for nodegroup"
|
104
|
+
option :all, type: :boolean, default: false, desc: "delete all nodegroups. can't be used with --name"
|
105
|
+
option :name, type: :string, desc: "delete a specific nodegroup. can't be used with --all"
|
106
|
+
def delete_nodegroup
|
107
|
+
nodegroups.each(&:delete)
|
108
|
+
end
|
109
|
+
|
110
|
+
desc "update-auth", "update aws auth configmap to allow all nodegroups to connect to control plane"
|
111
|
+
def update_auth
|
112
|
+
K8s::Auth.new(cluster_name).update
|
113
|
+
end
|
114
|
+
|
115
|
+
desc "detach-iam-policies", "detaches added policies to nodegroup IAM Role"
|
116
|
+
option :all, type: :boolean, default: false, desc: "detach from all nodegroups. can't be used with --name"
|
117
|
+
option :name, type: :string, desc: "detach from a specific nodegroup. can't be used with --all"
|
118
|
+
def detach_iam_policies
|
119
|
+
nodegroups.each(&:detach_iam_policies)
|
120
|
+
end
|
121
|
+
|
122
|
+
desc "set-iam-policies", "sets IAM policies to be attached to created nodegroups"
|
123
|
+
option :policies, type: :array, required: true, desc: "IAM policies ARNs"
|
124
|
+
def set_iam_policies
|
125
|
+
Config[cluster_name].set_iam_policies(options[:policies])
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "create-cluster-security-group", "creates a SG for cluster communication"
|
129
|
+
option :open_ports, type: :array, default: [], desc: "open ports on cluster nodes"
|
130
|
+
def create_cluster_security_group
|
131
|
+
open_ports = options[:open_ports].map(&:to_i)
|
132
|
+
gid = EC2::SecurityGroup.new(cluster_name, open_ports).create
|
133
|
+
Config[cluster_name].write({nodes_sg_id: gid})
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "update-dns HOSTNAME K8S_SERVICE_NAME", "alters route53 CNAME records to point to k8s service ELBs"
|
137
|
+
option :route53_hosted_zone_id, required: true, desc: "hosted zone ID for the cname record on route53"
|
138
|
+
option :elb_hosted_zone_id, required: true, desc: "hosted zone ID for the ELB on ec2"
|
139
|
+
option :namespace, default: "default", desc: "the k8s namespace of the service"
|
140
|
+
def update_dns(hostname, k8s_service_name)
|
141
|
+
Route53::Client.new(cluster_name).update_dns(hostname, k8s_service_name, options[:namespace], options[:route53_hosted_zone_id], options[:elb_hosted_zone_id])
|
142
|
+
end
|
143
|
+
|
144
|
+
desc "set-inter-vpc-networking TO_VPC_ID TO_SG_ID", "creates a vpc peering connection, sets route tables and allows network access on SG"
|
145
|
+
def set_inter_vpc_networking(to_vpc_id, to_sg_id)
|
146
|
+
VPC::Client.new(cluster_name).set_inter_vpc_networking(to_vpc_id, to_sg_id)
|
147
|
+
end
|
148
|
+
|
149
|
+
no_commands do
|
150
|
+
def cluster_name; options[:cluster_name]; end
|
151
|
+
|
152
|
+
def all_nodegroups; Config[cluster_name]["groups"].keys ;end
|
153
|
+
|
154
|
+
def nodegroups
|
155
|
+
ng = options[:group_name] ? [options[:group_name]] : all_nodegroups
|
156
|
+
ng.map {|n| NodeGroup.new(cluster_name, n)}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|