Создание AWS EKS кластера в Unix/Linux

Amazon EKS — это управляемый сервис, который упрощает запуск Kubernetes на AWS без необходимости установки, эксплуатации и обслуживания мастер нод в Kubernetes.

Не буду рассказывать что такое Кубернетес и для чего он нужен. Наверное и так уже все знают что это и как его юзать. Но может не все знают как можно его настроить в AWS с использованием EKS.

Полезное чтиво:

Установка minikube в Unix/Linux

Команды Kubernetes в Unix/Linux

Установка Kubernetes кластера в Unix/Linux

Установка Helm в Unix/Linux

Установка Spinnaker в Unix/Linux

Поехали….

Предустановка AWS EKS кластера в Unix/Linux

Ставим себе на машину:

  • kubectl
  • helm

Необходимо знать в какой сети нужен кластер:

  • Внутренняя сеть
  • Публичная сеть

У меня для примера, я использую внутреннюю сеть. Для того чтобы приступили к установки куба, еще, необходимо создать 2 роли:

  • arn:aws:iam::486668976666:role/AmazonEKSClusterRole — это роль со стандартными полисями (например — AmazonEKSClusterPolicy + все то, что необходимо будет для вашего проекта. Для работы с волюмами для подов я создавал отдельную полиси).
  • arn:aws:iam::486668976666:role/K8SWorkersRole — это роль с полисями которые необходимы при работе с воркер-нодами (Например — AmazonEKSWorkerNodePolicy и AmazonEKSVPCResourceController + если планируете юзать ECR — стоит приапачить еще и AmazonEC2ContainerRegistryReadOnly, как пример. Для работы с волюмами для подов я создавал отдельную полиси).

Приступим к установки.

Создание AWS EKS кластера через AWC CLI (aws eks) в Unix/Linux

Для начала, необходимо поставить AWS CLI на вашу систему с которой будете запускать команды. У меня MacOS, по этому — я ставил через HOMEBREW:

$ brew install awscli

Для остальных ОС, — не сильно отличаться должно…

Создаем кластер следующим образом (если нужно чтобы он был доступен в рамках VPC или через VPN), т.е internal:

$ aws eks create-cluster \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test \
	--kubernetes-version 1.17 \
	--role-arn arn:aws:iam::486668976666:role/AmazonEKSClusterRole \
	--resources-vpc-config subnetIds=subnet-065292d0e6abb34bc,subnet-0bed681cb074db448,subnet-0352a2addd013b8e2,securityGroupIds=sg-019f0b7291543066c,endpointPublicAccess=false,endpointPrivateAccess=true \
	--logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}' \
	--tags Name=aws-eks-test,createdby=vnatrov,environment=dev

Или, если необходимо создать кластер для того чтобы он был доступен с интернета, можете использовать следующую команду:

aws eks create-cluster \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test \
	--kubernetes-version 1.17 \
	--role-arn arn:aws:iam::486668976666:role/AmazonEKSClusterRole \
	--resources-vpc-config subnetIds=subnet-065292d0e6abb34bc,subnet-0bed681cb074db448,subnet-0352a2addd013b8e2,securityGroupIds=sg-019f0b7291543066c,endpointPublicAccess=true,endpointPrivateAccess=false \
	--logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}' \
	--tags Name=aws-eks-test,createdby=vnatrov,environment=dev

AWS EKS кластер создается около 10-15 минут (примерно) и чтобы проверить, можно использовать команду:

$ aws eks describe-cluster \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test \
	--query cluster.status

Если надоело играться и не нужен кластер, грохнуть можно так:

$ aws eks delete-cluster  \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test

Идем дальше, и следующим шагом будет создание «node group» т.е группы машин, которые будут использоваться в качестве воркеров и на них будут запускаться ПОД-ы (можно и на мастере запускать ПОД-ы, но мастер служит для других целей):

