В этой заметке я опишу, как развернуть серверное приложение на EKS с помощью Fargate. Я также рассмотрю все проблемы, с которыми я столкнулся во время развертывания. Это мой первый раз, когда я использую EKS!
- Шаг (1) — Настройка учетных данных и окружения
- Шаг (2) — Настройка VPC
- (3) Обеспечение кластера EKS с помощью eksctl
- Установка переменных окружения
- Создание кластера EKS
- Подключение к кластеру EKS
- (4) Развертывание приложения!
- Установка дополнения AWS Load Balancer Controller
- Развертывание приложения
- Решение проблемы: 504 таймаут шлюза
- Подведение итогов
- Дополнительно
Шаг (1) — Настройка учетных данных и окружения
-
Ниже приведены необходимые инструменты, которые нам понадобятся для успешного развертывания EKS в этом посте.
- AWS CLI v2: Установите, следуя этой документации.
- kubectl: установите версию 1.23.6, поскольку мы будем развертывать с помощью kubernetes версии 1.21.
curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.22.6/2022-03-09/bin/darwin/amd64/kubectl
cd ~/.kube
chmod +x ./kubectl
mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl &&
export PATH=$HOME/bin:$PATH
echo 'export PATH=$PATH:$HOME/bin' >> ~/.bash_profile
kubectl version --short --client
- eksctl: Следуйте этой документации для установки eksctl.
После установки всех трех вышеперечисленных инструментов создайте пользователя IAM с разрешенным доступом к программированию для использования в локальном терминале и выполните несколько задач. В моем случае я создал временного IAM пользователя и прикрепил к нему политику AdministratorAccess
.
Мы также будем использовать KMS, которая предоставляет простые способы настройки и управления ключами шифрования, используемыми различными службами AWS.
aws kms create-alias --alias-name alias/demo-eks --target-key-id $(aws kms create-key --query KeyMetadata.Arn --output text)
- В дальнейшем мы будем использовать ARN созданного CMK, поэтому давайте сохраним его как переменную окружения.
export MASTER_ARN=$(aws kms describe-key --key-id alias/demo-eks --query KeyMetadata.Arn --output text)
echo $MASTER_ARN > master_arn.txt
Шаг (2) — Настройка VPC
-
Теперь мы создадим новый VPC, который будет использоваться кластером EKS, который мы создадим позже.
-
eks-vpc-3az.yaml — это файл, который будет использоваться CloudFormation для создания ресурсов ниже.
- VPC.
- 3 публичные подсети.
- 3 частные подсети.
- 1 интернет-шлюз.
- 3 NAT-шлюза.
- 3 публичные таблицы маршрутов и 3 частные таблицы маршрутов для каждой подсети соответственно.
- Группы безопасности для кластера EKS.
-
Давайте создадим этот VPC с помощью следующей команды.
aws cloudformation deploy
--stack-name "demo-eks-vpc"
--template-file "eks-vpc-3az.yaml"
--capabilities CAPABILITY_NAMED_IAM
-
Примерно через 5 минут мы видим, что в AWS Management Console был создан совершенно новый VPC.
-
Перейдя на страницу CloudFormation, после выбора стека «demo-eks-vpc», мы можем увидеть результаты, как показано ниже на вкладке
output
.
(3) Обеспечение кластера EKS с помощью eksctl
Установка переменных окружения
- ID VPC, который мы создали в шаге (2), и ID подсети будут часто использоваться в этом шаге, поэтому запустим скрипт, как показано ниже, чтобы использовать их в качестве переменных окружения.
#VPC ID
export vpc_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=demo-eks-vpc | jq -r '.Vpcs[].VpcId')
echo $vpc_ID
#Subnet ID, CIDR, Subnet Name
aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)'
echo $vpc_ID > vpc_subnet.txt
aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' >> vpc_subnet.txt
cat vpc_subnet.txt
# Store VPC ID, Subnet IDs as environment variables.
export PublicSubnet01=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PublicSubnet01/{print $1}')
export PublicSubnet02=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PublicSubnet02/{print $1}')
export PublicSubnet03=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PublicSubnet03/{print $1}')
export PrivateSubnet01=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PrivateSubnet01/{print $1}')
export PrivateSubnet02=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PrivateSubnet02/{print $1}')
export PrivateSubnet03=$(aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_ID | jq -r '.Subnets[]|.SubnetId+" "+.CidrBlock+" "+(.Tags[]|select(.Key=="Name").Value)' | awk '/demo-eks-vpc-PrivateSubnet03/{print $1}')
echo "export vpc_ID=${vpc_ID}" | tee -a ~/.bash_profile
echo "export PublicSubnet01=${PublicSubnet01}" | tee -a ~/.bash_profile
echo "export PublicSubnet02=${PublicSubnet02}" | tee -a ~/.bash_profile
echo "export PublicSubnet03=${PublicSubnet03}" | tee -a ~/.bash_profile
echo "export PrivateSubnet01=${PrivateSubnet01}" | tee -a ~/.bash_profile
echo "export PrivateSubnet02=${PrivateSubnet02}" | tee -a ~/.bash_profile
echo "export PrivateSubnet03=${PrivateSubnet03}" | tee -a ~/.bash_profile
source ~/.bash_profile
- После выполнения всех команд, приведенных выше, идентификаторы VPC и подсети будут сохранены в переменных окружения. Также будет создан файл
vpc_subnet.txt
, который будет выглядеть следующим образом.
vpc-0e88a2ed7a32c0336
subnet-02b5356084f4355cb 10.11.16.0/20 demo-eks-vpc-PublicSubnet02
subnet-0ea280f1567234a3b 10.11.253.0/24 demo-eks-vpc-TGWSubnet03
subnet-0a79d22a3acf610bf 10.11.32.0/20 demo-eks-vpc-PublicSubnet03
subnet-0c96f4c64e724524b 10.11.251.0/24 demo-eks-vpc-TGWSubnet01
subnet-0d5d255e8542cf405 10.11.64.0/20 demo-eks-vpc-PrivateSubnet02
subnet-0c3c37774542ac95c 10.11.252.0/24 demo-eks-vpc-TGWSubnet02
subnet-07f97eaa984b5ced2 10.11.0.0/20 demo-eks-vpc-PublicSubnet01
subnet-0ebb353a91c36ab17 10.11.48.0/20 demo-eks-vpc-PrivateSubnet01
subnet-0e3c3abe52dbe07e8 10.11.80.0/20 demo-eks-vpc-PrivateSubnet03
- Давайте также сохраним код региона AWS.
export AWS_REGION=ap-northeast-2 # in my case
Создание кластера EKS
- Имя кластера и версия Kubernetes будут использоваться в yaml-файлах, поэтому давайте сохраним их как переменные окружения.
export ekscluster_name="demo-eks"
export eks_version="1.21"
-
Для создания кластера EKS мы будем использовать файл eks-cluster-3az.yaml.
-
Мы настроим узлы на использование Fargate вместо EC2, и, согласно этой документации, Fargate должен быть предоставлен в частных подсетях.
-
Выполним приведенную ниже команду, чтобы заполнить переменные окружения фактическими значениями в eks-cluster-3az.yaml
cat << EOF > eks-cluster-3az.yaml
# A simple example of ClusterConfig object:
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: ${ekscluster_name}
region: ${AWS_REGION}
version: "${eks_version}"
vpc:
id: ${vpc_ID}
subnets:
private:
PrivateSubnet01:
az: ${AWS_REGION}a
id: ${PrivateSubnet01}
PrivateSubnet02:
az: ${AWS_REGION}b
id: ${PrivateSubnet02}
PrivateSubnet03:
az: ${AWS_REGION}c
id: ${PrivateSubnet03}
secretsEncryption:
keyARN: ${MASTER_ARN}
fargateProfiles:
- name: demo-dev-fp
selectors:
- namespace: demo-dev
- namespace: kube-system
subnets:
- ${PrivateSubnet01}
- ${PrivateSubnet02}
- ${PrivateSubnet03}
cloudWatch:
clusterLogging:
enableTypes:
["api", "audit", "authenticator", "controllerManager", "scheduler"]
EOF
Профиль Fargate необходим для запуска ресурсов на Fargate.(fargateProfiles). Любые ресурсы, которые соответствуют критериям, определенным в
fargateProfiles.selectors
, будут запускаться на Fargate.
В примере выше мы использовали demo-dev, пространство имен, которое будут использовать ресурсы, связанные с приложением, и kube-system.
kube-system будет использоваться для предоставления дополнительных ресурсов, таких как aws-load-balancer-controller, который мы установим позже.
Если мы исключим пространство имен kube-system, то при установке aws-load-balancer-controller мы получим ошибку, как показано ниже.ingress 0/2 nodes are available: 2 node(s) had taint {eks.amazonaws.com/compute-type: fargate}, that the pod didn't tolerate.
- Теперь выполним приведенную ниже команду для создания кластера!
eksctl create cluster --config-file=eks-cluster-3az.yaml
Подключение к кластеру EKS
- Когда мы выполним команду
kubectl get svc
, мы получим результат, как показано ниже, что означает, что кластер EKS готов!
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 43m
Значение PORT(S) может быть другим, но не волнуйтесь.
(4) Развертывание приложения!
- Во-первых, давайте создадим пространство имен Kubernetes, где мы будем создавать ресурсы для нашего приложения.
Выше, когда мы создавали профиль faragte, мы поместили
namespace: demo-dev
в полеfargateProfiles.selectors
.
kubectl create ns demo-dev
Установка дополнения AWS Load Balancer Controller
-
AWS Load Balancer Controller управляет AWS Elastic Load Balancers(ELB), используемыми кластером Kubernetes. Этот контроллер обеспечивает:
- Предоставление нового AWS ALB при создании Kubernetes
Ingress
. - Предоставление нового AWS NLB при создании Kubernetes
LoadBalancer
.
- Предоставление нового AWS ALB при создании Kubernetes
-
Перед установкой AWS Load Balancer Controller необходимо сначала интегрировать провайдера OIDC.
-
Настройка OIDC ID Provider(IdP) в кластере EKS позволяет использовать роли AWS IAM для учетных записей служб Kubernetes, а это требует наличия провайдера IAM OIDC в кластере. Выполним приведенную ниже команду для интеграции OIDC в кластер.
eksctl utils associate-iam-oidc-provider --cluster demo-eks --approve
# 2022-08-23 16:04:39 [ℹ] will create IAM Open ID Connect provider for cluster "demo-eks" in "ap-northeast-2"
# 2022-08-23 16:04:40 [✔] created IAM Open ID Connect provider for cluster "demo-eks" in "ap-northeast-2"
Теперь мы готовы к установке дополнения AWS Load Balancer Controller! Установите его, следуя шагам, описанным в этой документации.
Развертывание приложения
- В моем случае я использовал приложение, которое по умолчанию использовало порт номер 8080. Я не хотел менять номер порта по умолчанию, поэтому я создал простой yaml файл (deployment.yaml) для развертывания Kubernetes, а также создал yaml файл для Kubernetes Service, как показано ниже.
apiVersion: v1
kind: Service
metadata:
name: demo-dev-svc
namespace: demo-dev
spec:
selector:
app: demo
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: NodePort
-
Как вы можете видеть, тип сервиса
NodePort
, и тип должен бытьNodePort
при использовании Fargate на EKS. -
Кроме того, сервис будет получать запросы с порта номер 80, и перенаправлять запрос в pods, используя порт pod’s номер 8080.
-
Наконец, давайте создадим Kubernetes Ingress, который в конечном итоге создаст AWS ALB с помощью дополнения AWS Load Balancer Controller.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-dev-ingress
namespace: demo-dev
annotations:
alb.ingress.kubernetes.io/load-balancer-name: demo-dev-lb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/subnets: ${PUBLIC_SUBNET_IDS}
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: ${ACM_CERT_ARN}
alb.ingress.kubernetes.io/security-groups: ${SECURITY_GROUP_FOR_ALB}
alb.ingress.kubernetes.io/healthcheck-port: "8080"
alb.ingress.kubernetes.io/healthcheck-path: /actuator/health
alb.ingress.kubernetes.io/success-codes: "200"
spec:
ingressClassName: alb
rules:
- host: alb-url.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-dev-svc
port:
number: 80
-
В спецификации мы заставим ALB перенаправлять все запросы к сервису
demo-dev-svc
Kubernetes. -
Об аннотациях вы можете прочитать в этом документе.
-
Обратите внимание, что
alb.ingress.kubernetes.io/target-type
должен быть установлен вip
при использовании Fargate. -
Также ALB, созданный при создании этого Ingress, должен получать трафик из интернета, поэтому его следует разместить в публичных подсетях(
alb.ingress.kubernetes.io/subnets: ${PUBLIC_SUBNET_IDS}
), и он должен быть ориентирован на интернет(alb.ingress.kubernetes.io/scheme: internet-facing
). -
Теперь, когда мы применим новый Ingress к Kubernetes, будет создан новый ALB с соответствующим настроенным правилом слушателя.
-
Но когда мы просмотрим проверку работоспособности ALB на целевых группах, она завершится неудачей, сообщив
504 gateway timeout
.
поскольку группа безопасности по умолчанию, прикрепленная к стручкам Fargate, не разрешает входящие запросы на порт 8080.
Решение проблемы: 504 таймаут шлюза
-
Это происходит потому, что стандартная группа безопасности, подключенная к капсулам Fargate, не разрешает входящие запросы на порт 8080.
-
Поэтому нам нужно настроить пользовательские группы безопасности для стручков Fargate, что описано в этой документации.
-
Согласно документации выше, новая группа безопасности должна:
- Разрешить входящий запрос на порт 53(TCP) от группы безопасности кластера EKS.
- Разрешить входящий запрос на порт 53(UDP) от группы безопасности кластера EKS.
-
Давайте создадим новую группу безопасности и применим приведенный ниже yaml-файл.
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
name: dev-sgp
namespace: demo-dev
spec:
podSelector:
matchLabels:
app: demo
securityGroups:
groupIds:
- ${NEW_CREATED_SECURITY_GROUP_ID}
- ${EKS_CLUSTER_SECURITY_GROUP_ID}
-
Когда мы применим yaml-файл, мы должны перезапустить все капсулы, так как новая группа безопасности не повлияет на уже запущенные капсулы.
-
Теперь, когда мы проверяем состояние ALB, мы видим, что проверка состояния целевых групп успешно выполнена, и все цели здоровы.
Подведение итогов
-
Вот и все! В этом посте я не хотел фокусироваться на основах Kubernetes, но хотел поделиться тем, как я устранял проблемы, с которыми столкнулся в процессе развертывания.
-
Кроме того, существует масса документов, с которыми можно ознакомиться, когда мы сталкиваемся с какими-либо проблемами при развертывании ресурсов Kubernetes. Я хотел свести эти документы к тому, что нам действительно нужно увидеть, поэтому я включил в этот пост так много ссылок на документы.
Дополнительно
- Когда мы войдем в AWS Management Console с учетной записью root и посетим страницу сервиса EKS, мы увидим предупреждение, как показано ниже.
Your current user or role does not have access to Kubernetes objects on this EKS cluster This may be due to the current user or role not having Kubernetes RBAC permissions to describe cluster resources or not having an entry in the cluster’s auth config map.
- Если вы хотите просмотреть свои ресурсы на кластере EKS, выполните следующую команду.
kubectl edit configmap aws-auth -n kube-system
- И добавьте следующие поля на ту же глубину, что и
mapRoles
.
mapUsers: |
- userarn: arn:aws:iam::[account_id]:root
groups:
- system:masters
- После сохранения и выхода вы сможете просматривать все ресурсы в вашем кластере EKS.