From e615431af0fe883c05614a1debb996ee48c554e3 Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Sun, 23 Jun 2019 17:00:23 +0530 Subject: [PATCH 01/22] Initial eks cluster template --- aws-auth.yaml | 18 + aws-vpn-gtw.tf | 14 + backend.tf | 12 + .../cluster-autoscalar/ca-iam-policy.tf | 59 ++++ cluster-addons/cluster-autoscalar/eks-ca.yaml | 154 ++++++++ .../ingress-controller/private-ingress.yaml | 333 ++++++++++++++++++ .../ingress-controller/public-ingress.yaml | 332 +++++++++++++++++ cluster-addons/kube2iam/kube2iam.yaml | 76 ++++ .../aggregated-metrics-reader.yaml | 12 + .../metrics-server/auth-delegator.yaml | 13 + .../metrics-server/auth-reader.yaml | 14 + .../metrics-server/metrics-apiservice.yaml | 14 + .../metrics-server-deployment.yaml | 42 +++ .../metrics-server-service.yaml | 15 + .../metrics-server/resource-reader.yaml | 29 ++ eks-cluster.tf | 95 +++++ eks-worker-node.tf | 267 ++++++++++++++ frankfurt-eks-vpc.tf | 127 +++++++ iam.tf | 95 +++++ outputs.tf | 59 ++++ private-route.tf | 22 ++ providers.tf | 15 + terraform-aws-eks-cluster | 1 + variables.tf | 41 +++ vpc-peering.tf | 36 ++ 25 files changed, 1895 insertions(+) create mode 100755 aws-auth.yaml create mode 100755 aws-vpn-gtw.tf create mode 100644 backend.tf create mode 100755 cluster-addons/cluster-autoscalar/ca-iam-policy.tf create mode 100644 cluster-addons/cluster-autoscalar/eks-ca.yaml create mode 100755 cluster-addons/ingress-controller/private-ingress.yaml create mode 100755 cluster-addons/ingress-controller/public-ingress.yaml create mode 100644 cluster-addons/kube2iam/kube2iam.yaml create mode 100755 cluster-addons/metrics-server/aggregated-metrics-reader.yaml create mode 100755 cluster-addons/metrics-server/auth-delegator.yaml create mode 100755 cluster-addons/metrics-server/auth-reader.yaml create mode 100755 cluster-addons/metrics-server/metrics-apiservice.yaml create mode 100755 cluster-addons/metrics-server/metrics-server-deployment.yaml create mode 100755 cluster-addons/metrics-server/metrics-server-service.yaml create mode 100755 cluster-addons/metrics-server/resource-reader.yaml create mode 100755 eks-cluster.tf create mode 100755 eks-worker-node.tf create mode 100755 frankfurt-eks-vpc.tf create mode 100644 iam.tf create mode 100755 outputs.tf create mode 100644 private-route.tf create mode 100755 providers.tf create mode 160000 terraform-aws-eks-cluster create mode 100644 variables.tf create mode 100644 vpc-peering.tf diff --git a/aws-auth.yaml b/aws-auth.yaml new file mode 100755 index 0000000..f013a4b --- /dev/null +++ b/aws-auth.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: aws-auth + namespace: kube-system +data: + mapRoles: | + - rolearn: arn:aws:iam::230367374156:role/terraform-eks-frankfurt-node + username: system:node:{{EC2PrivateDNSName}} + groups: + - system:bootstrappers + - system:nodes + + mapUsers: | + - userarn: arn:aws:iam::230367374156:user/eksuser + username: eksuser + groups: + - system:masters diff --git a/aws-vpn-gtw.tf b/aws-vpn-gtw.tf new file mode 100755 index 0000000..4c8a021 --- /dev/null +++ b/aws-vpn-gtw.tf @@ -0,0 +1,14 @@ +# create aws vpn gateway for EKS VPC Frankfurt +resource "aws_vpn_gateway" "vpn_gw" { + vpc_id = "${aws_vpc.frankfurt.id}" + + tags = "${ + map( + "Name", "eks aws vpn gateway frankfurt", + "OWNER", "Devops", + "TEAM", "Devops", + "ENVIRONMENT", "PROD", + "PRODUCT", "EKS", + ) + }" +} diff --git a/backend.tf b/backend.tf new file mode 100644 index 0000000..3f5a9be --- /dev/null +++ b/backend.tf @@ -0,0 +1,12 @@ +## A "backend" in Terraform determines how state is loaded. Its completely optional but recommended. +## Terraform remote state management - visit https://www.terraform.io/docs/backends/index.html +## eks-frankfurt is the folder inside the bucket that you are going to choose to store terraform state files. +## make sure you create it in advance. + +terraform { + backend "s3" { + bucket = "{var.s3_bucket_name}" + key = "eks-frankfurt/terraform.tfstate" + region = "us-east-1" + } +} diff --git a/cluster-addons/cluster-autoscalar/ca-iam-policy.tf b/cluster-addons/cluster-autoscalar/ca-iam-policy.tf new file mode 100755 index 0000000..9018940 --- /dev/null +++ b/cluster-addons/cluster-autoscalar/ca-iam-policy.tf @@ -0,0 +1,59 @@ +resource "aws_iam_role_policy" "frankfurt_ca_policy" { + name = "frankfurt_ca_policy" + role = "${aws_iam_role.frankfurt_ca_role.id}" + + policy = <-" + # Here: "-" + # This has to be adapted if you change either parameter + # when launching the nginx-ingress-controller. + - "ingress-controller-leader-nginx" + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: nginx-eksprivate-role-nisa-binding + namespace: ingress-eksprivate-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: nginx-eksprivate-role +subjects: + - kind: ServiceAccount + name: nginx-eksprivate-serviceaccount + namespace: ingress-eksprivate-nginx + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: nginx-eksprivate-clusterrole-nisa-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nginx-eksprivate-clusterrole +subjects: + - kind: ServiceAccount + name: nginx-eksprivate-serviceaccount + namespace: ingress-eksprivate-nginx +--- + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: default-eks-http-backend + labels: + app: default-eks-http-backend + namespace: ingress-eksprivate-nginx +spec: + replicas: 2 + selector: + matchLabels: + app: default-eks-http-backend + template: + metadata: + labels: + app: default-eks-http-backend + spec: + terminationGracePeriodSeconds: 60 + containers: + - name: default-eks-http-backend + # Any image is permissible as long as: + # 1. It serves a 404 page at / + # 2. It serves 200 on a /healthz endpoint + image: gcr.io/google_containers/defaultbackend:1.4 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: 30 + timeoutSeconds: 5 + ports: + - containerPort: 8080 + resources: + limits: + cpu: 10m + memory: 20Mi + requests: + cpu: 10m + memory: 20Mi +--- + +apiVersion: v1 +kind: Service +metadata: + name: default-eks-http-backend + namespace: ingress-eksprivate-nginx + labels: + app: default-eks-http-backend +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + app: default-eks-http-backend + +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-eksprivate-controller + namespace: ingress-eksprivate-nginx +spec: + replicas: 2 + selector: + matchLabels: + app: ingress-eksprivate-nginx + template: + metadata: + labels: + app: ingress-eksprivate-nginx + annotations: + prometheus.io/port: '10254' + prometheus.io/scrape: 'true' + spec: + serviceAccountName: nginx-eksprivate-serviceaccount + containers: + - name: nginx-ingress-controller + image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1 + args: + - /nginx-ingress-controller + - --default-backend-service=$(POD_NAMESPACE)/default-eks-http-backend + - --configmap=$(POD_NAMESPACE)/nginx-configuration + - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services + - --udp-services-configmap=$(POD_NAMESPACE)/udp-services + - --publish-service=$(POD_NAMESPACE)/ingress-eksprivate-nginx + - --annotations-prefix=nginx.ingress.kubernetes.io + - --ingress-class=private-nginx + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - name: http + containerPort: 80 + - name: https + containerPort: 443 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + runAsNonRoot: false +--- +kind: Service +apiVersion: v1 +metadata: + name: ingress-eksprivate-nginx + namespace: ingress-eksprivate-nginx + labels: + app: ingress-eksprivate-nginx + annotations: + # Specifies whether cross-zone load balancing is enabled for the load balancer + service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" + # Expose this as internal load balancer + service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" + # replace with the correct value of the generated certificate in the AWS console Mediaiqdigital.com + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:eu-central-1:230367374156:certificate/d5ea0711-b37c-49de-a407-f5857f09d229" + # the backend instances are HTTP + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" + # Map port 443 + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https" + # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. + service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' + # tags for ELB + service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "Name=frankfurt-private-ingess-controller,TEAM=Devops,PRODUCT=EKS,ENVIRONMENT=PRODUCTION" + # health check interval + service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: '5' + # ELB time out + service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: '3' + # health check unhealthy threshold + service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: '2' + # healthy threshold + service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: '2' + # connection draining + service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" + +spec: + type: LoadBalancer + selector: + app: ingress-eksprivate-nginx + ports: + - name: http + port: 80 + targetPort: http + - name: https + port: 443 + targetPort: http diff --git a/cluster-addons/ingress-controller/public-ingress.yaml b/cluster-addons/ingress-controller/public-ingress.yaml new file mode 100755 index 0000000..5d52609 --- /dev/null +++ b/cluster-addons/ingress-controller/public-ingress.yaml @@ -0,0 +1,332 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ingress-ekspublic-nginx +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: nginx-configuration + namespace: ingress-ekspublic-nginx + labels: + app: ingress-ekspublic-nginx +--- + +kind: ConfigMap +apiVersion: v1 +metadata: + name: tcp-services + namespace: ingress-ekspublic-nginx +--- + +kind: ConfigMap +apiVersion: v1 +metadata: + name: udp-services + namespace: ingress-ekspublic-nginx +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nginx-ekspublic-serviceaccount + namespace: ingress-ekspublic-nginx + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: nginx-ekspublic-clusterrole +rules: + - apiGroups: + - "" + resources: + - configmaps + - endpoints + - nodes + - pods + - secrets + verbs: + - list + - watch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch + - apiGroups: + - "extensions" + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - apiGroups: + - "extensions" + resources: + - ingresses/status + verbs: + - update + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: nginx-ekspublic-role + namespace: ingress-ekspublic-nginx +rules: + - apiGroups: + - "" + resources: + - configmaps + - pods + - secrets + - namespaces + verbs: + - get + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + # Defaults to "-" + # Here: "-" + # This has to be adapted if you change either parameter + # when launching the nginx-ingress-controller. + - "ingress-controller-leader-nginx" + verbs: + - get + - update + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: nginx-ekspublic-role-nisa-binding + namespace: ingress-ekspublic-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: nginx-ekspublic-role +subjects: + - kind: ServiceAccount + name: nginx-ekspublic-serviceaccount + namespace: ingress-ekspublic-nginx + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: nginx-ekspublic-clusterrole-nisa-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nginx-ekspublic-clusterrole +subjects: + - kind: ServiceAccount + name: nginx-ekspublic-serviceaccount + namespace: ingress-ekspublic-nginx +--- + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: default-eks-http-backend + labels: + app: default-eks-http-backend + namespace: ingress-ekspublic-nginx +spec: + replicas: 2 + selector: + matchLabels: + app: default-eks-http-backend + template: + metadata: + labels: + app: default-eks-http-backend + spec: + terminationGracePeriodSeconds: 60 + containers: + - name: default-eks-http-backend + # Any image is permissible as long as: + # 1. It serves a 404 page at / + # 2. It serves 200 on a /healthz endpoint + image: gcr.io/google_containers/defaultbackend:1.4 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: 30 + timeoutSeconds: 5 + ports: + - containerPort: 8080 + resources: + limits: + cpu: 10m + memory: 20Mi + requests: + cpu: 10m + memory: 20Mi +--- + +apiVersion: v1 +kind: Service +metadata: + name: default-eks-http-backend + namespace: ingress-ekspublic-nginx + labels: + app: default-eks-http-backend +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + app: default-eks-http-backend + +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-ekspublic-controller + namespace: ingress-ekspublic-nginx +spec: + replicas: 2 + selector: + matchLabels: + app: ingress-ekspublic-nginx + template: + metadata: + labels: + app: ingress-ekspublic-nginx + annotations: + prometheus.io/port: '10254' + prometheus.io/scrape: 'true' + spec: + serviceAccountName: nginx-ekspublic-serviceaccount + containers: + - name: nginx-ingress-controller + image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1 + args: + - /nginx-ingress-controller + - --default-backend-service=$(POD_NAMESPACE)/default-eks-http-backend + - --configmap=$(POD_NAMESPACE)/nginx-configuration + - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services + - --udp-services-configmap=$(POD_NAMESPACE)/udp-services + - --publish-service=$(POD_NAMESPACE)/ingress-ekspublic-nginx + - --annotations-prefix=nginx.ingress.kubernetes.io + - --ingress-class=public-nginx + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - name: http + containerPort: 80 + - name: https + containerPort: 443 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + runAsNonRoot: false +--- +kind: Service +apiVersion: v1 +metadata: + name: ingress-ekspublic-nginx + namespace: ingress-ekspublic-nginx + labels: + app: ingress-ekspublic-nginx + annotations: + # Specifies whether cross-zone load balancing is enabled for the load balancer + service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" + # Expose this as internal load balancer + # service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" + # replace with the correct value of the generated certificate in the AWS console Mediaiqdigital.com + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:eu-central-1:230367374156:certificate/d5ea0711-b37c-49de-a407-f5857f09d229" + # the backend instances are HTTP + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" + # Map port 443 + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https" + # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. + service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' + # tags for ELB + service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "Name=eks-public-ingress-controller,TEAM=Devops,PRODUCT=EKS,ENVRIONMENT=PRODUCTION" + # health check interval + service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: '5' + # ELB time out + service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: '3' + # health check unhealthy threshold + service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: '2' + # healthy threshold + service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: '2' + # connection draining + service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" + +spec: + type: LoadBalancer + selector: + app: ingress-ekspublic-nginx + ports: + - name: http + port: 80 + targetPort: http + - name: https + port: 443 + targetPort: http diff --git a/cluster-addons/kube2iam/kube2iam.yaml b/cluster-addons/kube2iam/kube2iam.yaml new file mode 100644 index 0000000..fdaef81 --- /dev/null +++ b/cluster-addons/kube2iam/kube2iam.yaml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube2iam + namespace: kube-system +--- +apiVersion: v1 +items: + - apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: kube2iam + rules: + - apiGroups: [""] + resources: ["namespaces","pods"] + verbs: ["get","watch","list"] + - apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: kube2iam + subjects: + - kind: ServiceAccount + name: kube2iam + namespace: kube-system + roleRef: + kind: ClusterRole + name: kube2iam + apiGroup: rbac.authorization.k8s.io +kind: List +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube2iam + namespace: kube-system + labels: + app: kube2iam +spec: + selector: + matchLabels: + name: kube2iam + template: + metadata: + labels: + name: kube2iam + spec: + serviceAccountName: kube2iam + hostNetwork: true + containers: + - image: jtblin/kube2iam:latest # instead of latest use 0.10.4 to fix iam cred 500 error + imagePullPolicy: Always + name: kube2iam + args: + - "--auto-discover-base-arn" + - "--auto-discover-default-role=true" + - "--iptables=true" + - "--host-ip=$(HOST_IP)" + - "--node=$(NODE_NAME)" + - "--host-interface=eni+" + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 8181 + hostPort: 8181 + name: http + securityContext: + privileged: true + tolerations: + - operator: Exists diff --git a/cluster-addons/metrics-server/aggregated-metrics-reader.yaml b/cluster-addons/metrics-server/aggregated-metrics-reader.yaml new file mode 100755 index 0000000..cdf3415 --- /dev/null +++ b/cluster-addons/metrics-server/aggregated-metrics-reader.yaml @@ -0,0 +1,12 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:aggregated-metrics-reader + labels: + rbac.authorization.k8s.io/aggregate-to-view: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: +- apiGroups: ["metrics.k8s.io"] + resources: ["pods"] + verbs: ["get", "list", "watch"] diff --git a/cluster-addons/metrics-server/auth-delegator.yaml b/cluster-addons/metrics-server/auth-delegator.yaml new file mode 100755 index 0000000..e3442c5 --- /dev/null +++ b/cluster-addons/metrics-server/auth-delegator.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: metrics-server:system:auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: metrics-server + namespace: kube-system diff --git a/cluster-addons/metrics-server/auth-reader.yaml b/cluster-addons/metrics-server/auth-reader.yaml new file mode 100755 index 0000000..f0616e1 --- /dev/null +++ b/cluster-addons/metrics-server/auth-reader.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: metrics-server-auth-reader + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: metrics-server + namespace: kube-system diff --git a/cluster-addons/metrics-server/metrics-apiservice.yaml b/cluster-addons/metrics-server/metrics-apiservice.yaml new file mode 100755 index 0000000..08b0530 --- /dev/null +++ b/cluster-addons/metrics-server/metrics-apiservice.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: apiregistration.k8s.io/v1beta1 +kind: APIService +metadata: + name: v1beta1.metrics.k8s.io +spec: + service: + name: metrics-server + namespace: kube-system + group: metrics.k8s.io + version: v1beta1 + insecureSkipTLSVerify: true + groupPriorityMinimum: 100 + versionPriority: 100 diff --git a/cluster-addons/metrics-server/metrics-server-deployment.yaml b/cluster-addons/metrics-server/metrics-server-deployment.yaml new file mode 100755 index 0000000..3c98cfa --- /dev/null +++ b/cluster-addons/metrics-server/metrics-server-deployment.yaml @@ -0,0 +1,42 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: metrics-server + namespace: kube-system +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: metrics-server + namespace: kube-system + labels: + k8s-app: metrics-server +spec: + selector: + matchLabels: + k8s-app: metrics-server + template: + metadata: + name: metrics-server + labels: + k8s-app: metrics-server + spec: + serviceAccountName: metrics-server + volumes: + # mount in tmp so we can safely use from-scratch images and/or read-only containers + - name: tmp-dir + emptyDir: {} + containers: + - name: metrics-server + image: k8s.gcr.io/metrics-server-amd64:v0.3.1 + imagePullPolicy: Always + command: + - /metrics-server + - --metric-resolution=30s + - --kubelet-insecure-tls + - --kubelet-preferred-address-types=InternalIP + volumeMounts: + - name: tmp-dir + mountPath: /tmp + diff --git a/cluster-addons/metrics-server/metrics-server-service.yaml b/cluster-addons/metrics-server/metrics-server-service.yaml new file mode 100755 index 0000000..082b00c --- /dev/null +++ b/cluster-addons/metrics-server/metrics-server-service.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: metrics-server + namespace: kube-system + labels: + kubernetes.io/name: "Metrics-server" +spec: + selector: + k8s-app: metrics-server + ports: + - port: 443 + protocol: TCP + targetPort: 443 diff --git a/cluster-addons/metrics-server/resource-reader.yaml b/cluster-addons/metrics-server/resource-reader.yaml new file mode 100755 index 0000000..574efc5 --- /dev/null +++ b/cluster-addons/metrics-server/resource-reader.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: system:metrics-server +rules: +- apiGroups: + - "*" + resources: + - pods + - nodes + - nodes/stats + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: system:metrics-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:metrics-server +subjects: +- kind: ServiceAccount + name: metrics-server + namespace: kube-system diff --git a/eks-cluster.tf b/eks-cluster.tf new file mode 100755 index 0000000..d9b7f4c --- /dev/null +++ b/eks-cluster.tf @@ -0,0 +1,95 @@ +# +# EKS Cluster Resources +# * IAM Role to allow EKS service to manage other AWS services +# * EC2 Security Group to allow networking traffic with EKS cluster +# * EKS Cluster +# + +resource "aws_iam_role" "frankfurt-cluster" { + name = "terraform-eks-frankfurt-cluster" + + assume_role_policy = < /tmp/mycrontab.txt +crontab -u ec2-user /tmp/mycrontab.txt + +sudo /etc/eks/bootstrap.sh --apiserver-endpoint '${aws_eks_cluster.frankfurt.endpoint}' --b64-cluster-ca '${aws_eks_cluster.frankfurt.certificate_authority.0.data}' '${var.cluster-name}' + +USERDATA +} + +resource "aws_launch_configuration" "frankfurt-private" { + iam_instance_profile = "${aws_iam_instance_profile.frankfurt-node.name}" + image_id = "ami-0c2709025eb548246" # eu-central-1 version 1.11.8 + instance_type = "r5.xlarge" + key_name = "rancher" + name_prefix = "terraform-eks-frankfurt-private" + security_groups = ["${aws_security_group.frankfurt-node.id}"] + user_data_base64 = "${base64encode(local.frankfurt-node-private-userdata)}" + + root_block_device { + delete_on_termination = true + volume_size = 200 + volume_type = "gp2" + } + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_autoscaling_group" "frankfurt-private" { + desired_capacity = 1 + launch_configuration = "${aws_launch_configuration.frankfurt-private.id}" + max_size = 5 + min_size = 1 + name = "terraform-eks-frankfurt-private" + vpc_zone_identifier = ["${aws_subnet.frankfurt-private.*.id}"] + + tag { + key = "Name" + value = "eks-worker-private-node" + propagate_at_launch = true + } + + tag { + key = "kubernetes.io/cluster/${var.cluster-name}" + value = "owned" + propagate_at_launch = true + } + + tag { + key = "k8s.io/cluster-autoscaler/enabled" + value = "" + propagate_at_launch = true + } + + tag { + key = "k8s.io/cluster-autoscaler/${var.cluster-name}" + value = "" + propagate_at_launch = true + } + + tag { + key = "TEAM" + value = "Devops" + propagate_at_launch = true + } + + tag { + key = "OWNER" + value = "Devops" + propagate_at_launch = true + } + + tag { + key = "PRODUCT" + value = "EKS" + propagate_at_launch = true + } + + tag { + key = "ENVIRONMENT" + value = "PROD" + propagate_at_launch = true + } + +} + + +# Adding EKS workers scaling policy for scale up/down +# Creating Cloudwatch alarms for both scale up/down + +resource "aws_autoscaling_policy" "eks-cpu-policy-private" { + name = "eks-cpu-policy-private" + autoscaling_group_name = "${aws_autoscaling_group.frankfurt-private.name}" + adjustment_type = "ChangeInCapacity" + scaling_adjustment = "1" + cooldown = "300" + policy_type = "SimpleScaling" +} + +# scaling up cloudwatch metric +resource "aws_cloudwatch_metric_alarm" "eks-cpu-alarm-private" { + alarm_name = "eks-cpu-alarm-private" + alarm_description = "eks-cpu-alarm-private" + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluation_periods = "2" + metric_name = "CPUUtilization" + namespace = "AWS/EC2" + period = "120" + statistic = "Average" + threshold = "80" + +dimensions = { + "AutoScalingGroupName" = "${aws_autoscaling_group.frankfurt-private.name}" +} + actions_enabled = true + alarm_actions = ["${aws_autoscaling_policy.eks-cpu-policy-private.arn}"] +} + +# scale down policy +resource "aws_autoscaling_policy" "eks-cpu-policy-scaledown-private" { + name = "eks-cpu-policy-scaledown-private" + autoscaling_group_name = "${aws_autoscaling_group.frankfurt-private.name}" + adjustment_type = "ChangeInCapacity" + scaling_adjustment = "-1" + cooldown = "300" + policy_type = "SimpleScaling" +} + +# scale down cloudwatch metric +resource "aws_cloudwatch_metric_alarm" "eks-cpu-alarm-scaledown-private" { + alarm_name = "eks-cpu-alarm-scaledown-private" + alarm_description = "eks-cpu-alarm-scaledown-private" + comparison_operator = "LessThanOrEqualToThreshold" + evaluation_periods = "2" + metric_name = "CPUUtilization" + namespace = "AWS/EC2" + period = "120" + statistic = "Average" + threshold = "5" + +dimensions = { + "AutoScalingGroupName" = "${aws_autoscaling_group.frankfurt-private.name}" +} + actions_enabled = true + alarm_actions = ["${aws_autoscaling_policy.eks-cpu-policy-scaledown-private.arn}"] +} + + +#### +#### Memory based scaling alarm and scaling policies +#### + +## scale up policy for eks node memory usage. +resource "aws_autoscaling_policy" "eks-mem-policy-private" { + name = "eks-mem-policy-private" + autoscaling_group_name = "${aws_autoscaling_group.frankfurt-private.name}" + adjustment_type = "ChangeInCapacity" + scaling_adjustment = "1" + cooldown = "300" + policy_type = "SimpleScaling" +} + +## Cloudwatch alarm for avg memory utlization +resource "aws_cloudwatch_metric_alarm" "eks-mem-alarm-private" { + alarm_name = "eks-mem-alarm-private" + alarm_description = "eks-mem-alarm-private" + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluation_periods = "5" + metric_name = "MemoryUtilization" + namespace = "System/Linux" + period = "60" + statistic = "Average" + threshold = "80" + +dimensions = { + "AutoScalingGroupName" = "${aws_autoscaling_group.frankfurt-private.name}" +} + actions_enabled = true + alarm_actions = ["${aws_autoscaling_policy.eks-mem-policy-private.arn}"] +} diff --git a/frankfurt-eks-vpc.tf b/frankfurt-eks-vpc.tf new file mode 100755 index 0000000..0fa1357 --- /dev/null +++ b/frankfurt-eks-vpc.tf @@ -0,0 +1,127 @@ +# +# EKS VPC Resources +# * VPC +# * Subnets +# * Internet Gateway +# * Route Table +# + +resource "aws_vpc" "frankfurt" { + cidr_block = "10.15.0.0/19" + enable_dns_hostnames = true + + tags = "${ + map( + "Name", "frankfurt-eks-vpc", + "kubernetes.io/cluster/${var.cluster-name}", "shared", + ) + }" +} + +## EKS public subnets +resource "aws_subnet" "frankfurt" { + count = "${length(var.public_subnets)}" + + availability_zone = "${data.aws_availability_zones.available.names[count.index]}" + cidr_block = "${var.public_subnets[count.index]}" + vpc_id = "${aws_vpc.frankfurt.id}" + + tags = "${ + map( + "Name", "frankfurt-eks-public-subnet", + "kubernetes.io/cluster/${var.cluster-name}", "shared", + ) + }" +} + + +## internet gateway +resource "aws_internet_gateway" "frankfurt" { + vpc_id = "${aws_vpc.frankfurt.id}" + + tags { + Name = "frankfurt-eks-frankfurt" + } +} + +resource "aws_route_table" "frankfurt" { + vpc_id = "${aws_vpc.frankfurt.id}" + + route { + cidr_block = "0.0.0.0/0" + gateway_id = "${aws_internet_gateway.frankfurt.id}" + } + +## route for vpc peering with prod vpc. ## +# route { +# cidr_block = "${var.prodvpc-cidr-block}" # variables.tf +# vpc_peering_connection_id = "${aws_vpc_peering_connection.eks2prodvpc.id}" +# } +# + +} + +resource "aws_route_table_association" "frankfurt" { + count = "${length(var.public_subnets)}" + + subnet_id = "${aws_subnet.frankfurt.*.id[count.index]}" + route_table_id = "${aws_route_table.frankfurt.id}" +} + +## EKS private subnets +## NAT gateway +## routing table, routing table association + +resource "aws_subnet" "frankfurt-private" { + count = "${length(var.private_subnets)}" + + availability_zone = "${data.aws_availability_zones.available.names[count.index]}" + cidr_block = "${var.private_subnets[count.index]}" + vpc_id = "${aws_vpc.frankfurt.id}" + + tags = "${ + map( + "Name", "frankfurt-eks-private-subnet", + "kubernetes.io/cluster/${var.cluster-name}", "shared", + "kubernetes.io/role/internal-elb", "1", + "TEAM", "Devops", + "PRODUCT", "EKS", + + ) + }" +} + +resource "aws_eip" "nat" { + vpc = true +} + +resource "aws_nat_gateway" "gw" { + count = 1 + + allocation_id = "${aws_eip.nat.id}" + subnet_id = "${aws_subnet.frankfurt.*.id[count.index]}" #public subnet + depends_on = ["aws_internet_gateway.frankfurt"] + + tags { + Name = "gw NAT" + } +} + + +resource "aws_route_table" "frankfurt-private" { + vpc_id = "${aws_vpc.frankfurt.id}" + + tags { + Name = "route table for private subnets", + TEAM = "Devops", + PRODUCT = "EKS", + ENVIRONMENT = "PROD", + } +} + +resource "aws_route_table_association" "frankfurt-private" { + count = "${length(var.private_subnets)}" + + subnet_id = "${aws_subnet.frankfurt-private.*.id[count.index]}" + route_table_id = "${aws_route_table.frankfurt-private.id}" +} diff --git a/iam.tf b/iam.tf new file mode 100644 index 0000000..7a7d141 --- /dev/null +++ b/iam.tf @@ -0,0 +1,95 @@ +# EKS currently documents this required userdata for EKS worker nodes to +# properly configure Kubernetes applications on the EC2 instance. +# We utilize a Terraform local here to simplify Base64 encoding this +# information into the AutoScaling Launch Configuration. +# More information: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/amazon-eks-nodegroup.yaml + +## updated AMI support for /etc/eks/bootstrap.sh +## + +resource "aws_iam_role" "frankfurt-node" { + name = "terraform-eks-frankfurt-node" + + assume_role_policy = < Date: Mon, 24 Jun 2019 15:08:59 +0530 Subject: [PATCH 02/22] added architecture PNG --- aws-vpn-gtw.tf | 6 +--- backend.tf | 14 ++++----- eks-cluster.tf | 7 ++--- eks-github.png | Bin 0 -> 67254 bytes eks-worker-node.tf | 73 ++++++++++++------------------------------- frankfurt-eks-vpc.tf | 15 +-------- variables.tf | 11 ++++++- 7 files changed, 41 insertions(+), 85 deletions(-) create mode 100644 eks-github.png diff --git a/aws-vpn-gtw.tf b/aws-vpn-gtw.tf index 4c8a021..008ec7c 100755 --- a/aws-vpn-gtw.tf +++ b/aws-vpn-gtw.tf @@ -4,11 +4,7 @@ resource "aws_vpn_gateway" "vpn_gw" { tags = "${ map( - "Name", "eks aws vpn gateway frankfurt", - "OWNER", "Devops", - "TEAM", "Devops", - "ENVIRONMENT", "PROD", - "PRODUCT", "EKS", + "Name", "eks aws vpn gateway frankfurt" ) }" } diff --git a/backend.tf b/backend.tf index 3f5a9be..7c08188 100644 --- a/backend.tf +++ b/backend.tf @@ -3,10 +3,10 @@ ## eks-frankfurt is the folder inside the bucket that you are going to choose to store terraform state files. ## make sure you create it in advance. -terraform { - backend "s3" { - bucket = "{var.s3_bucket_name}" - key = "eks-frankfurt/terraform.tfstate" - region = "us-east-1" - } -} +#terraform { +# backend "s3" { +# bucket = "{var.s3_bucket_name}" +# key = "eks-frankfurt/terraform.tfstate" +# region = "us-east-1" +# } +#} diff --git a/eks-cluster.tf b/eks-cluster.tf index d9b7f4c..7ba86a5 100755 --- a/eks-cluster.tf +++ b/eks-cluster.tf @@ -48,10 +48,7 @@ resource "aws_security_group" "frankfurt-cluster" { tags = "${ map( - "Name", "terraform-eks-frankfurt", - "OWNER", "Devops", - "PRODUCT", "EKS", - "TEAM", "Devops", + "Name", "terraform-eks-frankfurt" ) }" } @@ -81,7 +78,7 @@ resource "aws_eks_cluster" "frankfurt" { name = "${var.cluster-name}" role_arn = "${aws_iam_role.frankfurt-cluster.arn}" version = "${var.eks_version}" - enabled_cluster_log_types = ["api", "audit", "scheduler", "controllerManager"] + # enabled_cluster_log_types = ["api", "audit", "scheduler", "controllerManager"] vpc_config { security_group_ids = ["${aws_security_group.frankfurt-cluster.id}"] diff --git a/eks-github.png b/eks-github.png new file mode 100644 index 0000000000000000000000000000000000000000..4396ce34be3455623db854dcfa530e06a73700d4 GIT binary patch literal 67254 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 /tmp/mycrontab.txt -crontab -u ec2-user /tmp/mycrontab.txt - sudo /etc/eks/bootstrap.sh --apiserver-endpoint '${aws_eks_cluster.frankfurt.endpoint}' --b64-cluster-ca '${aws_eks_cluster.frankfurt.certificate_authority.0.data}' '${var.cluster-name}' USERDATA @@ -95,8 +83,8 @@ USERDATA resource "aws_launch_configuration" "frankfurt-private" { iam_instance_profile = "${aws_iam_instance_profile.frankfurt-node.name}" - image_id = "ami-0c2709025eb548246" # eu-central-1 version 1.11.8 - instance_type = "r5.xlarge" + image_id = "${var.eks-worker-ami}" ## visit https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html + instance_type = "${var.worker-node-instance_type}" # use instance variable key_name = "rancher" name_prefix = "terraform-eks-frankfurt-private" security_groups = ["${aws_security_group.frankfurt-node.id}"] @@ -104,7 +92,7 @@ resource "aws_launch_configuration" "frankfurt-private" { root_block_device { delete_on_termination = true - volume_size = 200 + volume_size = 50 volume_type = "gp2" } @@ -116,7 +104,7 @@ resource "aws_launch_configuration" "frankfurt-private" { resource "aws_autoscaling_group" "frankfurt-private" { desired_capacity = 1 launch_configuration = "${aws_launch_configuration.frankfurt-private.id}" - max_size = 5 + max_size = 2 min_size = 1 name = "terraform-eks-frankfurt-private" vpc_zone_identifier = ["${aws_subnet.frankfurt-private.*.id}"] @@ -132,42 +120,21 @@ resource "aws_autoscaling_group" "frankfurt-private" { value = "owned" propagate_at_launch = true } - - tag { - key = "k8s.io/cluster-autoscaler/enabled" - value = "" - propagate_at_launch = true - } - tag { - key = "k8s.io/cluster-autoscaler/${var.cluster-name}" - value = "" - propagate_at_launch = true - } - - tag { - key = "TEAM" - value = "Devops" - propagate_at_launch = true - } - - tag { - key = "OWNER" - value = "Devops" - propagate_at_launch = true - } - - tag { - key = "PRODUCT" - value = "EKS" - propagate_at_launch = true - } - - tag { - key = "ENVIRONMENT" - value = "PROD" - propagate_at_launch = true - } +## Enable this when you use cluster autoscaler within cluster. +## https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md + +# tag { +# key = "k8s.io/cluster-autoscaler/enabled" +# value = "" +# propagate_at_launch = true +# } +# +# tag { +# key = "k8s.io/cluster-autoscaler/${var.cluster-name}" +# value = "" +# propagate_at_launch = true +# } } diff --git a/frankfurt-eks-vpc.tf b/frankfurt-eks-vpc.tf index 0fa1357..cebc896 100755 --- a/frankfurt-eks-vpc.tf +++ b/frankfurt-eks-vpc.tf @@ -52,13 +52,6 @@ resource "aws_route_table" "frankfurt" { gateway_id = "${aws_internet_gateway.frankfurt.id}" } -## route for vpc peering with prod vpc. ## -# route { -# cidr_block = "${var.prodvpc-cidr-block}" # variables.tf -# vpc_peering_connection_id = "${aws_vpc_peering_connection.eks2prodvpc.id}" -# } -# - } resource "aws_route_table_association" "frankfurt" { @@ -83,10 +76,7 @@ resource "aws_subnet" "frankfurt-private" { map( "Name", "frankfurt-eks-private-subnet", "kubernetes.io/cluster/${var.cluster-name}", "shared", - "kubernetes.io/role/internal-elb", "1", - "TEAM", "Devops", - "PRODUCT", "EKS", - + "kubernetes.io/role/internal-elb", "1", ) }" } @@ -113,9 +103,6 @@ resource "aws_route_table" "frankfurt-private" { tags { Name = "route table for private subnets", - TEAM = "Devops", - PRODUCT = "EKS", - ENVIRONMENT = "PROD", } } diff --git a/variables.tf b/variables.tf index 496a7e9..d6a01d9 100644 --- a/variables.tf +++ b/variables.tf @@ -1,8 +1,17 @@ variable "cluster-name" { - default = "eks-frankfurt" + description = "Enter eks cluster name - example like eks-frankfurt" type = "string" } +variable "eks-worker-ami" { + default = "ami-02d5e7ca7bc498ef9" + description = "eks worker node ami for eks cluster 1.13 - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html" +} + +variable "worker-node-instance_type" { + description = "enter worker node instance type" +} + variable "public_subnets" { type = "list" default = ["10.15.0.0/22", "10.15.4.0/22", "10.15.8.0/22"] From a3ead4b768d458125881ba366299915fc2faaf23 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Mon, 24 Jun 2019 15:28:03 +0530 Subject: [PATCH 03/22] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index eab2718..9d140f2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # terraform-aws-eks-cluster This repository showcases the terraform we use to setup EKS cluster on AWS. + +# AWS EKS Architecture +![eks-architecture](https://user-images.githubusercontent.com/38158144/60009869-4052b880-9694-11e9-9580-bb76e6730503.png) From 13177670994f92cf9c2a90b9a994c702cf04bd64 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Mon, 24 Jun 2019 16:16:12 +0530 Subject: [PATCH 04/22] Update README.md --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d140f2..eee0a23 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,72 @@ -# terraform-aws-eks-cluster -This repository showcases the terraform we use to setup EKS cluster on AWS. +# Terraform-aws-eks-cluster +This repository showcases the terraform template that we use to setup our production ready EKS cluster on AWS. If you are looking to use EKS cluster on AWS then chances are high that you are already be having some sort of infrastructure on AWS and eventually be using VPC to create resources in. + +We have designed this template considering you have existing VPC `PRODVPC`. This `terraform` template creates new VPC for EKS cluster also lets you peer your existing VPC. This is done as a recommendatation and best practices suited for isolation. # AWS EKS Architecture ![eks-architecture](https://user-images.githubusercontent.com/38158144/60009869-4052b880-9694-11e9-9580-bb76e6730503.png) + +**Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. AWS resources that are created by this template listed below. + +- Creates a new VPC with CIDR Block - 10.15.0.0/19 in Frankfurt region. +- Creates 3 public & 3 private subnets with each size of 4056 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c) +- Creates recommened IAM service and EC2 roles required for EKS cluster. +- Create NAT Gateway. +- VPC peering connection. + + +### Before you start +Before you execute this template make sure following dependencies are met. + +- Install terraform +- Configure AWS CLI (make sure you have admin privileges - IAM admin access) +- AWS iam authenticator + + +### Setup +``` +$ git clone +$ cd +``` + +#### Terraform Plan +``` +$ terraform plan +``` + +#### Apply changes +``` +$ terraform apply +``` + +#### Configure kubectl +``` +$ aws eks --region eu-central-1 update-kubeconfig --name +``` +**Note:-** If AWS CLI and AWS iam authenticator setup correctly, above command should setup kubeconfig file in ~/.kube/config in your system. + +#### Verify EKS cluster +``` +$ kubectl get svc +``` + +**Output:** +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +svc/kubernetes ClusterIP 10.100.0.1 443/TCP 1m +``` + +Once cluster is verified succesfully, its time to create a configMap to add the worker nodes into the cluster. We have configured `output` with this template which will produce the configMap file content that you paste in *`aws-auth.yaml`*. + +#### Add worker node +``` +$ kubectl apply -f aws-auth.yaml +``` + +#### Nodes status - watch them joining the cluster +``` +$ kubectl get no -w +``` +**Note:-** You should be seeing nodes joining the cluster within less than minutes. + + From 77740047463bff01a36a5b7a17e0846dd2e3e823 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Mon, 24 Jun 2019 17:50:09 +0530 Subject: [PATCH 05/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eee0a23..1d20e5d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Terraform-aws-eks-cluster -This repository showcases the terraform template that we use to setup our production ready EKS cluster on AWS. If you are looking to use EKS cluster on AWS then chances are high that you are already be having some sort of infrastructure on AWS and eventually be using VPC to create resources in. +This repository showcases the terraform template that will help you to create EKS cluster on AWS. We have designed this template considering you have existing VPC `PRODVPC`. This `terraform` template creates new VPC for EKS cluster also lets you peer your existing VPC. This is done as a recommendatation and best practices suited for isolation. From 6322681b1d389c22e40d65c79e2a7739e8be3815 Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Wed, 26 Jun 2019 11:00:22 +0530 Subject: [PATCH 06/22] removed few variables and corrected few things --- aws-auth.yaml | 18 --------------- eks-architecture.png | Bin 0 -> 42028 bytes eks-worker-node.tf | 46 ------------------------------------- private-route.tf | 17 -------------- variables.tf | 19 +++------------ workstation-external-ip.tf | 19 +++++++++++++++ 6 files changed, 22 insertions(+), 97 deletions(-) create mode 100644 eks-architecture.png create mode 100644 workstation-external-ip.tf diff --git a/aws-auth.yaml b/aws-auth.yaml index f013a4b..e69de29 100755 --- a/aws-auth.yaml +++ b/aws-auth.yaml @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: aws-auth - namespace: kube-system -data: - mapRoles: | - - rolearn: arn:aws:iam::230367374156:role/terraform-eks-frankfurt-node - username: system:node:{{EC2PrivateDNSName}} - groups: - - system:bootstrappers - - system:nodes - - mapUsers: | - - userarn: arn:aws:iam::230367374156:user/eksuser - username: eksuser - groups: - - system:masters diff --git a/eks-architecture.png b/eks-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..ca4c4b14a77675856b0f20a1fc300df8b21fc9bc GIT binary patch literal 42028 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�#h0o-?}h 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 BjX3}S literal 0 HcmV?d00001 diff --git a/eks-worker-node.tf b/eks-worker-node.tf index 74f4480..0754686 100755 --- a/eks-worker-node.tf +++ b/eks-worker-node.tf @@ -58,18 +58,6 @@ resource "aws_security_group_rule" "frankfurt-node-ingress-hpa" { type = "ingress" } -# automatically allowing ssh on worker nodes from localwork station MYIP -resource "aws_security_group_rule" "frankfurt-cluster-ingress-workstation-ssh" { - cidr_blocks = ["${local.workstation-external-cidr}"] - description = "Allow workstation to ssh on worker nodes" - from_port = 22 - protocol = "tcp" - security_group_id = "${aws_security_group.frankfurt-cluster.id}" - to_port = 22 - type = "ingress" -} - - #### User data for worker launch locals { @@ -198,37 +186,3 @@ dimensions = { actions_enabled = true alarm_actions = ["${aws_autoscaling_policy.eks-cpu-policy-scaledown-private.arn}"] } - - -#### -#### Memory based scaling alarm and scaling policies -#### - -## scale up policy for eks node memory usage. -resource "aws_autoscaling_policy" "eks-mem-policy-private" { - name = "eks-mem-policy-private" - autoscaling_group_name = "${aws_autoscaling_group.frankfurt-private.name}" - adjustment_type = "ChangeInCapacity" - scaling_adjustment = "1" - cooldown = "300" - policy_type = "SimpleScaling" -} - -## Cloudwatch alarm for avg memory utlization -resource "aws_cloudwatch_metric_alarm" "eks-mem-alarm-private" { - alarm_name = "eks-mem-alarm-private" - alarm_description = "eks-mem-alarm-private" - comparison_operator = "GreaterThanOrEqualToThreshold" - evaluation_periods = "5" - metric_name = "MemoryUtilization" - namespace = "System/Linux" - period = "60" - statistic = "Average" - threshold = "80" - -dimensions = { - "AutoScalingGroupName" = "${aws_autoscaling_group.frankfurt-private.name}" -} - actions_enabled = true - alarm_actions = ["${aws_autoscaling_policy.eks-mem-policy-private.arn}"] -} diff --git a/private-route.tf b/private-route.tf index 7e33381..d427c69 100644 --- a/private-route.tf +++ b/private-route.tf @@ -3,20 +3,3 @@ resource "aws_route" "nat_gtw" { destination_cidr_block = "0.0.0.0/0" nat_gateway_id = "${aws_nat_gateway.gw.id}" } - - -resource "aws_route" "eks2prodvpc" { - route_table_id = "${aws_route_table.frankfurt-private.id}" - destination_cidr_block = "${var.prodvpc-cidr-block}" - vpc_peering_connection_id = "${aws_vpc_peering_connection.eks2prodvpc.id}" - -} - -resource "aws_route" "prodvpc2eks" { - route_table_id = "${var.prodvpc-route-table-id}" - destination_cidr_block = "${aws_vpc.frankfurt.cidr_block}" - vpc_peering_connection_id = "${aws_vpc_peering_connection.eks2prodvpc.id}" - -} - - diff --git a/variables.tf b/variables.tf index d6a01d9..3294ae1 100644 --- a/variables.tf +++ b/variables.tf @@ -8,6 +8,9 @@ variable "eks-worker-ami" { description = "eks worker node ami for eks cluster 1.13 - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html" } +# In eks worker node instance type directly affects the number of PODs can run on a Node. Choose wisely. +# https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt + variable "worker-node-instance_type" { description = "enter worker node instance type" } @@ -32,19 +35,3 @@ variable "eks_version" { description = "kubernetes cluster version provided by AWS EKS" } - -# update name to be peer vpc -variable "prodvpc-cidr-block" { - description = "Enter CIDR range of the VPC you want EKS VPC to peer with" - -} - -variable "prodvpc_id" { - description = "Enter VPC ID that you want EKS VPC to peer with" - -} - -variable "prodvpc-route-table-id" { - description = "Enter routing table ID of the exiting VPC that you want EKS vpc to peer with" - -} diff --git a/workstation-external-ip.tf b/workstation-external-ip.tf new file mode 100644 index 0000000..97e74a6 --- /dev/null +++ b/workstation-external-ip.tf @@ -0,0 +1,19 @@ +# +# Workstation External IP +# +# This configuration is not required and is +# only provided as an example to easily fetch +# the external IP of your local workstation to +# configure inbound EC2 Security Group access +# to the Kubernetes cluster. +# + +data "http" "workstation-external-ip" { + url = "http://ipv4.icanhazip.com" +} + +# Override with variable or hardcoded value if necessary +locals { + workstation-external-cidr = "${chomp(data.http.workstation-external-ip.body)}/32" +} + From 8a5a867bcf03a8d494b3fc06944bba6dc8f27f32 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 11:47:22 +0530 Subject: [PATCH 07/22] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 1d20e5d..549586a 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,21 @@ $ cd ``` #### Terraform Plan +The terraform plan command is used to create an execution plan. Always a good practice to run it before you apply it to see what all resources will be created. + +This will ask you to specify `cluster name` and worker node instance type. + ``` $ terraform plan +var.cluster-name + Enter eks cluster name - example like eks-frankfurt + + Enter a value: eks-frankfurt + +var.worker-node-instance_type + enter worker node instance type + + Enter a value: t2.medium ``` #### Apply changes From 6a2583ef92623eb81726d895959c89199bf9220a Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 14:37:57 +0530 Subject: [PATCH 08/22] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 549586a..66e65d0 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ We have designed this template considering you have existing VPC `PRODVPC`. This **Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. AWS resources that are created by this template listed below. -- Creates a new VPC with CIDR Block - 10.15.0.0/19 in Frankfurt region. -- Creates 3 public & 3 private subnets with each size of 4056 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c) +- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. You may want to change it, values are `variables.tf`. +- Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c) - Creates recommened IAM service and EC2 roles required for EKS cluster. -- Create NAT Gateway. -- VPC peering connection. +- Creates Internet & NAT Gateway required for public and private communications. +- Routing Table and routes for public and private subnets. ### Before you start From 361db3882c06ec783ba4f00e319adb87a27bf28d Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 14:40:03 +0530 Subject: [PATCH 09/22] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 66e65d0..a104b7d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ We have designed this template considering you have existing VPC `PRODVPC`. This **Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. AWS resources that are created by this template listed below. - Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. You may want to change it, values are `variables.tf`. -- Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c) +- Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c +- Creates security groups required for cluster and worker nodes. - Creates recommened IAM service and EC2 roles required for EKS cluster. - Creates Internet & NAT Gateway required for public and private communications. - Routing Table and routes for public and private subnets. @@ -29,6 +30,11 @@ $ git clone $ cd ``` +#### Initialize Terraform +``` +$ terraform init +``` + #### Terraform Plan The terraform plan command is used to create an execution plan. Always a good practice to run it before you apply it to see what all resources will be created. From bf0ec9a240de5c5aafb017d623aad8cae6065335 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 14:45:33 +0530 Subject: [PATCH 10/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a104b7d..146e27c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository showcases the terraform template that will help you to create EK We have designed this template considering you have existing VPC `PRODVPC`. This `terraform` template creates new VPC for EKS cluster also lets you peer your existing VPC. This is done as a recommendatation and best practices suited for isolation. # AWS EKS Architecture -![eks-architecture](https://user-images.githubusercontent.com/38158144/60009869-4052b880-9694-11e9-9580-bb76e6730503.png) +![github_eks](https://user-images.githubusercontent.com/38158144/60167519-e29fa700-9820-11e9-9ecc-86be99973cd7.png) **Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. AWS resources that are created by this template listed below. From 053b7b228c4d4153442886a758bc1206aa1e97d5 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 14:48:29 +0530 Subject: [PATCH 11/22] Update README.md --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 146e27c..6dee247 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# Terraform-aws-eks-cluster +# Introduction This repository showcases the terraform template that will help you to create EKS cluster on AWS. We have designed this template considering you have existing VPC `PRODVPC`. This `terraform` template creates new VPC for EKS cluster also lets you peer your existing VPC. This is done as a recommendatation and best practices suited for isolation. +--- + # AWS EKS Architecture ![github_eks](https://user-images.githubusercontent.com/38158144/60167519-e29fa700-9820-11e9-9ecc-86be99973cd7.png) @@ -88,4 +90,16 @@ $ kubectl get no -w ``` **Note:-** You should be seeing nodes joining the cluster within less than minutes. +--- + +## Contribution +We are happy to accept the changes that you think can help the utilities grow. + +Here are some things to note: + +* Raise a ticket for any requirement +* Discuss the implementation requirement or bug fix with the team members +* Fork the repository and solve the issue in one single commit +* Raise a PR regarding the same issue and attach the required documentation or provide a more detailed overview of the changes + From 1533cb2590da92bcd69d49f7eb87404aaa487d11 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Wed, 26 Jun 2019 16:04:17 +0530 Subject: [PATCH 12/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6dee247..71dca6d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ We have designed this template considering you have existing VPC `PRODVPC`. This # AWS EKS Architecture ![github_eks](https://user-images.githubusercontent.com/38158144/60167519-e29fa700-9820-11e9-9ecc-86be99973cd7.png) -**Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. AWS resources that are created by this template listed below. +**Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. - Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. You may want to change it, values are `variables.tf`. - Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c From 56c25b54e8e70bf3fff473eccfdba3a9e7e32460 Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Thu, 27 Jun 2019 13:55:49 +0530 Subject: [PATCH 13/22] removed files --- eks-github.png | Bin 67254 -> 0 bytes vpc-peering.tf | 36 ------------------------------------ 2 files changed, 36 deletions(-) delete mode 100644 eks-github.png delete mode 100644 vpc-peering.tf diff --git a/eks-github.png b/eks-github.png deleted file mode 100644 index 4396ce34be3455623db854dcfa530e06a73700d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67254 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 Date: Thu, 27 Jun 2019 14:30:04 +0530 Subject: [PATCH 14/22] added ssh keypair - input from user --- eks-worker-node.tf | 2 +- variables.tf | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/eks-worker-node.tf b/eks-worker-node.tf index 0754686..4fdbbeb 100755 --- a/eks-worker-node.tf +++ b/eks-worker-node.tf @@ -73,7 +73,7 @@ resource "aws_launch_configuration" "frankfurt-private" { iam_instance_profile = "${aws_iam_instance_profile.frankfurt-node.name}" image_id = "${var.eks-worker-ami}" ## visit https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html instance_type = "${var.worker-node-instance_type}" # use instance variable - key_name = "rancher" + key_name = "${var.ssh_key_pair}" name_prefix = "terraform-eks-frankfurt-private" security_groups = ["${aws_security_group.frankfurt-node.id}"] user_data_base64 = "${base64encode(local.frankfurt-node-private-userdata)}" diff --git a/variables.tf b/variables.tf index 3294ae1..6d09eb8 100644 --- a/variables.tf +++ b/variables.tf @@ -15,6 +15,11 @@ variable "worker-node-instance_type" { description = "enter worker node instance type" } +variable "ssh_key_pair" { + description = "Enter SSH keypair name that already exist in the account" + +} + variable "public_subnets" { type = "list" default = ["10.15.0.0/22", "10.15.4.0/22", "10.15.8.0/22"] From 56d697a82831d42a042c01627078a0428103680a Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Thu, 27 Jun 2019 15:21:04 +0530 Subject: [PATCH 15/22] Update README.md --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 71dca6d..bc74370 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ # Introduction This repository showcases the terraform template that will help you to create EKS cluster on AWS. -We have designed this template considering you have existing VPC `PRODVPC`. This `terraform` template creates new VPC for EKS cluster also lets you peer your existing VPC. This is done as a recommendatation and best practices suited for isolation. - --- # AWS EKS Architecture ![github_eks](https://user-images.githubusercontent.com/38158144/60167519-e29fa700-9820-11e9-9ecc-86be99973cd7.png) -**Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created by this template. +**Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created. -- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. You may want to change it, values are `variables.tf`. +- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. Feel free to change it, values are `variables.tf`. - Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c - Creates security groups required for cluster and worker nodes. - Creates recommened IAM service and EC2 roles required for EKS cluster. @@ -49,10 +47,15 @@ var.cluster-name Enter a value: eks-frankfurt +var.ssh_key_pair + Enter SSH keypair name that already exist in the account + + Enter a value: somename var.worker-node-instance_type enter worker node instance type Enter a value: t2.medium + ``` #### Apply changes From 10a2d3154853aeb2196ee950ca61c4f18cdaf070 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Thu, 27 Jun 2019 15:24:49 +0530 Subject: [PATCH 16/22] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bc74370..e0bb7f2 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ This repository showcases the terraform template that will help you to create EK ### Before you start Before you execute this template make sure following dependencies are met. -- Install terraform -- Configure AWS CLI (make sure you have admin privileges - IAM admin access) -- AWS iam authenticator +- [Install terraform](https://releases.hashicorp.com/terraform/0.11.13/) +- [Configure AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-linux-al2017.html) - make sure you configure AWS CLI with admin previliges +- [AWS iam authenticator](https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html) - Amazon EKS uses IAM to provide authentication to your Kubernetes cluster through the AWS IAM Authenticator for Kubernetes. ### Setup @@ -51,6 +51,7 @@ var.ssh_key_pair Enter SSH keypair name that already exist in the account Enter a value: somename + var.worker-node-instance_type enter worker node instance type From 5750722a0681b8b2cb66fc01ae1a402de57b5a50 Mon Sep 17 00:00:00 2001 From: DevOps Engineer <38158144+tprakash17@users.noreply.github.com> Date: Thu, 27 Jun 2019 15:26:38 +0530 Subject: [PATCH 17/22] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e0bb7f2..9203f30 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This repository showcases the terraform template that will help you to create EK **Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created. -- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC)in Frankfurt region. Feel free to change it, values are `variables.tf`. +- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC) in Frankfurt region. Feel free to change it, values are `variables.tf`. - Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c - Creates security groups required for cluster and worker nodes. - Creates recommened IAM service and EC2 roles required for EKS cluster. @@ -26,8 +26,8 @@ Before you execute this template make sure following dependencies are met. ### Setup ``` -$ git clone -$ cd +$ git clone https://github.com/MediaIQ/terraform-aws-eks-cluster.git +$ cd terraform-aws-eks-cluster ``` #### Initialize Terraform From 4b39d9cc695f827ebb8d24116bb25295fce2474e Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Tue, 9 Jul 2019 13:15:49 +0530 Subject: [PATCH 18/22] updated README and removed frankfurt specific key word from all the files --- README.md | 18 +- aws-vpn-gtw.tf | 6 +- backend.tf | 12 - .../cluster-autoscalar/ca-iam-policy.tf | 59 ---- cluster-addons/cluster-autoscalar/eks-ca.yaml | 154 -------- .../ingress-controller/private-ingress.yaml | 333 ------------------ .../ingress-controller/public-ingress.yaml | 332 ----------------- cluster-addons/kube2iam/kube2iam.yaml | 76 ---- .../aggregated-metrics-reader.yaml | 12 - .../metrics-server/auth-delegator.yaml | 13 - .../metrics-server/auth-reader.yaml | 14 - .../metrics-server/metrics-apiservice.yaml | 14 - .../metrics-server-deployment.yaml | 42 --- .../metrics-server-service.yaml | 15 - .../metrics-server/resource-reader.yaml | 29 -- eks-cluster.tf | 42 +-- eks-worker-node.tf | 54 +-- frankfurt-eks-vpc.tf | 50 +-- iam.tf | 26 +- outputs.tf | 6 +- private-route.tf | 4 +- providers.tf | 2 +- variables.tf | 7 +- 23 files changed, 113 insertions(+), 1207 deletions(-) delete mode 100644 backend.tf delete mode 100755 cluster-addons/cluster-autoscalar/ca-iam-policy.tf delete mode 100644 cluster-addons/cluster-autoscalar/eks-ca.yaml delete mode 100755 cluster-addons/ingress-controller/private-ingress.yaml delete mode 100755 cluster-addons/ingress-controller/public-ingress.yaml delete mode 100644 cluster-addons/kube2iam/kube2iam.yaml delete mode 100755 cluster-addons/metrics-server/aggregated-metrics-reader.yaml delete mode 100755 cluster-addons/metrics-server/auth-delegator.yaml delete mode 100755 cluster-addons/metrics-server/auth-reader.yaml delete mode 100755 cluster-addons/metrics-server/metrics-apiservice.yaml delete mode 100755 cluster-addons/metrics-server/metrics-server-deployment.yaml delete mode 100755 cluster-addons/metrics-server/metrics-server-service.yaml delete mode 100755 cluster-addons/metrics-server/resource-reader.yaml diff --git a/README.md b/README.md index 9203f30..e1955f1 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ This repository showcases the terraform template that will help you to create EK **Note** - Above architecture doesn't reflect all the components that are created by this template. However, it does give an idea about core infrastructure that will be created. -- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC) in Frankfurt region. Feel free to change it, values are `variables.tf`. -- Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones (eu-central-1a, eu-central-1b and eu-central-1c +- Creates a new VPC with CIDR Block - 10.15.0.0/19 (i.e 8190 IPs in a VPC) in a region of your choice. Feel free to change it, values are `variables.tf`. +- Creates 3 public & 3 private subnets with each size of 1024 IP addresses in each zones - Creates security groups required for cluster and worker nodes. - Creates recommened IAM service and EC2 roles required for EKS cluster. - Creates Internet & NAT Gateway required for public and private communications. @@ -42,16 +42,22 @@ This will ask you to specify `cluster name` and worker node instance type. ``` $ terraform plan + var.cluster-name - Enter eks cluster name - example like eks-frankfurt + Enter eks cluster name - example like eks-demo, eks-dev etc + + Enter a value: eks-demo - Enter a value: eks-frankfurt +var.region + Enter region you want to create EKS cluster in + + Enter a value: us-east-1 var.ssh_key_pair Enter SSH keypair name that already exist in the account - Enter a value: somename - + Enter a value: eks-keypair + var.worker-node-instance_type enter worker node instance type diff --git a/aws-vpn-gtw.tf b/aws-vpn-gtw.tf index 008ec7c..4723f39 100755 --- a/aws-vpn-gtw.tf +++ b/aws-vpn-gtw.tf @@ -1,10 +1,10 @@ -# create aws vpn gateway for EKS VPC Frankfurt +# create aws vpn gateway for EKS VPC resource "aws_vpn_gateway" "vpn_gw" { - vpc_id = "${aws_vpc.frankfurt.id}" + vpc_id = "${aws_vpc.eks.id}" tags = "${ map( - "Name", "eks aws vpn gateway frankfurt" + "Name", "eks aws vpn gateway" ) }" } diff --git a/backend.tf b/backend.tf deleted file mode 100644 index 7c08188..0000000 --- a/backend.tf +++ /dev/null @@ -1,12 +0,0 @@ -## A "backend" in Terraform determines how state is loaded. Its completely optional but recommended. -## Terraform remote state management - visit https://www.terraform.io/docs/backends/index.html -## eks-frankfurt is the folder inside the bucket that you are going to choose to store terraform state files. -## make sure you create it in advance. - -#terraform { -# backend "s3" { -# bucket = "{var.s3_bucket_name}" -# key = "eks-frankfurt/terraform.tfstate" -# region = "us-east-1" -# } -#} diff --git a/cluster-addons/cluster-autoscalar/ca-iam-policy.tf b/cluster-addons/cluster-autoscalar/ca-iam-policy.tf deleted file mode 100755 index 9018940..0000000 --- a/cluster-addons/cluster-autoscalar/ca-iam-policy.tf +++ /dev/null @@ -1,59 +0,0 @@ -resource "aws_iam_role_policy" "frankfurt_ca_policy" { - name = "frankfurt_ca_policy" - role = "${aws_iam_role.frankfurt_ca_role.id}" - - policy = <-" - # Here: "-" - # This has to be adapted if you change either parameter - # when launching the nginx-ingress-controller. - - "ingress-controller-leader-nginx" - verbs: - - get - - update - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - get - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: nginx-eksprivate-role-nisa-binding - namespace: ingress-eksprivate-nginx -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: nginx-eksprivate-role -subjects: - - kind: ServiceAccount - name: nginx-eksprivate-serviceaccount - namespace: ingress-eksprivate-nginx - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: nginx-eksprivate-clusterrole-nisa-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: nginx-eksprivate-clusterrole -subjects: - - kind: ServiceAccount - name: nginx-eksprivate-serviceaccount - namespace: ingress-eksprivate-nginx ---- - -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: default-eks-http-backend - labels: - app: default-eks-http-backend - namespace: ingress-eksprivate-nginx -spec: - replicas: 2 - selector: - matchLabels: - app: default-eks-http-backend - template: - metadata: - labels: - app: default-eks-http-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-eks-http-backend - # Any image is permissible as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: gcr.io/google_containers/defaultbackend:1.4 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi ---- - -apiVersion: v1 -kind: Service -metadata: - name: default-eks-http-backend - namespace: ingress-eksprivate-nginx - labels: - app: default-eks-http-backend -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: default-eks-http-backend - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-eksprivate-controller - namespace: ingress-eksprivate-nginx -spec: - replicas: 2 - selector: - matchLabels: - app: ingress-eksprivate-nginx - template: - metadata: - labels: - app: ingress-eksprivate-nginx - annotations: - prometheus.io/port: '10254' - prometheus.io/scrape: 'true' - spec: - serviceAccountName: nginx-eksprivate-serviceaccount - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-eks-http-backend - - --configmap=$(POD_NAMESPACE)/nginx-configuration - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - - --publish-service=$(POD_NAMESPACE)/ingress-eksprivate-nginx - - --annotations-prefix=nginx.ingress.kubernetes.io - - --ingress-class=private-nginx - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - name: http - containerPort: 80 - - name: https - containerPort: 443 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - securityContext: - runAsNonRoot: false ---- -kind: Service -apiVersion: v1 -metadata: - name: ingress-eksprivate-nginx - namespace: ingress-eksprivate-nginx - labels: - app: ingress-eksprivate-nginx - annotations: - # Specifies whether cross-zone load balancing is enabled for the load balancer - service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" - # Expose this as internal load balancer - service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" - # replace with the correct value of the generated certificate in the AWS console Mediaiqdigital.com - service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:eu-central-1:230367374156:certificate/d5ea0711-b37c-49de-a407-f5857f09d229" - # the backend instances are HTTP - service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" - # Map port 443 - service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https" - # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. - service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' - # tags for ELB - service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "Name=frankfurt-private-ingess-controller,TEAM=Devops,PRODUCT=EKS,ENVIRONMENT=PRODUCTION" - # health check interval - service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: '5' - # ELB time out - service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: '3' - # health check unhealthy threshold - service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: '2' - # healthy threshold - service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: '2' - # connection draining - service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" - -spec: - type: LoadBalancer - selector: - app: ingress-eksprivate-nginx - ports: - - name: http - port: 80 - targetPort: http - - name: https - port: 443 - targetPort: http diff --git a/cluster-addons/ingress-controller/public-ingress.yaml b/cluster-addons/ingress-controller/public-ingress.yaml deleted file mode 100755 index 5d52609..0000000 --- a/cluster-addons/ingress-controller/public-ingress.yaml +++ /dev/null @@ -1,332 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: ingress-ekspublic-nginx ---- -kind: ConfigMap -apiVersion: v1 -metadata: - name: nginx-configuration - namespace: ingress-ekspublic-nginx - labels: - app: ingress-ekspublic-nginx ---- - -kind: ConfigMap -apiVersion: v1 -metadata: - name: tcp-services - namespace: ingress-ekspublic-nginx ---- - -kind: ConfigMap -apiVersion: v1 -metadata: - name: udp-services - namespace: ingress-ekspublic-nginx ---- - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: nginx-ekspublic-serviceaccount - namespace: ingress-ekspublic-nginx - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: nginx-ekspublic-clusterrole -rules: - - apiGroups: - - "" - resources: - - configmaps - - endpoints - - nodes - - pods - - secrets - verbs: - - list - - watch - - update - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - watch - - apiGroups: - - "extensions" - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - "extensions" - resources: - - ingresses/status - verbs: - - update - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: nginx-ekspublic-role - namespace: ingress-ekspublic-nginx -rules: - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - - namespaces - verbs: - - get - - apiGroups: - - "" - resources: - - configmaps - resourceNames: - # Defaults to "-" - # Here: "-" - # This has to be adapted if you change either parameter - # when launching the nginx-ingress-controller. - - "ingress-controller-leader-nginx" - verbs: - - get - - update - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - get - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: nginx-ekspublic-role-nisa-binding - namespace: ingress-ekspublic-nginx -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: nginx-ekspublic-role -subjects: - - kind: ServiceAccount - name: nginx-ekspublic-serviceaccount - namespace: ingress-ekspublic-nginx - ---- - -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: nginx-ekspublic-clusterrole-nisa-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: nginx-ekspublic-clusterrole -subjects: - - kind: ServiceAccount - name: nginx-ekspublic-serviceaccount - namespace: ingress-ekspublic-nginx ---- - -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: default-eks-http-backend - labels: - app: default-eks-http-backend - namespace: ingress-ekspublic-nginx -spec: - replicas: 2 - selector: - matchLabels: - app: default-eks-http-backend - template: - metadata: - labels: - app: default-eks-http-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-eks-http-backend - # Any image is permissible as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: gcr.io/google_containers/defaultbackend:1.4 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi ---- - -apiVersion: v1 -kind: Service -metadata: - name: default-eks-http-backend - namespace: ingress-ekspublic-nginx - labels: - app: default-eks-http-backend -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: default-eks-http-backend - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-ekspublic-controller - namespace: ingress-ekspublic-nginx -spec: - replicas: 2 - selector: - matchLabels: - app: ingress-ekspublic-nginx - template: - metadata: - labels: - app: ingress-ekspublic-nginx - annotations: - prometheus.io/port: '10254' - prometheus.io/scrape: 'true' - spec: - serviceAccountName: nginx-ekspublic-serviceaccount - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-eks-http-backend - - --configmap=$(POD_NAMESPACE)/nginx-configuration - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - - --publish-service=$(POD_NAMESPACE)/ingress-ekspublic-nginx - - --annotations-prefix=nginx.ingress.kubernetes.io - - --ingress-class=public-nginx - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - name: http - containerPort: 80 - - name: https - containerPort: 443 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - securityContext: - runAsNonRoot: false ---- -kind: Service -apiVersion: v1 -metadata: - name: ingress-ekspublic-nginx - namespace: ingress-ekspublic-nginx - labels: - app: ingress-ekspublic-nginx - annotations: - # Specifies whether cross-zone load balancing is enabled for the load balancer - service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" - # Expose this as internal load balancer - # service.beta.kubernetes.io/aws-load-balancer-internal: "0.0.0.0/0" - # replace with the correct value of the generated certificate in the AWS console Mediaiqdigital.com - service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:eu-central-1:230367374156:certificate/d5ea0711-b37c-49de-a407-f5857f09d229" - # the backend instances are HTTP - service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" - # Map port 443 - service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https" - # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. - service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' - # tags for ELB - service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "Name=eks-public-ingress-controller,TEAM=Devops,PRODUCT=EKS,ENVRIONMENT=PRODUCTION" - # health check interval - service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: '5' - # ELB time out - service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: '3' - # health check unhealthy threshold - service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: '2' - # healthy threshold - service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: '2' - # connection draining - service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" - -spec: - type: LoadBalancer - selector: - app: ingress-ekspublic-nginx - ports: - - name: http - port: 80 - targetPort: http - - name: https - port: 443 - targetPort: http diff --git a/cluster-addons/kube2iam/kube2iam.yaml b/cluster-addons/kube2iam/kube2iam.yaml deleted file mode 100644 index fdaef81..0000000 --- a/cluster-addons/kube2iam/kube2iam.yaml +++ /dev/null @@ -1,76 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube2iam - namespace: kube-system ---- -apiVersion: v1 -items: - - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: kube2iam - rules: - - apiGroups: [""] - resources: ["namespaces","pods"] - verbs: ["get","watch","list"] - - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: kube2iam - subjects: - - kind: ServiceAccount - name: kube2iam - namespace: kube-system - roleRef: - kind: ClusterRole - name: kube2iam - apiGroup: rbac.authorization.k8s.io -kind: List ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: kube2iam - namespace: kube-system - labels: - app: kube2iam -spec: - selector: - matchLabels: - name: kube2iam - template: - metadata: - labels: - name: kube2iam - spec: - serviceAccountName: kube2iam - hostNetwork: true - containers: - - image: jtblin/kube2iam:latest # instead of latest use 0.10.4 to fix iam cred 500 error - imagePullPolicy: Always - name: kube2iam - args: - - "--auto-discover-base-arn" - - "--auto-discover-default-role=true" - - "--iptables=true" - - "--host-ip=$(HOST_IP)" - - "--node=$(NODE_NAME)" - - "--host-interface=eni+" - env: - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - ports: - - containerPort: 8181 - hostPort: 8181 - name: http - securityContext: - privileged: true - tolerations: - - operator: Exists diff --git a/cluster-addons/metrics-server/aggregated-metrics-reader.yaml b/cluster-addons/metrics-server/aggregated-metrics-reader.yaml deleted file mode 100755 index cdf3415..0000000 --- a/cluster-addons/metrics-server/aggregated-metrics-reader.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:aggregated-metrics-reader - labels: - rbac.authorization.k8s.io/aggregate-to-view: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: -- apiGroups: ["metrics.k8s.io"] - resources: ["pods"] - verbs: ["get", "list", "watch"] diff --git a/cluster-addons/metrics-server/auth-delegator.yaml b/cluster-addons/metrics-server/auth-delegator.yaml deleted file mode 100755 index e3442c5..0000000 --- a/cluster-addons/metrics-server/auth-delegator.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: metrics-server:system:auth-delegator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system diff --git a/cluster-addons/metrics-server/auth-reader.yaml b/cluster-addons/metrics-server/auth-reader.yaml deleted file mode 100755 index f0616e1..0000000 --- a/cluster-addons/metrics-server/auth-reader.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: metrics-server-auth-reader - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system diff --git a/cluster-addons/metrics-server/metrics-apiservice.yaml b/cluster-addons/metrics-server/metrics-apiservice.yaml deleted file mode 100755 index 08b0530..0000000 --- a/cluster-addons/metrics-server/metrics-apiservice.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: apiregistration.k8s.io/v1beta1 -kind: APIService -metadata: - name: v1beta1.metrics.k8s.io -spec: - service: - name: metrics-server - namespace: kube-system - group: metrics.k8s.io - version: v1beta1 - insecureSkipTLSVerify: true - groupPriorityMinimum: 100 - versionPriority: 100 diff --git a/cluster-addons/metrics-server/metrics-server-deployment.yaml b/cluster-addons/metrics-server/metrics-server-deployment.yaml deleted file mode 100755 index 3c98cfa..0000000 --- a/cluster-addons/metrics-server/metrics-server-deployment.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: metrics-server - namespace: kube-system ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: metrics-server - namespace: kube-system - labels: - k8s-app: metrics-server -spec: - selector: - matchLabels: - k8s-app: metrics-server - template: - metadata: - name: metrics-server - labels: - k8s-app: metrics-server - spec: - serviceAccountName: metrics-server - volumes: - # mount in tmp so we can safely use from-scratch images and/or read-only containers - - name: tmp-dir - emptyDir: {} - containers: - - name: metrics-server - image: k8s.gcr.io/metrics-server-amd64:v0.3.1 - imagePullPolicy: Always - command: - - /metrics-server - - --metric-resolution=30s - - --kubelet-insecure-tls - - --kubelet-preferred-address-types=InternalIP - volumeMounts: - - name: tmp-dir - mountPath: /tmp - diff --git a/cluster-addons/metrics-server/metrics-server-service.yaml b/cluster-addons/metrics-server/metrics-server-service.yaml deleted file mode 100755 index 082b00c..0000000 --- a/cluster-addons/metrics-server/metrics-server-service.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: metrics-server - namespace: kube-system - labels: - kubernetes.io/name: "Metrics-server" -spec: - selector: - k8s-app: metrics-server - ports: - - port: 443 - protocol: TCP - targetPort: 443 diff --git a/cluster-addons/metrics-server/resource-reader.yaml b/cluster-addons/metrics-server/resource-reader.yaml deleted file mode 100755 index 574efc5..0000000 --- a/cluster-addons/metrics-server/resource-reader.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: system:metrics-server -rules: -- apiGroups: - - "*" - resources: - - pods - - nodes - - nodes/stats - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: system:metrics-server -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:metrics-server -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system diff --git a/eks-cluster.tf b/eks-cluster.tf index 7ba86a5..1373975 100755 --- a/eks-cluster.tf +++ b/eks-cluster.tf @@ -5,8 +5,8 @@ # * EKS Cluster # -resource "aws_iam_role" "frankfurt-cluster" { - name = "terraform-eks-frankfurt-cluster" +resource "aws_iam_role" "eks-cluster" { + name = "terraform-eks-cluster" assume_role_policy = < Date: Mon, 15 Jul 2019 11:19:01 +0530 Subject: [PATCH 19/22] renamed frankfurt-eks-vpc.tf to eks-vpc.tf and updated configure kubectl section in README --- README.md | 2 +- frankfurt-eks-vpc.tf => eks-vpc.tf | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename frankfurt-eks-vpc.tf => eks-vpc.tf (100%) diff --git a/README.md b/README.md index e1955f1..ed1158c 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ $ terraform apply #### Configure kubectl ``` -$ aws eks --region eu-central-1 update-kubeconfig --name +$ aws eks --region update-kubeconfig --name ``` **Note:-** If AWS CLI and AWS iam authenticator setup correctly, above command should setup kubeconfig file in ~/.kube/config in your system. diff --git a/frankfurt-eks-vpc.tf b/eks-vpc.tf similarity index 100% rename from frankfurt-eks-vpc.tf rename to eks-vpc.tf From 9eb079463bed4a01fc99544405c1b0c9a3fb23ce Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Mon, 15 Jul 2019 11:23:51 +0530 Subject: [PATCH 20/22] updated configure kubectl section with - aws eks --region update-kubeconfig --name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed1158c..d7953ef 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ $ terraform apply #### Configure kubectl ``` -$ aws eks --region update-kubeconfig --name +$ aws eks --region update-kubeconfig --name ``` **Note:-** If AWS CLI and AWS iam authenticator setup correctly, above command should setup kubeconfig file in ~/.kube/config in your system. From dc7129e76a7e4cc1dc1db712541519742116bb11 Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Thu, 8 Aug 2019 11:50:23 +0530 Subject: [PATCH 21/22] updated description for the resources --- aws-auth.yaml | 5 +++++ eks-cluster.tf | 11 +++++++++++ eks-worker-node.tf | 2 +- private-route.tf | 1 + variables.tf | 6 ++---- workstation-external-ip.tf | 4 ++-- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/aws-auth.yaml b/aws-auth.yaml index e69de29..5eb61db 100755 --- a/aws-auth.yaml +++ b/aws-auth.yaml @@ -0,0 +1,5 @@ +## This will have the configMap data that you would need to add EKS worker nodes. +## We have configured this terraform template to display the configMap details as OUTPUT. +## Once ``terrform apply`` is successful, you should see configMap details in the end of the output. +## Create configMap by ``kubectl apply -f aws-auth.yaml`` + diff --git a/eks-cluster.tf b/eks-cluster.tf index 1373975..c2bf0a2 100755 --- a/eks-cluster.tf +++ b/eks-cluster.tf @@ -34,6 +34,7 @@ resource "aws_iam_role_policy_attachment" "eks-cluster-AmazonEKSServicePolicy" { role = "${aws_iam_role.eks-cluster.name}" } +## Crate EKS master security group resource "aws_security_group" "eks-cluster" { name = "terraform-eks-cluster" description = "Cluster communication with worker nodes" @@ -53,6 +54,11 @@ resource "aws_security_group" "eks-cluster" { }" } +## +## Required set of ports inbound / outbound +## More details - https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html +## + resource "aws_security_group_rule" "eks-cluster-ingress-node-https" { description = "Allow pods to communicate with the cluster API Server" from_port = 443 @@ -73,6 +79,11 @@ resource "aws_security_group_rule" "eks-cluster-ingress-workstation-https" { type = "ingress" } +## +## create EKS cluster +## attaching required EKS policies +## + resource "aws_eks_cluster" "eks-cluster" { name = "${var.cluster-name}" diff --git a/eks-worker-node.tf b/eks-worker-node.tf index 215f2b5..84f00a8 100755 --- a/eks-worker-node.tf +++ b/eks-worker-node.tf @@ -80,7 +80,7 @@ resource "aws_launch_configuration" "eks-private-lc" { root_block_device { delete_on_termination = true - volume_size = 50 + volume_size = 30 volume_type = "gp2" } diff --git a/private-route.tf b/private-route.tf index f5faaed..a37c289 100644 --- a/private-route.tf +++ b/private-route.tf @@ -1,3 +1,4 @@ +## Enable internal route for NAT gw resource "aws_route" "nat_gtw" { route_table_id = "${aws_route_table.eks-private.id}" destination_cidr_block = "0.0.0.0/0" diff --git a/variables.tf b/variables.tf index 85e95b1..82d6dbc 100644 --- a/variables.tf +++ b/variables.tf @@ -4,8 +4,7 @@ variable "cluster-name" { } variable "eks-worker-ami" { - default = "ami-02d5e7ca7bc498ef9" - description = "eks worker node ami for eks cluster 1.13 - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html" + description = "Please visit here - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html and select your pre-baked AMI depending on the cluster version and the region you are planning to launch cluster into" } # In eks worker node instance type directly affects the number of PODs can run on a Node. Choose wisely. @@ -36,8 +35,7 @@ variable "aws_profile" { } variable "eks_version" { - default = "1.13" - description = "kubernetes cluster version provided by AWS EKS" + description = "kubernetes cluster version provided by AWS EKS - It would be like 1.12 or 1.13" } diff --git a/workstation-external-ip.tf b/workstation-external-ip.tf index 97e74a6..42afb21 100644 --- a/workstation-external-ip.tf +++ b/workstation-external-ip.tf @@ -1,7 +1,7 @@ # -# Workstation External IP +# Local Workstation External IP # -# This configuration is not required and is +# Optional configuration is not required and is # only provided as an example to easily fetch # the external IP of your local workstation to # configure inbound EC2 Security Group access From aba9f9711fa07cee912032dfcb4f615ef363cb18 Mon Sep 17 00:00:00 2001 From: Tarun Prakash Date: Fri, 9 Aug 2019 10:57:30 +0530 Subject: [PATCH 22/22] updated description for subnets range in variables.tf --- terraform-aws-eks-cluster | 1 - variables.tf | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 160000 terraform-aws-eks-cluster diff --git a/terraform-aws-eks-cluster b/terraform-aws-eks-cluster deleted file mode 160000 index c496fe5..0000000 --- a/terraform-aws-eks-cluster +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c496fe58017a1280edd9289856553826c393d0f8 diff --git a/variables.tf b/variables.tf index 82d6dbc..e9485e6 100644 --- a/variables.tf +++ b/variables.tf @@ -21,11 +21,13 @@ variable "ssh_key_pair" { variable "public_subnets" { type = "list" + description = "you can replace these values as per your choice of subnet range" default = ["10.15.0.0/22", "10.15.4.0/22", "10.15.8.0/22"] } variable "private_subnets" { type = "list" + description = "you can replace these values as per your choice of subnet range" default = ["10.15.12.0/22", "10.15.16.0/22", "10.15.20.0/22"] }