$ aws eks create-nodegroup \
		--region us-east-1 \
		--profile aws-eks-test \
		--nodegroup-name aws-eks-test-nodegroup-1 \
		--cluster-name aws-eks-test \
		--scaling-config minSize=3,maxSize=3,desiredSize=3 \
		--disk-size 128 \
		--subnets subnet-065292d0e6abb34bc subnet-0bed681cb074db448 subnet-0352a2addd013b8e2 \
		--instance-types m5d.xlarge \
		--ami-type AL2_x86_64 \
		--remote-access ec2SshKey=aws-eks-test-eks-nodegroup1-key,sourceSecurityGroups=sg-093ee648c274f6e72 \
		--node-role arn:aws:iam::486668976666:role/K8SWorkersRole \
		--client-request-token $(aws eks get-token --region us-east-1 --profile aws-eks-test --cluster-name aws-eks-test | jq -r '.status.token') \
		--kubernetes-version 1.17 \
		--labels eks.io/managed-by=eks,eks.io/role=K8SWorkersRole \
		--tags Name=aws-eks-test-nodegroup1,createdby=vnatrov,environment=dev

Нужно подождать некоторое время чтобы машины создались. У меня, где-то потребовалось 5-10 минут.

Удалить можно созданные группы, можно так:

$ aws eks delete-nodegroup \
		--region us-east-1 \
		--profile aws-eks-test \
		--nodegroup-name aws-eks-test-nodegroup-1 \
		--cluster-name aws-eks-test

Созданный стек уже имеется, но нужно настроить еще необходимые компоненты, о которых я расскажу немного ниже.

Создание AWS EKS кластера через eksctl в Unix/Linux

Протестирую работу, и обязательно дополню статью.

Создание AWS EKS кластера через KOPS в Unix/Linux

Нужно собрать кластер и протестировать создание. После — все обновлю и добавлю.

Создание AWS EKS кластера через Terraform в Unix/Linux

Куда же без моего любимого Terrafrom-а, но у меня нет своего написанного модуля еще, но вот через определенный промежуток прийдется написать стек для работы для деплоя Кубернетеса на ПРОД.

Но готовый модуль давно уже имеется в инете, — terraform-aws-eks.

Создание AWS EKS кластера через другой способ в Unix/Linux

Возможно будет другой способ создания куба. Я знаю что есть еще AWS CloudFormation и через него можно сделать, — но он мне не нравится как сервис и я не хочу описывать его работу.

Настройка AWS EKS кластера в Unix/Linux

Смотрим на кластер:

$ kubectl cluster-info

Для интереса можно посмотреть сервисы которые использует кластер:

$ kubectl get svc

Пред-настройка AWS EKS кластера в Unix/Linux

Когда у нас имеется кластер, первое что необходимо — конечно же — это доступ к нему, а получить, можно его так:

$ aws eks update-kubeconfig \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test

Идем далее, создаем файл с названием (например):

$ vim aws-auth-cm.yaml

И вставляем:

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: arn:aws:iam::486668976666:instance-profile/K8SWorkersRole
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes

Деплоим конфиг-мапу себе в куб:

$ kubectl apply -f aws-auth-cm.yaml

Смотрим, появились ли ноды у нас:

$ kubectl get nodes --watch

Данный финт нужен для того чтобы worker ноды присоединились в кубернетес кластер.

Если есть необходимость поправить данный конфиг, можно заюзать:

$ kubectl edit -n kube-system configmap/aws-auth

Но скачать такой файл (но нужно еще поправить параметры для себя), можно так:

$ curl -O aws-auth-cm.yaml https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2019-01-09/aws-auth-cm.yaml

Сеть в AWS EKS кластера в Unix/Linux

У меня, при таком создании, не смогли приатачиться ноды к мастеру и мне нужно было что-то предпринять — и тут мне в голову пришло, — поиграться с сетью.

Устанавливаем weave драйвер следующим образом:

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

После данного действия, у меня появилась связь между AWS EKS и Kubernetes workers.

Собственно, если захотелось удалить:

$ kubectl delete -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

Так же, можно установить и поиграться с calico драйвером следующим образом:

$ kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.7.4/config/v1.7/aws-k8s-cni.yaml &&
kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.7.4/config/v1.7/cni-metrics-helper.yaml

Удаление:

$ kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.7.4/config/v1.7/aws-k8s-cni.yaml

Создадим пример для демо:

$ kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/release-1.7/config/v1.7/calico.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/00-namespace.yaml 
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/01-management-ui.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/02-backend.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/03-frontend.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/04-client.yaml

