25
AWS sin VMs - Capitulo 1: EKS Fargate
En esta serie de artículos intentaré cumplir un sueño personal, que es implementar una arquitectura de microservicios production-ready en AWS sin tener que administrar ni una sola maquina virtual. En términos de AWS, no vamos a crear ninguna instancia EC2.
Vamos a hacer uso extensivo de los servicios manejados de AWS, incluyendo Elastic Kubernetes Service, API Gateway, AWS WAF, ElasticSearch, Grafana, entre otros.
A continuación les presento un diagrama de lo que vamos a estar desplegando en éste y los próximos capítulos.
En esta primera edición vamos a enfocarnos en el despliegue de Kubernetes, haciendo uso de Fargate, lo que nos va a permitir tener un cluster de K8s totalmente manejado por AWS.
Vamos a asumir que tienen un conocimiento básico de AWS, Kubernetes y Terraform, y de que cuentan con las respectivas herramientas instaladas en sus máquinas.
El listado de herramientas a utilizar en este artículo son:
AWS nos presenta dos principales formas de desplegar un cluster de Kubernetes. Por un lado, tenemos la posibilidad de que AWS se haga cargo sólo del plano de control, dejándonos a nosotres la gestión de los nodos de cómputo.
Por otro lado, tenemos Fargate, que AWS describe como un motor de cómputo serverless que es compatible tanto con EKS como con ECS (el servicio de contenedores propio de AWS). Esto nos permite dejar a AWS la gestión completa de los nodos, tanto del plano de control, como de los nodos de cómputo. Como ya dijimos al comienzo, nuestro objetivo es no tener que manejar ninguna instancia, por lo cual iremos por esta alternativa.
Vamos a utilizar Terraform para crear nuestro cluster EKS y los recursos que éste necesita. A continuación les comparto un extracto relevante de éste.
resource "aws_eks_cluster" "main" {
name = "${var.name}-${var.environment}"
role_arn = aws_iam_role.eks_cluster_role.arn
enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
vpc_config {
subnet_ids = concat(aws_subnet.public.*.id, aws_subnet.private.*.id)
}
timeouts {
delete = "30m"
}
depends_on = [
aws_cloudwatch_log_group.eks_cluster,
aws_iam_role_policy_attachment.AmazonEKSClusterPolicy,
aws_iam_role_policy_attachment.AmazonEKSServicePolicy
]
}
Clonamos el repositorio con los archivos de Terraform y desplegamos el cluster. Pueden editar el archivo test.tfvars
para modificar parámetros como el nombre del cluster, o los CIDR de las subredes.
git clone https://github.com/BenjaDiaz/aws-sin-vms
cd aws-sin-vms/1-fargate
terraform apply -var-file=test.tfvars
Una vez creado el cluster, podemos configurar nuestro kubeconfig. Vamos a cargar en una variable de ambiente el nombre de nuestro cluster para así facilitarnos la vida.
CLUSTER_NAME=pinkiepie-test
aws --region us-east-1 eks update-kubeconfig --name $CLUSTER_NAME
Ahora deben configurar kubectl para que utilice el contexto correspondiente a nuestro nuevo cluster. Les recomiendo que para el manejo de contextos utilicen kubectx.
Ahora debiésemos poder listar los pods disponibles. Por ahora, sólo debiesen figurar los de coredns.
kubectl -n kube-system get pods
Antes de poder desplegar un pod en Fargate, es necesario definir un perfil que establezca qué pods van a poder ejecutarse sobre éste. A continuación crearemos uno para todos los recursos del namespace ponyville
. Sólo podremos desplegar pods que tengan un perfil de Fargate asociado.
eksctl create fargateprofile \
--cluster $CLUSTER_NAME \
--name ponyville \
--namespace ponyville
Por defecto, CoreDNS asume que se va a ejecutar sobre una instancia EC2. Para poder hacerlo funcionar en Fargate, es necesario hacer algunas modificaciones.
Primero creamos un perfil de Fargate para los pods de core-dns, que se encuentran en el namespace de kube-system:
eksctl create fargateprofile \
--cluster $CLUSTER_NAME \
--name coredns \
--namespace kube-system \
--labels k8s-app=kube-dns
Luego, editamos los pods de CoreDNS para que se puedan desplegar sobre Fargate:
kubectl patch deployment coredns \
-n kube-system \
--type json \
-p='[{"op": "remove", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1compute-type"}]'
Al cabo de unos minutos debiesen poder ver los pods de coredns en estado Ready.
La documentación oficial de AWS para esto la encuentran aquí:
https://docs.aws.amazon.com/eks/latest/userguide/fargate-getting-started.html#fargate-gs-coredns
Para poder acceder a nuestros servicios vía Ingress, necesitamos configurar un Ingress Controller que se haga cargo de la creación de Load Balancers en AWS. Hay una gran gama de alternativas, pero en nuestro caso utilizaremos ALB Ingress Controller.
Primero necesitamos habilitar la integración de roles IAM con Service Accounts de Kubernetes. Para esto hay que asociar un provider OIDC.
eksctl utils associate-iam-oidc-provider --cluster pinkiepie-test --approve
Luego creamos la politica IAM que va a utilizar el controller.
curl -o alb-ingress-iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/master/docs/examples/iam-policy.json
aws iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document file://alb-ingress-iam-policy.json
El controller también va a requerir de una ServiceAccount con los permisos respectivos. Primero creamos el ClusterRole y el RoleBinding.
cat > rbac-role.yaml <<-EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
rules:
- apiGroups:
- ""
- extensions
resources:
- configmaps
- endpoints
- events
- ingresses
- ingresses/status
- services
verbs:
- create
- get
- list
- update
- watch
- patch
- apiGroups:
- ""
- extensions
resources:
- nodes
- pods
- secrets
- services
- namespaces
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alb-ingress-controller
subjects:
- kind: ServiceAccount
name: alb-ingress-controller
namespace: kube-system
EOF
kubectl apply -f rbac-role.yaml
Ahora podemos crear la ServiceAccount.
AWS_ACCOUNT_ID=$(aws sts get-caller-identity | jq -r '.Account')
eksctl create iamserviceaccount \
--name alb-ingress-controller \
--namespace kube-system \
--cluster $CLUSTER_NAME \
--attach-policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/ALBIngressControllerIAMPolicy \
--approve
Antes de desplegar el controller, creamos otro perfil de Fargate para esto:
eksctl create fargateprofile \
--cluster $CLUSTER_NAME \
--name alb-ingress-controller \
--namespace kube-system \
--labels "app.kubernetes.io/name"=alb-ingress-controller
Finalmente desplegamos el controller.
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-vpc" | jq -r '.Vpcs[0].VpcId')
AWS_REGION=us-east-1
cat > alb-ingress-controller.yaml <<-EOF
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
namespace: kube-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: alb-ingress-controller
template:
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
spec:
containers:
- name: alb-ingress-controller
args:
- --ingress-class=alb
- --cluster-name=$CLUSTER_NAME
- --aws-vpc-id=$VPC_ID
- --aws-region=$AWS_REGION
image: docker.io/amazon/aws-alb-ingress-controller:v1.1.6
serviceAccountName: alb-ingress-controller
EOF
kubectl apply -f alb-ingress-controller.yaml
Ya tenemos todo listo para desplegar una aplicación de prueba.
kubectl create namespace ponyville
kubectl -n ponyville apply -f 2048.yaml
Ahora esperen unos minutos y debiesen poder ver el campo ADDRESS en el estado del ingress.
kubectl -n ponyville get ingresses.networking.k8s.io
Debiesen poder acceder a esa URL y visualizar la aplicación de prueba.
Gracias por llegar al final del primer capítulo de esta aventura! Desplegamos un cluster EKS, configuramos un Ingress Controller y desplegamos una aplicación de prueba. Todo esto sin tener que levantar ninguna máquina virtual!
En el próximo episodio vamos a automatizar la creación de registros en Route53 y luego configuraremos un API Gateway para poder acceder a un par de servicios de prueba que ejecutaremos en nuestro cluster EKS.
Nos vemos!
Todos los recursos que vayamos a utilizar en esta serie de artículos los pueden encontrar aquí:
25