├── website ├── static │ ├── .nojekyll │ └── img │ │ ├── meta.png │ │ ├── favicon.png │ │ ├── api-reorg.png │ │ ├── flux-flow.png │ │ ├── create-fork01.png │ │ ├── create-fork02.png │ │ ├── eks-rollback.png │ │ ├── gitops-toolkit.png │ │ ├── argo-workflows-00.png │ │ ├── argo-workflows-01.png │ │ ├── argo-workflows-02.png │ │ ├── argo-workflows-03.png │ │ ├── flux-flow-diagram.png │ │ ├── kubernetes-release.png │ │ ├── EKS-Upgrades-Workshop.png │ │ ├── ek-upgrades-workshop.png │ │ ├── github-repo-changes.png │ │ ├── eks-blue-green-upgrades.png │ │ ├── eks-kubernetes-release.png │ │ ├── EKS-Upgrades-EKS-Release.png │ │ ├── ek-upgrades-workshop-old.png │ │ ├── eks-upgrades-architecture.png │ │ ├── kubernetes-release-diagram.png │ │ ├── logo.svg │ │ ├── undraw_docusaurus_tree.svg │ │ └── undraw_docusaurus_mountain.svg ├── babel.config.js ├── docs │ ├── assets │ │ ├── menu.png │ │ ├── search.png │ │ ├── cloud9-arn.png │ │ ├── event-code.png │ │ ├── lab-icon.png │ │ ├── terminal.png │ │ ├── environment.png │ │ ├── openconsole.png │ │ ├── review-and-join.png │ │ ├── terminal-open.png │ │ ├── cloud9-environments.png │ │ ├── cluster_validation.png │ │ ├── workshop-event-page.png │ │ └── workshop-studio-home.png │ ├── 08-Blue-Green-upgrades.md │ ├── 10-conclusion.md │ ├── 01-environment.md │ ├── 03-connect-to-github-repo.md │ ├── 11_cleanup.md │ ├── 00-intro.md │ ├── 02-accessing-ide.md │ ├── 05-karpenter.md │ ├── 04-git-ops.md │ ├── 06-validating-state.md │ └── 07-upgrading-control-plane.md ├── src │ ├── components │ │ └── HomepageFeatures │ │ │ ├── styles.module.css │ │ │ └── index.js │ ├── pages │ │ └── index.md │ └── css │ │ └── custom.css ├── .gitignore ├── sidebars.js ├── package.json ├── README.md └── docusaurus.config.js ├── terraform ├── modules │ ├── flux_cd │ │ ├── outputs.tf │ │ ├── variables.tf │ │ └── main.tf │ └── base │ │ └── codebuild │ │ └── main.tf └── clusters │ ├── data.tf │ ├── providers.tf │ ├── variables.tf │ ├── README.md │ ├── outputs.tf │ ├── related_infra.tf │ └── main.tf ├── NOTICE ├── .DS_Store ├── docs └── static │ ├── menu.png │ ├── lab-icon.png │ ├── search.png │ ├── terminal.png │ ├── cloud9-arn.png │ ├── flux-flow.png │ ├── eks-rollback.png │ ├── environment.png │ ├── terminal-open.png │ ├── gitops-toolkit.png │ ├── flux-flow-diagram.png │ ├── cloud9-environments.png │ └── eks-blue-green-upgrades.png ├── gitops ├── karpenter-provisioner │ ├── kustomization.yaml │ └── 01-default-karpenter-provisioner.yaml ├── add-ons │ ├── kustomization.yaml │ ├── 01-metric-server.yaml │ ├── 02-karpenter.yaml │ └── 03-argo-workflows.yaml ├── applications │ ├── deprecated-manifests │ │ ├── kustomization.yaml │ │ ├── 03-deprecated-hpa.yaml │ │ └── 02-deprecated-cronjob.yaml │ ├── kustomization.yaml │ ├── 01-pdb-sample-app.yaml │ └── 01-sample-app.yaml ├── sources │ ├── kustomization.yaml │ ├── argo-workflows-helm.yaml │ ├── karpenter-helm.yaml │ └── metric-server-helm.yaml └── clusters │ └── cluster-demo │ ├── apps.yaml │ ├── sources.yaml │ ├── infra.yaml │ └── dependencies.yaml ├── upgrades-workflows ├── validate-apis.sh ├── validate-self-managed-add-ons.sh ├── Dockerfile ├── validate-aws-basics.sh ├── validate-managed-addons.sh └── upgrade-validate-workflow.yaml ├── CODE_OF_CONDUCT.md ├── .pre-commit-config.yaml ├── .github └── workflows │ └── production.yaml ├── .gitignore ├── README.md ├── CONTRIBUTING.md ├── install.sh └── LICENSE /website/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /terraform/modules/flux_cd/outputs.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/.DS_Store -------------------------------------------------------------------------------- /docs/static/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/menu.png -------------------------------------------------------------------------------- /docs/static/lab-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/lab-icon.png -------------------------------------------------------------------------------- /docs/static/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/search.png -------------------------------------------------------------------------------- /docs/static/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/terminal.png -------------------------------------------------------------------------------- /docs/static/cloud9-arn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/cloud9-arn.png -------------------------------------------------------------------------------- /docs/static/flux-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/flux-flow.png -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/static/eks-rollback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/eks-rollback.png -------------------------------------------------------------------------------- /docs/static/environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/environment.png -------------------------------------------------------------------------------- /docs/static/terminal-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/terminal-open.png -------------------------------------------------------------------------------- /website/docs/assets/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/menu.png -------------------------------------------------------------------------------- /website/static/img/meta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/meta.png -------------------------------------------------------------------------------- /docs/static/gitops-toolkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/gitops-toolkit.png -------------------------------------------------------------------------------- /website/docs/assets/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/search.png -------------------------------------------------------------------------------- /website/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/favicon.png -------------------------------------------------------------------------------- /docs/static/flux-flow-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/flux-flow-diagram.png -------------------------------------------------------------------------------- /website/docs/assets/cloud9-arn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/cloud9-arn.png -------------------------------------------------------------------------------- /website/docs/assets/event-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/event-code.png -------------------------------------------------------------------------------- /website/docs/assets/lab-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/lab-icon.png -------------------------------------------------------------------------------- /website/docs/assets/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/terminal.png -------------------------------------------------------------------------------- /website/static/img/api-reorg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/api-reorg.png -------------------------------------------------------------------------------- /website/static/img/flux-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/flux-flow.png -------------------------------------------------------------------------------- /docs/static/cloud9-environments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/cloud9-environments.png -------------------------------------------------------------------------------- /website/docs/assets/environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/environment.png -------------------------------------------------------------------------------- /website/docs/assets/openconsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/openconsole.png -------------------------------------------------------------------------------- /website/static/img/create-fork01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/create-fork01.png -------------------------------------------------------------------------------- /website/static/img/create-fork02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/create-fork02.png -------------------------------------------------------------------------------- /website/static/img/eks-rollback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/eks-rollback.png -------------------------------------------------------------------------------- /docs/static/eks-blue-green-upgrades.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/docs/static/eks-blue-green-upgrades.png -------------------------------------------------------------------------------- /website/docs/assets/review-and-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/review-and-join.png -------------------------------------------------------------------------------- /website/docs/assets/terminal-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/terminal-open.png -------------------------------------------------------------------------------- /website/static/img/gitops-toolkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/gitops-toolkit.png -------------------------------------------------------------------------------- /website/static/img/argo-workflows-00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/argo-workflows-00.png -------------------------------------------------------------------------------- /website/static/img/argo-workflows-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/argo-workflows-01.png -------------------------------------------------------------------------------- /website/static/img/argo-workflows-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/argo-workflows-02.png -------------------------------------------------------------------------------- /website/static/img/argo-workflows-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/argo-workflows-03.png -------------------------------------------------------------------------------- /website/static/img/flux-flow-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/flux-flow-diagram.png -------------------------------------------------------------------------------- /website/static/img/kubernetes-release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/kubernetes-release.png -------------------------------------------------------------------------------- /terraform/clusters/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_eks_cluster_auth" "this" { 2 | name = module.eks.cluster_name 3 | } 4 | 5 | data "aws_availability_zones" "available" {} -------------------------------------------------------------------------------- /website/docs/assets/cloud9-environments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/cloud9-environments.png -------------------------------------------------------------------------------- /website/docs/assets/cluster_validation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/cluster_validation.png -------------------------------------------------------------------------------- /website/docs/assets/workshop-event-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/workshop-event-page.png -------------------------------------------------------------------------------- /website/docs/assets/workshop-studio-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/docs/assets/workshop-studio-home.png -------------------------------------------------------------------------------- /website/static/img/EKS-Upgrades-Workshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/EKS-Upgrades-Workshop.png -------------------------------------------------------------------------------- /website/static/img/ek-upgrades-workshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/ek-upgrades-workshop.png -------------------------------------------------------------------------------- /website/static/img/github-repo-changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/github-repo-changes.png -------------------------------------------------------------------------------- /website/static/img/eks-blue-green-upgrades.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/eks-blue-green-upgrades.png -------------------------------------------------------------------------------- /website/static/img/eks-kubernetes-release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/eks-kubernetes-release.png -------------------------------------------------------------------------------- /website/static/img/EKS-Upgrades-EKS-Release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/EKS-Upgrades-EKS-Release.png -------------------------------------------------------------------------------- /website/static/img/ek-upgrades-workshop-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/ek-upgrades-workshop-old.png -------------------------------------------------------------------------------- /website/static/img/eks-upgrades-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/eks-upgrades-architecture.png -------------------------------------------------------------------------------- /website/static/img/kubernetes-release-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orenmazor/eks-cluster-upgrades-workshop/main/website/static/img/kubernetes-release-diagram.png -------------------------------------------------------------------------------- /gitops/karpenter-provisioner/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - 01-default-karpenter-provisioner.yaml -------------------------------------------------------------------------------- /website/docs/08-Blue-Green-upgrades.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: blue-green-upgrades 3 | sidebar_label: 'Blue Green Upgrades' 4 | sidebar_position: 7 5 | --- 6 | 7 | :::info 8 | Under construction 9 | ::: -------------------------------------------------------------------------------- /gitops/add-ons/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - 01-metric-server.yaml 5 | # - 02-karpenter.yaml 6 | # - 03-argo-workflows.yaml -------------------------------------------------------------------------------- /gitops/applications/deprecated-manifests/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - 02-deprecated-cronjob.yaml 5 | - 03-deprecated-hpa.yaml -------------------------------------------------------------------------------- /gitops/sources/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - metric-server-helm.yaml 5 | - karpenter-helm.yaml 6 | - argo-workflows-helm.yaml -------------------------------------------------------------------------------- /gitops/applications/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - 01-sample-app.yaml 5 | - 01-pdb-sample-app.yaml 6 | # - deprecated-manifests -------------------------------------------------------------------------------- /upgrades-workflows/validate-apis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "====================== Kubent Deprecated APIs report ======================" > /tmp/kubent-report.txt 4 | /usr/local/bin/kubent | tee -a /tmp/kubent-report.txt -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /gitops/sources/argo-workflows-helm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: source.toolkit.fluxcd.io/v1beta2 3 | kind: HelmRepository 4 | metadata: 5 | name: argo 6 | namespace: flux-system 7 | spec: 8 | interval: 1m0s 9 | url: https://argoproj.github.io/argo-helm -------------------------------------------------------------------------------- /gitops/applications/01-pdb-sample-app.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: policy/v1 3 | kind: PodDisruptionBudget 4 | metadata: 5 | name: nginx-pdb 6 | namespace: default 7 | spec: 8 | minAvailable: 3 9 | selector: 10 | matchLabels: 11 | app: nginx -------------------------------------------------------------------------------- /gitops/sources/karpenter-helm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: source.toolkit.fluxcd.io/v1beta2 3 | kind: HelmRepository 4 | metadata: 5 | name: karpenter 6 | namespace: flux-system 7 | spec: 8 | type: "oci" 9 | interval: 1m0s 10 | url: oci://public.ecr.aws/karpenter/ -------------------------------------------------------------------------------- /gitops/sources/metric-server-helm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: source.toolkit.fluxcd.io/v1beta2 3 | kind: HelmRepository 4 | metadata: 5 | name: metrics-server 6 | namespace: flux-system 7 | spec: 8 | interval: 10m0s 9 | url: https://kubernetes-sigs.github.io/metrics-server -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /gitops/applications/deprecated-manifests/03-deprecated-hpa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: nginx-hpa 6 | namespace: default 7 | spec: 8 | scaleTargetRef: 9 | apiVersion: apps/v1 10 | kind: Deployment 11 | name: nginx 12 | minReplicas: 3 13 | maxReplicas: 10 -------------------------------------------------------------------------------- /terraform/clusters/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.aws_region 3 | } 4 | 5 | provider "kubernetes" { 6 | host = module.eks.cluster_endpoint 7 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) 8 | token = data.aws_eks_cluster_auth.this.token 9 | } 10 | -------------------------------------------------------------------------------- /gitops/clusters/cluster-demo/apps.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 2 | kind: Kustomization 3 | metadata: 4 | name: apps 5 | namespace: flux-system 6 | spec: 7 | interval: 1m0s 8 | sourceRef: 9 | kind: GitRepository 10 | name: flux-system 11 | path: ./gitops/applications 12 | prune: true 13 | validation: client -------------------------------------------------------------------------------- /gitops/clusters/cluster-demo/sources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 2 | kind: Kustomization 3 | metadata: 4 | name: sources 5 | namespace: flux-system 6 | spec: 7 | interval: 1m0s 8 | sourceRef: 9 | kind: GitRepository 10 | name: flux-system 11 | path: ./gitops/sources 12 | prune: true 13 | validation: client -------------------------------------------------------------------------------- /gitops/clusters/cluster-demo/infra.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 2 | kind: Kustomization 3 | metadata: 4 | name: infrastructure 5 | namespace: flux-system 6 | spec: 7 | dependsOn: 8 | - name: sources 9 | interval: 1m0s 10 | sourceRef: 11 | kind: GitRepository 12 | name: flux-system 13 | path: ./gitops/add-ons 14 | prune: true 15 | validation: client -------------------------------------------------------------------------------- /upgrades-workflows/validate-self-managed-add-ons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "====================== Self Managed Add-ons ======================" > /tmp/self-addon-report.txt 4 | kubectl get helmreleases -nflux-system | tee -a /tmp/self-addon-report.txt 5 | echo "====================== Deprecated API in helm charts ======================" >> /tmp/self-addon-report.txt 6 | pluto detect-helm -o wide | tee -a /tmp/self-addon-report.txt -------------------------------------------------------------------------------- /gitops/clusters/cluster-demo/dependencies.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 2 | kind: Kustomization 3 | metadata: 4 | name: karpenter-provisioner 5 | namespace: flux-system 6 | spec: 7 | dependsOn: 8 | - name: infrastructure 9 | interval: 1m0s 10 | sourceRef: 11 | kind: GitRepository 12 | name: flux-system 13 | path: ./gitops/karpenter-provisioner 14 | prune: true 15 | validation: client -------------------------------------------------------------------------------- /terraform/clusters/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | default = "eks-upgrades-workshop" 3 | } 4 | 5 | variable "aws_region" {} # Defined in script 6 | 7 | variable "vpc_cidr" { 8 | default = "10.35.0.0/16" 9 | } 10 | 11 | variable "cluster_version" { 12 | default = "1.24" 13 | } 14 | 15 | variable "git_branch" { 16 | default = "main" 17 | } 18 | 19 | variable "git_password" {} 20 | 21 | variable "git_username" {} 22 | 23 | variable "git_url" {} -------------------------------------------------------------------------------- /gitops/add-ons/01-metric-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: helm.toolkit.fluxcd.io/v2beta1 3 | kind: HelmRelease 4 | metadata: 5 | name: metrics-server 6 | namespace: flux-system 7 | labels: 8 | self-managed-add-on: true 9 | add-on-version: "3.8.4" 10 | spec: 11 | releaseName: metrics-server 12 | targetNamespace: kube-system 13 | storageNamespace: kube-system 14 | interval: 10m0s 15 | chart: 16 | spec: 17 | chart: metrics-server 18 | version: 3.8.4 19 | sourceRef: 20 | kind: HelmRepository 21 | name: metrics-server 22 | values: 23 | apiService: 24 | create: true 25 | install: {} -------------------------------------------------------------------------------- /terraform/clusters/README.md: -------------------------------------------------------------------------------- 1 | # How to deploy 2 | 3 | You will need to fork this 4 | 5 | Execute `install.sh` script passing the following parameters: 6 | 7 | - git_password 8 | - git_username 9 | - git_url 10 | - git_branch 11 | - aws_region 12 | 13 | Your execution should look linke this: 14 | 15 | ```bash 16 | ./install.sh ghp_xxxxxxxxx user_name https://github.com/user_name/eks-cluster-upgrades-workshop.git your_desired_branch 17 | ``` 18 | 19 | After that you will need to uncomment lines `5` and `6` of `gitops/add-ons/kustomization.yaml` file 20 | 21 | Then you can push the changes to your desired branch and flux will reconcile the changes -------------------------------------------------------------------------------- /website/src/pages/index.md: -------------------------------------------------------------------------------- 1 | :::info 2 | This workshop is performing upgrades from version `1.24` 3 | ::: 4 | 5 | ![Kubernetes version release](../../static/img/ek-upgrades-workshop.png) 6 | 7 | 8 | # About the workshop 9 | 10 | The Amazon EKS cluster upgrades workshop is built to provide you with a reference architecture that can help make your Amazon EKS Cluster upgrades **less painful and more seamless**. To achieve this, we have used a `GitOps` strategy with `Fluxv2` for components reconciliation (all add-ons and apps are managed by flux), `Karpenter` for Node Scaling along with `AWS Fargate` for hosting the addons, and `Argo Workflows` to validate what has to be changed before running the upgrade. 11 | 12 | :::info 13 | **Workshop expected duration:** 1,5 hours 14 | ::: 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /gitops/applications/deprecated-manifests/02-deprecated-cronjob.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1beta1 2 | kind: CronJob 3 | metadata: 4 | name: hello 5 | namespace: default 6 | spec: 7 | schedule: "0 0 * * *" 8 | jobTemplate: 9 | spec: 10 | template: 11 | spec: 12 | nodeSelector: # Force scale on Karpenter nodes 13 | node-type: applications 14 | tolerations: # Force scale on Karpenter nodes 15 | - key: "applications" 16 | operator: "Exists" 17 | effect: "NoSchedule" 18 | containers: 19 | - name: hello 20 | image: busybox:1.28 21 | imagePullPolicy: IfNotPresent 22 | command: 23 | - /bin/sh 24 | - -c 25 | - date; echo Hello from the Kubernetes cluster 26 | restartPolicy: OnFailure 27 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/adrienverge/yamllint.git 4 | rev: v1.17.0 5 | hooks: 6 | - id: yamllint 7 | args: [-c=.yamllint] 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v4.4.0 10 | hooks: 11 | - id: check-merge-conflict 12 | - id: trailing-whitespace 13 | - id: check-added-large-files 14 | - id: end-of-file-fixer 15 | args: [--no-ensure-ascii, --autofix] 16 | - repo: https://github.com/bridgecrewio/checkov.git 17 | rev: 2.0.975 18 | hooks: 19 | - id: checkov 20 | args: [-d .] 21 | - repo: https://github.com/Agilicus/pre-commit-hook-k8svalidate.git 22 | rev: v0.0.8 23 | hooks: 24 | - id: k8svalidate 25 | files: .yaml$ 26 | - repo: https://github.com/Yelp/detect-secrets 27 | rev: v1.2.0 28 | hooks: 29 | - id: detect-secrets -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /website/docs/10-conclusion.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: Conclusion 3 | sidebar_label: 'Conclusion' 4 | sidebar_position: 10 5 | --- 6 | 7 | In conclusion, this workshop has provided valuable insights into streamlining the Cluster upgrade process through automation. The adoption of a GitOps approach, coupled with the deployment of add-ons, significantly simplifies the upgrade process. With Fluxv2 ensuring that our repository reflects the installed add-ons, we can confidently proceed with cluster upgrades. Additionally, leveraging Fargate to host all add-ons offers the advantage of eliminating the need to manage underlying infrastructure, further easing the node upgrade process. Finally, we have gained knowledge on the usefulness of Karpenter, which ensures that newly spun-up nodes match the Control Plane API version, aiding in the upgrade step. Overall, these techniques and tools enhance the efficiency and reliability of cluster upgrades. 8 | 9 | :::note 10 | Feel free to ajust this architrecture based on your needs. 11 | ::: -------------------------------------------------------------------------------- /.github/workflows/production.yaml: -------------------------------------------------------------------------------- 1 | name: "ci-cd pipeline" 2 | 3 | on: workflow_dispatch 4 | 5 | # push: 6 | # branches: 7 | # - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js 20.x 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: 20.x 18 | cache: 'npm' 19 | cache-dependency-path: website/package-lock.json 20 | - name: Install dependencies 21 | run: npm install 22 | working-directory: website 23 | - name: Build file 24 | run: npm run build 25 | working-directory: website 26 | 27 | 28 | - name: Deploy production to Netlify 29 | uses: South-Paw/action-netlify-deploy@v1.2.0 30 | with: 31 | github-token: ${{ secrets.GITHUB_TOKEN }} 32 | netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} 33 | netlify-site-id: ${{ secrets.NETLIFY_SITE_ID }} 34 | build-dir: './website/build' 35 | comment-on-commit: true -------------------------------------------------------------------------------- /terraform/modules/flux_cd/variables.tf: -------------------------------------------------------------------------------- 1 | variable "cluster_endpoint" {} 2 | 3 | variable "ca" {} 4 | 5 | variable "token" {} 6 | 7 | variable "git_branch" { 8 | default = "main" 9 | } 10 | 11 | variable "git_username" { 12 | } 13 | 14 | 15 | variable "git_password" { 16 | } 17 | 18 | variable "git_url" {} 19 | 20 | variable "namespace" { 21 | default = "flux-system" 22 | } 23 | 24 | variable "activate_helm_controller" { 25 | default = true 26 | } 27 | 28 | variable "activate_image_automation_controller" { 29 | default = false 30 | } 31 | 32 | variable "image_automation_controller_sa_annotations" { 33 | default = "" 34 | } 35 | 36 | variable "activate_image_reflection_controller" { 37 | default = false 38 | } 39 | 40 | variable "image_reflection_controller_sa_annotations" { 41 | default = "" 42 | } 43 | 44 | variable "activate_kustomize_controller" { 45 | default = true 46 | } 47 | 48 | variable "activate_notification_controller" { 49 | default = true 50 | } 51 | 52 | variable "activate_source_controller" { 53 | default = true 54 | } -------------------------------------------------------------------------------- /gitops/applications/01-sample-app.yaml: -------------------------------------------------------------------------------- 1 | # TBD: Here will be the sample application, deployed in Karpenter Node, needs to apply taint and tolerations 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: nginx 7 | name: nginx 8 | namespace: default 9 | spec: 10 | replicas: 3 11 | selector: 12 | matchLabels: 13 | app: nginx 14 | strategy: {} 15 | template: 16 | metadata: 17 | labels: 18 | app: nginx 19 | spec: 20 | containers: 21 | - image: nginx:latest 22 | name: nginx 23 | ports: 24 | - containerPort: 80 25 | resources: 26 | requests: 27 | memory: "128Mi" 28 | cpu: "256m" 29 | limits: 30 | memory: "128Mi" 31 | cpu: "256m" 32 | nodeSelector: # Force scale on Karpenter nodes 33 | node-type: applications 34 | tolerations: # Force scale on Karpenter nodes 35 | - key: "applications" 36 | operator: "Exists" 37 | effect: "NoSchedule" 38 | status: {} 39 | -------------------------------------------------------------------------------- /gitops/add-ons/02-karpenter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: karpenter 5 | --- 6 | apiVersion: helm.toolkit.fluxcd.io/v2beta1 7 | kind: HelmRelease 8 | metadata: 9 | name: karpenter 10 | namespace: flux-system 11 | labels: 12 | self-managed-add-on: true 13 | add-on-version: "v0.27.3" 14 | spec: 15 | releaseName: karpenter 16 | targetNamespace: karpenter 17 | storageNamespace: karpenter 18 | interval: 1m0s 19 | chart: 20 | spec: 21 | chart: karpenter 22 | version: v0.27.3 23 | sourceRef: 24 | kind: HelmRepository 25 | name: karpenter 26 | values: 27 | serviceAccount: 28 | create: true 29 | name: karpenter # SA created via eksctl or 30 | annotations: 31 | eks.amazonaws.com/role-arn: KARPENTER_IRSA # Replace 32 | settings: 33 | aws: 34 | clusterName: eks-upgrades-workshop 35 | clusterEndpoint: CLUSTER_ENDPOINT # Replace 36 | defaultInstanceProfile: KARPENTER_INSTANCE_PROFILE # Replace 37 | # interruptionQueueName: eks-upgrade-demo 38 | install: {} 39 | -------------------------------------------------------------------------------- /upgrades-workflows/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.14 2 | 3 | RUN ARCH=amd64 \ 4 | && PLATFORM=$(uname -s)_$ARCH \ 5 | && apk update && apk add curl \ 6 | && curl -sLO "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz" \ 7 | && tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz \ 8 | && mv /tmp/eksctl /usr/local/bin \ 9 | && curl -sSL https://git.io/install-kubent | sh \ 10 | && curl --silent --location "https://github.com/FairwindsOps/pluto/releases/download/v5.16.1/pluto_5.16.1_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp \ 11 | && mv /tmp/pluto /usr/local/bin \ 12 | && curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \ 13 | && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl \ 14 | && apk add aws-cli \ 15 | && curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp \ 16 | && mv /tmp/eksctl /usr/local/bin \ 17 | && apk add jq 18 | 19 | COPY . / 20 | RUN chmod +x /*.sh -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "2.4.0", 18 | "@docusaurus/preset-classic": "2.4.0", 19 | "@mdx-js/react": "^1.6.22", 20 | "clsx": "^1.2.1", 21 | "prism-react-renderer": "^1.3.5", 22 | "react": "^17.0.2", 23 | "react-dom": "^17.0.2" 24 | }, 25 | "devDependencies": { 26 | "@docusaurus/module-type-aliases": "2.4.0" 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.5%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | }, 40 | "engines": { 41 | "node": ">=16.14" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/terraform 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=terraform 3 | 4 | ### Terraform ### 5 | # Local .terraform directories 6 | **/.terraform/* 7 | *.terraform.* 8 | # .tfstate files 9 | *.tfstate 10 | *.tfstate.* 11 | 12 | # Crash log files 13 | crash.log 14 | crash.*.log 15 | 16 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 17 | # password, private keys, and other secrets. These should not be part of version 18 | # control as they are data points which are potentially sensitive and subject 19 | # to change depending on the environment. 20 | *.tfvars 21 | *.tfvars.json 22 | 23 | # Ignore override files as they are usually used to override resources locally and so 24 | # are not checked in 25 | override.tf 26 | override.tf.json 27 | *_override.tf 28 | *_override.tf.json 29 | 30 | # Include override files you do wish to add to version control using negated pattern 31 | # !example_override.tf 32 | 33 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 34 | # example: *tfplan* 35 | 36 | # Ignore CLI configuration files 37 | .terraformrc 38 | terraform.rc 39 | secrets.tf 40 | todelete.yaml 41 | 42 | # End of https://www.toptal.com/developers/gitignore/api/terraform 43 | -------------------------------------------------------------------------------- /upgrades-workflows/validate-aws-basics.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Input parameters 4 | cluster_role_name=$1 5 | vpc_id=$2 6 | cluster_security_group_id=$3 7 | aws_region=$4 8 | 9 | # Validate subnets for at least 5 IPs 10 | if aws ec2 describe-subnets --filters "Name=vpc-id,Values=${vpc_id}" --query "Subnets[?AvailableIpAddressCount > \`5\`].SubnetId" --output text --region ${aws_region} | grep . >/dev/null; then 11 | subnet_check="At least one subnet has more than 5 IPs available" 12 | else 13 | subnet_check="No subnet has more than 5 IPs available" 14 | fi 15 | 16 | # Validate cluster role existence 17 | if aws iam get-role --role-name ${cluster_role_name} --region ${aws_region} &>/dev/null; then 18 | role_check="Cluster role exists" 19 | else 20 | role_check="Cluster role does not exist" 21 | fi 22 | 23 | # Validate cluster security group existence 24 | if aws ec2 describe-security-groups --group-ids ${cluster_security_group_id} --region ${aws_region} &>/dev/null; then 25 | sg_check="Cluster security group exists" 26 | else 27 | sg_check="Cluster security group does not exist" 28 | fi 29 | 30 | echo "========================== AWS BASICS VALIDATION ==========================" > /tmp/my_file.txt 31 | # Persist the checks in the file 32 | echo "Subnet Check: ${subnet_check}" >> /tmp/my_file.txt 33 | echo "Role Check: ${role_check}" >> /tmp/my_file.txt 34 | echo "Security Group Check: ${sg_check}" >> /tmp/my_file.txt -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | Make sure you have `yarn` package installed. 8 | 9 | [Classic Yarn Package installation](https://classic.yarnpkg.com/lang/en/docs/install/). 10 | [Install via `corepacp`/`npm`](https://yarnpkg.com/getting-started/install). 11 | 12 | ### Clone [this](https://github.com/aws-samples/eks-cluster-upgrades-workshop) repository. 13 | 14 | ``` 15 | git clone https://github.com/aws-samples/eks-cluster-upgrades-workshop.git 16 | ``` 17 | 18 | ### Initialize the website repo. 19 | 20 | ``` 21 | $ yarn 22 | ``` 23 | 24 | ### Local Development 25 | 26 | ``` 27 | $ yarn start 28 | ``` 29 | 30 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 31 | 32 | ### Build 33 | 34 | ``` 35 | $ yarn build 36 | ``` 37 | 38 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 39 | 40 | ### Deployment 41 | 42 | Using SSH: 43 | 44 | ``` 45 | $ USE_SSH=true yarn deploy 46 | ``` 47 | 48 | Not using SSH: 49 | 50 | ``` 51 | $ GIT_USER= yarn deploy 52 | ``` 53 | 54 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 55 | -------------------------------------------------------------------------------- /website/docs/01-environment.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: env 3 | sidebar_label: 'Environment' 4 | sidebar_position: 1 5 | --- 6 | 7 | # Selecting your environment 8 | 9 | This workshop can run in two different ways: 10 | 11 | - `AWS Event`: All the resources are already deployed as part of the event, including the `Amazon EKS Cluster` along with all networking resources and permissions, you can proceed to [**Accessing Cloud9 IDE**](./02-accessing-ide.md). 12 | - `Self`: You will need to deploy the Cloudformation template in order to deploy the environment. 13 | 14 | ## Creating the environment, self event 15 | 16 | :::caution 17 | Only proceed with this step if executing it by your own 18 | ::: 19 | 20 | In order to start the environment, you will need to deploy the following Cloudformation template. This can be done, either via console or terminal: 21 | 22 | [EKS Upgrades Workshop CF](https://raw.githubusercontent.com/aws-samples/eks-cluster-upgrades-workshop/feat/workshop_v2/helpers/cloudformation-new-stack.yaml) 23 | 24 | Give the name, `eks-upgrades-workshop` to you stack 25 | 26 | The above Cloudformation script will provision a `Cloud9` with all the required tools in order to execute the workshop along with `AWS VPC`, `Amazon EKS Cluster`, `IAM roles and permissions`, `Install Flux V2`. 27 | 28 | :::tip 29 | Wait at least `20 minutes` before moving on, this will give time to Cloudformation and SSM finishes its deploy. Might be a good time for a break. 30 | 31 | Only proceed after the SSM Run Command has finished. [Check here!](https://console.aws.amazon.com/systems-manager/run-command/executing-commands) 32 | ::: -------------------------------------------------------------------------------- /terraform/clusters/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # VPC 3 | ################################################################################ 4 | output "aws_vpc_id" { 5 | value = module.vpc.vpc_id 6 | } 7 | 8 | output "aws_region" { 9 | value = var.aws_region 10 | } 11 | 12 | ################################################################################ 13 | # Cluster 14 | ################################################################################ 15 | output "cluster_iam_role_name" { 16 | value = module.eks.cluster_iam_role_name 17 | } 18 | 19 | output "cluster_name" { 20 | description = "The Amazon Resource Name (ARN) of the cluster, use" 21 | value = module.eks.cluster_id 22 | } 23 | 24 | output "cluster_endpoint" { 25 | value = module.eks.cluster_endpoint 26 | } 27 | 28 | output "cluster_primary_security_group_id" { 29 | value = module.eks.cluster_primary_security_group_id 30 | } 31 | 32 | ################################################################################ 33 | # Karpenter 34 | ################################################################################ 35 | output "karpenter_irsa" { 36 | value = module.karpenter_irsa_role.iam_role_arn 37 | } 38 | 39 | output "karpenter_instance_profile" { 40 | value = aws_iam_instance_profile.karpenter_instance_profile.name 41 | } 42 | 43 | ################################################################################ 44 | # Argo Workflows 45 | ################################################################################ 46 | output "argo_workflows_irsa" { 47 | value = module.argo_workflows_eks_role.iam_role_arn 48 | } 49 | 50 | output "argo_workflows_bucket_name" { 51 | value = aws_s3_bucket.argo-artifacts.id 52 | } 53 | 54 | output "argo_workflows_bucket_arn" { 55 | value = aws_s3_bucket.argo-artifacts.arn 56 | } -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import styles from './styles.module.css'; 4 | 5 | const FeatureList = [ 6 | { 7 | title: 'Easy to Use', 8 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 9 | description: ( 10 | <> 11 | Docusaurus was designed from the ground up to be easily installed and 12 | used to get your website up and running quickly. 13 | 14 | ), 15 | }, 16 | { 17 | title: 'Focus on What Matters', 18 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 19 | description: ( 20 | <> 21 | Docusaurus lets you focus on your docs, and we'll do the chores. Go 22 | ahead and move your docs into the docs directory. 23 | 24 | ), 25 | }, 26 | { 27 | title: 'Powered by React', 28 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 29 | description: ( 30 | <> 31 | Extend or customize your website layout by reusing React. Docusaurus can 32 | be extended while reusing the same header and footer. 33 | 34 | ), 35 | }, 36 | ]; 37 | 38 | function Feature({Svg, title, description}) { 39 | return ( 40 |
41 |
42 | 43 |
44 |
45 |