Смотрим, создался ли демонсэт:

$ kubectl get daemonset calico-node --namespace kube-system

Смотрим чтобы создались поды:

$ kubectl get pods --all-namespaces --watch

Открываем другую вкладку в консоле и выполняем:

$ kubectl port-forward service/management-ui -n management-ui 9001

Т.е пробросили порты себе на локальную тачку. Открываем локалхост на 9001 и должны увидеть приложенько.

Давайте играться с калико-драйвером и забаним что-то, например:

$ kubectl apply -n stars -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/default-deny.yaml
kubectl apply -n client -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/default-deny.yaml

Обновляем страничку и увидим что трафик не везде ходит.

Идем дальше и выполняем:

$ kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/allow-ui.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/allow-ui-client.yaml

И сново смотрим что вышло. И можно такое сделать:

$ kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/backend-policy.yaml

Обновите и поглядите что будет. И последнее:

$ kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/policies/frontend-policy.yaml

Удаляем после тестов:

$ kubectl delete -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/release-1.7/config/v1.7/calico.yaml
kubectl delete -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/04-client.yaml
kubectl delete -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/03-frontend.yaml
kubectl delete -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/02-backend.yaml
kubectl delete -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/01-management-ui.yaml
kubectl delete -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/tutorials/stars-policy/manifests/00-namespace.yaml

Знаю что имеется еще пару драйверов, но я с ними не пробовал работать. Можно еще настроить sNAT и ходить в мир через Internet Gateway. Документация есть на сайте Амазон.

Storage в AWS EKS кластера в Unix/Linux

Смотрим что используете по-дефолту:

$ kubectl get storageclass

Можно использовать стандартный провайдер и подружить EBS с AWS EKS, для этого создаем StorageClass, например:

$ cat <<EOF | kubectl apply -f -
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: io1-10iopsPerGB
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
  fsType: ext4
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: io1-500iopsPerGB
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "500"
  fsType: ext4
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: io2-10iopsPerGB
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io2
  iopsPerGB: "10"
  fsType: ext4
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: io2-500iopsPerGB
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io2
  iopsPerGB: "500"
  fsType: ext4
EOF

Но еще имеется сторонний драйвер который советует сам AWS и для этого, нужно добавить полиси. Их пример можно скачать:

$ curl -O AmazonEbsCsiDriver.json https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/v0.6.0/docs/example-iam-policy.json

Можно создать их руками в консоле Амазона или так:

$ aws iam create-policy \
 --region us-east-1 \
 --profile aws-eks-test \
 --policy-name AmazonEbsCsiDriver \
 --policy-document file://AmazonEbsCsiDriver.json

Ну а после, — аттачим их к своей роле:

$ aws iam attach-role-policy \
 --region us-east-1 \
 --profile aws-eks-test \
 --policy-arn arn:aws:iam::486668976666:policy/AmazonEbsCsiDriver \
 --role-name arn:aws:iam::486668976666:role/K8SWorkersRole

Ну или через AWS Console можно выполнить аттачмент. Деплоим EBS CSI Driver:

$ kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=master"

Или можно тоже самое сделать через хелм:

$ helm upgrade --install aws-ebs-csi-driver \
 --namespace kube-system \
 --set enableVolumeScheduling=true \
 --set enableVolumeResizing=true \
 --set enableVolumeSnapshot=true \
 https://github.com/kubernetes-sigs/aws-ebs-csi-driver/releases/download/v0.7.0/helm-chart.tgz

А далее, можем проверить, все ли впорядке:

$ kubectl get pod -n kube-system -l "app.kubernetes.io/name=aws-ebs-csi-driver,app.kubernetes.io/instance=aws-ebs-csi-driver"

После этого можно создать тест и потестировать.

Чтобы подружить AWS EFS и ваш кластер, необходимо установить:

$ kubectl apply -k "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/ecr/?ref=release-1.0"

Если у вас фаргет под капотом, то стоит установить для работы с EFS-ом:

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/deploy/kubernetes/base/csidriver.yaml

Создаем AWS EFS и берем с него ID, он нам понадобится. Сейчас создаем ресурсы:

