Skip to content

Commit b88b70d

Browse files
authored
Merge pull request #96 from gruntwork-io/yori-upgrade-cmd
Introduce `eks sync-core-components` subcommand
2 parents 8eb5ca1 + 87ea8c4 commit b88b70d

File tree

7 files changed

+633
-0
lines changed

7 files changed

+633
-0
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ The following commands are available as part of `kubergrunt`:
5757
* [token](#token)
5858
* [oidc-thumbprint](#oidc-thumbprint)
5959
* [deploy](#deploy)
60+
* [sync-core-components](#sync-core-components)
6061
1. [k8s](#k8s)
6162
* [wait-for-ingress](#wait-for-ingress)
6263
* [kubectl](#kubectl)
@@ -245,6 +246,25 @@ Currently `kubergrunt` does not implement any checks for these resources to be i
245246
plan to bake in checks into the deployment command to verify that all services have a disruption budget set, and warn
246247
the user of any services that do not have a check.
247248

249+
#### sync-core-components
250+
251+
This subcommand will sync the core components of an EKS cluster to match the deployed Kubernetes version by following
252+
the steps listed [in the official documentation](https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html).
253+
254+
The core components managed by this command are:
255+
256+
- kube-proxy
257+
- Amazon VPC CNI plug-in
258+
- CoreDNS
259+
260+
By default, this command will rotate the images without waiting for the Pods to be redeployed. You can use the `--wait`
261+
option to force the command to wait until all the Pods have been replaced.
262+
263+
Example:
264+
265+
```bash
266+
kubergrunt eks sync-core-components --eks-cluster-arn EKS_CLUSTER_ARN
267+
```
248268

249269
### k8s
250270

cmd/eks.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ var (
5656
Value: 15 * time.Second,
5757
Usage: "The amount of time to sleep between retries as duration (e.g 10m = 10 minutes) for retry loops during the command. The total amount of time this command will try is based on max-retries and sleep-between-retries. Defaults to 15 seconds.",
5858
}
59+
waitTimeoutFlag = cli.StringFlag{
60+
Name: "wait-timeout",
61+
Value: "10m",
62+
Usage: "The amount of time to wait for operations to complete, expressed as a duration (e.g., 10m = 10 minutes). Defaults to 10 minutes.",
63+
}
5964

6065
// Token related flags
6166
clusterIDFlag = cli.StringFlag{
@@ -123,6 +128,26 @@ func SetupEksCommand() cli.Command {
123128
oidcIssuerUrlFlag,
124129
},
125130
},
131+
cli.Command{
132+
Name: "sync-core-components",
133+
Usage: "Update the core Kubernetes applications deployed on to the EKS cluster to match the Kubernetes version.",
134+
Description: `Update the core Kubernetes applications deployed on to an EKS cluster to ensure that the versions match with the expected versions deployed for the configured Kubernetes version.
135+
136+
There are three core applications on an EKS cluster:
137+
- kube-proxy
138+
- coredns
139+
- VPC CNI Plugin
140+
141+
Each of these are managed in Kubernetes as DaemonSet, Deployment, and DaemonSet respectively. This command will use kubectl under the hood to patch the manifests to deploy the expected version based on what the current Kubernetes version is of the cluster. As such, this command should be run every time the Kubernetes version is updated on the EKS cluster.
142+
143+
The versions deployed are based on what is listed in the official guide provided by AWS: https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html`,
144+
Action: syncClusterComponents,
145+
Flags: []cli.Flag{
146+
eksClusterArnFlag,
147+
waitFlag,
148+
waitTimeoutFlag,
149+
},
150+
},
126151
cli.Command{
127152
Name: "deploy",
128153
Usage: "Zero downtime roll out of cluster updates to worker nodes.",
@@ -284,3 +309,14 @@ func rollOutDeployment(cliContext *cli.Context) error {
284309
waitSleepBetweenRetries,
285310
)
286311
}
312+
313+
// Command action for `kubergrunt eks sync-core-components`
314+
func syncClusterComponents(cliContext *cli.Context) error {
315+
eksClusterArn, err := entrypoint.StringFlagRequiredE(cliContext, eksClusterArnFlag.Name)
316+
if err != nil {
317+
return err
318+
}
319+
shouldWait := cliContext.Bool(waitFlag.Name)
320+
waitTimeout := cliContext.String(waitTimeoutFlag.Name)
321+
return eks.SyncClusterComponents(eksClusterArn, shouldWait, waitTimeout)
322+
}

eks/errors.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,23 @@ type NoPeerCertificatesError struct {
124124
func (err NoPeerCertificatesError) Error() string {
125125
return fmt.Sprintf("Could not find any peer certificates for URL %s", err.URL)
126126
}
127+
128+
// UnsupportedEKSVersion is returned when the Kubernetes version of the EKS cluster is not supported.
129+
type UnsupportedEKSVersion struct {
130+
version string
131+
}
132+
133+
func (err UnsupportedEKSVersion) Error() string {
134+
return fmt.Sprintf("%s is not a supported version for kubergrunt eks upgrade. Please contact [email protected] for more info.", err.version)
135+
}
136+
137+
// CoreComponentUnexpectedConfigurationErr error is returned when the EKS core components are in an unexpected
138+
// configuration, such as a different number of containers.
139+
type CoreComponentUnexpectedConfigurationErr struct {
140+
component string
141+
reason string
142+
}
143+
144+
func (err CoreComponentUnexpectedConfigurationErr) Error() string {
145+
return fmt.Sprintf("Core component %s is in unexpected configuration: %s", err.component, err.reason)
146+
}

eks/fixture/aws-k8s-cni.yaml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: aws-node
6+
rules:
7+
- apiGroups:
8+
- crd.k8s.amazonaws.com
9+
resources:
10+
- "*"
11+
verbs:
12+
- "*"
13+
- apiGroups: [""]
14+
resources:
15+
- pods
16+
- nodes
17+
- namespaces
18+
verbs: ["list", "watch", "get"]
19+
- apiGroups: ["extensions"]
20+
resources:
21+
- daemonsets
22+
verbs: ["list", "watch"]
23+
24+
---
25+
apiVersion: v1
26+
kind: ServiceAccount
27+
metadata:
28+
name: aws-node
29+
namespace: kube-system
30+
31+
---
32+
apiVersion: rbac.authorization.k8s.io/v1
33+
kind: ClusterRoleBinding
34+
metadata:
35+
name: aws-node
36+
roleRef:
37+
apiGroup: rbac.authorization.k8s.io
38+
kind: ClusterRole
39+
name: aws-node
40+
subjects:
41+
- kind: ServiceAccount
42+
name: aws-node
43+
namespace: kube-system
44+
45+
---
46+
kind: DaemonSet
47+
apiVersion: apps/v1
48+
metadata:
49+
name: aws-node
50+
namespace: kube-system
51+
labels:
52+
k8s-app: aws-node
53+
spec:
54+
updateStrategy:
55+
type: RollingUpdate
56+
rollingUpdate:
57+
maxUnavailable: "10%"
58+
selector:
59+
matchLabels:
60+
k8s-app: aws-node
61+
template:
62+
metadata:
63+
labels:
64+
k8s-app: aws-node
65+
spec:
66+
priorityClassName: system-node-critical
67+
affinity:
68+
nodeAffinity:
69+
requiredDuringSchedulingIgnoredDuringExecution:
70+
nodeSelectorTerms:
71+
- matchExpressions:
72+
- key: "beta.kubernetes.io/os"
73+
operator: In
74+
values:
75+
- linux
76+
- key: "beta.kubernetes.io/arch"
77+
operator: In
78+
values:
79+
- amd64
80+
- key: eks.amazonaws.com/compute-type
81+
operator: NotIn
82+
values:
83+
- fargate
84+
serviceAccountName: aws-node
85+
hostNetwork: true
86+
tolerations:
87+
- operator: Exists
88+
containers:
89+
- image: 602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni:v1.5.7
90+
imagePullPolicy: Always
91+
ports:
92+
- containerPort: 61678
93+
name: metrics
94+
name: aws-node
95+
env:
96+
- name: AWS_VPC_K8S_CNI_LOGLEVEL
97+
value: DEBUG
98+
- name: MY_NODE_NAME
99+
valueFrom:
100+
fieldRef:
101+
fieldPath: spec.nodeName
102+
resources:
103+
requests:
104+
cpu: 10m
105+
securityContext:
106+
privileged: true
107+
volumeMounts:
108+
- mountPath: /host/opt/cni/bin
109+
name: cni-bin-dir
110+
- mountPath: /host/etc/cni/net.d
111+
name: cni-net-dir
112+
- mountPath: /host/var/log
113+
name: log-dir
114+
- mountPath: /var/run/docker.sock
115+
name: dockersock
116+
- mountPath: /var/run/dockershim.sock
117+
name: dockershim
118+
volumes:
119+
- name: cni-bin-dir
120+
hostPath:
121+
path: /opt/cni/bin
122+
- name: cni-net-dir
123+
hostPath:
124+
path: /etc/cni/net.d
125+
- name: log-dir
126+
hostPath:
127+
path: /var/log
128+
- name: dockersock
129+
hostPath:
130+
path: /var/run/docker.sock
131+
- name: dockershim
132+
hostPath:
133+
path: /var/run/dockershim.sock
134+
135+
---
136+
apiVersion: apiextensions.k8s.io/v1beta1
137+
kind: CustomResourceDefinition
138+
metadata:
139+
name: eniconfigs.crd.k8s.amazonaws.com
140+
spec:
141+
scope: Cluster
142+
group: crd.k8s.amazonaws.com
143+
versions:
144+
- name: v1alpha1
145+
served: true
146+
storage: true
147+
names:
148+
plural: eniconfigs
149+
singular: eniconfig
150+
kind: ENIConfig

0 commit comments

Comments
 (0)