{title}

46 |

{description}

47 |
48 |
49 | ); 50 | } 51 | 52 | export default function HomepageFeatures() { 53 | return ( 54 |
55 |
56 |
57 | {FeatureList.map((props, idx) => ( 58 | 59 | ))} 60 |
61 |
62 |
63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /website/docs/03-connect-to-github-repo.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: github_repo 3 | sidebar_label: 'Connect to GitHub' 4 | sidebar_position: 3 5 | --- 6 | 7 | # Connect to GitHub: 8 | 9 | Since we are using a GitOps approach, we will need to install and connect `FluxV2` to a GitHub repository. 10 | 11 | ## GitHub Personal Access Token 12 | 13 | :::info 14 | If you don't have one token yet, check the [Creating a personal access token guide](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). 15 | ::: 16 | 17 | :::caution 18 | Remember to use the GitHub legacy tokens 19 | ::: 20 | 21 | ```bash 22 | export GITHUB_TOKEN= 23 | export GITHUB_USER= 24 | export GIT_BRANCH=main 25 | ``` 26 | 27 | ```bash 28 | echo "export GITHUB_TOKEN=${GITHUB_TOKEN}" | tee -a ~/.bash_profile 29 | echo "export GITHUB_USER=${GITHUB_USER}" | tee -a ~/.bash_profile 30 | echo "export GIT_BRANCH=${GIT_BRANCH}" | tee -a ~/.bash_profile 31 | ``` 32 | 33 | ## Create a fork of this [repo](https://github.com/aws-samples/eks-cluster-upgrades-workshop) in your GitHub account. 34 | 35 | ![Create fork](../static/img/create-fork01.png) 36 | 37 | ![Create fork2](../static/img/create-fork02.png) 38 | 39 | ## Execute install.sh script 40 | 41 | Now go back to your `Cloud9` IDE and execute the `install.sh` script present on `/home/ec2-user/environment` folder. 42 | 43 | ```bash 44 | cd /home/ec2-user/environment && bash install.sh 45 | ``` 46 | 47 | Fill all the asked questions, and when it asks your for terraform state, make sure to point to the following path `/home/ec2-user/environment/terraform.tfstate`, see example below. 48 | 49 | ```bash 50 | Enter the tf_state path (leave blank to generate infrastructure from scratch): /home/ec2-user/environment/terraform.tfstate 51 | ``` 52 | 53 | After this, the script will initialize and install `FluxV2` in your cluster pointing to your forked `GitHub` repository defined earlier. If everything succeeded, you should see the following output. 54 | 55 | ``` 56 | Now proceed to flux module 57 | ``` 58 | -------------------------------------------------------------------------------- /terraform/modules/base/codebuild/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "codebuild" { 2 | bucket = "codebuildbucket-${var.codebuild_project_name}" 3 | } 4 | 5 | resource "aws_s3_bucket_acl" "codebuild" { 6 | bucket = aws_s3_bucket.codebuild.id 7 | acl = "private" 8 | } 9 | 10 | resource "aws_iam_role" "codebuild" { 11 | name = "codebuildrole-${var.codebuild_project_name}" 12 | 13 | assume_role_policy = < /tmp/managed-addons.txt 17 | 18 | if [[ $3 == "--validate-support-target-version" ]]; then 19 | echo "Validating if add-ons are supported in the target version" 20 | upgrade_need=false 21 | for addon in $current_addons; do 22 | if [[ ! $(echo "$target_addons" | grep -w "$addon") ]]; then 23 | addon_name=$(echo $addon | cut -d"&" -f1) 24 | addon_version=$(echo $addon | cut -d"&" -f2) 25 | echo "Add-on $addon_name version $addon_version is not supported in the target version" >> /tmp/managed-addons.txt 26 | upgrade_need=true 27 | fi 28 | done 29 | if ! $upgrade_need; then 30 | echo "Add-on upgrade not needed, all add-ons are supported in the target version" >> /tmp/managed-addons.txt 31 | fi 32 | 33 | elif [[ $3 == "--validate-if-needs-to-upgrade" ]]; then 34 | echo "Validate if there is any add-on version upgrade to perform" 35 | for addon in $current_addons; do 36 | addon_name=$(echo $addon | cut -d"&" -f1) 37 | addon_version=$(echo $addon | cut -d"&" -f2) 38 | latest_version=$(echo "$target_addons" | grep $addon_name | awk -F"&" '{print $2}' | sort -rV | head -n 1) 39 | if [[ ! -z "$latest_version" && "$addon_version" != "$latest_version" ]]; then 40 | echo "Need to upgrade $addon_name from $addon_version to $latest_version" >> /tmp/managed-addons.txt 41 | fi 42 | done 43 | 44 | else 45 | echo "Please provide the parameter --validate-support-target-version or --validate-if-needs-to-upgrade" 46 | fi 47 | -------------------------------------------------------------------------------- /website/docs/11_cleanup.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: cleanup 3 | sidebar_label: 'Cleanup' 4 | sidebar_position: 11 5 | --- 6 | 7 | # Cleanup 8 | 9 | 10 | Congratulations on completing the EKS Upgrades Workshop! To avoid incurring unnecessary costs and to keep your AWS environment, it is important to clean up the resources created during the workshop. 11 | 12 | ## Terraform destroy 13 | 14 | ```bash 15 | cd /home/ec2-user/environment/eks-cluster-upgrades-workshop/terraform/clusters 16 | 17 | terraform state rm 'module.flux_v2' 18 | 19 | terraform destroy -var="git_password=$GITHUB_TOKEN" -var="git_username=$GITHUB_USER" -var="git_url=https://github.com/$GITHUB_USER/eks-cluster-upgrades-workshop.git" -var="git_branch=$GIT_BRANCH" -var="aws_region=$AWS_REGION" -var="cluster_version=1.25" --auto-approve 20 | ``` 21 | 22 | ## Remove Cloudformation Stacks (Only if executing this workshop outside of an AWS event) 23 | 24 | To do this, you can run the following Bash command with a for loop that lists the AWS CloudFormation stacks, selects the stacks with the names karpenter-eks-upgrade-demo, aws-cloud9-eks-upgrades-workshop, and eks-workshop, and then deletes them in that order: 25 | 26 | ```bash 27 | for stack in $(aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE --query "StackSummaries[?contains(StackName, 'Karpenter-eks-upgrade-demo') || contains(StackName, 'aws-cloud9-eks-upgrades-workshop') || contains(StackName, 'cloudformation')].StackName" --output text); do 28 | if [ $stack == "aws-cloud9-eks-upgrades-workshop"* ]; then 29 | aws cloudformation delete-stack --stack-name $stack 30 | fi 31 | if [ $stack == "eks-upgrades-workshop" ]; then 32 | aws cloudformation delete-stack --stack-name $stack 33 | fi 34 | if [ $stack == "cloudformation" ]; then 35 | aws cloudformation delete-stack --stack-name $stack 36 | fi 37 | done 38 | ``` 39 | 40 | This command will delete the AWS resources created during the workshop in the order specified to ensure a clean removal. Be sure to have the AWS CLI installed and configured with your AWS credentials for the command to work. 41 | 42 | 43 | Also, remember to delete any extra resource you may have added to the account during the workshop! 44 | -------------------------------------------------------------------------------- /gitops/add-ons/03-argo-workflows.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: argo-workflows 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRole 8 | metadata: 9 | name: full-permissions-cluster-role 10 | rules: 11 | - apiGroups: ["*"] 12 | resources: ["*"] 13 | verbs: ["*"] 14 | --- 15 | # TODO: Add annotation IRSA created with terraform 16 | apiVersion: v1 17 | kind: ServiceAccount 18 | metadata: 19 | name: full-permissions-service-account 20 | namespace: argo-workflows 21 | annotations: 22 | eks.amazonaws.com/role-arn: ARGO_WORKFLOWS_IRSA 23 | --- 24 | apiVersion: rbac.authorization.k8s.io/v1 25 | kind: ClusterRoleBinding 26 | metadata: 27 | name: full-permissions-cluster-role-binding 28 | roleRef: 29 | apiGroup: rbac.authorization.k8s.io 30 | kind: ClusterRole 31 | name: full-permissions-cluster-role 32 | subjects: 33 | - kind: ServiceAccount 34 | name: full-permissions-service-account 35 | namespace: argo-workflows 36 | --- 37 | # TODO: Configure s3 artifact output 38 | apiVersion: helm.toolkit.fluxcd.io/v2beta1 39 | kind: HelmRelease 40 | metadata: 41 | name: argo-workflows 42 | namespace: flux-system 43 | labels: 44 | self-managed-add-on: "true" 45 | add-on-version: "0.28.2" 46 | spec: 47 | releaseName: argo-workflows 48 | targetNamespace: argo-workflows 49 | storageNamespace: argo-workflows 50 | interval: 1m0s 51 | chart: 52 | spec: 53 | chart: argo-workflows 54 | version: 0.28.2 55 | sourceRef: 56 | kind: HelmRepository 57 | name: argo 58 | values: 59 | useStaticCredentials: false 60 | artifactRepository: 61 | s3: 62 | bucket: ARGO_WORKFLOWS_BUCKET_NAME 63 | region: AWS_REGION 64 | endpoint: s3.amazonaws.com 65 | workflow: 66 | serviceAccount: 67 | create: true 68 | name: "argo-workflow" 69 | annotations: 70 | eks.amazonaws.com/role-arn: ARGO_WORKFLOWS_IRSA # Add IRSA for EKS add-on validate 71 | rbac: 72 | create: true 73 | controller: 74 | workflowNamespaces: # Give permission to other namespaces, to use Karpenter 75 | - argo-workflows 76 | server: 77 | serviceType: LoadBalancer 78 | serviceAccount: 79 | annotations: 80 | eks.amazonaws.com/role-arn: ARGO_WORKFLOWS_IRSA 81 | extraArgs: 82 | - --auth-mode=server # This is for demonstration purposes only 83 | install: {} 84 | 85 | # https://github.com/argoproj/argo-helm/blob/main/charts/argo-workflows/values.yaml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EKS Cluster Upgrades Workshop 2 | 3 | ![Tests](https://github.com/aws-samples/eks-cluster-upgrades-workshop/actions/workflows/production.yaml/badge.svg?branch=main) 4 | 5 | :bangbang: THIS WORKSHOP IS PERFORMING UPGRADES FROM VERSION `1.24` :bangbang: 6 | 7 | This workshop covers best practices that are applicable for both older and newer versions of Kubernetes. We are committed to keeping our content up-to-date with the latest Amazon EKS releases, Let's get started! 8 | 9 | [Click here to access the workshop](https://eks-upgrades-workshop.netlify.app/) 10 | 11 | ## Introduction 12 | 13 | The Amazon cluster upgrades workshop is built to provide you with a reference architecture that can help make your Amazon EKS Cluster upgrades less painful and more seamless. To achieve this, we will be using a GitOps strategy with Fluxv2 for components reconciliation and Karpenter for Node Scaling. 14 | 15 | ### Why this architecture? 16 | 17 | One of the key benefits of using GitOps is that it enables us to use a mono repository approach for deploying both add-ons and applications. This approach makes the upgrade process much smoother because we have a single location to look at for deprecated API versions and ensure that add-ons are backwards compatible. 18 | 19 | ![EKS Architecture](website/static/img/eks-upgrades-architecture.png) 20 | 21 | By the end of this workshop, you will have a solid understanding of how to use GitOps with Fluxv2 and Karpenter to simplify the EKS Cluster upgrade process. We hope that this will help you to streamline your workflow and ensure that your infrastructure is always up-to-date and functioning smoothly. So, let's dive in and get started! 22 | 23 | 24 | ## Navigating the repository 25 | 26 | The top level repository can be split is to several areas. 27 | 28 | ### Site content 29 | 30 | The workshop content itself is a `docusaurus` site. All workshop content is written using Markdown and can be found in `website`. 31 | 32 | ### Learner environment 33 | 34 | To spin -up your learn environment, go to [`website`](./website/README.md#local-development) page and follow the instructions to run your docussaurus website. 35 | 36 | ### Locally deploy with terraform: 37 | 38 | **You will need to fork this repo.** 39 | 40 | Once forked, execute the `install.sh` (located in the root of this repo) script and fill te asked questions: 41 | 42 | ```bash 43 | bash ./install.sh 44 | ``` 45 | 46 | > When asked for `tf_state_path` leave it empty to provision all the components 47 | 48 | After that you will need to uncomment lines `5` and `6` of `gitops/add-ons/kustomization.yaml` file 49 | 50 | Then you can push the changes to your desired branch and flux will reconcile the changes 51 | 52 | ## Security 53 | 54 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 55 | 56 | ## License 57 | 58 | This project is licensed under the Apache-2.0 License. 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /terraform/modules/flux_cd/main.tf: -------------------------------------------------------------------------------- 1 | provider "kubernetes" { 2 | host = var.cluster_endpoint 3 | cluster_ca_certificate = base64decode(var.ca) 4 | token = var.token 5 | } 6 | 7 | provider "helm" { 8 | kubernetes { 9 | host = var.cluster_endpoint 10 | cluster_ca_certificate = base64decode(var.ca) 11 | token = var.token 12 | } 13 | } 14 | 15 | resource "kubernetes_namespace" "flux_system" { 16 | metadata { 17 | name = "flux-system" 18 | } 19 | } 20 | 21 | resource "helm_release" "flux2-sync" { 22 | name = "flux-system" 23 | namespace = var.namespace 24 | repository = "https://fluxcd-community.github.io/helm-charts" 25 | chart = "flux2-sync" 26 | 27 | set { 28 | name = "secret.create" 29 | value = true 30 | } 31 | 32 | set { 33 | name = "secret.data" 34 | value = jsonencode({ 35 | username = var.git_username 36 | password = var.git_password 37 | }) 38 | } 39 | 40 | set { 41 | name = "gitRepository.spec.ref.branch" 42 | value = var.git_branch 43 | } 44 | 45 | set { 46 | name = "gitRepository.spec.url" 47 | value = var.git_url # The repository URL, can be an HTTP/S or SSH address. 48 | } 49 | 50 | set { 51 | name = "kustomization.spec.path" 52 | value = "gitops/clusters/cluster-demo" 53 | } 54 | 55 | depends_on = [helm_release.flux2, kubernetes_namespace.flux_system] 56 | } 57 | 58 | # TODO: Implement IRSA and change the Service Account name, for Image Controller 59 | resource "helm_release" "flux2" { 60 | name = "flux2" 61 | namespace = var.namespace 62 | repository = "https://fluxcd-community.github.io/helm-charts" 63 | chart = "flux2" 64 | 65 | set { 66 | name = "helmController.create" 67 | value = var.activate_helm_controller 68 | } 69 | 70 | set { 71 | name = "imageAutomationController.create" 72 | value = var.activate_image_automation_controller 73 | } 74 | 75 | set { 76 | name = "imageAutomationController.serviceAccount.annotations" 77 | value = var.image_automation_controller_sa_annotations 78 | } 79 | 80 | set { 81 | name = "imageReflectionController.create" 82 | value = var.activate_image_reflection_controller 83 | } 84 | 85 | set { 86 | name = "imageReflectionController.serviceAccount.annotations" 87 | value = var.image_reflection_controller_sa_annotations 88 | } 89 | 90 | set { 91 | name = "kustomizeController.create" 92 | value = var.activate_kustomize_controller 93 | } 94 | 95 | set { 96 | name = "notificationController.create" 97 | value = var.activate_notification_controller 98 | } 99 | 100 | set { 101 | name = "sourceController.create" 102 | value = var.activate_source_controller 103 | } 104 | 105 | depends_on = [kubernetes_namespace.flux_system] 106 | } -------------------------------------------------------------------------------- /website/docs/00-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: intro 3 | sidebar_label: 'Introduction' 4 | sidebar_position: 0 5 | --- 6 | 7 | import Tabs from '@theme/Tabs'; 8 | import TabItem from '@theme/TabItem'; 9 | 10 | # Introduction 11 | 12 | One of the key considerations for people who have chosen Amazon Elastic Kubernetes Service (EKS) as their container management platform is to plan for cluster upgrades. The Kubernetes project is constantly updating with new features, design updates, and bug fixes, and new minor versions are released on average every three months and are supported for about twelve months after their release. 13 | 14 | ## Kubernetes project release process 15 | 16 | The Kubernetes project usually launches new minor versions on average every three months, and every version is supported for about twelve months after their release. 17 | 18 | 19 | ![Kubernetes version release](../static/img/kubernetes-release-diagram.png) 20 | 21 | :::warning 22 | Before adopting Kubernetes, be sure that you will have the commitment to stay up to date with the new platform versions. 23 | ::: 24 | 25 | ## Amazon EKS release process 26 | 27 | Amazon EKS is typically some weeks behind the latest Kubernetes version, this is because before a new version of Kubernetes is made available on EKS, **it is thoroughly tested to ensure stability and compatibility with other AWS services and tools.** 28 | 29 | 30 | 31 | 32 | ### EKS and Kubernetes support duration: 33 | 34 | 35 | 36 | 14+ months (EKS Support duration can be extended based on the amount of breaking changes introduced in a certain version ) 37 | 38 | 39 | 12 months 40 | 41 | 42 | 43 | 44 | :::note 45 | Amazon EKS is committed to supporting at least four production-ready versions of Kubernetes. Whereas the Kubernetes project only supports the latest 3 versions. 46 | ::: 47 | 48 | ## Workshop architecture 49 | 50 | The base architecture composed by `Amazon EKS Cluster`, `EKS Managed Add-ons`, and `Flux` is deployed with Terraform. 51 | 52 | `Flux` enables us to use a `mono repository` approach for deploying both `Self-Managed Add-Ons` and `Apps`. 53 | This approach makes the upgrade process much smoother because we have a single location to look at for deprecated API versions and ensure that add-ons are backwards compatible. 54 | 55 | ![EKS Architecture](../static/img/eks-upgrades-architecture.png) 56 | 57 | During the next steps of this workshop, you learn how to setup those components and gain a solid understanding of how to use `GitOps with Fluxv2`, `Karpenter`, and `Argo Workflows` to simplify the EKS Cluster upgrade process. We hope that this will help you streamline your workflow and ensure that your infrastructure is always up-to-date and functioning smoothly. So, let's dive in and get started! 58 | 59 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 31 | 32 | 34 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /website/docs/02-accessing-ide.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: cloud9 3 | sidebar_label: 'Accessing Cloud9 IDE' 4 | sidebar_position: 2 5 | --- 6 | 7 | # Accessing the IDE 8 | 9 | As part of the lab environment, you have access to an AWS Cloud9 IDE. 10 | 11 | To access the Cloud9 IDE, log into your [AWS console](https://console.aws.amazon.com/) and search for Cloud9 in the menu bar at the top of the screen: 12 | 13 | ![Search for the Cloud9 service](./assets/search.png) 14 | 15 | When the main Cloud9 screen opens, expand the menu on the left side of the screen: 16 | 17 | ![Access Cloud9 service menu](./assets/menu.png) 18 | 19 | There will be a Cloud9 environment named **eks-upgrades-workshop** available. Click the **Open** button to launch the IDE: 20 | 21 | ![Open the Cloud9 IDE](./assets/environment.png) 22 | 23 | :::tip 24 | 25 | If you do not see the eks-upgrades-workshop Cloud9 environment, this is because it is owned by another IAM user. Change the owner on Cloud9 Console. 26 | 27 | ::: 28 | 29 | Once the IDE has loaded, we recommend you use the **+** button and select **New Terminal** to open a new full screen terminal window. 30 | 31 | ![Open new Cloud9 terminal](./assets/terminal-open.png) 32 | 33 | This will open a new tab with a fresh terminal. 34 | 35 | :::info 36 | You might see the following message: `An error occurred (AccessDeniedException) when calling the UpdateEnvironment operation: User: arn:aws:sts::xxxxxxxxxx:assumed-role/eks-upgrades-admin/i-xxxxxxxxxxx is not authorized to perform: cloud9:UpdateEnvironment on resource: xxxxxxxx with an explicit deny in an identity-based policy` 37 | 38 | This is because we are disabling AWS temporary credentials. You can ignore it and move on 39 | ::: 40 | 41 | ![Shows new Cloud9 terminal](./assets/terminal.png) 42 | 43 | You may also close the small terminal at the bottom if you wish. 44 | 45 | Your IDE comes pre-configured to access the workshop EKS cluster and also provides a set of tools you will need, like the `aws` and `kubectl`, `pluto`, `eksctl`, `kubent` CLI tools. 46 | 47 | ```bash 48 | kubectl version 49 | pluto version 50 | eksctl version 51 | kubent version 52 | aws --version 53 | kubent --version 54 | ``` 55 | 56 | Along with the Cloud9 instance, this workshop already has provisioned for you all needed resources, including the Amazon EKS cluster. Check that by running the follow command. 57 | 58 | ``` 59 | kubectl get nodes 60 | ``` 61 | 62 | You should see the following output: 63 | 64 | ```output 65 | NAME STATUS ROLES AGE VERSION 66 | fargate-ip-10-35-28-29.us-east-2.compute.internal Ready 53m v1.24.12-eks-f4dc2c0 67 | fargate-ip-10-35-37-154.us-east-2.compute.internal Ready 53m v1.24.12-eks-f4dc2c0 68 | fargate-ip-10-35-38-99.us-east-2.compute.internal Ready 53m v1.24.12-eks-f4dc2c0 69 | fargate-ip-10-35-45-57.us-east-2.compute.internal Ready 53m v1.24.12-eks-f4dc2c0 70 | ``` 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /website/docs/05-karpenter.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: karpenter 3 | sidebar_label: 'Karpenter' 4 | sidebar_position: 5 5 | --- 6 | 7 | # Karpenter during the upgrade process 8 | 9 | Karpenter is a Kubernetes node scaling that has the goal of automatically launches just the right compute resources to handle your cluster’s applications. Many people position Karpenter just to save money, making Spot instance usage easier, but Karpenter can also help a customer reduce their operational overhead. Karpenter, by default, will use Amazon EKS optimized AMIs. Whenever Karpenter launches a new node, it will match the Control Plane version of that node. It means that after an upgrade process you don’t need to upgrade all your Nodes at once, you can let Karpenter little by little replace nodes with old kubelet version, to new ones that matches EKS Control Plane version. 10 | 11 | ## Exploring the workload 12 | 13 | In the previous module we have enabled `karpenter` in flux `kustomization` file. In [Karpenter provisioner](https://karpenter.sh/preview/concepts/provisioners/) we have defined specific labels and a taint, see manifest below: 14 | 15 | ```yaml 16 | apiVersion: karpenter.sh/v1alpha5 17 | kind: Provisioner 18 | metadata: 19 | name: default 20 | spec: 21 | providerRef: 22 | name: default 23 | taints: 24 | - key: applications 25 | effect: NoSchedule 26 | labels: 27 | node-type: applications 28 | # Provisioner file continues 29 | ``` 30 | 31 | This will make sure that only applications that we define both `NodeSelector` and a `Toleration` to karpenter taint will be scheduled into Karpenter nodes. Let's verify our `sample-app` manifest: 32 | 33 | ```bash 34 | cat /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/01-sample-app.yaml | grep nodeSelector -A5 35 | ``` 36 | 37 | The output should look like this: 38 | 39 | ```yaml 40 | nodeSelector: # Force scale on Karpenter nodes 41 | node-type: applications 42 | tolerations: # Force scale on Karpenter nodes 43 | - key: "applications" 44 | operator: "Exists" 45 | effect: "NoSchedule" 46 | ``` 47 | 48 | ## Verify Node provisioning 49 | 50 | Karpenter will provision Nodes based on Pods in Pending state, since we already had our sample-app Pods in that state let's check if Karpenter already provisioned a Node to handle that workload, first let's validate that our sample-app Pods are up and running: 51 | 52 | ```bash 53 | kubectl -n default get pod 54 | ``` 55 | 56 | The output should look like this: 57 | 58 | ``` 59 | NAME READY STATUS RESTARTS AGE 60 | nginx-6b855ddcb7-457ls 1/1 Running 0 58m 61 | nginx-6b855ddcb7-bbck2 1/1 Running 0 58m 62 | nginx-6b855ddcb7-kphps 1/1 Running 0 58m 63 | ``` 64 | 65 | Now let's verify the new Node by passing `node-type=applications` label: 66 | 67 | ``` 68 | kubectl get nodes -l node-type=applications 69 | ``` 70 | 71 | Your output should me similar to this: 72 | 73 | ``` 74 | NAME STATUS ROLES AGE VERSION 75 | ip-192-168-60-113.ec2.internal Ready 21m v1.24.xx-eks-a59e1f0 76 | ``` 77 | 78 | :::tip 79 | In the above command you will see that Karpenter by default will match the kubelet Node version with the EKS Control Plane version. 80 | ::: 81 | 82 | To make sure that those Pods are running in this new Node created by Karpenter, let's execute the following command: 83 | 84 | ```bash 85 | kubectl -n default get pods -o wide --field-selector spec.nodeName=$(kubectl get nodes -l node-type=applications | awk '/ip/ {print $1}') 86 | ``` 87 | 88 | The output should look like this: 89 | 90 | ``` 91 | NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 92 | nginx-c5bfd7b85-9snbt 1/1 Running 0 48m 10.35.33.113 ip-10-35-46-50.us-east-2.compute.internal 93 | nginx-c5bfd7b85-g67lb 1/1 Running 0 48m 10.35.33.115 ip-10-35-46-50.us-east-2.compute.internal 94 | nginx-c5bfd7b85-swmvj 1/1 Running 0 48m 10.35.33.112 ip-10-35-46-50.us-east-2.compute.internal 95 | ``` 96 | 97 | In this module, we used Karpenter for Node scaling, making sure that just what we apply both `toleration` and `NodeSelector` will be scheduled in Karpenter Nodes. -------------------------------------------------------------------------------- /terraform/clusters/related_infra.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Karpenter Role to use in nodes created by Karpenter 3 | ################################################################################ 4 | 5 | resource "aws_iam_role" "karpenter_node_role" { 6 | name = "KarpenterNodeRole-${var.name}" 7 | assume_role_policy = </ pathname under which your site is served 16 | // For GitHub pages deployment, it is often '//' 17 | baseUrl: '/', 18 | 19 | // GitHub pages deployment config. 20 | // If you aren't using GitHub pages, you don't need these. 21 | organizationName: 'aws-samples', // Usually your GitHub org/user name. 22 | projectName: 'eks-upgrades-workshop', // Usually your repo name. 23 | 24 | onBrokenLinks: 'throw', 25 | onBrokenMarkdownLinks: 'warn', 26 | 27 | // Even if you don't use internalization, you can use this field to set useful 28 | // metadata like html lang. For example, if your site is Chinese, you may want 29 | // to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | 'classic', 38 | /** @type {import('@docusaurus/preset-classic').Options} */ 39 | ({ 40 | docs: { 41 | sidebarPath: require.resolve('./sidebars.js'), 42 | // Please change this to your repo. 43 | // Remove this to remove the "edit this page" links. 44 | editUrl: 45 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', 46 | }, 47 | blog: { 48 | showReadingTime: true, 49 | // Please change this to your repo. 50 | // Remove this to remove the "edit this page" links. 51 | editUrl: 52 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', 53 | }, 54 | theme: { 55 | customCss: require.resolve('./src/css/custom.css'), 56 | }, 57 | }), 58 | ], 59 | ], 60 | 61 | themeConfig: 62 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 63 | ({ 64 | colorMode: { 65 | defaultMode: 'dark', 66 | disableSwitch: true 67 | }, 68 | // Replace with your project's social card 69 | image: 'img/meta.png', 70 | navbar: { 71 | title: 'EKS Upgrades Workshop', 72 | logo: { 73 | alt: 'AWS Logo', 74 | src: 'img/logo.svg', 75 | }, 76 | items: [ 77 | { 78 | type: 'doc', 79 | docId: 'intro', 80 | position: 'left', 81 | label: 'Start', 82 | }, 83 | 84 | // { 85 | // type: 'doc', 86 | // docId: 'create-the-environment/select-your-environment', 87 | // position: 'left', 88 | // label: 'Setup', 89 | // }, 90 | // { 91 | // type: 'doc', 92 | // docId: 'explore-environment/why-gitops', 93 | // position: 'left', 94 | // label: 'GitOps', 95 | // }, 96 | // { 97 | // type: 'doc', 98 | // docId: 'karpenter-scaling/karpenter-scaling', 99 | // position: 'left', 100 | // label: 'Karpenter', 101 | // }, 102 | // { 103 | // type: 'doc', 104 | // docId: 'validating-state/validating-state', 105 | // position: 'left', 106 | // label: 'Validating', 107 | // }, 108 | // { 109 | // type: 'doc', 110 | // docId: 'eks-control-plane-upgrade/eks-upgrade', 111 | // position: 'left', 112 | // label: 'Control Plane', 113 | // }, 114 | // { 115 | // type: 'doc', 116 | // docId: 'managed-nodes-upgrade/managed-nodes-upgrade', 117 | // position: 'left', 118 | // label: 'Nodes', 119 | // }, 120 | // { 121 | // type: 'doc', 122 | // docId: 'upgrade-managed-addons/managed-addons-upgrade', 123 | // position: 'left', 124 | // label: 'Add-ons', 125 | // }, 126 | // { 127 | // type: 'doc', 128 | // docId: 'rollout-nodes-with-karpenter/rollout-nodes', 129 | // position: 'left', 130 | // label: 'Karpenter Rollout', 131 | // }, 132 | // { 133 | // type: 'doc', 134 | // docId: 'Conclusion', 135 | // position: 'left', 136 | // label: 'Conclusion', 137 | // }, 138 | { 139 | type: 'doc', 140 | docId: 'cleanup', 141 | position: 'left', 142 | label: 'Cleanup', 143 | }, 144 | { 145 | href: 'https://github.com/aws-samples/eks-cluster-upgrades-workshop', 146 | label: 'GitHub', 147 | position: 'right', 148 | }, 149 | ], 150 | }, 151 | footer: { 152 | style: 'dark', 153 | links: [ 154 | // { 155 | // title: 'Docs', 156 | // items: [ 157 | // { 158 | // label: 'Tutorial', 159 | // to: '/docs/intro', 160 | // }, 161 | // ], 162 | // }, 163 | // { 164 | // title: 'Community', 165 | // items: [ 166 | // { 167 | // label: 'Stack Overflow', 168 | // href: 'https://stackoverflow.com/questions/tagged/docusaurus', 169 | // }, 170 | // { 171 | // label: 'Discord', 172 | // href: 'https://discordapp.com/invite/docusaurus', 173 | // }, 174 | // { 175 | // label: 'Twitter', 176 | // href: 'https://twitter.com/docusaurus', 177 | // }, 178 | // ], 179 | // }, 180 | // { 181 | // title: 'More', 182 | // items: [ 183 | // { 184 | // label: 'Blog', 185 | // to: '/blog', 186 | // }, 187 | // { 188 | // label: 'GitHub', 189 | // href: 'https://github.com/facebook/docusaurus', 190 | // }, 191 | // ], 192 | // }, 193 | ], 194 | copyright: `© ${new Date().getFullYear()} Amazon Web Services, Inc. or its affiliates. All rights reserved.`, 195 | }, 196 | prism: { 197 | theme: lightCodeTheme, 198 | darkTheme: darkCodeTheme, 199 | }, 200 | }), 201 | }; 202 | 203 | module.exports = config; 204 | -------------------------------------------------------------------------------- /upgrades-workflows/upgrade-validate-workflow.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Workflow 4 | metadata: 5 | name: cluster-upgrade-validate-workflow 6 | namespace: argo-workflows 7 | spec: 8 | templates: 9 | - name: validate-aws-basics 10 | inputs: 11 | parameters: 12 | - name: VPC_ID 13 | value: AWS_VPC_ID 14 | - name: AWS_REGION 15 | value: REGION_AWS 16 | - name: CLUSTER_IAM_ROLE_NAME 17 | value: AWS_CLUSTER_IAM_ROLE_NAME 18 | - name: CLUSTER_SG_ID 19 | value: CLUSTER_SECURITY_GROUP_ID 20 | container: 21 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 22 | command: ["/bin/sh","-c"] 23 | args: ['./validate-aws-basics.sh {{inputs.parameters.CLUSTER_IAM_ROLE_NAME}} {{inputs.parameters.VPC_ID}} {{inputs.parameters.CLUSTER_SG_ID}} {{inputs.parameters.AWS_REGION}}'] 24 | outputs: 25 | parameters: 26 | - name: aws-basics 27 | valueFrom: 28 | path: /tmp/my_file.txt 29 | artifacts: 30 | # generate hello-art artifact from /tmp/hello_world.txt 31 | # artifacts can be directories as well as files 32 | - name: aws-basics 33 | path: /tmp/my_file.txt 34 | - name: validate-apis 35 | container: 36 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 37 | command: ["/bin/sh","-c"] 38 | args: ['./validate-apis.sh'] 39 | outputs: 40 | parameters: 41 | - name: kubent-report 42 | valueFrom: 43 | path: /tmp/kubent-report.txt 44 | artifacts: 45 | # generate hello-art artifact from /tmp/hello_world.txt 46 | # artifacts can be directories as well as files 47 | - name: kubent-report 48 | path: /tmp/kubent-report.txt 49 | - name: validate-add-ons-self-managed 50 | container: 51 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 52 | command: ["/bin/sh","-c"] 53 | args: ['./validate-self-managed-add-ons.sh'] 54 | outputs: 55 | parameters: 56 | - name: self-managed-add-on-report 57 | valueFrom: 58 | path: /tmp/self-addon-report.txt 59 | artifacts: 60 | # generate hello-art artifact from /tmp/hello_world.txt 61 | # artifacts can be directories as well as files 62 | - name: self-managed-add-on-report 63 | path: /tmp/self-addon-report.txt 64 | - name: validate-eks-managed-add-ons 65 | inputs: 66 | parameters: 67 | - name: CLUSTER_NAME 68 | value: eks-upgrades-workshop 69 | - name: AWS_REGION 70 | value: REGION_AWS 71 | container: 72 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 73 | command: ["/bin/sh","-c"] 74 | args: ["./validate-managed-addons.sh {{inputs.parameters.AWS_REGION}} {{inputs.parameters.CLUSTER_NAME}} --validate-if-needs-to-upgrade"] # Change your region and cluster name 75 | outputs: 76 | parameters: 77 | - name: eks-managed-add-on-report 78 | valueFrom: 79 | path: /tmp/managed-addons.txt 80 | artifacts: 81 | # generate hello-art artifact from /tmp/hello_world.txt 82 | # artifacts can be directories as well as files 83 | - name: eks-managed-add-on-report 84 | path: /tmp/managed-addons.txt 85 | - name: get-eks-k8s-documentation 86 | inputs: 87 | parameters: 88 | - name: k8s_version 89 | value: "1.25" 90 | container: 91 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 92 | command: ["/bin/sh","-c"] 93 | args: ['echo "====================== Must look URLs ======================" > /tmp/eks-k8s-docs.txt && echo "K8s Rel notes: https://relnotes.k8s.io/?kinds=api-change&kinds=deprecation&releaseVersions={{inputs.parameters.k8s_version}}.0" >> /tmp/eks-k8s-docs.txt && echo "EKS Notes: https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-{{inputs.parameters.k8s_version}}" >> /tmp/eks-k8s-docs.txt'] # Change your region and cluster name 94 | outputs: 95 | parameters: 96 | - name: notes 97 | valueFrom: 98 | path: /tmp/eks-k8s-docs.txt 99 | artifacts: 100 | # generate hello-art artifact from /tmp/hello_world.txt 101 | # artifacts can be directories as well as files 102 | - name: k8s-eks-notes 103 | path: /tmp/eks-k8s-docs.txt 104 | - name: consolidate-report 105 | inputs: 106 | parameters: 107 | - name: aws-basics 108 | - name: kubent-report 109 | - name: self-managed-add-on-report 110 | - name: eks-managed-add-on-report 111 | - name: k8s-eks-notes 112 | container: 113 | image: public.ecr.aws/i9m4f0j6/eks-validate-image:9 114 | command: ["/bin/sh","-c"] 115 | args: ["echo '{{inputs.parameters.aws-basics}} \n {{inputs.parameters.kubent-report}} \n {{inputs.parameters.self-managed-add-on-report}} \n {{inputs.parameters.eks-managed-add-on-report}} \n {{inputs.parameters.k8s-eks-notes}}' > /tmp/full-report.txt"] 116 | outputs: 117 | artifacts: 118 | # generate hello-art artifact from /tmp/hello_world.txt 119 | # artifacts can be directories as well as files 120 | - name: full-report 121 | path: /tmp/full-report.txt 122 | - name: cluster-upgrade-validate 123 | steps: 124 | - - name: validate-aws-basics 125 | template: validate-aws-basics 126 | - - name: validate-apis 127 | template: validate-apis 128 | - - name: validate-add-ons-self-managed 129 | template: validate-add-ons-self-managed 130 | - - name: validate-eks-managed-add-ons 131 | template: validate-eks-managed-add-ons 132 | - - name: get-eks-k8s-documentation 133 | template: get-eks-k8s-documentation 134 | - - name: consolidate-report 135 | template: consolidate-report 136 | arguments: 137 | parameters: 138 | # Pass the hello-param output from the generate-parameter step as the message input to print-message 139 | - name: aws-basics 140 | value: "{{steps.validate-aws-basics.outputs.parameters.aws-basics}}" 141 | - name: kubent-report 142 | value: "{{steps.validate-apis.outputs.parameters.kubent-report}}" 143 | - name: self-managed-add-on-report 144 | value: "{{steps.validate-add-ons-self-managed.outputs.parameters.self-managed-add-on-report}}" 145 | - name: eks-managed-add-on-report 146 | value: "{{steps.validate-eks-managed-add-ons.outputs.parameters.eks-managed-add-on-report}}" 147 | - name: k8s-eks-notes 148 | value: "{{steps.get-eks-k8s-documentation.outputs.parameters.notes}}" 149 | entrypoint: cluster-upgrade-validate 150 | serviceAccountName: full-permissions-service-account 151 | arguments: 152 | parameters: 153 | - name: k8s_version 154 | value: "1.25" 155 | - name: VPC_ID 156 | value: "vpc-04a2856d6fddf5f4f" 157 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to prompt for yes/no input 4 | prompt_yes_no() { 5 | local question=$1 6 | local default=$2 7 | local answer 8 | 9 | # Set default value if provided 10 | if [[ $default == "yes" ]]; then 11 | question+=" [Y/n]: " 12 | elif [[ $default == "no" ]]; then 13 | question+=" [y/N]: " 14 | else 15 | question+=" [y/n]: " 16 | fi 17 | 18 | # Prompt for input 19 | read -p "$question" answer 20 | 21 | # Set default value if input is empty 22 | if [[ -z $answer ]]; then 23 | answer=$default 24 | fi 25 | 26 | # Convert input to lowercase using 'tr' 27 | answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]') 28 | 29 | # Check if answer is valid 30 | if [[ $answer == "y" || $answer == "yes" ]]; then 31 | echo "yes" 32 | else 33 | echo "no" 34 | fi 35 | } 36 | 37 | # Function to prompt for sensitive input 38 | prompt_sensitive() { 39 | local question=$1 40 | local answer 41 | 42 | # Prompt for input (hide input) 43 | read -sp "$question" answer 44 | echo "$answer" 45 | } 46 | 47 | # Function to replace variables in files using sed 48 | replace_variables() { 49 | local file=$1 50 | local replacements=$2 51 | 52 | # Perform the replacements using sed 53 | for key in "${!replacements[@]}"; do 54 | sed -i'' -e "s|$key|${replacements[$key]}|g" "$file" 55 | done 56 | } 57 | 58 | # Function to build the git_url 59 | build_git_url() { 60 | local base_url="https://github.com/aws-samples/eks-cluster-upgrades-workshop" 61 | local username=$1 62 | 63 | local git_url="${base_url/aws-samples/$username}" 64 | echo "$git_url" 65 | } 66 | 67 | # Prompt for fork creation 68 | fork_created=$(prompt_yes_no "Have you already created your fork?" "no") 69 | 70 | # Prompt for personal access token 71 | token_created=$(prompt_yes_no "Have you already created your personal access token?" "no") 72 | 73 | # Check if both answers are "yes" 74 | if [[ $fork_created == "yes" && $token_created == "yes" ]]; then 75 | # Prompt for git username 76 | read -p "Enter your git username: " git_username 77 | read -p "Enter your git branch (leave blank to set to main): " git_branch 78 | 79 | # create an if to validate the branch and set main as default if not provided by user 80 | if [[ -z $git_branch ]]; then 81 | git_branch="main" 82 | echo "Branch set to main." 83 | fi 84 | 85 | 86 | # Prompt for GitHub personal access token (same as git password) 87 | git_password=$(prompt_sensitive "Enter your GitHub personal access token: ") 88 | 89 | # Prompt for AWS region 90 | read -p "Enter your AWS region: " aws_region 91 | 92 | # Build the git_url 93 | git_url=$(build_git_url "$git_username") 94 | 95 | # Output the collected inputs 96 | echo -e "\nFork created: $fork_created" 97 | echo "Token created: $token_created" 98 | echo "Git username: $git_username" 99 | echo "AWS region: $aws_region" 100 | echo "Git URL: $git_url" 101 | 102 | # Proceed with further actions 103 | echo "Proceeding with further actions... Cloning your forked GitHub Repository" 104 | git clone "$git_url" -b $git_branch 105 | 106 | read -p "Enter the tf_state path (leave blank to generate infrastructure from scratch): " tf_state_path 107 | 108 | if [[ -n $tf_state_path ]]; then 109 | # Copy tf_state file to current directory 110 | cp "$tf_state_path" eks-cluster-upgrades-workshop/terraform/clusters/terraform.tfstate 111 | echo "Terraform state file copied to current directory." 112 | fi 113 | 114 | cd eks-cluster-upgrades-workshop/terraform/clusters 115 | 116 | echo "Configuring Terraform" 117 | 118 | terraform init 119 | 120 | terraform plan -var="git_password=$git_password" -var="git_username=$git_username" -var="git_url=$git_url" -var="git_branch=$git_branch" -var="aws_region=$aws_region" 121 | 122 | # TODO: add aws_region on terraform apply command 123 | terraform apply -var="git_password=$git_password" -var="git_username=$git_username" -var="git_url=$git_url" -var="git_branch=$git_branch" -var="aws_region=$aws_region" --auto-approve 124 | 125 | sleep 5 126 | # TODO: add aws_region on terraform apply command 127 | terraform apply -var="git_password=$git_password" -var="git_username=$git_username" -var="git_url=$git_url" -var="git_branch=$git_branch" -var="aws_region=$aws_region" --auto-approve 128 | 129 | aws eks --region $aws_region update-kubeconfig --name eks-upgrades-workshop 130 | 131 | echo "Change needed variables on template for GitOps" 132 | 133 | # Retrieve Terraform outputs and set them as environment variables 134 | 135 | ARGO_WORKFLOWS_BUCKET_ARN=$(terraform output -raw argo_workflows_bucket_arn) 136 | ARGO_WORKFLOWS_BUCKET_NAME=$(terraform output -raw argo_workflows_bucket_name) 137 | ARGO_WORKFLOWS_IRSA=$(terraform output -raw argo_workflows_irsa) 138 | AWS_REGION=$(terraform output -raw aws_region) 139 | AWS_VPC_ID=$(terraform output -raw aws_vpc_id) 140 | CLUSTER_ENDPOINT=$(terraform output -raw cluster_endpoint) 141 | CLUSTER_IAM_ROLE_NAME=$(terraform output -raw cluster_iam_role_name) 142 | CLUSTER_SECURITY_GROUP_ID=$(terraform output -raw cluster_primary_security_group_id) 143 | KARPENTER_INSTANCE_PROFILE=$(terraform output -raw karpenter_instance_profile) 144 | KARPENTER_IRSA=$(terraform output -raw karpenter_irsa) 145 | 146 | pwd 147 | # Define the file paths 148 | karpenter_file="../../gitops/add-ons/02-karpenter.yaml" 149 | argo_workflows_file="../../gitops/add-ons/03-argo-workflows.yaml" 150 | upgrades_workflow_file="../../upgrades-workflows/upgrade-validate-workflow.yaml" 151 | 152 | # Perform the replacements using sed (macOS) 153 | sed -i'' -e "s|ARGO_WORKFLOWS_BUCKET_ARN|$ARGO_WORKFLOWS_BUCKET_ARN|g" "$karpenter_file" 154 | sed -i'' -e "s|ARGO_WORKFLOWS_BUCKET_NAME|$ARGO_WORKFLOWS_BUCKET_NAME|g" "$karpenter_file" 155 | sed -i'' -e "s|ARGO_WORKFLOWS_IRSA|$ARGO_WORKFLOWS_IRSA|g" "$karpenter_file" 156 | sed -i'' -e "s|CLUSTER_ENDPOINT|$CLUSTER_ENDPOINT|g" "$karpenter_file" 157 | sed -i'' -e "s|KARPENTER_INSTANCE_PROFILE|$KARPENTER_INSTANCE_PROFILE|g" "$karpenter_file" 158 | sed -i'' -e "s|KARPENTER_IRSA|$KARPENTER_IRSA|g" "$karpenter_file" 159 | sed -i'' -e "s|AWS_REGION|$AWS_REGION|g" "$karpenter_file" 160 | 161 | sed -i'' -e "s|ARGO_WORKFLOWS_BUCKET_ARN|$ARGO_WORKFLOWS_BUCKET_ARN|g" "$argo_workflows_file" 162 | sed -i'' -e "s|ARGO_WORKFLOWS_BUCKET_NAME|$ARGO_WORKFLOWS_BUCKET_NAME|g" "$argo_workflows_file" 163 | sed -i'' -e "s|ARGO_WORKFLOWS_IRSA|$ARGO_WORKFLOWS_IRSA|g" "$argo_workflows_file" 164 | sed -i'' -e "s|CLUSTER_ENDPOINT|$CLUSTER_ENDPOINT|g" "$argo_workflows_file" 165 | sed -i'' -e "s|KARPENTER_INSTANCE_PROFILE|$KARPENTER_INSTANCE_PROFILE|g" "$argo_workflows_file" 166 | sed -i'' -e "s|KARPENTER_IRSA|$KARPENTER_IRSA|g" "$argo_workflows_file" 167 | sed -i'' -e "s|AWS_REGION|$AWS_REGION|g" "$argo_workflows_file" 168 | 169 | sed -i'' -e "s|AWS_VPC_ID|$AWS_VPC_ID|g" "$upgrades_workflow_file" 170 | sed -i'' -e "s|REGION_AWS|$AWS_REGION|g" "$upgrades_workflow_file" 171 | sed -i'' -e "s|AWS_CLUSTER_IAM_ROLE_NAME|$CLUSTER_IAM_ROLE_NAME|g" "$upgrades_workflow_file" 172 | sed -i'' -e "s|CLUSTER_SECURITY_GROUP_ID|$CLUSTER_SECURITY_GROUP_ID|g" "$upgrades_workflow_file" 173 | 174 | # Applying deprecated manifests 175 | kubectl apply -f ../../gitops/applications/deprecated-manifests 176 | echo 177 | 178 | echo "Now proceed to flux module" 179 | else 180 | echo "You need to create your fork and personal access token before proceeding." 181 | fi 182 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | 2 | Focus on What Matters 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /website/docs/06-validating-state.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: validating-state 3 | sidebar_label: 'Validating State' 4 | sidebar_position: 5 5 | --- 6 | 7 | # Validating State 8 | 9 | :::info 10 | This is just a suggested approach on how to implement a workflow to create an upgrade plan. 11 | ::: 12 | 13 | Checking for deprecated APIs and updating your manifests to use the latest API versions before upgrading your Kubernetes cluster is crucial for preventing compatibility issues, avoiding downtime, maintaining a secure and stable environment, easing maintenance, staying informed about Kubernetes changes, and ensuring compliance with best practices. Using tools like Pluto, kube no trouble and kubectl convert streamlines the process of identifying and updating deprecated APIs, making it easier to maintain a healthy Kubernetes environment. 14 | 15 |
16 | 17 |
18 | 19 | 20 | 21 | ## Argo workflows validate pipeline 22 | 23 | For this workshop, we have automated all the validation steps in an `argo-workflows` pipeline, so let's run our workflow to verify what are the things that we need to change. 24 | 25 | ```bash 26 | cd /home/ec2-user/environment/eks-cluster-upgrades-workshop/upgrades-workflows && kubectl apply -f upgrade-validate-workflow.yaml 27 | ``` 28 | 29 | Getting Argo workflows UI URL: 30 | 31 | ```bash 32 | echo $(kubectl get svc -nargo-workflows | awk '{print $4}' | grep -vi external):2746/workflows?limit=50 33 | ``` 34 | :::note 35 | Workflow can take a while to appear 36 | ::: 37 | 38 | Open URL in your favourite browser. You are going to the workflow applied earlier in the running state. 39 | 40 | ![GitOps toolkit](../static/img/argo-workflows-00.png) 41 | 42 | Now click in the workflow and you are gonna be able to see all the validation steps that this workflow is executing: 43 | 44 | ![GitOps toolkit](../static/img/argo-workflows-01.png) 45 | 46 | The workflow will validate the following things: 47 | 48 | - **AWS Basics** ([Verify that your AWS account has all the resources needed to perform cluster upgrade](https://aws.github.io/aws-eks-best-practices/upgrades/#verify-basic-eks-requirements-before-upgrading)). 49 | - **Validate deprecated APIs** (Using [kubent](https://github.com/doitintl/kube-no-trouble), we will look for deprecate or removed APIs that we still using and we need to replace before upgrading). 50 | - **Validate Self Managed Add-ons** (Using [pluto](https://github.com/FairwindsOps/pluto), it will look for deprecated APIs in Helm charts, since we have all the self-managed add-ons deployed using charts). 51 | - **Validate Managed Add-ons** (Validate if we need to upgrade your AWS EKS managed add-ons using [eksctl](https://eksctl.io/) and [awscli](https://aws.amazon.com/pt/cli/)). 52 | - **Get Kubernetes/EKS documentation** (It will generate for you the links that you should look at before moving on with the cluster upgrade). 53 | 54 | ## Checking workflow report 55 | 56 | On the workflow that, in the last step under `consolidate-report` download the `full-report.tgz` 57 | 58 | ![GitOps toolkit](../static/img/argo-workflows-02.png) 59 | 60 | Open the report, it should look like the following: 61 | 62 | ``` 63 | ========================== AWS BASICS VALIDATION ========================== 64 | Subnet Check: At least one subnet has more than 5 IPs available 65 | Role Check: Cluster role exists 66 | Security Group Check: Cluster security group exists 67 | ====================== Kubent Deprecated APIs report ====================== 68 | __________________________________________________________________________________________ 69 | >>> Deprecated APIs removed in 1.25 <<< 70 | ------------------------------------------------------------------------------------------ 71 | KIND NAMESPACE NAME API_VERSION REPLACE_WITH (SINCE) 72 | CronJob default hello batch/v1beta1 batch/v1 (1.21.0) 73 | PodSecurityPolicy eks.privileged policy/v1beta1 (1.21.0) 74 | __________________________________________________________________________________________ 75 | >>> Deprecated APIs removed in 1.26 <<< 76 | ------------------------------------------------------------------------------------------ 77 | KIND NAMESPACE NAME API_VERSION REPLACE_WITH (SINCE) 78 | HorizontalPodAutoscaler default nginx-hpa autoscaling/v2beta1 autoscaling/v2 (1.23.0) 79 | ====================== Self Managed Add-ons ====================== 80 | NAME AGE READY STATUS 81 | argo-workflows 38m True Release reconciliation succeeded 82 | karpenter 38m True Release reconciliation succeeded 83 | metrics-server 68m True Release reconciliation succeeded 84 | ====================== Deprecated API in helm charts ====================== 85 | There were no resources found with known deprecated apiVersions. 86 | =========================== EKS Managed add-ons =========================== 87 | Need to upgrade aws-ebs-csi-driver from v1.19.0-eksbuild.1 to v1.19.0-eksbuild.2 88 | Need to upgrade kube-proxy from v1.24.10-eksbuild.2 to v1.25.9-eksbuild.1 89 | ====================== Must look URLs ====================== 90 | K8s Rel notes: https://relnotes.k8s.io/?kinds=api-change&kinds=deprecation&releaseVersions=1.25.0 91 | EKS Notes: https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-1.25 92 | ``` 93 | 94 | As you can see, the only thing that we need to change is what `kube-no-trouble` have identified under `Deprecated APIs removed in 1.25` and `Deprecated APIs removed in 1.26`. We don't have any `self-managed add-on` using a deprecated API, and for the `managed add-ons` aws is managing them, so we will upgrade them when we upgrade our Control Plane using Terraform. 95 | 96 | ## Using kubectl convert to change the manifests 97 | 98 | The `Kubent Deprecated APIs report` have identified two manifests using depreacated API versions: 99 | 100 | ``` 101 | KIND NAMESPACE NAME API_VERSION REPLACE_WITH (SINCE) 102 | CronJob default hello batch/v1beta1 batch/v1 (1.21.0) 103 | 104 | KIND NAMESPACE NAME API_VERSION REPLACE_WITH (SINCE) 105 | HorizontalPodAutoscaler default nginx-hpa autoscaling/v2beta1 autoscaling/v2 (1.23.0) 106 | ``` 107 | 108 | Let's update those using kubectl convert, those manifests are being reconciled by Flux, let's start by changing the `CronJob`: 109 | 110 | ```bash 111 | kubectl convert -f /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/02-deprecated-cronjob.yaml > /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/02-deprecated-cronjob.bak && mv /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/02-deprecated-cronjob.bak /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/02-deprecated-cronjob.yaml 112 | ``` 113 | 114 | Let's do the same thing for the `HorizontalPodAutoscaler` manifest: 115 | 116 | ```bash 117 | kubectl convert -f /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/03-deprecated-hpa.yaml > /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/03-deprecated-hpa.bak && mv /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/03-deprecated-hpa.bak /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/deprecated-manifests/03-deprecated-hpa.yaml 118 | ``` 119 | 120 | Let's uncomment `kustomization.yaml` file to flux watch those manifests: 121 | 122 | ```bash 123 | sed -i 's/# //' /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/kustomization.yaml 124 | ``` 125 | 126 | Now let's commit the changes to your GitHub repository, so flux can apply those changes. 127 | 128 | ```bash 129 | cd /home/ec2-user/environment/eks-cluster-upgrades-workshop/ 130 | git add . 131 | git commit -m "Changed deprecated APIs" 132 | git push origin $GIT_BRANCH 133 | ``` 134 | 135 | Flux will now detect the changes and start the reconciliation process. It does this by periodically polling the GitHub repository for changes. You can monitor the Flux logs to observe the reconciliation process: 136 | 137 | ```bash 138 | kubectl -n flux-system get pod -o name | grep -i source | while read POD; do kubectl -n flux-system logs -f $POD --since=1m; done 139 | ``` 140 | You should see logs indicating that the new changes have been detected and applied to the cluster: 141 | 142 | ```json 143 | {"level":"info","ts":"2023-06-05T19:56:11.469Z","msg":"stored artifact for commit 'Changed deprecated APIs'","controller":"gitrepository","controllerGroup":"source.toolkit.fluxcd.io","controllerKind":"GitRepository","GitRepository":{"name":"flux-system","namespace":"flux-system"},"namespace":"flux-system","name":"flux-system","reconcileID":"d1808938-8d2c-43f7-8bc0-0d1419778546"} 144 | ``` 145 | 146 | ## Run argo workflows validate pipeline again 147 | 148 | Now let's run the pipeline again to see if we have made all the needed changes before proceeding with the Cluster Upgrade. Open `argo-workflows` ui, select your workflow and click in `RESUBMIT`. 149 | 150 | ![GitOps toolkit](../static/img/argo-workflows-03.png) 151 | 152 | Argo will create a new workflow. Now let's wait until this new workflow has finished and then download the latest report as you have done earlier. Open the report, it should look like below: 153 | 154 | ``` 155 | ========================== AWS BASICS VALIDATION ========================== 156 | Subnet Check: At least one subnet has more than 5 IPs available 157 | Role Check: Cluster role exists 158 | Security Group Check: Cluster security group exists 159 | ====================== Kubent Deprecated APIs report ====================== 160 | __________________________________________________________________________________________ 161 | >>> Deprecated APIs removed in 1.25 <<< 162 | ------------------------------------------------------------------------------------------ 163 | KIND NAMESPACE NAME API_VERSION REPLACE_WITH (SINCE) 164 | PodSecurityPolicy eks.privileged policy/v1beta1 (1.21.0) 165 | ====================== Self Managed Add-ons ====================== 166 | NAME AGE READY STATUS 167 | argo-workflows 178m True Release reconciliation succeeded 168 | karpenter 178m True Release reconciliation succeeded 169 | metrics-server 3h29m True Release reconciliation succeeded 170 | ====================== Deprecated API in helm charts ====================== 171 | There were no resources found with known deprecated apiVersions. 172 | =========================== EKS Managed add-ons =========================== 173 | Need to upgrade aws-ebs-csi-driver from v1.19.0-eksbuild.1 to v1.19.0-eksbuild.2 174 | Need to upgrade kube-proxy from v1.24.10-eksbuild.2 to v1.25.9-eksbuild.1 175 | ====================== Must look URLs ====================== 176 | K8s Rel notes: https://relnotes.k8s.io/?kinds=api-change&kinds=deprecation&releaseVersions=1.25.0 177 | EKS Notes: https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-1.25 178 | ``` 179 | 180 | As you can see, we do not have any other deprecated API in use, so we can move on to upgrade our EKS Control Plane. 181 | 182 | :::caution 183 | This pipeline is just for helping during the validation, it is strogly recommended to look into every add-on specific release notes to make sure that no add-on needs to be upgraded before upgrading EKS Control Plane. 184 | ::: 185 | :::tip 186 | PodSecurityPolicy is managed by EKS. We don't need to do anything about it 187 | ::: -------------------------------------------------------------------------------- /website/docs/07-upgrading-control-plane.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: upgrading-control-plane 3 | sidebar_label: 'Upgrade Amazon EKS' 4 | sidebar_position: 6 5 | --- 6 | 7 | # Upgrading EKS 8 | 9 | In this guide, we'll go through the process of upgrading your Amazon Elastic Kubernetes Service (EKS) cluster, which is essential for maintaining optimal performance, security, and availability. 10 | 11 | We also will cover the importance of updates, how AWS manages EKS upgrades, and what happens when an upgrade fails. Finally, we will provide instructions on how to update the eksctl.yaml file in the helpers folder and apply the changes using the eksctl command. 12 | 13 | ## How AWS Manages EKS Upgrades 14 | 15 | The EKS upgrade process is managed by AWS to ensure a seamless and safe transition between Kubernetes versions. Here is a detailed breakdown of the steps AWS takes to upgrade the EKS control plane: 16 | 17 | ![BLUE GREEN](../static/img/eks-blue-green-upgrades.png) 18 | 19 | 1. **Pre-upgrade checks**: AWS first performs pre-upgrade checks, including assessing the current cluster state and evaluating the compatibility of the new version with your workloads. If any issues are detected, the upgrade process will not proceed. 20 | 21 | 2. **Backup and snapshot**: Before initiating the upgrade, AWS takes a backup of your existing control plane and creates a snapshot of your etcd data store. This is done to ensure data consistency and to enable rollback in case of an upgrade failure. 22 | 23 | :::tip 24 | For additional data protection, consider using [Velero](https://velero.io/), an open-source tool that simplifies the backup and recovery process for Kubernetes cluster resources and persistent volumes. Velero allows you to schedule and manage backups, as well as restore processes, providing an extra layer of safety for your data. 25 | ::: 26 | 27 | 3. **Creating a new control plane**: AWS creates a new control plane with the desired Kubernetes version. This new control plane runs in parallel with your existing control plane, ensuring minimal disruption to your workloads. 28 | 29 | 4. **Testing compatibility**: The new control plane is tested for compatibility with your workloads, including running automated tests to verify that your applications continue to function as expected. 30 | 31 | :::tip 32 | The goal is to minimize potential disruptions during the upgrade process and maintain the stability of your services. It's important to mention that this only looks for your application health and not for API's that may be removed or deprecated 33 | ::: 34 | 35 | 5. **Switching control plane endpoints**: Once compatibility is confirmed, AWS switches the control plane endpoints (API server) to the new control plane. This switch happens atomically, resulting in minimal downtime during the upgrade process. 36 | 37 | 6. **Terminating the old control plane**: The old control plane is terminated once the upgrade is complete, and all resources associated with it are cleaned up. 38 | 39 | ### EKS Rollback on Upgrade Failure 40 | 41 | ![BLUE GREEN](../static/img/eks-rollback.png) 42 | 43 | In case an EKS upgrade fails, AWS has measures in place to minimize disruption and revert the control plane to its previous version: 44 | 45 | 1. **Detecting the failure:** AWS constantly monitors the upgrade process to detect any issues. If a problem arises during the upgrade, the process is immediately halted. 46 | 47 | 2. **Restoring from backup:** AWS uses the backup and snapshot created before the upgrade to restore the control plane and etcd data store to their previous state. 48 | 49 | 3. **Switching control plane endpoints:** AWS atomically switches the control plane endpoints back to the previous control plane, ensuring minimal downtime. 50 | 51 | 4. **Terminating the new control plane:** Once the rollback is complete, AWS terminates the new control plane and cleans up any associated resources. 52 | 53 | 5. **Post-rollback assessment:** After the rollback, AWS will assess the reasons behind the upgrade failure and provide guidance on how to address the issues. You will need to troubleshoot and resolve the problems before attempting the upgrade again. 54 | 55 | ## Upgrading EKS Cluster 56 | 57 | We have used terraform to spin-up our cluster, all the add-ons are managed via Flux and we already have done the validation of deprecated APIs and add-ons, let's apply the cluster upgrade to a newer version: 58 | 59 | ```bash 60 | cd /home/ec2-user/environment/eks-cluster-upgrades-workshop/terraform/clusters 61 | 62 | terraform plan -var="git_password=$GITHUB_TOKEN" -var="git_username=$GITHUB_USER" -var="git_url=https://github.com/$GITHUB_USER/eks-cluster-upgrades-workshop.git" -var="git_branch=$GIT_BRANCH" -var="aws_region=$AWS_REGION" -var="cluster_version=1.25" 63 | ``` 64 | 65 | As you can see we are defining the variable `cluster_version=1.25` forcing terraform to change the Control Plane to version `1.25`. Also since we are using EKS managed add-ons we can upgrade tham all together to the latest available version, see snippet below of the output of `terraform plan`: 66 | 67 | 68 | ```json 69 | # module.eks.time_sleep.this[0] must be replaced 70 | +/- resource "time_sleep" "this" { 71 | ~ id = "2023-06-05T15:14:32Z" -> (known after apply) 72 | ~ triggers = { # forces replacement 73 | ~ "cluster_version" = "1.24" -> "1.25" 74 | # (3 unchanged elements hidden) 75 | } 76 | # (1 unchanged attribute hidden) 77 | } 78 | 79 | ~ resource "aws_eks_addon" "before_compute" { 80 | ~ addon_version = "v1.12.6-eksbuild.2" -> (known after apply) 81 | id = "eks-upgrades-workshop:vpc-cni" 82 | tags = { 83 | "Blueprint" = "eks-upgrades-workshop" 84 | "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" 85 | "karpenter.sh/discovery" = "eks-upgrades-workshop" 86 | } 87 | # (8 unchanged attributes hidden) 88 | 89 | # (1 unchanged block hidden) 90 | } 91 | 92 | # module.eks.aws_eks_addon.this["aws-ebs-csi-driver"] will be updated in-place 93 | ~ resource "aws_eks_addon" "this" { 94 | ~ addon_version = "v1.19.0-eksbuild.1" -> (known after apply) 95 | id = "eks-upgrades-workshop:aws-ebs-csi-driver" 96 | tags = { 97 | "Blueprint" = "eks-upgrades-workshop" 98 | "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" 99 | "karpenter.sh/discovery" = "eks-upgrades-workshop" 100 | } 101 | # (7 unchanged attributes hidden) 102 | 103 | # (1 unchanged block hidden) 104 | } 105 | 106 | # module.eks.aws_eks_addon.this["coredns"] will be updated in-place 107 | ~ resource "aws_eks_addon" "this" { 108 | ~ addon_version = "v1.9.3-eksbuild.3" -> (known after apply) 109 | id = "eks-upgrades-workshop:coredns" 110 | tags = { 111 | "Blueprint" = "eks-upgrades-workshop" 112 | "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" 113 | "karpenter.sh/discovery" = "eks-upgrades-workshop" 114 | } 115 | # (8 unchanged attributes hidden) 116 | 117 | # (1 unchanged block hidden) 118 | } 119 | 120 | # module.eks.aws_eks_addon.this["kube-proxy"] will be updated in-place 121 | ~ resource "aws_eks_addon" "this" { 122 | ~ addon_version = "v1.24.10-eksbuild.2" -> (known after apply) 123 | id = "eks-upgrades-workshop:kube-proxy" 124 | tags = { 125 | "Blueprint" = "eks-upgrades-workshop" 126 | "GithubRepo" = "github.com/aws-ia/terraform-aws-eks-blueprints" 127 | "karpenter.sh/discovery" = "eks-upgrades-workshop" 128 | } 129 | # (7 unchanged attributes hidden) 130 | 131 | # (1 unchanged block hidden) 132 | } 133 | ``` 134 | 135 | As you can see, using terraform we are forcing all the `managed-add-ons` also to be upgraded to the latest available version, now let's apply the script. 136 | 137 | ```bash 138 | terraform apply --auto-approve -var="git_password=$GITHUB_TOKEN" -var="git_username=$GITHUB_USER" -var="git_url=https://github.com/$GITHUB_USER/eks-cluster-upgrades-workshop.git" -var="git_branch=$GIT_BRANCH" -var="aws_region=$AWS_REGION" -var="cluster_version=1.25" 139 | ``` 140 | 141 | :::note 142 | The upgrade process can take a while, might be a good time for a break! 143 | ::: 144 | 145 | After it finished, let's validate that our cluster is really in the desired version by running the follow command: 146 | 147 | ```bash 148 | kubectl version | grep -i server 149 | ``` 150 | 151 | The output should be similar to this: 152 | 153 | ```json 154 | Server Version: version.Info{Major:"1", Minor:"25+", GitVersion:"v1.25.9-eks-0a21954", GitCommit:"eb82cd845d007ae98d215744675dcf7ff024a5a3", GitTreeState:"clean", BuildDate:"2023-04-15T00:37:59Z", GoVersion:"go1.19.8", Compiler:"gc", Platform:"linux/amd64"} 155 | ``` 156 | 157 | As you can see, the Server Version is now `1.25` 158 | 159 | ## Upgrading Nodes 160 | 161 | In this workshop both `self-managed` and `managed` add-ons are hosted in Fargate micro-vms, it means that we don't need to worry about the upgrade of the things that are hosted using Fargate since it is a serverless way to run applications. But our `sample-app` is running in Nodes provisioned by Karpenter, so let's explore what challenges can be involved when upgrading Nodes, and how Karpenter will help us. 162 | 163 | Karpenter by default will use `Amazon EKS optimized AMIs`, whenever Karpenter launches a new node, it will match the Control Plane version of that node. It means that after an upgrade process you don't need to upgrade all your Nodes at once, you can let Karpenter little by little replace nodes with old kubelet version, to new ones that matches EKS Control Plane version. 164 | 165 | ### Rollout Karpenter nodes 166 | 167 | Getting the Node name that we will perform the drain: 168 | 169 | ```bash 170 | kubectl get nodes -l node-type=applications 171 | ``` 172 | 173 | Output should look like this: 174 | 175 | ```bash 176 | NAME STATUS ROLES AGE VERSION 177 | ip-192-168-6-9.ec2.internal Ready 21h v1.24.xx-eks-a59e1f0 178 | ``` 179 | 180 | Validate if all of our application pods are running in the same Node: 181 | 182 | ```bash 183 | kubectl -n default get pods -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName 184 | ``` 185 | 186 | Output should look like this: 187 | 188 | ``` 189 | NAME STATUS NODE 190 | nginx-c5bfd7b85-9snbt Running ip-10-35-46-50.us-east-2.compute.internal 191 | nginx-c5bfd7b85-g67lb Running ip-10-35-46-50.us-east-2.compute.internal 192 | nginx-c5bfd7b85-swmvj Running ip-10-35-46-50.us-east-2.compute.internal 193 | ``` 194 | 195 | As you can see, all the 3 nginx replicas are running in the same node, let's start by using `kubectl cordon` to mark your old nodes as `unschedulable`: 196 | 197 | ```bash 198 | kubectl cordon $(kubectl get nodes -l node-type=applications -oname) 199 | 200 | kubectl get nodes -l node-type=applications 201 | ``` 202 | 203 | You should see an output similar to this: 204 | 205 | ```bash 206 | NAME STATUS ROLES AGE VERSION 207 | ip-192-168-6-9.ec2.internal Ready,SchedulingDisabled 21h v1.24.xx-eks-a59e1f0 208 | ``` 209 | 210 | `STATUS` will be SchedulingDisabled, because `kubectl cordon` command have applied a taint into this node to make sure new pods are not schedule in it. 211 | 212 | Let's drain our Node, using `kubectl drain` to safely evict all of your pods from your old nodes to the new ones. 213 | 214 | ```bash 215 | kubectl drain $(kubectl get nodes -l node-type=applications -oname) --ignore-daemonsets 216 | ``` 217 | 218 | The output should be similar to this. 219 | 220 | ```bash 221 | node/ip-10-35-46-50.us-east-2.compute.internal already cordoned 222 | Warning: ignoring DaemonSet-managed Pods: kube-system/aws-node-629pr, kube-system/ebs-csi-node-rfgzv, kube-system/kube-proxy-q2b56 223 | evicting pod default/nginx-c5bfd7b85-swmvj 224 | evicting pod default/nginx-c5bfd7b85-9snbt 225 | evicting pod default/hello-28100160-4gwbq 226 | evicting pod default/nginx-c5bfd7b85-g67lb 227 | error when evicting pods/"nginx-c5bfd7b85-g67lb" -n "default" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget. 228 | error when evicting pods/"nginx-c5bfd7b85-swmvj" -n "default" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget. 229 | error when evicting pods/"nginx-c5bfd7b85-9snbt" -n "default" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget. 230 | pod/hello-28100160-4gwbq evicted 231 | ``` 232 | 233 | Ops! it seems that we have a too agressive `Pod Disruption Budget` let's fix that. 234 | 235 | #### Adjusting PDBs (Pod Diruption Budgets) 236 | 237 | Let's see how our PDB is configured now: 238 | 239 | ```bash 240 | kubectl get pdb 241 | ``` 242 | 243 | As you can see we have the `MIN AVAILABLE` of 3, and we have only 3 replicas of our sample-app running, so this PDB is considered `TOO AGRESSIVE`, let's change that: 244 | 245 | ```bash 246 | cat <<'EOF' > /home/ec2-user/environment/eks-cluster-upgrades-workshop/gitops/applications/01-pdb-sample-app.yaml 247 | apiVersion: policy/v1 248 | kind: PodDisruptionBudget 249 | metadata: 250 | name: nginx-pdb 251 | namespace: default 252 | spec: 253 | minAvailable: 1 254 | selector: 255 | matchLabels: 256 | app: nginx 257 | EOF 258 | ``` 259 | 260 | We have changed the `minAvailable` from `3` to `1`, this will give us space to drain. Commit and push the changes to the repository: 261 | 262 | ```bash 263 | cd /home/ec2-user/environment/eks-cluster-upgrades-workshop/ 264 | git add . 265 | git commit -m "Changed PDB manifest from 3 to 1" 266 | git push origin $GIT_BRANCH 267 | ``` 268 | 269 | Wait few seconds, and validate that Flux has applied the new PDB: 270 | 271 | ```bash 272 | kubectl -n default get pdb/nginx-pdb -w 273 | ``` 274 | 275 | You should see the output similar to this: 276 | 277 | ``` 278 | NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE 279 | nginx-pdb 1 N/A 2 36m 280 | ``` 281 | 282 | As we can see we have changed the `MIN AVAILABLE` to `1` so now we can have `2` `ALLOWED DISRUPTIONS`. 283 | 284 | :::note 285 | This can change depending on each use case, remember to always configure PDBs based on your needs. 286 | ::: 287 | 288 | ### Rollout Karpenter nodes (Adjusted PDB) 289 | 290 | Now, try to drain your node again: 291 | 292 | ```bash 293 | kubectl drain $(kubectl get nodes -l node-type=applications -oname) --ignore-daemonsets 294 | ``` 295 | 296 | Since we are defining at least `1` replica available, `Karpenter` will deploy a new Node for us before terminating the old one to guarantee HA. After it finished let's see the new node that we have. 297 | 298 | ```bash 299 | kubectl get nodes -l node-type=applications 300 | ``` 301 | 302 | You should see the following output: 303 | 304 | ``` 305 | NAME STATUS ROLES AGE VERSION 306 | ip-10-35-10-230.us-east-2.compute.internal Ready 69s v1.25.xx-eks-0a21954 307 | ``` 308 | 309 | As you can see, we have two nodes managed by Karpenter, one that is being drained with version `1.24` and a new one with version `1.25`, Karpenter notice those pods that were evicted before and create a new node to handle those pods, let's verify again: 310 | 311 | ```bash 312 | kubectl get nodes -l node-type=applications 313 | kubectl -n default get pods -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName 314 | ``` 315 | 316 | You should now be able to see only a single Node managed by Karpenter, and all pods running in this new Node. -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_mountain.svg: -------------------------------------------------------------------------------- 1 | 2 | Easy to Use 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | --------------------------------------------------------------------------------