$ cat <<EOF | kubectl apply -f -
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: csi-efs
provisioner: efs.csi.aws.com

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pvc-0
  namespace: storage
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: csi-efs
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-ea1f3e68 # YOUR CREATED EFS ID HERE!
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/nodegroup
          operator: In
          values:
          - poc-nodegroup-1

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: volume-0
  namespace: storage
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: csi-efs
  resources:
    requests:
      storage: 10Gi
EOF

Замечание: Не забываем менять некоторые параметры в файле!

А удалить можно через kubectl delete (по аналогии что и в примерах выше).

Установка Kubernetes Dashboard (Web UI):

-1-

Ставим нужные компоненты:

$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml && \
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml

PS: Версия может быть не актуальна и необходимо смотреть последний RC.

Создаем ServiceAccount для кластера:

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: eks-admin
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: eks-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: eks-admin
  namespace: kube-system
EOF

Создаем ServiceAccount для входа в борду:

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
EOF

Смотрим деплоймент:

$ kubectl get deployment metrics-server -n kube-system

Для входа в админку, нужен будет токен, по этому — получаем его так:

$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')

Или, только нужное поле:

$ aws eks get-token --cluster-name eksworkshop-eksctl | jq -r '.status.token'

Или вот так:

$ kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

Сейчас можно выполнить прокси с задеплоинного ПОД-а себе на машину:

$ kubectl proxy

В данном случае, дефолтный порт — 8001. Или с указанием дополнительных полей:

$ kubectl proxy --port=8080 --address=0.0.0.0 --disable-filter=true &

Для тестов можно выполнить курл и поглядеть все ли норм:

$ curl http://localhost:8080/api

Чтобы не юзать прокси, можно так же использовать форвардинг-порта:

$ kubectl port-forward -n kubernetes-dashboard service/kubernetes-dashboard 8080:443

Или:

$ kubectl port-forward \
--insecure-skip-tls-verify=true \
--kubeconfig="/Users/vnatarov/.kube/config" \
-n kubernetes-dashboard \
service/kubernetes-dashboard 8080:443

Открываем браузер:

http://localhost:8080/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login

Удаляем созданное барахло:

# pkill -f 'kubectl proxy --port=8080' &&\
kubectl delete -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml && \
kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml

-2-

$ helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/ &&\
kubectl create ns kubernetes-dashboard &&\
helm install kubernetes-dashboard -n kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard

Делаем форвардинг порта:

$ export POD_NAME=$(kubectl get pods -n kubernetes-dashboard -l "app.kubernetes.io/name=kubernetes-dashboard,app.kubernetes.io/instance=kubernetes-dashboard" -o jsonpath="{.items[0].metadata.name}")
echo https://127.0.0.1:8443/
kubectl -n kubernetes-dashboard port-forward $POD_NAME 8443:8443

Для апгрейда, можно юзать:

$ helm upgrade -f values.yaml kubernetes-dashboard ./ -n kubernetes-dashboard

Удалить можно так:

$ helm uninstall kubernetes-dashboard -n kubernetes-dashboard

Замечание: список деплойментов, можно вывести:

$ helm list -n kubernetes-dashboard

Если проблемы с сертификатом, то можно решить их одним из способов.

-1-

Можно в Хроме выключить проверку сертификатов с локалхоста (проще простого):

chrome://flags/#allow-insecure-localhost

-2-

На самом кластере можно выкл проверку ТЛС-а:

$ kubectl config set-cluster aws-eks-test --insecure-skip-tls-verify=true

-3-

Генерируем самоподписные серты:

$ mkdir certs &&\
openssl req -nodes -newkey rsa:2048 -keyout certs/dashboard.key -out certs/dashboard.csr -subj "/C=/ST=/L=/O=/OU=/CN=kubernetes-dashboard" &&\
openssl x509 -req -sha256 -days 365 -in certs/dashboard.csr -signkey certs/dashboard.key -out certs/dashboard.crt

Создаем сикрет и пушим ключи в куб:

$ kubectl create secret generic kubernetes-dashboard-certs --from-file=certs -n kubernetes-dashboard

Проверяем все ли зааплоадилось:

$ kubectl describe secret/kubernetes-dashboard-certs -n kubernetes-dashboard

И последним что нужно сделать — это отредактировать деплоймент:

