{"id":13624005,"url":"https://github.com/xjantoth/aws-eks-devopsinuse","last_synced_at":"2025-04-15T20:33:13.371Z","repository":{"id":55227784,"uuid":"258001385","full_name":"xjantoth/aws-eks-devopsinuse","owner":"xjantoth","description":"Learn AWS EKS Kubernetes cluster and devops in AWS (Part 1)","archived":false,"fork":false,"pushed_at":"2023-01-25T12:55:26.000Z","size":18403,"stargazers_count":10,"open_issues_count":1,"forks_count":19,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-08T12:42:51.286Z","etag":null,"topics":["aws","eks","terraform"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xjantoth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-22T19:35:25.000Z","updated_at":"2024-06-03T08:19:51.000Z","dependencies_parsed_at":"2023-02-14T07:31:43.016Z","dependency_job_id":null,"html_url":"https://github.com/xjantoth/aws-eks-devopsinuse","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xjantoth%2Faws-eks-devopsinuse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xjantoth%2Faws-eks-devopsinuse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xjantoth%2Faws-eks-devopsinuse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xjantoth%2Faws-eks-devopsinuse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xjantoth","download_url":"https://codeload.github.com/xjantoth/aws-eks-devopsinuse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249148290,"owners_count":21220510,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","eks","terraform"],"created_at":"2024-08-01T21:01:37.768Z","updated_at":"2025-04-15T20:33:13.337Z","avatar_url":"https://github.com/xjantoth.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# Learn AWS EKS Kubernetes cluster and devops in AWS (Part 1) \n**Starting AWS EKS cluster manually in AWS web console**\n\n - [1. Introduction](#1-introduction)\n - [2. EKS cluster costs few cents per hour](#2-eks-cluster-costs-few-cents-per-hour)\n - [3. Allow seeing billing data for IAM user](#3-allow-seeing-billing-data-for-iam-user)\n - [4. Create budget in AWS to be notified by email](#4-create-budget-in-aws-to-be-notified-by-email)\n - [5. Create an extra user and group in AWS with admin privilages](#5-create-an-extra-user-and-group-in-aws-with-admin-privilages)\n - [6. Install awscli and kubectl binaries](#6-install-awscli-and-kubectl-binaries)\n - [7. Retrive programatic access from AWS and configure aws cli](#7-retrive-programatic-access-from-aws-and-configure-aws-cli)\n - [8. Create EKS control plane IAM role in AWS web console](#8-create-eks-control-plane-iam-role-in-aws-web-console)\n - [9. Create EKS node group IAM role in AWS web console](#9-create-eks-node-group-iam-role-in-aws-web-console)\n - [10. Create SSH key pair in AWS console](#10-create-ssh-key-pain-in-aws-console)\n - [11. Create EKS cluster in AWS web console](#11-create-eks-cluster-in-aws-web-console)\n - [12. Create EKS node group in AWS web console](#12-create-eks-node-group-in-aws-web-console)\n - [13. Create KUBECONFIG at your local](#13-create-kubeconfig-at-your-local)\n - [14. Create configmap for NGINX deployment to AWS EKS cluster](#14-create-configmap-for-nginx-deployment-to-aws-eks-cluster)\n - [15. Execute Nginx deployment against AWS EKS Kubernetes cluster](#15-execute-nginx-deployment-against-aws-eks-kubernetes-cluster)\n - [16. Explore Nginx pod by attaching to a running container](#16-explore-nginx-pod-by-attaching-to-a-running-container)\n - [17. SSH to physical EC2 instances within your Kubernetes cluster in AWS](#17-ssh-to-physical-ec2-instances-within-your-kubernetes-cluster-in-aws)\n - [18. Clean up](#18-clean-up)\n\n**Using terrafrom to manage AWS EKS cluster**\n\n - [19. Install terrafrom binary at your local](#19-install-terrafrom-binary-at-your-local)\n - [20. Run terrafrom init and validate to initialize required plugins](#20-run-terrafrom-init-and-validate-to-initialize-required-plugins)\n - [21. Fill up terraform.eks.tfvars file with your AWS security credentials](#21-fill-up-terraformekstfvars-file-with-your-aws-security-credentials)\n - [22. Run terrafrom plan and terrafrom apply](#22-run-terrafrom-plan-and-terrafrom-apply)\n - [23. Uncomment iam.tf and run terrafrom apply to create mandatory AWS IAM roles](#23-uncomment-iamtf-and-run-terrafrom-apply-to-create-mandatory-aws-iam-roles)\n - [24. Run terraform apply uncomment sg.tf to create extra Security Group](#24-run-terraform-apply-uncomment-sgtf-to-create-extra-security-group)\n - [25. Uncomment file subnets.tf and run terraform apply to create Subnets in AWS](#25-uncomment-file-subnetstf-and-run-terraform-apply-to-create-subnets-in-aws)\n - [26. Uncomment aws eks cluster section in main.tf to create AWS EKS cluster control plane](#26-uncomment-aws-eks-cluster-section-in-maintf-to-create-aws-eks-cluster-control-plane)\n - [27. Uncomment aws eks node group resource section in main.tf to create AWS EKS node group](#27-uncomment-aws-eks-node-group-resource-section-in-maintf-to-create-aws-eks-node-group)\n - [28. Setup communication between your PC and AWS EKS cluster](#28-setup-communication-between-your-pc-and-aws-eks-cluster)\n - [29. Explore terrafrom console command](#29-explore-terrafrom-console-command)\n - [30. First NGINX deployment by kubectl to AWS EKS cluster created by terraform](#30-first-nginx-deployment-by-kubectl-to-aws-eks-cluster-created-by-terraform)\n - [31. Executing terrafrom destroy will not work when terrafrom run incrementaly](#31-executing-terrafrom-destroy-will-not-work-when-terrafrom-run-incrementaly)\n - [32. Provison and destroy AWS EKS Kubernetes cluster with terrafrom](#32-provison-and-destroy-aws-eks-kubernetes-cluster-with-terrafrom)\n\n\n# Learn AWS EKS Kubernetes cluster with Helm Charts (Part 2)\n**Helm charts**\n\n - [33. Desired Infrastructure with helm charts](#33-desired-infrastructure-with-helm-charts)\n - [34. Setting up Infrastracture via docker-compose at local](#34-setting-up-infrastracture-via-docker-compose-at-local)\n - [35. Explore backend part of the setup](#35-explore-backend-part-of-the-setup)\n - [36. Push docker images to docker hub](#36-push-docker-images-to-docker-hub)\n - [37. Install helm and helmfile binaries](#37-install-helm-and-helmfile-binaries)\n - [38. Creating backend helm chart](#38-creating-backend-helm-chart)\n - [39. Modify Chart yaml file for backend helm chart](#39-modify-chart-yaml-file-for-backend-helm-chart)\n - [40. Modify values yaml file for backend helm chart](#40-modify-values-yaml-file-for-backend-helm-chart)\n - [41. Modify service yaml file for backend helm chart](#41-modify-service-yaml-file-for-backend-helm-chart)\n - [42. Modify deployment yaml file for backend helm chart](#42-modify-deployment-yaml-file-for-backend-helm-chart)\n - [43. Create brand new secret yaml file for backend helm chart](#43-create-brand-new-secret-yaml-file-for-backend-helm-chart)\n - [44. Create helper function in helpers tpl file](#44-create-helper-function-in-helpers-tpl-file)\n - [45. Learn how to template backend helm chart and set values](#45-learn-how-to-template-backend-helm-chart-and-set-values)\n - [46. Creating frontend React app helm chart](#46-creating-frontend-react-app-helm-chart)\n - [47. Setup values yaml file for frontend helm chart](#47-setup-values-yaml-file-for-frontend-helm-chart)\n - [48. Setup service yaml file for frontend helm chart](#48-setup-service-yaml-file-for-frontend-helm-chart)\n - [49. Setup deployment yaml file for frontend helm chart](#49-setup-deployment-yaml-file-for-frontend-helm-chart)\n - [50. Learn how to template frontend helm chart](#50-learn-how-to-template-frontend-helm-chart)\n\n\u003c!-- - [1. Introduction](#1-introduction)--\u003e\n### Introduction to Part 2 of this course\n\n![](img/devopsinuse.png)\n\n- Section 1. **Provisioning of AWS EKS Kubernetes cluster manually in AWS console**\n    - AWS EKS **control plane** ($0.10/hour per AWS EKS cluster)\n    - AWS EKS **node group**\n    - proceed with a simple **Nginx web server** Kubernetes deployment\n    \u003cbr/\u003e\u003cbr/\u003e\n\n- Section 2. **Write terrafrom code to provision **AWS EKS K8S cluster** automatically** \n    - applying terrafrom code *\"file by file\"*\n    - apply all terrafrom code *\"all at once\"*\n    - demonstrate another simple **Nginx web server** Kubernetes deployment\n    - *Tip*: \n        - `terraform apply -var-file terraform.eks.tfvars`\n        - **work** with AWS EKS cluster ...\n        - `helm delete \u003chc-name\u003e`, `kubectl delete -f \u003cfile-name\u003e.yaml`\n        - `terraform destroy -var-file terraform.eks.tfvars`\n    \u003cbr/\u003e\u003cbr/\u003e\n\n- Section 3. **Leveraging helm charts for AWS EKS Kubernetes deployment**\n    - creating **frontend** / **backend + postgresql** / **nginx ingress controller** architecture \n    - using custom made  **frontend** / **backend + postgresql** applications\n    - creating onw **frontend** and **backend** helm charts\n\n**Important notes**:\n* please **run** `terraform destroy -var-file terraform.eks.tfvars` **whenever** you not using your resources in AWS\n* all **materials** can be found at my **Github** project\n  - `https://github.com/xjantoth/aws-eks-devopsinuse`\n* **feel free** to post any question into **Q\u0026A section**\n* **all** videos are recorded in **Full HD** however Udemy's player use *HD*\n* I'm greatful for your **reviews** - please drop some **COMMENTS** :)\n* please setup **budget** within your **Free AWS account** to be notified if from some reason AWS is going to **charge some fees**.\n\n\u003cbr/\u003e\u003cbr/\u003e\n\n* the best way how to use this cousre: [Materials for each lecture at xjantoth Github repository](https://github.com/xjantoth/aws-eks-devopsinuse)\n* **AWS EKS** (Elastic Kubernetes Service) **costs $0.10/hour/per** K8S cluster !!!\n\n\u003c!-- - [2. EKS cluster costs few cents per hour](#2-eks-cluster-costs-few-cents-per-hour)--\u003e\n### 2. EKS cluster costs few cents per hour\n\n* **Kubernetes** is:\n  - portable, \n  - extensible, \n  - open-source platform \n* for managing containerized workloads and services, that **facilitates** both:\n  -  declarative configuration, \n  -  automation. \n* It has a large, rapidly growing ecosystem. \n\n* **platform** helps you to schedule  docker containers and perform robust deployments\n\n![](img/eks-not-free-4.png)\n\n* **assuming** that **AWS Free Tier** is used for this course \n  - `t2.micro` instance (is complient for **AWS Free Tier** usage)\n  - `t3.micro` instance (is complient for **AWS Free Tier** usage)\n\n![](img/eks-not-free-1.png)\n\n\n* what **has to be paid for** is **AWS EKS control plane** (Kubernetes masters)\n* AWS charges **$0.10 / per hour** per **AWS EKS cluster**\n* if AWS EKS cluster is **used for 10 hours**:  `10h x $0.10 = $1.0` plus TAX\n* **Shut down** your **AWS EKS Kubernetes cluster** whenever not **using it !!!**\n\n\n![](img/eks-not-free-2.png)\n\n\n* ***Amazon Container Services*** section in AWS console\n* region: **Frankfurt (eu-central-1)** has been choosen which indicates **$0.10 / per hour** per **AWS EKS cluster**\n\n![](img/eks-not-free-3.png)\n\n\n\u003c!-- - [3. Allow seeing billing data for IAM user](#3-allow-seeing-billing-data-for-iam-user)--\u003e\n### 3. Allow seeing billing data for IAM user\n\n* Login to your **root** AWS account in **AWS Free Tier**.\u003cbr/\u003e\n* The access to a **billing information** is **disabled** by default for **IAM accounts**\n\n![](img/allow-billing-in-root-account-0.png)\n\n* **Input user/password** from your phone to authenticate and login to the **root** account.\u003cbr/\u003e \n\n![](img/allow-billing-in-root-account-1.png)\n\n* **Input MFA code** from your phone to authenticate and login to the **root** account.\u003cbr/\u003e \n\n![](img/allow-billing-in-root-account-2.png)\n\n* Click at **My Account** item from **drop down menu**\n\n![](img/billing-permissions-0.png)\n\n* Click **Edit** to allow - ***Activate IAM Access*** for other IAM accounts than root account.\n\n![](img/billing-permissions-1.png)\n\n* Hit **Update** button to take ***Activate IAM Access*** for other IAM accounts than root account.\n\n![](img/billing-permissions-2.png)\n\n\u003c!-- - [4. Create budget in AWS to be notified by email](#4-create-budget-in-aws-to-be-notified-by-email)--\u003e\n### 4. Create budget in AWS to be notified by email\n\nFind a **Budget** section in AWS web console and hit **Create a budget** button.\n\n![](img/budget-1.png)\n\nSelect **Cost budget** - this is the most simple and reasonable option for now.\n\n![](img/budget-2.png)\n\n**Assing some Name** to your budget.\n\n![](img/budget-3.png)\n\n\n**Choose** *Budget Amount* e.g. $5 (Whatever amont you like)\n\n![](img/budget-4.png)\n\nFind **Email constacts** section and input some email address you would like to be notified at.\n\n![](img/budget-5.png)\n\nHit **Confirm bufget** button and everything should be set up.\n\n![](img/budget-6.png)\n\nFinally hit **Create** button.\n\n![](img/budget-7.png)\n\n![](img/budget-8.png)\n\n\u003c!-- - [5. Create an extra user and group in AWS with admin privilages](#5-create-an-extra-user-and-group-in-aws-with-admin-privilages)--\u003e\n### 5. Create an extra user and group in AWS with admin privilages\n\n![](img/create-iam-1.png)\n\n![](img/create-iam-2.png)\n\n![](img/create-iam-3.png)\n\n![](img/create-iam-4.png)\n\n![](img/create-iam-5.png)\n\n![](img/create-iam-6.png)\n\n![](img/create-iam-7.png)\n\n![](img/create-iam-8.png)\n\n\n\n\u003c!-- - [6. Install awscli and kubectl binaries](#6-install-awscli-and-kubectl-binaries)--\u003e\n### 6. Install awscli and kubectl binaries\n\n* **Install** awscli binary\nhttps://docs.aws.amazon.com/cli/latest/userguide/install-linux-al2017.html\n\n* Please **configure** these two files:\n  - ~/.aws/credentials\n  - ~/.aws/config\n\n\n![](img/aws-cli-1.png)\n\nLink: https://kubernetes.io/docs/tasks/tools/install-kubectl/\n\n```\ncurl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl\nchmod +x ./kubectl\nsudo mv ./kubectl /usr/local/bin/kubectl\nkubectl version --client\n```\n![](img/kubectl-1.png)\n\n\u003c!-- - [7. Retrive programatic access from AWS and configure aws cli](#7-retrive-programatic-access-from-aws-and-configure-aws-cli)--\u003e\n### 7. Retrive programatic access from AWS and configure aws cli\n\n![](img/aws-cli-2.png)\n\n![](img/aws-cli-3.png)\n\n![](img/aws-cli-4.png)\n\n\n**edit file:** `~/.aws/credentials`\n```bash\nvim  ~/.aws/credentials\n\n...\n[terraform]\naws_access_key_id = ...\naws_secret_access_key = ...\n\n[devopsinuse]\naws_access_key_id = ...\naws_secret_access_key = ...\n...\n\n:wq!\n```\n\n**edit file:** `~/.aws/config`\n\n```bash\nvim ~/.aws/config\n\n...\n[profile terraform]\nregion=eu-central-1\n\n[profile devopsinuse]\nregion=eu-central-1\n...\n\n:wq!\n```\n\n**Make sure** that your `aws` is configured correctly and can talk to AWS\n```bash\naws iam list-users --profile devopsinuse\n{\n    \"Users\": [\n        {\n            \"Path\": \"/\",\n            \"UserName\": \"devopsinuse\",\n            \"UserId\": \"AFSDFSDFSDFSDFSD\",\n            \"Arn\": \"arn:aws:iam::61111111116:user/devopsinuse\",\n            \"CreateDate\": \"...\",\n            \"PasswordLastUsed\": \"...\"\n        },\n        {\n            \"Path\": \"/\",\n            \"UserName\": \"terraform\",\n            \"UserId\": \"ADSGDSDASDASFSDFSDB\",\n            \"Arn\": \"arn:aws:iam::61111111116:user/terraform\",\n            \"CreateDate\": \"...\"\n        }\n    ]\n}\n```\n\u003c!-- - [8. Create EKS control plane IAM role in AWS web console](#8-create-eks-control-plane-iam-role-in-aws-web-console)--\u003e\n### 8. Create EKS control plane IAM role in AWS web console\n\n![](img/eks-iam-cluster-role-1.png)\n\n![](img/eks-iam-cluster-role-2.png)\n\n![](img/eks-iam-cluster-role-3.png)\n\n![](img/eks-iam-cluster-role-4.png)\n\n![](img/eks-iam-cluster-role-5.png)\n\n![](img/eks-iam-cluster-role-6.png)\n\n![](img/eks-iam-cluster-role-7.png)\n\n\n\u003c!-- - [9. Create EKS node group IAM role in AWS web console](#9-create-eks-node-group-iam-role-in-aws-web-console)--\u003e\n### 9. Create EKS node group IAM role in AWS web console\n\nFind **Roles** section under ***Identity and Access Management (IAM)***\n\n![](img/eks-iam-cluster-role-1.png)\n\nClick at ***EC2*** from *Choose a use case* menu when creating AWS IAM role for ***EKS node group***\n\n![](img/eks-iam-node-group-1.png)\n\n\n**Search manually** for these **3 policies** for **EKS node group** and \nmark then once found in **checkbox**\n* *AmazonEC2ContainerRegistryReadOnly*\n\n![](img/eks-iam-node-group-2.png)\n\n**Search manually** for these **3 policies** for **EKS node group** and \nmark then once found in **checkbox**\n* *AmazonEKSWorkerNodePolicy*\n\n![](img/eks-iam-node-group-3.png)\n\n**Search manually** for these **3 policies** for **EKS node group** and \nmark then once found in **checkbox**\n* *AmazonEKS_CNI_Policy*\n\nThis time you can ***click: Next: Tags*** blue button if all **three** *IAM Policies* are **check-boxed**\n\n![](img/eks-iam-node-group-4.png)\n\n**Tags are optional** however, they help to identify leftovers once you want to clean your AWS account\n\n![](img/eks-iam-node-group-5.png)\n\n\n**Review** your AWS IAM role and assign some **Role name** to it ***e.g. DIU-EKSNodeGroupRole***\n\n![](img/eks-iam-node-group-6.png)\n\nRole ***DIU-EKSNodeGroupRole*** is finally created\n\n![](img/eks-iam-node-group-7.png)\n\n\n\u003c!-- - [10. Create SSH key pair in AWS console](#10-create-ssh-key-pain-in-aws-console)--\u003e\n### 10. Create SSH key pair in AWS console\n\n![](img/ssh-keys-1.png)\n\n![](img/ssh-keys-2.png)\n\n![](img/ssh-keys-3.png)\n\n\n![](img/sg-3.png)\n\n\n\u003c!-- - [11. Create EKS cluster in AWS web console](#11-create-eks-cluster-in-aws-web-console)--\u003e\n### 11. Create EKS cluster in AWS web console\n\n![](img/eks-control-plane-1.png)\n\n![](img/eks-control-plane-2.png)\n\n![](img/eks-control-plane-3.png)\n\n![](img/eks-control-plane-4.png)\n\n![](img/eks-control-plane-5.png)\n\n![](img/eks-control-plane-6.png)\n\n\n\u003c!-- - [12. Create EKS node group in AWS web console](#12-create-eks-node-group-in-aws-web-console)--\u003e\n### 12. Create EKS node group in AWS web console\n\n![](img/node-group-1.png)\n\n![](img/node-group-2.png)\n\n![](img/node-group-3.png)\n\n![](img/node-group-4.png)\n\n![](img/node-group-5.png)\n\n![](img/node-group-6.png)\n\n![](img/node-group-7.png)\n\n![](img/node-group-8.png)\n\n![](img/node-group-9.png)\n\n![](img/node-group-10.png)\n\n![](img/node-group-11.png)\n\n![](img/node-group-12.png)\n\n\n\u003c!-- - [13. Create KUBECONFIG at your local](#13-create-kubeconfig-at-your-local)--\u003e\n### 13. Create KUBECONFIG at your local\n\n**Run this** command get the content of your `~/.kube/config` file at your local\n\n```bash\naws eks --region eu-central-1 update-kubeconfig --name diu-eks-cluster --profile devopsinuse\n\nAdded new context arn:aws:eks:eu-central-1:611111111116:cluster/diu-eks-cluster to /home/username/.kube/config\n```\n\n**If you now go and take** a look what is inside the file: `~/.kube/config`, you will find a correct connection settings to be able to **communicate** with your **AWS EKS Kubernetes cluster** under your **AWS Free Tier account**\n\n\nRun following commands to make sure that you can communicte with your **AWS EKS Kubernetes cluster** under your **AWS Free Tier account**\n\n```bash\nkubectl get nodes\nNAME                                            STATUS   ROLES    AGE     VERSION\nip-172-31-20-97.eu-central-1.compute.internal   Ready    \u003cnone\u003e   9m2s    v1.15.10-eks-bac369\nip-172-31-3-232.eu-central-1.compute.internal   Ready    \u003cnone\u003e   8m55s   v1.15.10-eks-bac369\n\nkubectl get pods -A\nNAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE\nkube-system   aws-node-ldt44             1/1     Running   0          9m14s\nkube-system   aws-node-s6nb9             1/1     Running   0          9m7s\nkube-system   coredns-5b6dbb4b59-4rjkm   1/1     Running   0          23m\nkube-system   coredns-5b6dbb4b59-bnxs4   1/1     Running   0          23m\nkube-system   kube-proxy-ncm6q           1/1     Running   0          9m14s\nkube-system   kube-proxy-zffwq           1/1     Running   0          9m7s\n```\n\n\u003c!-- - [14. Create configmap for NGINX deployment to AWS EKS cluster](#14-create-configmap-for-nginx-deployment-to-aws-eks-cluster)--\u003e\n### 14. Create configmap for NGINX deployment to AWS EKS cluster\n\n```bash\ntree deployment-eks-nginx-manual\ndeployment-eks-nginx-manual\n├── deployment-eks-nginx-manual.yaml\n├── index-eks-nginx-manual_files\n│   ├── bootstrap.min.css\n│   ├── bootstrap.min.js\n│   ├── Chart.min.js\n│   ├── dashboard.css\n│   ├── feather.min.js\n│   ├── jquery-3.2.1.slim.min.js\n│   └── popper.min.js\n└── index-eks-nginx-manual.html\n\n```\n\n\nCreate configmap kubernetes object **nginx-cm**\n```bash\ncd deployment-eks-nginx-manual/\n\nkubectl create configmap nginx-cm \\\n--from-file=\"index-eks-nginx-manual.html\" \\\n--from-file=\"index-eks-nginx-manual_files/bootstrap.min.css\" \\\n--from-file=\"index-eks-nginx-manual_files/bootstrap.min.js\" \\\n--from-file=\"index-eks-nginx-manual_files/Chart.min.js\" \\\n--from-file=\"index-eks-nginx-manual_files/dashboard.css\" \\\n--from-file=\"index-eks-nginx-manual_files/feather.min.js\" \\\n--from-file=\"index-eks-nginx-manual_files/jquery-3.2.1.slim.min.js\" \\\n--from-file=\"index-eks-nginx-manual_files/popper.min.js\"\n```\n\n**Explore** file: `deployment-eks-nginx-manual.yaml` for creating **deployment** and **service** Kubernetes objects\n\n![](img/nginx-1.png)\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n        volumeMounts:\n        - mountPath: /usr/share/nginx/html/index.html\n          readOnly: true\n          name: nginx-cm\n          subPath: index.html\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/bootstrap.min.css\n          readOnly: true\n          name: nginx-cm\n          subPath: bootstrap.min.css\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/bootstrap.min.js\n          readOnly: true\n          name: nginx-cm\n          subPath: bootstrap.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/Chart.min.js\n          readOnly: true\n          name: nginx-cm\n          subPath: Chart.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/dashboard.css\n          readOnly: true\n          name: nginx-cm\n          subPath: dashboard.css\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/feather.min.js\n          readOnly: true\n          name: nginx-cm\n          subPath: feather.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/jquery-3.2.1.slim.min.js\n          readOnly: true\n          name: nginx-cm\n          subPath: jquery-3.2.1.slim.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/popper.min.js\n          readOnly: true\n          name: nginx-cm\n          subPath: popper.min.js\n      \n      volumes:\n      # Do not forget to run this command up front\n      # kubectl create configmap nginx-cm --from-file=index-eks-nginx-manual.html\n      - name: nginx-cm\n        configMap:\n          name: nginx-cm \n          items:\n            - key: index-eks-nginx-manual.html\n              path: index.html\n            - key: bootstrap.min.css\n              path: bootstrap.min.css\n            - key: bootstrap.min.js\n              path: bootstrap.min.js\n            - key: Chart.min.js\n              path: Chart.min.js\n            - key: dashboard.css\n              path: dashboard.css\n            - key: feather.min.js\n              path: feather.min.js\n            - key: jquery-3.2.1.slim.min.js\n              path: jquery-3.2.1.slim.min.js\n            - key: popper.min.js\n              path: popper.min.js\n\n              \n\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx\nspec:\n  type: NodePort\n  ports:\n  - port: 80\n    targetPort: 80\n    nodePort: 30111\n  selector:\n    app: nginx\n\n```\n![](img/nginx-1.png)\n\n\u003c!-- - [15. Execute Nginx deployment against AWS EKS Kubernetes cluster](#15-execute-nginx-deployment-against-aws-eks-kubernetes-cluster)--\u003e\n### 15. Execute Nginx deployment against AWS EKS Kubernetes cluster\n**Execute deployment** of your **Nginx** web server with **custom content**\n```bash\nkubectl apply -f deployment-eks-nginx-manual.yaml\n```\n\n**Retrive** IP Addresses of your **physical nodes** in AWS\n\n```bash\n kubectl get nodes -o wide | awk -F\" \" '{print $1\"\\t\"$7}'\nNAME    EXTERNAL-IP\nip-172-31-20-97.eu-central-1.compute.internal   35.157.105.203\nip-172-31-3-232.eu-central-1.compute.internal   3.121.160.180\n```\n**Allow** port `30111` in ***Security Group*** section in AWS console\n\n![](img/sg-2.png)\n\n![](img/eks-manual-nginx-nodes-1.png)\n\n![](img/eks-manual-nginx-nodes-2.png)\n\n\n\n**SSH tunnel approach** without the need to seup Security group in AWS\n\n```bash\nssh -o \"IdentitiesOnly yes\" \\\n-i  ~/.ssh/devopsinuse.pem \\\nec2-user@35.157.105.203 \\\n-L30111:127.0.0.1:30111\n```\n![](img/ssh-keys-4.png)\n\n\n\u003c!-- - [16. Explore Nginx pod by attaching to a running container](#16-explore-nginx-pod-by-attaching-to-a-running-container)--\u003e\n### 16. Explore Nginx pod by attaching to a running container\n\nExplore Nginx pod by attaching to **a running container**\n\n\n**Get the list** of all available pods within **default** namespace\n```bash\nkubectl get pods                                    \nNAME                     READY   STATUS    RESTARTS   AGE\nnginx-6d786774cd-fmtgh   1/1     Running   0          31m\n\nkubectl exec -it  nginx-6d786774cd-fmtgh -- bash\nroot@nginx-6d786774cd-fmtgh:/# \n\n\nroot@nginx-6d786774cd-fmtgh:/# ls usr/share/nginx/html/index* -l\n-rw-r--r-- 1 root root 10:17 usr/share/nginx/html/index.html\n\nusr/share/nginx/html/index-eks-nginx-manual_files:\ntotal 516\n-rw-r--r-- 1 root root  10:17 Chart.min.js\n-rw-r--r-- 1 root root  10:17 bootstrap.min.css\n-rw-r--r-- 1 root root  10:17 bootstrap.min.js\n-rw-r--r-- 1 root root  10:17 dashboard.css\n-rw-r--r-- 1 root root  10:17 feather.min.js\n-rw-r--r-- 1 root root  10:17 jquery-3.2.1.slim.min.js\n-rw-r--r-- 1 root root  10:17 popper.min.js\n```\n\n**Ask Kubernetes** to provide a list of available **deployments**\n\n```bash\n# get all deployments in default namespace\nkubectl get deployment nginx -o yaml         \n\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  annotations:\n    deployment.kubernetes.io/revision: \"1\"\n    kubectl.kubernetes.io/last-applied-configuration: | \n      {...}\n  creationTimestamp: \"...\"\n  generation: 1\n  labels:\n    app: nginx\n  name: nginx\n  namespace: default\n  resourceVersion: \"15772\"\n  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx\n  uid: 83a88f7c-19f9-40b6-a3e6-76b6afc3f445\nspec:\n  progressDeadlineSeconds: 600\n  replicas: 1\n  revisionHistoryLimit: 2\n  selector:\n    matchLabels:\n      app: nginx\n  strategy:\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n    type: RollingUpdate\n  template:\n    metadata:\n      creationTimestamp: null\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - image: nginx\n        imagePullPolicy: Always\n        name: nginx\n        ports:\n        - containerPort: 80\n          protocol: TCP\n        resources: {}\n        terminationMessagePath: /dev/termination-log\n        terminationMessagePolicy: File\n        volumeMounts:\n        - mountPath: /usr/share/nginx/html/index.html\n          name: nginx-cm\n          readOnly: true\n          subPath: index.html\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/bootstrap.min.css\n          name: nginx-cm\n          readOnly: true\n          subPath: bootstrap.min.css\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/bootstrap.min.js\n          name: nginx-cm\n          readOnly: true\n          subPath: bootstrap.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/Chart.min.js\n          name: nginx-cm\n          readOnly: true\n          subPath: Chart.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/dashboard.css\n          name: nginx-cm\n          readOnly: true\n          subPath: dashboard.css\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/feather.min.js\n          name: nginx-cm\n          readOnly: true\n          subPath: feather.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/jquery-3.2.1.slim.min.js\n          name: nginx-cm\n          readOnly: true\n          subPath: jquery-3.2.1.slim.min.js\n        - mountPath: /usr/share/nginx/html/index-eks-nginx-manual_files/popper.min.js\n          name: nginx-cm\n          readOnly: true\n          subPath: popper.min.js\n      dnsPolicy: ClusterFirst\n      restartPolicy: Always\n      schedulerName: default-scheduler\n      securityContext: {}\n      terminationGracePeriodSeconds: 30\n      volumes:\n      - configMap:\n          defaultMode: 420\n          items:\n          - key: index-eks-nginx-manual.html\n            path: index.html\n          - key: bootstrap.min.css\n            path: bootstrap.min.css\n          - key: bootstrap.min.js\n            path: bootstrap.min.js\n          - key: Chart.min.js\n            path: Chart.min.js\n          - key: dashboard.css\n            path: dashboard.css\n          - key: feather.min.js\n            path: feather.min.js\n          - key: jquery-3.2.1.slim.min.js\n            path: jquery-3.2.1.slim.min.js\n          - key: popper.min.js\n            path: popper.min.js\n          name: nginx-cm\n        name: nginx-cm\nstatus:\n  availableReplicas: 1\n  conditions:\n   ...\n    type: Progressing\n  observedGeneration: 1\n  readyReplicas: 1\n  replicas: 1\n  updatedReplicas: 1\n\n```\n\n**Ask Kubernetes** for all available services within **default** namespace\n\n```bash\nkubectl get service  nginx -o yaml\napiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    kubectl.kubernetes.io/last-applied-configuration: |\n      {}\n  creationTimestamp: \"...\"\n  name: nginx\n  namespace: default\n  resourceVersion: \"15759\"\n  selfLink: /api/v1/namespaces/default/services/nginx\n  uid: 67ad2770-154a-4dc4-aa32-a4c2d53af8d2\nspec:\n  clusterIP: 10.100.210.78\n  externalTrafficPolicy: Cluster\n  ports:\n  - nodePort: 30111\n    port: 80\n    protocol: TCP\n    targetPort: 80\n  selector:\n    app: nginx\n  sessionAffinity: None\n  type: NodePort\nstatus:\n  loadBalancer: {}\n```\n\n\u003c!-- - [17. SSH to physical EC2 instances within your Kubernetes cluster in AWS](#17-ssh-to-physical-ec2-instances-within-your-kubernetes-cluster-in-aws)--\u003e\n### 17. SSH to physical EC2 instances within your Kubernetes cluster in AWS\n\nIn order to **SSH you your Kubenretes cluster EC2 instances**, it is important to **allow** (enable) port `22` in **Security Group** in AWS web console\n\n\n**Retrive IP Addresses** of your physical nodes (EC2 instances) in AWS\n\n```bash\nkubectl get nodes -o wide | awk -F\" \" '{print $1\"\\t\"$7}'\nNAME    EXTERNAL-IP\nip-172-31-20-97.eu-central-1.compute.internal   35.157.105.203\nip-172-31-3-232.eu-central-1.compute.internal   3.121.160.180\n```\n\n**SSH** to a node (EC2 instance) with the **first IP Address**\n\n```bash\nssh -o \"IdentitiesOnly yes\" \\\n-i  ~/.ssh/devopsinuse.pem \\\nec2-user@35.157.105.203 \n```\n\n**SSH** to a node (EC2 instance) with **the second IP Address**\n\n```bash\nssh -o \"IdentitiesOnly yes\" \\\n-i  ~/.ssh/devopsinuse.pem \\\nec2-user@3.121.160.180\n```\n\n\n\u003c!-- - [18. Clean up](#18-clean-up)--\u003e\n### 18. Clean up\n\nClean up **Network Interfaces**\n\n![](img/delete-eks-1.png)\n\n![](img/delete-eks-2.png)\n\nClean up **AWS EKS node group**\n\n![](img/delete-eks-3.png)\n\n![](img/delete-eks-4.png)\n\n![](img/delete-eks-5.png)\n\n![](img/delete-eks-6.png)\n\n\nClean up **AWS EKS control plane**\n\n![](img/delete-eks-7.png)\n\n![](img/delete-eks-8.png)\n\n![](img/delete-eks-9.png)\n\n![](img/delete-eks-10.png)\n\nDelete **AWS IAM roles**\n\n![](img/delete-eks-11.png)\n\n\n# 2. Using terrafrom to manage AWS EKS cluster\n\n\u003c!-- - [19. Install terrafrom binary at your local](#19-install-terrafrom-binary-at-your-local)--\u003e\n\n### 19. Install terrafrom binary at your local\n\nLink: https://www.terraform.io/downloads.html\n\n![](img/terraform-3.png)\n\n**Download** `*.zip` file from the lin below. **Unzip** files to a proper location at your local e.g. `/usr/bin`.\n\n```bash\ncurl -L --output /tmp/terraform.zip  \\\nhttps://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip\n\nsudo unzip -d /usr/bin/ /tmp/terraform.zip \n\nterraform -version\nTerraform v0.12.24\n```\n\n\u003c!-- - [20. Run terrafrom init and validate to initialize required plugins](#20-run-terrafrom-init-and-validate-to-initialize-required-plugins)--\u003e\n### 20. Run terrafrom init and validate to initialize required plugins\n\nNavigate to `eks-terraform` folder and list it to see the **terrafrom files**\n\n```bash\ncd eks-terraform\ntree\n.\n├── iam.tf\n├── main.tf\n├── outputs.tf\n├── sg.tf\n├── subnets.tf\n├── terraform.eks.tfvars\n├── terraform.eks.tfvars.git\n├── terraform.tfstate\n└── variables.tf\n```\n* Most of the files have completly **commented lines** for now.\n* When **touching this code** for the first time, there should be no hidden `.terrafrom` folder present. \n* `.terraform` folder stores all neceassary **terrafrom plugins** used within this code\n* **plugins** will be downloaded to `terraform` folder  after `terraform init` command run\n\n```bash\n …  sbx  aws-eks-devopsinuse  eks-terraform   master ✚ 1 … 1  terraform init \n\nInitializing the backend...\n\nInitializing provider plugins...\n- Checking for available provider plugins...\n- Downloading plugin for provider \"aws\" (hashicorp/aws) 2.60.0...\n\nThe following providers do not have any version constraints in configuration,\nso the latest version was installed.\n\nTo prevent automatic upgrades to new major versions that may contain breaking\nchanges, it is recommended to add version = \"...\" constraints to the\ncorresponding provider blocks in configuration, with the constraint strings\nsuggested below.\n\n* provider.aws: version = \"~\u003e 2.60\"\n\nTerraform has been successfully initialized!\n\nYou may now begin working with Terraform. Try running \"terraform plan\" to see\nany changes that are required for your infrastructure. All Terraform commands\nshould now work.\n\nIf you ever set or change modules or backend configuration for Terraform,\nrerun this command to reinitialize your working directory. If you forget, other\ncommands will detect it and remind you to do so if necessary.\n```\n\n**Take a look** what is now stored in `.terraform` folder\n\n```bash\n …  sbx  aws-eks-devopsinuse  eks-terraform   master ✚ 1 … 3  tree .terraform \n.terraform\n└── plugins\n    └── linux_amd64\n        ├── lock.json\n        └── terraform-provider-aws_v2.60.0_x4\n\n2 directories, 2 files\n```\n\n\n\u003c!-- - [21. Fill up terraform.eks.tfvars file with your AWS security credentials](#21-fill-up-terraformekstfvars-file-with-your-aws-security-credentials)--\u003e\n### 21. Fill up terraform.eks.tfvars file with your AWS security credentials\n\n* to start using **terrafrom** it only takes few commands to learn in the begining\n* most comonly used commands will be:\n  - `terraform init`\n  - `terraform plan`\n  - `terraform apply`\n  - `terraform destroy`\n  - `terraform show`\n  - `terraform console`\n  - `terraform validate`\n  - `terraform fmt -recursive`\n\u003cbr/\u003e\n\u003cbr/\u003e\n* Before running `terraform plan` and `terraform apply` to see what the code is about to create - it is **neceassary** to setup credentials to make **terrafrom** binary talk to AWS.\n\n* there are **several main ways** how to setup this communication: \n  - **(1)** export **env. variables** to console you are using:\n\n    `export AWS_ACCESS_KEY_ID=\"...\"` \u003cbr/\u003e\n    `export AWS_SECRET_ACCESS_KEY=\"...\"` \u003cbr/\u003e\n    `export AWS_DEFAULT_REGION=\"eu-central-1\"`\n\n  - **(2)** configure **two files** (since we configured **aws cli** `--profile`):\n\n    `~/.aws/credentials`\u003cbr/\u003e\n    `~/.aws/config`\u003cbr/\u003e \n    `export AWS_PROFILE=\"devopsinuse\"`\n  - **(3)** use `-var-file` **flag** when running `terrafrom \u003ccommand\u003e -var-file terraform.eks.tfvars`\u003cbr/\u003e\n    `terraform destroy  -var-file terraform.eks.tfvars`\n\n**Please** fill up file: `terraform.eks.tfvars`\n\n![](img/aws-cli-3.png)\n\n![](img/aws-cli-4.png)\n\n\n```bash\ncat terraform.eks.tfvars\n\naws_region     = \"eu-central-1\"\naws_access_key = \"...\"\naws_secret_key = \"...\"\nssh_public_key = \"/home/user/.ssh/eks-aws.pub\"\ncustom_tags = {\n  Name      = \"diu-eks-cluster-tag\"\n  Terraform = \"true\"\n  Delete    = \"true\"\n}\n\neks-cluster-name = \"diu-eks-cluster\"\nkubernetes-version = \"1.16\"\n\ndesired_number_nodes = 2\nmax_number_nodes = 3\nmin_number_nodes = 1\n\ntcp_ports = [\"22\", \"30111\", \"30222\", \"30333\"]\n```\n\n\n**Generate SSH key** pair:\n```bash\nSSH_KEYS=~/.ssh/eks-aws\n\nif [ ! -f \"$SSH_KEYS\" ]\nthen\n   echo -e \"\\nCreating SSH keys ...\"\n   ssh-keygen -t rsa -C \"eks-aws\" -N '' -f $SSH_KEYS\nelse\n   echo -e \"\\nSSH keys are already in place\\!\"\nfi\n```\n\n\u003c!-- - [22. Run terrafrom plan and terrafrom apply](#22-run-terrafrom-plan-and-terrafrom-apply)--\u003e\n### 22. Run terrafrom plan and terrafrom apply\n\n**Run** `terraform validate` and `terraform fmt -recursive` first to validate the code and do a proper formatting of the terrafrom code\n\n```bash\nterraform validate\nSuccess! The configuration is valid.\n\nterraform fmt -recursive\n```\n\n* it's mostly refered that **terraform** has 3 main files with a correspondng naming convention:\n  - `main.tf`\n  - `variables.tf`\n  - `outputs.tf`\n  - `----------------`\n  - `terraform.eks.tfvars` (extra var file)\n\n![](img/terraform-2.png)\n\n`terraform plan` will throw an **error**:\n```bash\nterrafrom plan\n\nvar.aws_access_key\n  AWS region\n  Enter a value: \n```\n\n\nrun: `terraform plan -var-file terraform.eks.tfvars` with **an extra flag**: `-var-file`\n\n```bash\nterraform plan -var-file terraform.eks.tfvars\nRefreshing Terraform state in-memory prior to plan...\nThe refreshed state will be used to calculate this plan, but will not be\npersisted to local or remote state storage.\n\ndata.aws_vpc.default: Refreshing state...\ndata.aws_availability_zones.default: Refreshing state...\ndata.aws_subnet_ids.default: Refreshing state...\n\n------------------------------------------------------------------------\n\nNo changes. Infrastructure is up-to-date.\n\nThis means that Terraform did not detect any differences between your\nconfiguration and real physical resources that exist. As a result, no\nactions need to be performed.\n```\n\nThe **reason** why terrafrom is not going to do anything special in paricular is that **most of the files are commented**. There are just few lines without comments in `main.tf`file. \n\nHowever, the files `variables.tf` and `outputs.tf` keep **few active (uncommented) lines** and once `terraform apply -var-file terraform.eks.tfvars` is executed, there will be some output.\n\n\n**Run** `terraform apply -var-file terraform.eks.tfvars` command:\n\n```bash\nterraform apply -var-file terraform.eks.tfvars\n\ndata.aws_availability_zones.default: Refreshing state...\ndata.aws_vpc.default: Refreshing state...\ndata.aws_subnet_ids.default: Refreshing state...\n\nApply complete! Resources: 0 added, 0 changed, 0 destroyed.\n\nOutputs:\n\naws_availability_zones = {\n  \"group_names\" = [\n    \"eu-central-1\",\n  ]\n  \"id\" = \"...\"\n  \"names\" = [\n    \"eu-central-1a\",\n    \"eu-central-1b\",\n    \"eu-central-1c\",\n  ]\n  \"state\" = \"available\"\n  \"zone_ids\" = [\n    \"euc1-az2\",\n    \"euc1-az3\",\n    \"euc1-az1\",\n  ]\n}\nvpc_id = vpc-111117e\n```\n\n\u003c!-- - [23. Uncomment iam.tf and run terrafrom apply to create mandatory AWS IAM roles](#23-uncomment-iamtf-and-run-terrafrom-apply-to-create-mandatory-aws-iam-roles)--\u003e\n### 23. Uncomment iam.tf and run terrafrom apply to create mandatory AWS IAM roles\n\nRemove comments from `iam.tf` file:\n\nIAM AWS role for **EKS control plane**\n\n```bash\n# IAM AWS role for EKS control plane\nresource \"aws_iam_role\" \"diu-eks-cluster\" {\n  name = \"diu-EksClusterIAMRole-tf\"\n\n  assume_role_policy = \u003c\u003cPOLICY\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Service\": \"eks.amazonaws.com\"\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}\nPOLICY\n}\n\nresource \"aws_iam_role_policy_attachment\" \"diu-eks-cluster-AmazonEKSClusterPolicy\" {\n  policy_arn = \"arn:aws:iam::aws:policy/AmazonEKSClusterPolicy\"\n  role       = aws_iam_role.diu-eks-cluster.name\n}\n\nresource \"aws_iam_role_policy_attachment\" \"diu-eks-cluster-AmazonEKSServicePolicy\" {\n  policy_arn = \"arn:aws:iam::aws:policy/AmazonEKSServicePolicy\"\n  role       = aws_iam_role.diu-eks-cluster.name\n}\n```\n\nIAM AWS role for AWS **EKS Node Group**\n\n```bash\n# IAM AWS role for Node Group\nresource \"aws_iam_role\" \"diu-eks-cluster-node-group\" {\n  name = \"diu-EksClusterNodeGroup-tf\"\n\n  assume_role_policy = jsonencode({\n    Statement = [{\n      Action = \"sts:AssumeRole\"\n      Effect = \"Allow\"\n      Principal = {\n        Service = \"ec2.amazonaws.com\"\n      }\n    }]\n    Version = \"2012-10-17\"\n  })\n}\n\nresource \"aws_iam_role_policy_attachment\" \"diu-eks-cluster-node-group-AmazonEKSWorkerNodePolicy\" {\n  policy_arn = \"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy\"\n  role       = aws_iam_role.diu-eks-cluster-node-group.name\n}\n\nresource \"aws_iam_role_policy_attachment\" \"diu-eks-cluster-node-group-AmazonEKS_CNI_Policy\" {\n  policy_arn = \"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy\"\n  role       = aws_iam_role.diu-eks-cluster-node-group.name\n}\n\nresource \"aws_iam_role_policy_attachment\" \"diu-eks-cluster-node-group-AmazonEC2ContainerRegistryReadOnly\" {\n  policy_arn = \"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly\"\n  role       = aws_iam_role.diu-eks-cluster-node-group.name\n}\n```\n\nPlease run `terraform apply -var-file terraform.eks.tfvars`\n\n```bash\nterraform apply -var-file terraform.eks.tfvars\n\n\ndata.aws_availability_zones.default: Refreshing state...\ndata.aws_vpc.default: Refreshing state...\ndata.aws_subnet_ids.default: Refreshing state...\n\nAn execution plan has been generated and is shown below.\nResource actions are indicated with the following symbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_iam_role.diu-eks-cluster will be created\n  + resource \"aws_iam_role\" \"diu-eks-cluster\" {\n      + arn                   = (known after apply)\n      + assume_role_policy    = jsonencode(\n            {\n              + Statement = [\n                  + {\n\n  ...\n  ... \n  ...\n\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n\n```\n![](img/iam-tf-1.png)\n\n\n\u003c!-- - [24. Run terraform apply uncomment sg.tf to create extra Security Group](#24-run-terraform-apply-uncomment-sgtf-to-create-extra-security-group)--\u003e\n### 24. Run terraform apply uncomment sg.tf to create extra Security Group \n\nhttps://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html\n\n```bash\nkubernetes.io/cluster/\u003ccluster-name\u003e owned\n```\n\nPlease uncomment all lines from `sg.tf` file and run `terraform apply -var-file terraform.eks.tfvars` command:\n\n```bash\n\n\nterraform apply -var-file terraform.eks.tfvars\naws_iam_role.diu-eks-cluster-node-group: Refreshing state... [id=diu-EksClusterNodeGroup-tf]\n  + create\n  ...\n  ... \n  ... \n\nTerraform will perform the following actions:\n\n  # aws_security_group.eks_cluster_node_group will be created\n  + resource \"aws_security_group\" \"eks_cluster_node_group\" {\n      + arn                    = (known after apply)\n      + description            = \"Allow TLS inbound traffic\"\n      + egress                 = [\n              + self             = false\n              + to_port          = 0\n              ...\n              ...\n              ... \n            },\n        ]\n      + id                     = (known after apply)\n      + ingress                = [\n          + {\n              + cidr_blocks      = [\n                  + \"0.0.0.0/0\",\n                ]\n              + description      = \"Allow incoming SSH traffic\"\n              ...\n              ... \n              ...\n              + to_port          = 22\n            },\n        ]\n      + name                   = \"EKSClusterNodeGroupSecurityGroup\"\n      + owner_id               = (known after apply)\n      + revoke_rules_on_delete = false\n      + tags                   = {\n          + \"Delete\"    = \"true\"\n          + \"Name\"      = \"diu-eks-cluster-tag\"\n          + \"Terraform\" = \"true\"\n        }\n      + vpc_id                 = \"vpc-149f497e\"\n    }\n\nPlan: 1 to add, 0 to change, 0 to destroy.\n\nDo you want to perform these actions?\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n\n```\n\n![](img/sg-tf-1.png)\n\n```bash\naws ec2 describe-security-groups --group-names EKSClusterNodeGroupSecurityGroup --profile devopsinuse\n{\n    \"SecurityGroups\": [\n        {\n            \"Description\": \"Allow TLS inbound traffic\",\n            \"GroupName\": \"EKSClusterNodeGroupSecurityGroup\",\n            \"IpPermissions\": [\n                {\n                    \"FromPort\": 22,\n                    \"IpProtocol\": \"tcp\",\n                    \"IpRanges\": [\n                        {\n                            \"CidrIp\": \"0.0.0.0/0\",\n                            \"Description\": \"Allow incoming SSH traffic\"\n                        }\n                    ],\n                    \"Ipv6Ranges\": [],\n                    \"PrefixListIds\": [],\n                    \"ToPort\": 22,\n                    \"UserIdGroupPairs\": []\n                }\n            ],\n            \"OwnerId\": \"...\",\n            \"GroupId\": \"sg-0bb7b99d2f18d67b2\",\n            \"IpPermissionsEgress\": [\n                {\n                    \"IpProtocol\": \"-1\",\n                    \"IpRanges\": [\n                        {\n                            \"CidrIp\": \"0.0.0.0/0\",\n                            \"Description\": \"Allow all outbound traffic\"\n                        }\n                    ],\n                    \"Ipv6Ranges\": [],\n                    \"PrefixListIds\": [],\n                    \"UserIdGroupPairs\": []\n                }\n            ],\n            \"Tags\": [\n                {\n                    \"Key\": \"Name\",\n                    \"Value\": \"diu-eks-cluster-tag\"\n                },\n                {\n                    \"Key\": \"Delete\",\n                    \"Value\": \"true\"\n                },\n                {\n                    \"Key\": \"Terraform\",\n                    \"Value\": \"true\"\n                }\n            ],\n        }\n    ]\n}\n\n```\n\n\u003c!-- - [25. Uncomment file subnets.tf and run terraform apply to create Subnets in AWS](#25-uncomment-file-subnetstf-and-run-terraform-apply-to-create-subnets-in-aws)--\u003e\n### 25. Uncomment file subnets.tf and run terraform apply to create Subnets in AWS \nUncomment `subnets.tf` file:\n\n```bash\ncat  subnets.tf\nresource \"aws_subnet\" \"this\" {\n  count = 3\n\n  availability_zone       = data.aws_availability_zones.default.names[count.index]\n  cidr_block              = cidrsubnet(data.aws_vpc.default.cidr_block, 8, 100 + count.index)\n  vpc_id                  = data.aws_vpc.default.id\n  map_public_ip_on_launch = true\n\n  tags = merge({\n    \"kubernetes.io/cluster/${var.eks-cluster-name}\" = \"shared\"\n    },\n    var.custom_tags\n  )\n}\n```\n\nRun `terraform apply -var-file terraform.eks.tfvars` to create **subnets** within a default VPC in AWS Free tier account\n\n```bash\nterraform apply -var-file terraform.eks.tfvars\n\naws_iam_role.diu-eks-cluster-node-group: Refreshing state... [id=diu-EksClusterNodeGroup-tf]\n...\n...\nAn execution plan has been generated and is shown below.\nResource actions are indicated with the following symbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_subnet.this[0] will be created\n  + resource \"aws_subnet\" \"this\" {\n      + arn                             = (known after apply)\n      + assign_ipv6_address_on_creation = false\n      + availability_zone               = \"eu-central-1a\"\n      + availability_zone_id            = (known after apply)\n      + cidr_block                      = \"172.31.100.0/24\"\n      + id                              = (known after apply)\n      + ipv6_cidr_block                 = (known after apply)\n      + ipv6_cidr_block_association_id  = (known after apply)\n      + map_public_ip_on_launch         = true\n      + owner_id                        = (known after apply)\n      + tags                            = {\n          + \"Delete\"                                = \"true\"\n          + \"Name\"                                  = \"diu-eks-cluster-tag\"\n          + \"Terraform\"                             = \"true\"\n          + \"kubernetes.io/cluster/diu-eks-cluster\" = \"shared\"\n        }\n      + vpc_id                          = \"vpc-149f497e\"\n    }\n\n  # aws_subnet.this[1] will be created\n  + resource \"aws_subnet\" \"this\" {\n      + arn                             = (known after apply)\n      + assign_ipv6_address_on_creation = false\n      + availability_zone               = \"eu-central-1b\"\n      + availability_zone_id            = (known after apply)\n      + cidr_block                      = \"172.31.101.0/24\"\n      + id                              = (known after apply)\n      + ipv6_cidr_block                 = (known after apply)\n      + ipv6_cidr_block_association_id  = (known after apply)\n      + map_public_ip_on_launch         = true\n      + owner_id                        = (known after apply)\n      + tags                            = {\n          + \"Delete\"                                = \"true\"\n          + \"Name\"                                  = \"diu-eks-cluster-tag\"\n          + \"Terraform\"                             = \"true\"\n          + \"kubernetes.io/cluster/diu-eks-cluster\" = \"shared\"\n        }\n      + vpc_id                          = \"vpc-149f497e\"\n    }\n\n  # aws_subnet.this[2] will be created\n  + resource \"aws_subnet\" \"this\" {\n      + arn                             = (known after apply)\n      + assign_ipv6_address_on_creation = false\n      + availability_zone               = \"eu-central-1c\"\n      + availability_zone_id            = (known after apply)\n      + cidr_block                      = \"172.31.102.0/24\"\n      + id                              = (known after apply)\n      + ipv6_cidr_block                 = (known after apply)\n      + ipv6_cidr_block_association_id  = (known after apply)\n      + map_public_ip_on_launch         = true\n      + owner_id                        = (known after apply)\n      + tags                            = {\n          + \"Delete\"                                = \"true\"\n          + \"Name\"                                  = \"diu-eks-cluster-tag\"\n          + \"Terraform\"                             = \"true\"\n          + \"kubernetes.io/cluster/diu-eks-cluster\" = \"shared\"\n        }\n      + vpc_id                          = \"vpc-149f497e\"\n    }\n\nPlan: 3 to add, 0 to change, 0 to destroy.\n\nDo you want to perform these actions?\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n\n```\n\n![](img/subnets-tf-1.png)\n\n\n\u003c!-- - [26. Uncomment aws eks cluster section in main.tf to create AWS EKS cluster control plane](#26-uncomment-aws-eks-cluster-section-in-maintf-to-create-aws-eks-cluster-control-plane)--\u003e\n### 26. Uncomment aws eks cluster section in main.tf to create AWS EKS cluster control plane\n\nThis time it will be important to navigate to `main.tf` file and uncomment the section for the **resource: aws_eks_cluster** to provision AWS EKS cluster (Kubernetes control plane)\n\n```bash\nvim main.tf\n\n...\n# Uncomment to create AWS EKS cluster (Kubernetes control plane) - start\nresource \"aws_eks_cluster\" \"this\" {\n  name     = var.eks-cluster-name\n  role_arn = aws_iam_role.diu-eks-cluster.arn\n  version  = \"1.16\"\n\n  vpc_config {\n    # subnet_ids = [\"${aws_subnet.example1.id}\", \"${aws_subnet.example2.id}\"]\n    # security_group_ids = list(aws_security_group.eks_cluster.id)\n    subnet_ids = [for subnet in [for value in aws_subnet.this : value] : subnet.id]\n  }\n\n  # Ensure that IAM Role permissions are created before and deleted after EKS Cluster handling.\n  # Otherwise, EKS will not be able to properly delete EKS managed EC2 infrastructure such as Security Groups.\n  depends_on = [\n    aws_iam_role_policy_attachment.diu-eks-cluster-AmazonEKSClusterPolicy,\n    aws_iam_role_policy_attachment.diu-eks-cluster-AmazonEKSServicePolicy,\n  ]\n}\n# Uncomment to create AWS EKS cluster (Kubernetes control plane) - start\n\n...\n:wq!\n\n```\n\nPlease **run** `terraform apply -var-file terraform.eks.tfvars` to create **aws_eks_cluster** terraform resource and provision AWS EKS cluster (Kubernetes control plane) in AWS.\n\n```bash\n terraform apply -var-file terraform.eks.tfvars\n\ndata.aws_vpc.default: Refreshing state...\n...\n...\naws_security_group.eks_cluster_node_group: Refreshing state... [id=sg-0bb7b99d2f18d67b2]\n\nAn execution plan has been generated and is shown below.\nResource actions are indicated with the following symbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_eks_cluster.this will be created\n  + resource \"aws_eks_cluster\" \"this\" {\n      + arn                   = (known after apply)\n      + certificate_authority = (known after apply)\n      + created_at            = (known after apply)\n      + endpoint              = (known after apply)\n      + id                    = (known after apply)\n      + identity              = (known after apply)\n      + name                  = \"diu-eks-cluster\"\n      + platform_version      = (known after apply)\n      + role_arn              = \"arn:aws:iam::61111116:role/diu-EksClusterIAMRole-tf\"\n      + status                = (known after apply)\n      + version               = (known after apply)\n\n      + vpc_config {\n          + cluster_security_group_id = (known after apply)\n          + endpoint_private_access   = false\n          + endpoint_public_access    = true\n          + public_access_cidrs       = (known after apply)\n          + subnet_ids                = [\n              + \"subnet-029206922e7523d47\",\n              + \"subnet-075c3500bf9838fc8\",\n              + \"subnet-08808f0e072d6874e\",\n            ]\n          + vpc_id                    = (known after apply)\n        }\n    }\n\nPlan: 1 to add, 0 to change, 0 to destroy.\n\nDo you want to perform these actions?\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n```\n![](img/main-eks-cp-tf-1.png)\n\n![](img/main-eks-cp-tf-2.png)\n\n\n\u003c!-- - [27. Uncomment aws eks node group resource section in main.tf to create AWS EKS node group](#27-uncomment-aws-eks-node-group-resource-section-in-maintf-to-create-aws-eks-node-group)--\u003e\n### 27. Uncomment aws eks node group resource section in main.tf to create AWS EKS node group\n\n```bash\n\nterraform apply -var-file terraform.eks.tfvars\ndata.aws_vpc.default: Refreshing state...\n\n...\n...\nAn execution plan has been generated and is shown below.\nResource actions are indicated with the following symbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_eks_node_group.this will be created\n  + resource \"aws_eks_node_group\" \"this\" {\n      + ami_type        = (known after apply)\n      + arn             = (known after apply)\n      + cluster_name    = \"diu-eks-cluster\"\n      + disk_size       = (known after apply)\n      + id              = (known after apply)\n      + instance_types  = [\n          + \"t3.micro\",\n        ]\n      + node_group_name = \"diu-eks-cluster-node-group\"\n      + node_role_arn   = \"arn:aws:iam::61111111116:role/diu-EksClusterNodeGroup-tf\"\n      + release_version = (known after apply)\n      + resources       = (known after apply)\n      + status          = (known after apply)\n      + subnet_ids      = [\n          + \"subnet-029206922e7523d47\",\n          + \"subnet-075c3500bf9838fc8\",\n          + \"subnet-08808f0e072d6874e\",\n        ]\n      + tags            = {\n          + \"Delete\"    = \"true\"\n          + \"Name\"      = \"diu-eks-cluster-tag\"\n          + \"Terraform\" = \"true\"\n        }\n      + version         = (known after apply)\n\n      + remote_access {\n          + ec2_ssh_key               = \"aws-eks-ssh-key\"\n          + source_security_group_ids = [\n              + \"sg-0bb7b99d2f18d67b2\",\n            ]\n        }\n\n      + scaling_config {\n          + desired_size = 2\n          + max_size     = 3\n          + min_size     = 1\n        }\n    }\n\n  # aws_key_pair.this will be created\n  + resource \"aws_key_pair\" \"this\" {\n      + fingerprint = (known after apply)\n      + id          = (known after apply)\n      + key_name    = \"aws-eks-ssh-key\"\n      + key_pair_id = (known after apply)\n      + public_key  = \"ssh-rsa AAA.....xyz\n    }\n\nPlan: 2 to add, 0 to change, 0 to destroy.\n\nDo you want to perform these actions?\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n\n```\n\n![](img/main-eks-ng-tf-1.png)\n\n![](img/main-eks-ng-tf-2.png)\n\n\u003c!-- - [28. Setup communication between your PC and AWS EKS cluster](#28-setup-communication-between-your-pc-and-aws-eks-cluster)--\u003e\n### 28. Setup communication between your PC and AWS EKS cluster\n\n```bash\necho \"\" \u003e ~/.kube/config \u0026\u0026 cat ~/.kube/config\n\naws eks --region eu-central-1 \\\nupdate-kubeconfig \\\n--name diu-eks-cluster \\\n--profile devopsinuse \u0026\u003e /dev/null\n\nAdded new context arn:aws:eks:eu-central-1:611111116:cluster/diu-eks-cluster to /home/\u003cusername\u003e/.kube/config\n```\n\n**If you now go and take a look** what is inside the **file**: `~/.kube/config`, you will find a correct **connection settings** to be able to communicate with your **AWS EKS Kubernetes cluster** under your AWS Free Tier account\n\nRun following commands to make sure that you can communicte with your AWS EKS Kubernetes cluster under your AWS Free Tier account\n\n```bash\nkubectl get nodes\nNAME                                              STATUS   ROLES    AGE   VERSION\nip-172-31-101-85.eu-central-1.compute.internal    Ready    \u003cnone\u003e   11m   v1.15.10-eks-bac369\nip-172-31-102-164.eu-central-1.compute.internal   Ready    \u003cnone\u003e   11m   v1.15.10-eks-bac369\n\nkubectl get pods -A\nNAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE\nkube-system   aws-node-tpnfj             1/1     Running   0          11m\nkube-system   aws-node-w5bh5             1/1     Running   0          11m\nkube-system   coredns-5b6dbb4b59-8h9wd   1/1     Running   0          41m\nkube-system   coredns-5b6dbb4b59-r5bz6   1/1     Running   0          41m\nkube-system   kube-proxy-lnjwr           1/1     Running   0          11m\nkube-system   kube-proxy-z945r           1/1     Running   0          11m\n```\n\n\n\u003c!-- - [29. Explore terrafrom console command](#29-explore-terrafrom-console-command)--\u003e\n### 29. Explore terrafrom console command\n\n**Run** `terrafrom console -var-file terraform.eks.tfvars` command to start **terraform console** and print whatever variable present within `terraform.eks.tfvars` file.\n\n```bash\nterraform console -var-file terraform.eks.tfvars\n\u003e \n\n\u003e var.custom_tags\n{\n  \"Delete\" = \"true\"\n  \"Name\" = \"diu-eks-cluster-tag\"\n  \"Terraform\" = \"true\"\n}\n\n\u003e var.eks-cluster-name\ndiu-eks-cluster\n\u003e \n\n\u003e var.aws_region\neu-central-1\n\n```\n\nLet's say there is the requirement to modify `tag name`: **Name** and append some string to already existing one.\n\n```bash\n\u003e {for a, b in var.custom_tags : a =\u003e (a == \"Name\" ? format(\"%s-%s\", b, \"terraform\") : b)}\n\n{\n  \"Delete\" = \"true\"\n  \"Name\" = \"diu-eks-cluster-tag-terraform\"\n  \"Terraform\" = \"true\"\n}\n```\n\nIf you for example need to do a megre of two maps - to add extra tag to **custom_tags** variable:\n\n```bash\n\u003e merge({for a, b in var.custom_tags : a =\u003e (a == \"Name\" ? format(\"%s-%s\", b, \"terraform\") : b)}, {extra-key = \"extra-value\"})\n{\n  \"Delete\" = \"true\"\n  \"Name\" = \"diu-eks-cluster-tag-terraform\"\n  \"Terraform\" = \"true\"\n  \"extra-key\" = \"extra-value\"\n}\n\n```\n\n\n\u003c!-- - [30. First NGINX deployment by kubectl to AWS EKS cluster created by terraform](#30-first-nginx-deployment-by-kubectl-to-aws-eks-cluster-created-by-terraform)--\u003e\n### 30. First NGINX deployment by kubectl to AWS EKS cluster created by terraform\n\n```bash\ndeployment-eks-nginx-terraform\n├── deployment-eks-nginx-terraform.yaml\n├── index-eks-nginx-terraform_files\n│   ├── bootstrap.min.css\n│   ├── bootstrap.min.js\n│   ├── Chart.min.js\n│   ├── dashboard.css\n│   ├── feather.min.js\n│   ├── jquery-3.2.1.slim.min.js\n│   └── popper.min.js\n└── index-eks-nginx-terraform.html\n\n1 directory, 9 files\n```\n\n**Create configmap** kubernetes object nginx-cm\n```bash\ncd deployment-eks-nginx-terraform/\n\nkubectl create configmap nginx-cm \\\n--from-file=index-eks-nginx-terraform.html \\\n--from-file=index-eks-nginx-terraform_files/bootstrap.min.css \\\n--from-file=index-eks-nginx-terraform_files/bootstrap.min.js \\ \n--from-file=index-eks-nginx-terraform_files/Chart.min.js \\\n--from-file=index-eks-nginx-terraform_files/dashboard.css \\\n--from-file=index-eks-nginx-terraform_files/feather.min.js \\\n--from-file=index-eks-nginx-terraform_files/jquery-3.2.1.slim.min.js \\\n--from-file=index-eks-nginx-terraform_files/popper.min.js\n```\n\n\n![](img/sg-4.png)\n\n**Execute** deployment of your Nginx web server with custom content\n\n```\nkubectl apply -f deployment-eks-nginx-terraform.yaml\n```\n\n\n**Check whether desired** kubernetes objects have been created\n\n```bash\nkubectl get deployment,svc\nNAME                          READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.extensions/nginx   0/1     1            0           9s\n\nNAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE\nservice/kubernetes   ClusterIP   10.100.0.1       \u003cnone\u003e        443/TCP        101m\nservice/nginx        NodePort    10.100.176.217   \u003cnone\u003e        80:30111/TCP   9s\n\n\n\n# Check for pods\nkubectl get pods\nNAME                     READY   STATUS    RESTARTS   AGE\nnginx-656bf99f5d-4pjgt   1/1     Running   0          8s\n\n```\n\n\n**Retrive** IP Addresses of your **physical nodes** in AWS\n\n```bash\nNAME\tEXTERNAL-IP\nip-172-31-101-85.eu-central-1.compute.internal\t18.156.166.86\nip-172-31-102-164.eu-central-1.compute.internal\t35.158.24.165\n```\n\n![](img/nginx-tf-2.png)\n\n![](img/nginx-tf-3.png)\n\n**SSH tunnel** approach without the need to seup Security group in AWS\n\n```bash\nssh -o \"IdentitiesOnly yes\" \\\n-i  ~/.ssh/eks-aws \\\nec2-user@35.158.24.165 \\\n-L30111:127.0.0.1:30111\n\nssh -o \"IdentitiesOnly yes\" \\\n-i  ~/.ssh/eks-aws \\\nec2-user@18.156.166.86 \\\n-L30111:127.0.0.1:30111\n\n```\n\n![](img/nginx-tf-1.png)\n\n**Explore** Nginx deployment in AWS EKS provisioned by terrafrom\n\n```bash\n kubectl get pods  \nNAME                     READY   STATUS    RESTARTS   AGE\nnginx-656bf99f5d-4pjgt   1/1     Running   0          26m\nkubectl exec -it  nginx-656bf99f5d-4pjgt -- bash                               \nroot@nginx-656bf99f5d-4pjgt:/# ls usr/share/nginx/html/index* -l\n-rw-r--r-- 1 root root 16062 usr/share/nginx/html/index.html\n\nusr/share/nginx/html/index-eks-nginx-terraform_files:\ntotal 516\n-rw-r--r-- 1 root root 157843 Chart.min.js\n-rw-r--r-- 1 root root 144877 bootstrap.min.css\n-rw-r--r-- 1 root root  48944 bootstrap.min.js\n-rw-r--r-- 1 root root   1539 dashboard.css\n-rw-r--r-- 1 root root  75779 feather.min.js\n-rw-r--r-- 1 root root  69597 jquery-3.2.1.slim.min.js\n-rw-r--r-- 1 root root  19188 popper.min.js\nroot@nginx-656bf99f5d-4pjgt:/# \n\n```\n\n\u003c!-- - [31. Executing terrafrom destroy will not work when terrafrom run incrementaly](#31-executing-terrafrom-destroy-will-not-work-when-terrafrom-run-incrementaly)--\u003e\n### 31. Executing terrafrom destroy will not work when terrafrom run incrementaly\n\n![](img/terraform-4.png)\n**Run** `terraform destroy  -var-file terraform.eks.tfvars` command to **delete all prevoiusly** created AWS resources\n\n**Quick recap** on how the cluster was brought to life.\n\nprerequisites:\n  - **Clear some** left overs from: ~/.kube/config file \n```bash\necho \"\" \u003e ~/.kube/config \u0026\u0026 cat ~/.kube/config\n```\n\n  - **Navigate** to terraform code folder\n```bash\ncd eks-terraform\nrm terraform.tfstate.backup terraform.tfstate .terraform -rf\nls  ~/.ssh/eks-aws.pub\n/home/\u003cusername\u003e/.ssh/eks-aws.pub: OpenSSH RSA public key\n\n```\n\n  - **Make** sure that terraform.eks.tfvars file is configured correctlly\nand remeber that at this point **most of the terrafrom code** has comments - effectively it will not be take into an account `# sed -i 's/^/#/' iam.tf outputs.tf sg.tf subnets.tf`  and `sed -i '/^.*EKS_CLUSTER_START.*/,/^.*EKS_NODE_GROUP_END.*/s/^/#/' main.tf`\n\n\n```bash\nterraform init\nterraform validate\nterraform fmt -recursive\nterraform apply -var-file terraform.eks.tfvars\n```\n\n1. Remove the **comments** from `iam.tf` file\n```bash\n# Check AWS IAM Roles before running terraform apply ...\naws iam list-roles --profile devopsinuse --region eu-central-1 | jq '.Roles [].RoleName'\n\"AWSServiceRoleForAmazonEKS\"\n\"AWSServiceRoleForAmazonEKSNodegroup\"\n\"AWSServiceRoleForAutoScaling\"\n\"AWSServiceRoleForSupport\"\n\"AWSServiceRoleForTrustedAdvisor\"\n\n# Create 2 IAM AWS Roles and make sure htat you uncommented iam.tf file\nsed -i 's/^#//' iam.tf # removes comments from file\nterraform validate\nterraform apply -var-file terraform.eks.tfvars\n\n# if there is no any issue 2 IAM AWS Roles will be created\naws iam list-roles --profile devopsinuse --region eu-central-1 | jq '.Roles [].RoleName' \n\"AWSServiceRoleForAmazonEKS\"\n\"AWSServiceRoleForAmazonEKSNodegroup\"\n\"AWSServiceRoleForAutoScaling\"\n\"AWSServiceRoleForSupport\"\n\"AWSServiceRoleForTrustedAdvisor\"\n\"diu-EksClusterIAMRole-tf\"\n\"diu-EksClusterNodeGroup-tf\"\n```\n\n2. Remove **all comments** from `sg.tf` file and run terrafrom apply\n\n```bash\n# Check for the Security group before terraform apply -var-file terraform.eks.tfvars\naws ec2 describe-security-groups --profile devopsinuse --region eu-central-1 | jq '.SecurityGroups [].GroupName'\n\"default\"\n\n# apply sg.tf terrrafrom code\nsed  's/^#//' -i sg.tf\nterraform validate\nterraform apply -var-file terraform.eks.tfvars\n \n# Check for the Security group after terraform apply -var-file terraform.eks.tfvars\naws ec2 describe-security-groups --profile devopsinuse --region eu-central-1 | jq '.SecurityGroups [].GroupName'\n\"EKSClusterNodeGroupSecurityGroup\"\n\"default\"\n\n```\n\n3. Remove **comments from subnets.tf** file and run terrafrom apply ...\n\n```bash\n# Check for the extra Subnets before terraform apply -var-file terraform.eks.tfvars\naws ec2 describe-subnets --profile devopsinuse --region eu-central-1 | jq '.Subnets [].SubnetId'\n\"subnet-1f3cc963\"\n\"subnet-ca01f986\"\n\"subnet-9b75cbf1\"\n\n# apply subnets.tf terrrafrom code\nsed  's/^#//' -i subnets.tf\nterraform validate\nterraform apply -var-file terraform.eks.tfvars\n \n# Check for the extra Subnets before terraform apply -var-file terraform.eks.tfvars\naws ec2 describe-subnets --profile devopsinuse --region eu-central-1 | jq '.Subnets [].SubnetId'\n\"subnet-064d6205839537b7b\"\n\"subnet-06aab122584ff2903\"\n\"subnet-1f3cc963\"\n\"subnet-092c8c9af4f4501e6\"\n\"subnet-ca01f986\"\n\"subnet-9b75cbf1\"\n```\n\n4. Remove **comments from main.tf** file and correcponding section for **AWS EKS cluster**\n\n```bash\n# Check whether you got any AWS EKS cluster before you gonna run terrafrom apply ...\naws eks list-clusters --profile devopsinuse --region eu-central-1\n{\n    \"clusters\": []\n}\n\n# apply main.tf terrrafrom code for AWS EKS cluster\nsed -e '/^.*EKS_CLUSTER_START.*/,/^.*EKS_CLUSTER_END.*/s/^#//' -i main.tf\nterraform validate\nterraform apply -var-file terraform.eks.tfvars\n\n# Check whether you got any AWS EKS cluster after you gonna run terrafrom apply ...\naws eks list-clusters --profile devopsinuse --region eu-central-1\n{\n    \"clusters\": [\n        \"diu-eks-cluster\"\n    ]\n}\n\n```\n\n5. Remove **comments from main.tf** file and terrafrom section for **AWS EKS Node Group**\n\n```bash\n# Check whether you got any AWS EKS node group before you gonna run terrafrom apply ...\naws eks list-nodegroups --cluster-name diu-eks-cluster --profile devopsinuse --region eu-central-1\n{\n    \"nodegroups\": []\n}\n\n# apply main.tf terrrafrom code for AWS EKS cluster\nsed -e '/^.*EKS_NODE_GROUP_START.*/,/^.*EKS_NODE_GROUP_END.*/s/^#//' -i main.tf\nterraform validate\nterraform apply -var-file terraform.eks.tfvars\n\n# Check whether you got any AWS EKS node group after you gonna run terrafrom apply ...\naws eks list-nodegroups --cluster-name diu-eks-cluster --profile devopsinuse --region eu-central-1\n{\n    \"nodegroups\": [\n        \"diu-eks-cluster-node-group\"\n    ]\n}\n\n\n# List EC2 instances within AGS belonging to AWS EKS node group\naws ec2 describe-instances --filters Name=instance-type,Values=t3.micro --profile devopsinuse --region eu-central-1 | jq '.Reservations [].Instances [].Tags'\n[\n  {\n    \"Key\": \"aws:autoscaling:groupName\",\n    \"Value\": \"eks-dcb90a4c-5373-6ef1-67cf-9706e0bb913b\"\n  },\n  ...\n  ...\n  {\n    \"Value\": \"1\"\n  }\n]\n\n\n# retrive ASG, Lunch template, ...\naws autoscaling describe-auto-scaling-groups --profile devopsinuse --region eu-central-1 | jq '(.AutoScalingGroups [].AutoScalingGroupName), (.AutoScalingGroups [].LaunchTemplate)'\n\"eks-dcb90a4c-5373-6ef1-67cf-9706e0bb913b\"\n{\n  \"LaunchTemplateId\": \"lt-0f98da1f10a5bf8e7\",\n  \"LaunchTemplateName\": \"eks-dcb90a4c-5373-6ef1-67cf-9706e0bb913b\",\n  \"Version\": \"1\"\n}\n\n\n# List AWS ENI Network Interfaces\naws ec2 describe-network-interfaces  --profile devopsinuse --region eu-central-1 | jq '(.NetworkInterfaces [].Description), (.NetworkInterfaces [].NetworkInterfaceId)'\n\"aws-K8S-i-044c234e0f9b30818\"\n\"Amazon EKS diu-eks-cluster\"\n\"\"\n\"aws-K8S-i-08d8fcb2bf3d16b54\"\n\"\"\n\"Amazon EKS diu-eks-cluster\"\n\"eni-0b82e1be272606a79\"\n\"eni-0f6bcf69497705f5a\"\n\"eni-0c8a4d31f6ae0a841\"\n\"eni-06a9cc7fdfcb57b43\"\n\"eni-03e6ba9d77782d502\"\n\"eni-0a44e20c8afc8badc\"\n\n```\n\n**On Amazon Elastic Kubernetes Service (EKS)**, \nthe maximum number of pods per node depends on the node type and ranges from 4 to 737.\n\n*Pod number mapping*: https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt\n\n**On Google Kubernetes Engine (GKE)**, \nthe limit is 100 pods per node, regardless of the type of node.\n\n**On Azure Kubernetes Service (AKS)**, \nthe default limit is 30 pods per node but it can be increased up to 250.\n\n\nConfigure your `~/.kube/config` file to be able to communicate to your **AWS EKS Kubernetes cluster**\n\n```bash\n# run this command:\naws eks --region eu-central-1 update-kubeconfig --name diu-eks-cluster --profile devopsinuse\n```\n\nExamine a quick **deployment**:\n\n```bash\nkubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml\nkubectl scale --replicas=2 deployment nginx-deployment\nkubectl expose deployment nginx-deployment --port=80 --target-port=80\n\nkubectl exec -it nginx-deployment-574b87c764-hjtcm -- sed -i 's/Welcome to nginx/Hello from Kubernetes at port 30111/'  /usr/share/nginx/html/index.html\n\nkubectl get nodes -o wide | awk -F\" \" '{print $1\"\\t\"$7}'        \nNAME    EXTERNAL-IP\nip-172-31-100-208.eu-central-1.compute.internal 18.195.216.59\nip-172-31-102-105.eu-central-1.compute.internal 3.120.228.32\n```\n![](img/sg-problem-7.png)\n\n![](img/sg-problem-6.png)\n\n\n\n\nTerrafrom destroy AWS EKS cluster and all the other resources\n```bash\nterraform destroy -var-file terraform.eks.tfvars       \ndata.aws_availability_zones.default: Refreshing state...\naws_key_pair.this: Refreshing state... [id=aws-eks-ssh-key]\n\n...\n...\n\napsed]\naws_eks_node_group.this: Still destroying... [id=diu-eks-cluster:diu-eks-cluster-node-group, 3m0s elapsed]\naws_eks_node_group.this: Still destroying... [id=diu-eks-cluster:diu-eks-cluster-node-group, 3m10s elapsed]\naws_eks_node_group.this: Still destroying... [id=diu-eks-cluster:diu-eks-cluster-node-group, 3m20s elapsed]\n\nError: error waiting for EKS Node Group (diu-eks-cluster:diu-eks-cluster-node-group) deletion: Ec2SecurityGroupDeletionFailure: DependencyViolation - resource has a dependent object. Resource IDs: [sg-0647cbc6b8a83da15]\n\n```\n\n**Delete problematic AWS ENI** interface for **eks-remoteAccess-XYZ** Security Group and corresponfing **eni-111111111111**\n\n```bash\naws ec2 delete-network-interface --network-interface-id eni-0096ccb8555c18958 --profile devopsinuse --region eu-central-1\n```\n\n![](img/sg-problem-1.png)\n\n![](img/sg-problem-2.png)\n\n![](img/sg-problem-3.png)\n\n![](img/sg-problem-4.png)\n\n![](img/sg-problem-5.png)\n\n\n\n\n**Now** Terrafrom destroy AWS EKS cluster will **work**\n```bash\nterraform destroy -var-file terraform.eks.tfvars\n\n...\naws_subnet.this[0]: Destroying... [id=subnet-064d6205839537b7b]\naws_subnet.this[2]: Destroying... [id=subnet-092c8c9af4f4501e6]\naws_subnet.this[1]: Destroying... [id=subnet-06aab122584ff2903]\naws_subnet.this[2]: Destruction complete after 1s\naws_subnet.this[1]: Destruction complete after 1s\naws_subnet.this[0]: Destruction complete after 1s\naws_iam_role_policy_attachment.diu-eks-cluster-AmazonEKSClusterPolicy: Destruction complete after 1s\naws_iam_role_policy_attachment.diu-eks-cluster-AmazonEKSServicePolicy: Destruction complete after 1s\naws_iam_role.diu-eks-cluster: Destroying... [id=diu-EksClusterIAMRole-tf]\naws_iam_role.diu-eks-cluster: Destruction complete after 2s\n\nDestroy complete! Resources: 14 destroyed.\n```\n\n\u003c!-- - [32. Provison and destroy AWS EKS Kubernetes cluster with terrafrom](#32-provison-and-destroy-aws-eks-kubernetes-cluster-with-terrafrom)--\u003e\n### 32. Provison and destroy AWS EKS Kubernetes cluster with terrafrom\n\n* **git clone** https://github.com/xjantoth/aws-eks-devopsinuse.git\n* **uncomment** all files from `eks-terraform/` folder at once:\n  - `sed  's/^#//' -i iam.tf`          \n  - `sed  's/^#//' -i sg.tf`          \n  - `sed  's/^#//' -i subnets.tf`     \n  - `sed -e '/^.*EKS_CLUSTER_START.*/,/^.*EKS_CLUSTER_END.*/s/^#//' -i main.tf`\n  - `sed -e '/^.*EKS_NODE_GROUP_START.*/,/^.*EKS_NODE_GROUP_END.*/s/^#//' -i main.tf`\n  - variables.tf  (this file is uncommented all the time)\n  - outputs.tf    (does not really matter whether it's uncommented or not)\n\n* **fill up all** the lines in `terraform.eks.tfvars` file\n\n```bash\necho \"\" \u003e ~/.kube/config \u0026\u0026 cat ~/.kube/config\ncd eks-terraform\nrm terraform.tfstate.backup terraform.tfstate .terraform -rf\nls  ~/.ssh/eks-aws.pub\nterraform init\nterraform validate\nterraform fmt -recursive\n```\n\n\n![](img/terraform-5.png)\n\n**Provision** your AWS EKS Kubernetes cluster with all the required AWS resources by executing **one command**\n```bash\nterraform apply -var-file terraform.eks.tfvars\n```\n\n**Setup** correct  **kubeconfig** file:\n```bash\naws eks --region eu-central-1 update-kubeconfig --name diu-eks-cluster\n```\n\nGo through a quick **kubernetes deployment** to verify your AWS EKS cluster:\n\n```bash\nkubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml\nkubectl scale --replicas=2 deployment nginx-deployment\nkubectl expose deployment nginx-deployment --port=80 --target-port=80\n\nkubectl exec -it nginx-deployment-574b87c764-hjtcm -- sed -i 's/Welcome to nginx/Hello from K8s: terraform apply -var-file terraform.eks.tfvars/'  /usr/share/nginx/html/index.html\n\n# edit Kubenretes service on the fly\n# set service type: NodePort and nodePort: 30111\nEDITOR=vim kubectl edit svc nginx-deployment\n\n\nkubectl get nodes -o wide | awk -F\" \" '{print $1\"\\t\"$7}'\nNAME    EXTERNAL-IP\nip-172-31-100-208.eu-central-1.compute.internal 18.195.216.59\nip-172-31-102-105.eu-central-1.compute.internal 3.120.228.32\n```\n\n\n**Destroy / get rid of** your **AWS EKS Kubernetes cluster** with all **the required AWS resources** by *executing* **one command**\n```bash\nterraform destroy -var-file terraform.eks.tfvars\n```\n\n# Learn AWS EKS Kubernetes cluster with Helm Charts (Part 2)\n![](img/devopsinuse.png)\n\n**Introduction**\n- **Leveraging helm charts** for AWS EKS Kubernetes deployment\n    - using custom made  **frontend** / **backend + postgresql** applications\n    - writing **Dockerfiles**\n    - **docker-compose** specification for:\n      - backend,\n      - frontend,\n      - Nginx Reverse Proxy,\n      - PostgreSQL \n    - **build** docker images\n    - learning about **helm** and **helmfile** binaries\n    - create **backend** helm chart (for dockerized  custom written Python Flask application)\n    - create **fronetend** helm chart (for dockerized custom written React application)\n    - using **Nginx Ingress Controller** helm chart(used as reverse proxy)\n    - using **PostgreSQL database** helm chart as **dependency** for backend helm chart\n\n\n\n**!!! This course is a the second part of my previous course and it is highly recommended to ENROLL in:**\n\n*Learn AWS EKS Kubernetes cluster and devops in AWS (Part 1)*\n\n**unless** you are **familiar** with AWS EKS(Elastic Kubernetes Service) solution and **you can set it up on your OWN**.\n\n!!! If **someone** do not insist to use AWS EKS for deployment - and **already** having Kubenretes cluster **available** somewhere else ready to use - **ONLY and ONLY** in that case this course can be used as STANDALONE.\n\n\n\n**Important notes**:\n* please **run** `terraform destroy -var-file terraform.eks.tfvars` **whenever** you not using your resources in AWS\n* all **materials** can be found at my **Github** project\n  - `https://github.com/xjantoth/aws-eks-devopsinuse`\n* **feel free** to post any question into **Q\u0026A section**\n* **all** videos are recorded in **Full HD** however Udemy's player use *HD*\n* I'm greatful for your **reviews** - please drop some **COMMENTS** :)\n* please setup **budget** within your **Free AWS account** to be notified if from some reason AWS is going to **charge some fees**.\n\n\u003cbr/\u003e\u003cbr/\u003e\n\n\n##  3. Helm charts\n\n\u003c!-- - [33. Desired Infrastructure with helm charts](#33-desired-infrastructure-with-helm-charts)--\u003e\n### 33. Desired Infrastructure with helm charts\n\n![](img/nginx-2.png)\n\nHow to start up the whole setup all at once `docker-compose`:\n* nginx\n* front-end\n* back-end\n* postgresql\n\n\n\u003c!-- - [34. Setting up Infrastracture via docker-compose at local](#34-setting-up-infrastracture-via-docker-compose-at-local)--\u003e\n### 34. Setting up Infrastracture via docker-compose at local\n\n**Make sure** that commands are installed at your PC:\n* `docker`\n* `docker-compose`\n\n\n![](img/docker-compose-schema-1.png)\n\n**Follow** the instructions to bring up **the entire infrastracture up and running** by executing og one command: `docker-compose  up --build`\n```bash\ngit clone https://github.com/xjantoth/aws-eks-devopsinuse.git\ncd aws-eks-devopsinuse\n```\n\n**Delete** all existing docker rrelated resources at your local\n```bash\ndocker system prune --all\n```\nExplore file: `docker-compose.yaml`\n\n```yaml\n---\nversion: '3'\nservices:\n\n  # Nginx (Reverse proxy) specification\n  ingress:\n    image: docker.io/devopsinuse/nginx-docker-compose:v1.0.0\n    ports:\n      - 8080:30000\n    container_name: nginx\n    build:\n      context: ./nginx/\n      dockerfile: Dockerfile\n    links:\n      - backend\n      - frontend\n\n  # Frontend (React app) specification\n  frontend:\n    image: docker.io/devopsinuse/front-end:v1.0.0\n    depends_on:\n      - backend\n    build:\n      context: ./frontend/\n      dockerfile: Dockerfile\n    ports:\n      - 3000:80\n    container_name: frontend\n    links:\n      - backend\n\n  # Backend (Python Flask) specification\n  backend:\n    image: docker.io/devopsinuse/back-end:v1.0.0\n    depends_on:\n      - db\n    build:\n      context: ./backend/\n      dockerfile: Dockerfile\n    ports:\n      - 8000:8000\n    container_name: backend\n    environment:\n      - VIRTUAL_HOST=backend\n      - PSQL_DB_USER=micro\n      - PSQL_DB_PASS=password\n      - PSQL_DB_NAME=microservice\n      - PSQL_DB_ADDRESS=postgresql\n      - PSQL_DB_PORT=5432\n\n  # PostgreSQL (dependency for Python Flask)\n  db:\n    image: postgres:alpine\n    ports:\n      - 5432:5432\n    container_name: postgresql\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=password\n    volumes:\n      - ./db.sql:/docker-entrypoint-initdb.d/db.sql\n\n```\n\n\n**Build** and **start** four docker containers (nginx, fronend, backend and database) via **docker-compose**\n```bash\ndocker-compose  up --build\n```\n\n\n\u003c!-- - [35. Explore backend part of the setup](#35-explore-backend-part-of-the-setup)--\u003e\n### 35. Explore backend part of the setup\n\n![](img/docker-compose-schema-1.png)\n\n**Call** \"Save IP address\" like button directly from command line **via Nginx reverse proxy**\n```bash\ncurl -s -X POST http://127.0.0.1:8080/api/ipaddress | jq\n{\n  \"id\": 8,\n  \"created\": \"2020-06-03 16:38:53.304293\",\n  \"ipaddress\": \"172.18.0.3\"\n}\n\n```\n\n**Call** \"Save IP address\" like button directly **at port 8000**\n```bash\n curl -s -X POST http://127.0.0.1:8000/api/ipaddress | jq \n{\n  \"id\": 7,\n  \"created\": \"2020-06-03 16:38:34.259627\",\n  \"ipaddress\": \"172.18.0.3\"\n}\n```\n\n\n**Get all IP addressess saved in database** via Nginx reverse proxy **at port 8080**\n```bash\ncurl -s -X GET http://127.0.0.1:8080/api/ipaddress | jq \n[\n  {\n    \"id\": 1,\n    \"created\": \"2020-06-02 09:34:30.797599\",\n    \"ipaddress\": \"172.18.0.3\"\n  },\n  {\n    \"id\": 2,\n    \"created\": \"2020-06-02 09:34:32.146712\",\n    \"ipaddress\": \"172.18.0.3\"\n  },\n...\n  {\n    \"id\": 8,\n    \"created\": \"2020-06-03 16:38:53.304293\",\n    \"ipaddress\": \"172.18.0.3\"\n  }\n]\n\n```\n\n**Get all IP addressess saved in database** directly **at port 8000**\n```bash\ncurl -s -X GET http://127.0.0.1:8000/api/ipaddress | jq\n[\n  {\n    \"id\": 1,\n    \"created\": \"2020-06-02 09:34:30.797599\",\n    \"ipaddress\": \"172.18.0.3\"\n  },\n  {\n    \"id\": 2,\n...\n  {\n    \"id\": 8,\n    \"created\": \"2020-06-03 16:38:53.304293\",\n    \"ipaddress\": \"172.18.0.3\"\n  }\n]\n\n```\n\n**Delete** a record from the **database via Nginx reverse proxy at port 8080**\n```bash\ncurl -s -X DELETE \"http://127.0.0.1:8080/api/ipaddress?id=7\" | jq\n{\n  \"msg\": \"Entry with id: 7 deleted\"\n}\n\n```  \n\n**Delete** a record from the **database directly at port 8000**\n```bash\ncurl -s -X DELETE \"http://127.0.0.1:8000/api/ipaddress?id=8\" | jq\n{\n  \"msg\": \"Entry with id: 8 deleted\"\n}\n\n```  \n\n\n\u003c!-- - [36. Push docker images to docker hub](#36-push-docker-images-to-docker-hub)--\u003e\n### 36. Push docker images to docker hub\n**Check built** docker images\n\n```bash\ndocker images\n\ndevopsinuse/nginx-docker-compose   v1.0.0              \ndevopsinuse/front-end              v1.0.0              \ndevopsinuse/back-end               v1.0.0              \n...\n\n```\n\n**Push** docker images to your **account** at https://hub.docker.com/\nThis step is not **mandatory** if using already existing docker images **under devopsinuse account** at https://hub.docker.com/\n\n```bash\n# Login to your https://hub.docker.com/ account first\ndocker login --username devopsinuse\n\n# Push previously build docker images to your **account** at https://hub.docker.com/\ndocker push docker.io/devopsinuse/nginx-docker-compose:v1.0.0\ndocker push docker.io/devopsinuse/front-end:v1.0.0\ndocker push docker.io/devopsinuse/back-end:v1.0.0\n```\n\n**Make** sure that you have this line in `/etc/hosts`\n```bash\n# Make sure that you have this line in /etc/hosts\n# This can be easily done even on Windows OS (do a little search)\nvim /etc/hosts\n...\n\n127.0.0.1 k8s-ingress-name\n...\n:wq!\n```\n\n![](img/docker-compose-1.png)\n\n\n\u003c!-- - [37. Install helm and helmfile binaries](#37-install-helm-and-helmfile-binaries)--\u003e\n### 37. Install helm and helmfile binaries\n\n**Install** helm v3\n```bash\ncurl -L https://get.helm.sh/helm-v3.2.1-linux-amd64.tar.gz | \\\nsudo tar xvzf - --strip-components=1 -C /usr/local/bin/ linux-amd64/helm\nsudo chmod +x /usr/local/bin/helm\n\n# In case you have no helm chart repository added\nhelm repo add stable https://kubernetes-charts.storage.googleapis.com/\nhelm repo update\n```\n\n**Install helmfile** binary\n\n```bash\nsudo curl -L \\\n--output /usr/bin/helmfile \\\nhttps://github.com/roboll/helmfile/releases/download/v0.116.0/helmfile_linux_amd64\nsudo chmod +x /usr/bin/helmfile\n```\n\n\u003c!-- - [38. Creating backend helm chart](#38-creating-backend-helm-chart)--\u003e\n### 38. Creating backend helm chart\n\n**Create** backend helm chart from scatch\n\n![](img/backend-hc-1.png)\n```bash\n# Creating \"backend\" helm chart\ncd backend/hc\nhelm create backend\n\n# Take a look how it looks inside of backend/ helm chart\ntree -L 2 backend\nbackend\n├── charts\n├── Chart.yaml\n├── templates\n│   ├── deployment.yaml\n│   ├── _helpers.tpl\n│   ├── hpa.yaml\n│   ├── ingress.yaml\n│   ├── NOTES.txt\n│   ├── serviceaccount.yaml\n│   ├── service.yaml\n│   └── tests\n└── values.yaml\n\n```\n\n**Files** to be modified (done by running four `sed commands`):\n* `backend/Chart.yaml`\n* `backend/values.yaml`\n* `backend/templates/service.yaml`\n* `backend/templates/deployment.yaml`\n* `backend/templates/secret.yaml` (completly new file)\n* `backend/templates/_helpers.tpl` (append at the and of this file)\n\n\n\u003c!-- - [39. Modify Chart yaml file for backend helm chart](#39-modify-chart-yaml-file-for-backend-helm-chart)--\u003e\n### 39. Modify Chart yaml file for backend helm chart\n\n**Shape** your `Chart.yaml` file:\n\n```bash\n# Adding custom description to Chart.yaml file\nsed -E \\\n-e 's/^(description:).*/\\1 Backend Flask app helm chart/' \\\n-e 's/^(appVersion:).*/\\1 v1.0.0 /' \\\n-e '$a  \\\\ndependencies: \\n- name: postgresql \\n  version: \"9.8.1\" \\n  repository: \"https://charts.bitnami.com/bitnami\" \\n' \\\n-i backend/Chart.yaml\n```\n\nAdding **bitnami** `helm chart repository` to my **local**\n\n```bash\nhelm repo list\nhelm repo add bitnami https://charts.bitnami.com/bitnami\n\n# Determine latest version of bitnami helm chart\nhelm search repo bitnami/postgresql -l | head\nNAME                    CHART VERSION   APP VERSION     DESCRIPTION\nbitnami/postgresql      9.8.1           11.9.0          Chart for PostgreSQL, an object-relational data...\nbitnami/postgresql      9.8.0           11.9.0          Chart for PostgreSQL, an object-relational data...\nbitnami/postgresql      9.7.2           11.9.0          Chart for PostgreSQL, an object-relational data...\nbitnami/postgresql      9.7.1           11.9.0          Chart for PostgreSQL, an object-relati\n```\n\n**Run** `helm dependency update` for **postgresql** helm chart\n\n```bash\n# Downloads helm chart: to charts/ folder\ncd backend \u0026\u0026 helm dependency update \u0026\u0026 cd ..\n```\n\n\n\u003c!-- - [40. Modify values yaml file for backend helm chart](#40-modify-values-yaml-file-for-backend-helm-chart)--\u003e\n### 40. Modify values yaml file for backend helm chart\n**Setup** file: `backend/values.yaml` within **backend** helm chart\n\n```bash\n# Setting up \"backend/values.yaml\" file\nsed -E \\\n-e '/^.*port:.*/a \\ \\ nodePort:' \\\n-e 's/^(.*paths:).*/\\1 [\"\\/api\"]/' \\\n-e '/^ingress.*/,/^\\s*tls:.*/s/^(.*-\\shost: )(.*)/\\1 k8s-ingress-name/' \\\n-e '/^.*pullPolicy:.*/a \\ \\ containerPort: 8000' \\\n-e '/^.*pullPolicy:.*/a \\ \\ # Database connection settings:' \\\n-e '/^.*pullPolicy:.*/a \\ \\ env:' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ secret:' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ \\ \\ PSQL_DB_USER: \"micro\"' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ \\ \\ PSQL_DB_PASS: \"password\"' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ \\ \\ PSQL_DB_NAME: \"microservice\"' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ \\ \\ PSQL_DB_ADDRESS: \"backend-postgresql\"' \\\n-e '/^.*pullPolicy:.*/a \\ \\ \\ \\ \\ \\ PSQL_DB_PORT: \"5432\"' \\\n-e '$a \\\\nlivenessProbe: \\/api\\/health' \\\n-e '$a \\\\nreadinessProbe: \\/api\\/health' \\\n-e 's/^(.*repository:).*/\\1 devopsinuse\\/back-end/' \\\n-i backend/values.yaml\n\ncat \u003c\u003c'EOF' \u003e\u003ebackend/values.yaml\n\npostgresql:\n  image:\n    registry: docker.io\n    repository: bitnami/postgresql\n    tag: latest\n    debug: true\n\n  global:\n    postgresql:\n      postgresqlUsername: postgres\n      postgresqlPassword: password\n\n  persistence:\n    enabled: false\n\n  pgHbaConfiguration: |\n    local all all trust\n    host all all localhost trust\n    host microservice micro 172.31.0.0/16 password\n\n  initdbScripts:\n    db-init.sql: |\n      CREATE DATABASE microservice;\n      CREATE USER micro WITH ENCRYPTED PASSWORD 'password';\n      GRANT ALL PRIVILEGES ON DATABASE microservice TO micro;\n      ALTER DATABASE microservice OWNER TO micro;\n\nEOF\n```\n\n\u003c!-- - [41. Modify service yaml file for backend helm chart](#41-modify-service-yaml-file-for-backend-helm-chart)--\u003e\n### 41. Modify service yaml file for backend helm chart\n\n**Do some little** changes in file: `backend/templates/service.yaml`\n```bash\n# Setup \"containerPort\" in file: \"backend/templates/service.yaml\" \nsed -E \\\n-e 's/^(.*targetPort:).*/\\1 {{ .Values.image.containerPort | default 80 }}/' \\\n-e '/^.*targetPort:.*/a \\ \\ \\ \\ {{- if (and (eq .Values.service.type \"NodePort\") (not (empty .Values.service.nodePort))) }}\\n      nodePort: {{ .Values.service.nodePort }}\\n    {{- end }}' \\\n-i backend/templates/service.yaml\n```\n\n\n\u003c!-- - [42. Modify deployment yaml file for backend helm chart](#42-modify-deployment-yaml-file-for-backend-helm-chart)--\u003e\n### 42. Modify deployment yaml file for backend helm chart\n**Do another little** changes in file: `backend/templates/deployment.yaml`\n\n```bash\n# Setup \"livenessProbe\" and \"readinessProbe\" in backend/templates/deployment.yaml\nsed -E \\\n-e '/^\\s*livenessProbe:.*/,/^\\s*port:.*/s/^(.*port:)(.*)/\\1 {{ .Values.image.containerPort | default \"http\" }}/' \\\n-e '/^\\s*readinessProbe:.*/,/^\\s*port:.*/s/^(.*port:)(.*)/\\1 {{ .Values.image.containerPort | default \"http\" }}/' \\\n-e '/^\\s*livenessProbe:.*/,/^\\s*port:.*/s/^(.*path:)(.*)/\\1 {{ .Values.livenessProbe | default \"\\/\" }}/' \\\n-e '/^\\s*readinessProbe:.*/,/^\\s*port:.*/s/^(.*path:)(.*)/\\1 {{ .Values.readinessProbe | default \"\\/\" }}/' \\\n-e 's/^(.*containerPort:).*/\\1 {{ .Values.image.containerPort }}/' \\\n-e '/^.*image:.*/a \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ env:' \\\n-e '/^.*image:.*/a \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ {{- include \"helpers.list-env-variables\" . | indent 10 }}' \\\n-i backend/templates/deployment.yaml\n```\n\n\u003c!-- - [43. Create brand new secret yaml file for backend helm chart](#43-create-brand-new-secret-yaml-file-for-backend-helm-chart)--\u003e\n### 43. Create brand new secret yaml file for backend helm chart\n**Create** a completly new file: `backend/templates/secret.yaml`\n\n```bash\n# Creating file: \"backend/templates/secret.yaml\"\ncat \u003c\u003c'EOF' \u003e\u003ebackend/templates/secret.yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: database-conection\ntype: Opaque\ndata:\n  {{- range $key, $val := .Values.image.env.secret }}\n  {{ $key }}: {{ $val | b64enc }}\n  {{- end}}\n\nEOF\n```\n\n\u003c!-- - [44. Create helper function in helpers tpl file](#44-create-helper-function-in-helpers-tpl-file)--\u003e\n### 44. Create helper function in helpers tpl file\n**Define and append** new variable in file: `backend/templates/_helpers.tpl`\n\n```bash\n# Enrich file: \"backend/templates/_helpers.tpl\"\ncat \u003c\u003c'EOF' \u003e\u003ebackend/templates/_helpers.tpl\n\n{{/*\nCreate the looper to define secret mounts as ENV variables\n*/}}\n\n{{- define \"helpers.list-env-variables\"}}\n{{- range $key, $val := .Values.image.env.secret }}\n- name: {{ $key }}\n  valueFrom:\n    secretKeyRef:\n      name: database-conection\n      key: {{ $key }}\n{{- end}}\n{{- end}}\nEOF\n```\n\n\u003c!-- - [45. Learn how to template backend helm chart and set values](#45-learn-how-to-template-backend-helm-chart-and-set-values)--\u003e\n### 45. Learn how to template backend helm chart and set values\n\n**Learn** how to template helm chart with colors\n```bash\n# Template your backend helm chart\nhelm template backend \n\n# Check which files have been templated\nhelm template backend | grep \"# Source\" | sort\n...\n# Source: backend/charts/postgresql/templates/configmap.yaml\n# Source: backend/charts/postgresql/templates/initialization-configmap.yaml\n# Source: backend/charts/postgresql/templates/secrets.yaml\n# Source: backend/charts/postgresql/templates/statefulset.yaml\n# Source: backend/charts/postgresql/templates/svc-headless.yaml\n# Source: backend/charts/postgresql/templates/svc.yaml\n# Source: backend/templates/deployment.yaml\n# Source: backend/templates/secret.yaml\n# Source: backend/templates/serviceaccount.yaml\n# Source: backend/templates/service.yaml\n# Source: backend/templates/tests/test-connection.yaml\n...\n\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\nbackend\n```\n\n![](img/2020-10-01_13-24.png)\n\n```bash\n# template only file: \"backend/templates/service.yaml\"\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/service.yaml\nbackend\n\n\n# template only file: \"backend/templates/secret.yaml\"\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/secret.yaml\nbackend\n\n\n# template only file: \"backend/templates/deployment.yaml\"\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/deployment.yaml\nbackend\n\n\n# template only file: \"backend/templates/ingress.yaml\"\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/ingress.yaml\nbackend\n\n# template only file: \"backend/templates/ingress.yaml\"\nhelm template backend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only backend/templates/service.yaml\nbackend\n\n\n# Little nice feature to make your work more colorful\nhighlight -S yaml \u003c(helm template backend \\\n--show-only templates/ingress.yaml \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\nbackend)\n```\n\n**Check** for potential errors by running `helm lint \u003chelm chart-name\u003e`\n```bash\n# Check for potential errors\nhelm lint backend\n```\n\n\n\u003c!-- - [46. Creating frontend React app helm chart](#46-creating-frontend-react-app-helm-chart)--\u003e\n### 46. Creating frontend React app helm chart\n\n**Create** frontend helm chart\n```bash\n# Creating \"frontend\" helm chart\ncd frontend/hc\nhelm create frontend\n\ntree -L 2 frontend\nfrontend\n├── charts\n├── Chart.yaml\n├── templates\n│   ├── deployment.yaml\n│   ├── _helpers.tpl\n│   ├── hpa.yaml\n│   ├── ingress.yaml\n│   ├── NOTES.txt\n│   ├── serviceaccount.yaml\n│   ├── service.yaml\n│   └── tests\n└── values.yaml\n\n```\n\n**Files** to be modified (done by running four `sed commands`):\n* `frontend/Chart.yaml`\n* `frontend/values.yaml`\n* `frontend/templates/service.yaml`\n* `frontend/templates/deployment.yaml`\n\n**Adding custom description** and **appVersion** to Chart.yaml file\n```bash\n# Adding custom description to Chart.yaml file\nsed -E \\\n-e 's/^(description:).*/\\1 Frontend React app helm chart/' \\\n-e 's/^(appVersion:).*/\\1 v1.0.0 /' \\\n-i frontend/Chart.yaml\n```\n\n\n\u003c!-- - [47. Setup values yaml file for frontend helm chart](#47-setup-values-yaml-file-for-frontend-helm-chart)--\u003e\n### 47. Setup values yaml file for frontend helm chart\n\n**Setup** file: frontend/values.yaml within frontend helm chart\n```bash\n# Setting up \"frontend/values.yaml\" file\nsed -E \\\n-e '/^.*port:.*/a \\ \\ nodePort:' \\\n-e 's/^(.*paths:).*/\\1 [\"\\/app\"]/' \\\n-e '/^ingress.*/,/^\\s*tls:.*/s/^(.*-\\shost: )(.*)/\\1 k8s-ingress-name/' \\\n-e '/^.*pullPolicy:.*/a \\ \\ containerPort: 80' \\\n-e '$a \\\\nlivenessProbe: \\/app' \\\n-e '$a \\\\nreadinessProbe: \\/app' \\\n-e 's/^(.*repository:).*/\\1 devopsinuse\\/front-end/' \\\n-i frontend/values.yaml\n```\n\n\n\u003c!-- - [48. Setup service yaml file for frontend helm chart](#48-setup-service-yaml-file-for-frontend-helm-chart)--\u003e\n### 48. Setup service yaml file for frontend helm chart\n**Modifying** file: `frontend/templates/service.yaml`\n```bash\n# Setup \"containerPort\" in file: \"frontend/templates/service.yaml\" \nsed -E \\\n-e 's/^(.*targetPort:).*/\\1 {{ .Values.image.containerPort | default 80 }}/' \\\n-e '/^.*targetPort:.*/a \\ \\ \\ \\ {{- if (and (eq .Values.service.type \"NodePort\") (not (empty .Values.service.nodePort))) }}\\n      nodePort: {{ .Values.service.nodePort }}\\n    {{- end }}' \\\n-i frontend/templates/service.yaml\n```\n\n\n\u003c!-- - [49. Setup deployment yaml file for frontend helm chart](#49-setup-deployment-yaml-file-for-frontend-helm-chart)--\u003e\n### 49. Setup deployment yaml file for frontend helm chart\n\n**Setup** important **livenessProbe** and **readinessProbe** in file: `frontend/templates/deployment.yaml`\n```bash\n# Setup \"livenessProbe\" and \"readinessProbe\" in frontend/templates/deployment.yaml\nsed -E \\\n-e '/^\\s*livenessProbe:.*/,/^\\s*port:.*/s/^(.*port:)(.*)/\\1 {{ .Values.image.containerPort | default \"http\" }}/' \\\n-e '/^\\s*readinessProbe:.*/,/^\\s*port:.*/s/^(.*port:)(.*)/\\1 {{ .Values.image.containerPort | default \"http\" }}/' \\\n-e '/^\\s*livenessProbe:.*/,/^\\s*port:.*/s/^(.*path:)(.*)/\\1 {{ .Values.livenessProbe | default \"\\/\" }}/' \\\n-e '/^\\s*readinessProbe:.*/,/^\\s*port:.*/s/^(.*path:)(.*)/\\1 {{ .Values.readinessProbe | default \"\\/\" }}/' \\\n-e 's/^(.*containerPort:).*/\\1 {{ .Values.image.containerPort }}/' \\\n-i frontend/templates/deployment.yaml\n```\n\n\u003c!-- - [50. Learn how to template frontend helm chart](#50-learn-how-to-template-frontend-helm-chart)--\u003e\n### 50. Learn how to template frontend helm chart\n\n\n**Learn** how to template helm chart with colors\n```bash\n# Template your frontend helm chart\nhelm template frontend \n\n# Check which files have been templated\n...\nhelm template frontend --set ingress.enabled=true | grep \"# Source\" | sort\n# Source: frontend/templates/deployment.yaml\n# Source: frontend/templates/ingress.yaml\n# Source: frontend/templates/serviceaccount.yaml\n# Source: frontend/templates/service.yaml\n# Source: frontend/templates/tests/test-connection.yaml\n...\n```\n\nUse **helm template ...** command to template a particular file\n```bash\n# template only file: \"frontend/templates/service.yaml\"\nhelm template frontend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/service.yaml \\\nfrontend\n\n# template only file: \"frontend/templates/deployment.yaml\"\nhelm template frontend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/deployment.yaml \\\nfrontend\n\n\n# template only file: \"frontend/templates/ingress.yaml\"\nhelm template frontend \\\n--set service.type=NodePort  \\\n--set service.nodePort=30111 \\\n--set image.containerPort=8000 \\\n--set ingress.enabled=true \\\n--show-only templates/ingress.yaml \\\nfrontend\n```\n\n**Learn** how to template helm chart with colors\n```bash\n# Little nice feature to make your work more colorful\nhighlight -S yaml \u003c(helm \\\ntemplate frontend \\\n--show-only templates/deployment.yaml \\\n--set service.type=NodePort \\\n--set service.nodePort=30222 \\\n--set image.containerPort=87 \\\n--set ingress.enabled=true frontend)\n```\n**Check** for potential errors by running `helm lint \u003chelm chart-name\u003e`\n\n**Verify** that helm chart has no error\n```bash\n# Check for potential errors\nhelm lint frontend\n```\n\n\n\u003c!-- - [51. Deploy backend helm chart](#51-deploy-backend-helm-chart)--\u003e\n### 51. Deploy backend helm chart\n\n**Reminder** how to start AWS EKS cluster by terraform:\n\n* **git clone** https://github.com/xjantoth/aws-eks-devopsinuse.git\n\n* to **comment** terraform files (getting back to initial clear state). This helps to get the terraform code to the **state right after fresh** `git clone https://github.com/xjantoth/aws-eks-devopsinuse.git` command.\n  - `sed -i 's/^/#/' iam.tf outputs.tf sg.tf subnets.tf`  \n  - `sed -i '/^.*EKS_CLUSTER_START.*/,/^.*EKS_NODE_GROUP_END.*/s/^/#/' main.tf`\n\n\n* **uncomment** all files from `eks-terraform/` folder at once:\n  - `sed  's/^#//' -i iam.tf`\n  - `sed  's/^#//' -i sg.tf`\n  - `sed  's/^#//' -i subnets.tf`\n  - `sed 's/^#//' -i outputs.tf`\n  - `sed -e '/^.*EKS_CLUSTER_START.*/,/^.*EKS_CLUSTER_END.*/s/^#//' -i main.tf`\n  - `sed -e '/^.*EKS_NODE_GROUP_START.*/,/^.*EKS_NODE_GROUP_END.*/s/^#//' -i main.tf`\n  - variables.tf  (this file is uncommented all the time)\n  - outputs.tf    (does not **really** matter whether it's uncommented or not)\n\n**Notes**:\n```bash\necho \"\" \u003e ~/.kube/config \u0026\u0026 cat ~/.kube/config\ncd eks-terraform\nrm terraform.tfstate.backup terraform.tfstate .terraform -rf\nls  ~/.ssh/eks-aws.pub\nterraform init\nterraform validate\nterraform fmt -recursive\n```\n\n\n**Slightly modified** terrafrom code:\n\n```bash\ncat terraform.eks.tfvars\n\naws_region     = \"eu-central-1\"\naws_access_key = \"...\"\naws_secret_key = \"...\"\nssh_public_key = \"~/.ssh/eks-aws.pub\"\ncustom_tags = {\n  Name      = \"diu-eks-cluster-tag\"\n  Terraform = \"true\"\n  Delete    = \"true\"\n}\n\neks-cluster-name   = \"diu-eks-cluster\"\nkubernetes-version = \"1.16\"\n\ndesired_number_nodes = 8\nmax_number_nodes     = 9\nmin_number_nodes     = 1\n\ntcp_ports = [\"22\", \"30111\", \"30222\", \"30333\"]\n```\n\n**Bring** up your AWS EKS Kubernetes cluster (this will take about ~15min)\n\n```bash\nterraform apply -var-file terraform.eks.tfvars\n```\n\n\nUpdate **KUBECONFIG** once AWS EKS cluster is up and running\n```bash\naws eks --region eu-central-1 update-kubeconfig --name diu-eks-cluster --profile devopsinuse\n```\n\n\n**Deploy** backend helm chart to AWS EKS cluster\n\n```bash\n# Example how to deploy backend helm chart\nhelm install backend \\\n--set service.type=NodePort \\\n--set service.nodePort=30333 \\\n--set replicaCount=1  \\\n--set ingress.enabled=true \\\nbackend\n```\n\n**Retrive all kubernetes objects** created with backend deployment\n```bash\nkubectl get pods,svc,ing,deployment,rs,secret\n```\n\n**Retrive public** IP addresses of your Kubernetes nodes\n\n```bash\nkubectl get nodes -o wide | awk -F\" \" '{print $1\"\\t\"$7}'\n```\n**Call** \"Save IP address\" like button directly from command line **via Kubernetes Node Port 30333**\n```bash\ncurl -s -X POST http://11.22.33.44:30333/api/ipaddress | jq\n```\n\n**Get all IP addressess saved in database** directly **at port 30333**\n```bash\ncurl -s -X GET http://11.22.33.44:30333/api/ipaddress | jq\n```\n\n**Delete** a record from the **database via Kubernetes Node Port at port 30333**\n```bash\ncurl -s -X DELETE \"http://11.22.33.44:30333/api/ipaddress?id=7\" | jq\n```\n\n\n\u003c!-- - [52. Deploy your frontend helm chart](#52-deploy-your-frontend-helm-chart)--\u003e\n### 52. Deploy your frontend helm chart\n\n**Deploy** frontend helm chart to a Kubernetes cluster\n```bash\n# Example how to deploy ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxjantoth%2Faws-eks-devopsinuse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxjantoth%2Faws-eks-devopsinuse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxjantoth%2Faws-eks-devopsinuse/lists"}