$ kubectl edit deploy kubernetes-dashboard -o yaml -n kubernetes-dashboard

И приводим к виду:

- args:
  - --tls-cert-file=/certs/dashboard.crt
  - --tls-key-file=/certs/dashboard.key

Перебьем под-ы:

$ kubectl delete pod -n kubernetes-dashboard -l app.kubernetes.io/name=kubernetes-dashboard

Дружим Control plane метрики с Prometheus

Смотрим рав метрики:

$ kubectl get --raw /metrics

Создам новый NS:

$ kubectl create namespace prometheus

Деплоим необходимое:

$ helm install prometheus stable/prometheus \
    --namespace prometheus \
    --set alertmanager.persistentVolume.storageClass="gp2",server.persistentVolume.storageClass="gp2",grafana.service.type=LoadBalancer

Или:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
		helm repo add stable https://kubernetes-charts.storage.googleapis.com/
		helm repo update
		helm install prometheus-stack prometheus-community/kube-prometheus-stack \
		--namespace prometheus \
		--set grafana.service.type=LoadBalancer,grafana.adminPassword="I'mrobot"

Проверяем сервис и можем логинится. Можно проверить, есть ли поды так:

$ kubectl get pods --namespace prometheus -l "release=prometheus-stack"

Если необходимо удалить, можно это сделать так:

$ helm list -n prometheus
$ helm uninstall prometheus-stack -n prometheus
$ kubectl delete namespace prometheus

Еще один способ создать и получать метрики, — это задеплоить через ХЕЛМ:

$ helm install metrics-server stable/metrics-server --set hostNetwork.enabled=true

Смотрим логи деплойменга:

$ kubectl logs -n kube-system deploy/metrics-metrics-server

А сейчас, можно получать метрики с куба (они нужны будут для скейлинга ПОД-ов):

$ kubectl top nodes NAME 

Но об скейле — немного позже…

External DNS

Попозже будет. Нет необходимости юзать.

Работаем с serviceaccounts в Kubernetes

TBD.

Создаем масштабирование (автоскейлинг) cluster-autoscaler в AWS EKS кластере

Начну с того, что создам NodeGroup для работы со скейлом:

AWS_EKS_NODEGROUP="nodegroup1" && \
aws eks create-nodegroup \
	--region us-east-1 \
	--profile aws-eks-test \
	--nodegroup-name ${AWS_EKS_NODEGROUP} \
	--cluster-name aws-eks-test \
	--scaling-config minSize=1,maxSize=5,desiredSize=1 \
	--disk-size 30 \
	--subnets subnet-065292d0e6abb34bc subnet-0bed681cb074db448 subnet-0352a2addd013b8e2 \
	--instance-types m5d.xlarge \
	--ami-type AL2_x86_64 \
	--remote-access ec2SshKey=aws-eks-test-eks-nodegroup1-key,sourceSecurityGroups=sg-093ee648c274f6e72 \
	--node-role arn:aws:iam::486668976666:role/K8SWorkersRole \
	--client-request-token $(aws eks get-token --region us-east-1 --profile aws-eks-test --cluster-name aws-eks-test | jq -r '.status.token') \
	--kubernetes-version 1.17 \
	--labels eks.io/managed-by=eks,eks.io/role=K8SWorkersRole,DeploymentRole=${AWS_EKS_NODEGROUP} \
	--tags Name=${AWS_EKS_NODEGROUP},createdby=vnatarov,environment=dev,node-role.kubernetes.io/${AWS_EKS_NODEGROUP}=true,DeploymentRole=${AWS_EKS_NODEGROUP},node-role.kubernetes.io/nodegroup1=nodegroup1,k8s.io/cluster-autoscaler/enabled=true,k8s.io/cluster-autoscaler/nodegroup1=true

PS: Правим под свои нужды, но теги нужно оставить (не все, но все что касается скейла — необходимы).

Смотрим, на состояния машин(ы):

$ kubectl get nodes -o wide

Пока не будет состояние «Ready», можно ждать, но а пока (для удобства) я навешаю лейблы:

$ kubectl label --overwrite nodes ip-10-130-1-205.ec2.internal node-role.kubernetes.io/nodegroup1=nodegroup1

Чтобы отвесить ее, выполняем:

$ kubectl label node ip-10-130-1-240.ec2.internal node-role.kubernetes.io/nodegroup1-

Проверим, что у нас имеется в AWS ASG:

$ NODE_GROUP_NAME="nodegroup1"
aws autoscaling \
    describe-auto-scaling-groups \
    --region us-east-1 \
	--profile aws-eks-test \
    --query "AutoScalingGroups[? Tags[? (Key=='eks:nodegroup-name') && Value=='${NODE_GROUP_NAME}']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" \
    --output text

Можно пробросить переменные для дальнейшего использования:

$ export NODE_GROUP_NAME="nodegroup1" &&\
export ASG_NAME=$(aws autoscaling describe-auto-scaling-groups --region us-east-1 --profile aws-eks-test --query "AutoScalingGroups[? Tags[? (Key=='eks:nodegroup-name') && Value=='${NODE_GROUP_NAME}']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" --output text | awk '{print $1}')

Обновить ASGб можно так:

$ aws autoscaling \
    update-auto-scaling-group \
    --region us-east-1 \
	--profile aws-eks-test \
    --auto-scaling-group-name ${ASG_NAME} \
    --min-size 1 \
    --desired-capacity 1 \
    --max-size 5

И так, сейчас займусь автоскейлом EC2 машинок. Для удобства, создам папку для проекта:

$ mkdir -p ~/environment/cluster-autoscaler

Полиси, будет такая:

$ cat <<EoF > ~/environment/cluster-autoscaler/k8s-asg-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeLaunchTemplateVersions"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}
EoF

Создаем ее:

$ aws iam create-policy   \
	--region us-east-1 \
	--profile aws-eks-test \
  	--policy-name k8s-asg-policy \
  	--policy-document file://~/environment/cluster-autoscaler/k8s-asg-policy.json

После чего, аттачим даную полись в вашу роль!

Проверим наличие identity в кластере:

$ aws eks describe-cluster \
	--region us-east-1 \
	--profile aws-eks-test \
	--name aws-eks-test \
	--query "cluster.identity.oidc.issuer" \
	--output text

Создаем ServiceAccount:

cat <<EoF > ~/environment/cluster-autoscaler/ServiceAccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::486668976666:role/K8SWorkersRole
EoF

Применяем найстройки:

$ kubectl apply -f ~/environment/cluster-autoscaler/ServiceAccount.yaml

NOTE: Можно и без нее, т.к я буду использовать ее в другом месте с другим названием, но можно и создать ее тут.

Далее, качаем автоскейлер для AWS EKS:

$ wget -O ~/environment/cluster-autoscaler/ca-autodiscover_nodegroup1.yaml https://www.eksworkshop.com/beginner/080_scaling/deploy_ca.files/cluster-autoscaler-autodiscover.yaml

Или, то что предлагает AWS документация:

$ wget -O ~/environment/cluster-autoscaler/ca-autodiscover_nodegroup1.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

Далее, поправим файл при необходимости, мой выглядит так:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler-nodegroup-1
  name: cluster-autoscaler-nodegroup-1
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler-nodegroup-1
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler-nodegroup-1
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler-nodegroup-1
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler-nodegroup-1
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create","list","watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler-nodegroup-1
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler-nodegroup-1
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler-nodegroup-1
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler-nodegroup-1
    namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler-nodegroup-1
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler-nodegroup-1
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler-nodegroup-1
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler-nodegroup-1
    namespace: kube-system

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler-nodegroup-1
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
    spec:
      serviceAccountName: cluster-autoscaler-nodegroup-1
      containers:
        - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.17.3
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 300Mi
            requests:
              cpu: 100m
              memory: 300Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/nodegroup1
            - --balance-similar-node-groups
            - --skip-nodes-with-system-pods=false
          env:
            - name: AWS_REGION
              value: us-east-1
            - name: AWS_ROLE_ARN
              value: arn:aws:iam::486668976666:role/AmazonEKSClusterRole
            # - name: AWS_WEB_IDENTITY_TOKEN_FILE
            #   value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt
              readOnly: true
          imagePullPolicy: "Always"
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"

Нужно проставить теги с вашими нуждами + поменять имедж!

Идем в AWS ASG и добавляем ключи:

k8s.io/cluster-autoscaler/enabled
k8s.io/cluster-autoscaler/nodegroup1

Значения ставим «true». Сохраняем и… можем деплоить сие-чудо:

$ kubectl apply -f ~/environment/cluster-autoscaler/ca-autodiscover_nodegroup1.yaml

Делаем аннотейшен (как говорит AWS доки):

$ kubectl -n kube-system \
	annotate deployment.apps/cluster-autoscaler-nodegroup1 \
	cluster-autoscaler.kubernetes.io/safe-to-evict="false"

Смотрим деплоймент, все ли там гладко и хватает всего-ли:

$ kubectl -n kube-system logs -f deployment/cluster-autoscaler-nodegroup1 

Для тестирования, можно использовать любой деплоймент. При этом, автоскейлер должен понять что в кубе не хватает ресурсов и проскейлит ноду(ы) еще.

После чего, прибить можно все барахло так:

$ kubectl delete -f ~/environment/cluster-autoscaler/ca-autodiscover_nodegroup1.yaml && \
AWS_EKS_NODEGROUP="nodegroup1" && \
aws eks delete-nodegroup \
		--region us-east-1 \
		--profile aws-eks-test \
		--nodegroup-name ${AWS_EKS_NODEGROUP} \
		--cluster-name aws-eks-test

Создаем HPA масштабирование (автоскейлинг POD-ов) в AWS EKS кластере

Создаем файл с таким содержанием:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: hpa-nodegroup-1
  namespace: nodegroup-1

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: hpa-nodegroup-1
  namespace: nodegroup-1
rules:
- apiGroups: ["autoscaling"]
  resources: ["horizontalpodautoscalers"]
  verbs: ["get", "list", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: hpa-nodegroup-1
  namespace: nodegroup-1
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: hpa-nodegroup-1
subjects:
- kind: ServiceAccount
  name: hpa-nodegroup-1
  namespace: nodegroup-1

---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-nodegroup-1-autoscaleby-cpu
  namespace: nodegroup-1
spec:
  minReplicas: 1 # minimum replicas of pods
  maxReplicas: 4 # maximum replicas of pods
  scaleTargetRef:
    apiVersion: apps/v1
    kind: StatefulSet
    name: nodegroup-1 # TARGET name of the StatefulSet the autoscaler need to be run on
  targetCPUUtilizationPercentage: 30 # CPU maximum amount of use on the pod is set to 30%.
  
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-nodegroup-1-autoscaleby-mem
  namespace: nodegroup-1
spec:
  minReplicas: 1 # minimum replicas of pods
  maxReplicas: 4 # maximum replicas of pods
  scaleTargetRef:
    apiVersion: apps/v1
    kind: StatefulSet
    name: nodegroup-1 # StatefulSet name
  metrics:
  - type: Resource
    resource:
      name: memory
      targetAverageUtilization: 40

    # - type: Resource
    #   resource:
    #     name: cpu
    #     targetAverageValue: 20m

Задеплоим его:

kubectl apply -f ~/environment/cluster-autoscaler/hpa_nodergroup-1.yaml

Смотрим на hpa:

$ kubectl get hpa -A

или:

$ kubectl get horizontalpodautoscalers.autoscaling -A

Можно поиграться и сделать реплику:

$ kubectl scale statefulsets -n nodegroup-1 hpa_nodergroup-1 --replicas=2

После некоторого времени, HPA прибьет реплику из-за необходимости (если не будет CPU/Mem утилизации).

Как-то так.

Полезные DEBUG-инг/фичи

Если не деплоили tiller в K8S, то возможно убить ресурсы так (Пример с неймспейсом):

$ export NAM_SPACE="management-ui";
kubectl get ns $NAM_SPACE -o json  > tmp.json && \
curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/$NAM_SPACE/finalize

Для удаление всех ресурсов с куба, можно заюзать:

$ kubectl delete daemonsets,replicasets,services,deployments,pods,rc --all

А на этом, у меня все, статья «Создание AWS EKS кластера в Unix/Linux» завершена.

This entry was posted in Без рубрики. Bookmark the permalink.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.