Un Application Load Balancer est un pont créé entre le trafic entrant et plusieurs cibles (par exemple plusieurs pods/replicas pour une application). Son objectif est de permettre aux applications hébergées sur vos pods d’avoir une haute disponibilité.
Nous allons maintenant voir comment implémenter un Application Load Balancer grâce à 2 ingress controllers : l’ALB ingress controller et le Nginx ingress controller. Pourquoi en utiliser 2 ?
Dans ce tutoriel, nous allons déployer les 2. Il est important de noter que le Nginx ingress controller gérera toutes les ressources d'entrée de vos applications dans votre cluster EKS tandis que l’ALB ingress controller gérera le cycle de vie de votre instance ALB. (cf schéma ci-dessous)
Etant donné que l’implémentation de votre ALB se fait dans votre cluster EKS, votre Chart Helm ALB ingress controller aura besoin de permissions pour créer des ressources AWS. Le Chart Helm aura besoin d’un rôle AWS lui permettant de déployer une instance ALB que vous pourrez lui créer dans le service AWS IAM.
Qu’est ce qu’un identity provider AWS ?
Un identity provider donne à un utilisateur externe certaines autorisations au sein d’AWS.
Pour le créer nous avons besoin de 3 éléments : le type de l’identity provider, son droit et son URL.
aws eks describe-cluster --name <CLUSTER_NAME> --query “cluster.identity.oidc.issuer” --output text
https://oidc.eks.<region>.amazonaws.com/id/EXAMPLE86F27C29EF05B482628D9790EA706
Une fois que vous aurez récupéré l’ensemble des informations nécessaires, il faudra vous rendre dans la console AWS, dans le service IAM et cliquer sur la section “Identity provider”. Dans cette section, vous pourrez créer un provider comme illustré ci-dessous :
Le Chart Helm devra utiliser un rôle IAM de cet Identity Provider. Il vous faut donc créer un nouveau rôle IAM.
Dans la section “Identity provider”, choisissez le bon provider puis entrez le droit : "sts.amazonaws.com".
Ensuite, ajoutez les politiques suivantes pour ce rôle :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:UpdateAutoScalingGroup",
"ec2:AttachVolume",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateRoute",
"ec2:CreateSecurityGroup",
"ec2:CreateTags",
"ec2:CreateVolume",
"ec2:DeleteRoute",
"ec2:DeleteSecurityGroup",
"ec2:DeleteVolume",
"ec2:DescribeInstances",
"ec2:DescribeRouteTables",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeVolumes",
"ec2:DescribeVolumesModifications",
"ec2:DescribeVpcs",
"ec2:DescribeDhcpOptions",
"ec2:DescribeNetworkInterfaces",
"ec2:DetachVolume",
"ec2:ModifyInstanceAttribute",
"ec2:ModifyVolume",
"ec2:RevokeSecurityGroupIngress",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
"elasticloadbalancing:AttachLoadBalancerToSubnets",
"elasticloadbalancing:ConfigureHealthCheck",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateLoadBalancerListeners",
"elasticloadbalancing:CreateLoadBalancerPolicy",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:DeleteListener",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DeleteLoadBalancerListeners",
"elasticloadbalancing:DeleteTargetGroup",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeLoadBalancerPolicies",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DetachLoadBalancerFromSubnets",
"elasticloadbalancing:ModifyListener",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer",
"elasticloadbalancing:SetLoadBalancerPoliciesOfListener",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iam:CreateServiceLinkedRole",
"Resource": "*",
"Condition": {
"StringLike": {
"iam:AWSServiceName": "elasticloadbalancing.amazonaws.com"
}
}
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:DescribeCertificate",
"acm:ListCertificates",
"acm:GetCertificate"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateSecurityGroup",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:DeleteSecurityGroup",
"ec2:DescribeAccountAttributes",
"ec2:DescribeAddresses",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInternetGateways",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeTags",
"ec2:DescribeVpcs",
"ec2:ModifyInstanceAttribute",
"ec2:ModifyNetworkInterfaceAttribute",
"ec2:RevokeSecurityGroupIngress"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:AddListenerCertificates",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateRule",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:DeleteListener",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DeleteRule",
"elasticloadbalancing:DeleteTargetGroup",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeListenerCertificates",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeRules",
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:ModifyListener",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:ModifyRule",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:RemoveListenerCertificates",
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:SetIpAddressType",
"elasticloadbalancing:SetSecurityGroups",
"elasticloadbalancing:SetSubnets",
"elasticloadbalancing:SetWebACL"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"iam:GetServerCertificate",
"iam:ListServerCertificates"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cognito-idp:DescribeUserPoolClient"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"waf-regional:GetWebACLForResource",
"waf-regional:GetWebACL",
"waf-regional:AssociateWebACL",
"waf-regional:DisassociateWebACL"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"tag:GetResources",
"tag:TagResources"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"waf:GetWebACL"
],
"Resource": "*"
}
]
}
Nous disposons désormais d'un rôle IAM prêt à être utilisé par un compte de service dans votre cluster EKS. Il nous faut désormais installer le Nginx ingress controller puis le ALB ingress controller.
Avant de débuter l’installation de vos ingress controllers, vous allez tagguer vos sous-réseaux. Pour créer l’instance ALB dans les bons sous-réseaux vous devez apposer les tags suivants à votre ALB ingress controller :
------ For public subnets ------
- Key: kubernetes.io/cluster/<CLUSTERNAME>
Value: shared
- Key: kubernetes.io/role/elb
Value: 1
------ For private subnets ------
Key: kubernetes.io/role/internal-elb
Value: 1
Pour l’installer, vous allez ajouter un nouveau repo Helm à votre cluster “http://storage.googleapis.com/kubernetes-charts-incubator” grâce à la commande :
helm add repo <repository_name>>https://kubernetes-charts.storage.googleapis.com
Vous pouvez choisir le nom de repo que vous souhaitez. Une fois que c’est fait, vous pouvez désormais installer le Chart Helm avec la commande suivante :
helm install <repository_name>/nginx-ingress --set-string controller.service.externalTrafficPolicy=Local --set-string controller.service.type=NodePort --set controller.publishService.enabled=true --set serviceAccount.create=true --set rbac.create=true --set-string controller.config.server-tokens=false --set-string controller.config.use-proxy-protocol=false --set-string controller.config.compute-full-forwarded-for=true --set-string controller.config.use-forwarded-headers=true --set controller.metrics.enabled=true --set controller.autoscaling.maxReplicas=1 --set controller.autoscaling.minReplicas=1 --set controller.autoscaling.enabled=true --namespace kube-system
Tout d’abord, vous devez ajouter le bon repo Helm à ce chart : helm add repo <repo_name> <http://storage.googleapis.com/kubernetes-charts-incubator
>
Ensuite, vous allez pouvoir installer ce Chart Helm “ALB Ingress controller” puis le Chart Helm suivant :
helm install <repo_name>/aws-alb-ingress-controller --set clusterName=<CLUSTER_NAME> --set awsRegion=<AWS_REGION> --set awsVpcID=<VPC_ID> --set rbac.serviceAccountAnnotations.eks\.amazonaws\.com/role-arn=<ROLE_ARN> --set scope.ingressClass=alb --namespace kube-system
N’oubliez pas de changer les variables suivantes :
<CLUSTER_NAME>
(par le nom de votre cluster)<AWS_REGION>
(par la région AWS correspondante)<VPC_ID>
(par le bon ID VPC)<ROLE_ARN>
(par le rôle IAM que vous avez créé)Pour vérifier que les pods sont correctement crées, exécutez la commande suivante :
kubectl get pods -n kube-system
On configure plusieurs variables dans le Chart Helm mais il est important d’avoir en tête que le Nginx ingress controller sera un service Nodeport et non ClusterIP.
Pour connecter l’ALB au Nginx ingress controller, vous allez devoir créer une ressource d’entrée Kubernetes dans le namespace kube-system avec la configuration suivante :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/certificate-arn: <CERTIFICATE_ARN>
alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/subnets: <SUBNETS_LIST>
kubernetes.io/ingress.class: alb
name: alb-ingress-connect-nginx
namespace: kube-system
spec:
backend:
serviceName: <NGINX_INGRESS_CONTROLLER_SERVICE_NAME>
servicePort: http
Dans ce fichier, changez <CERTIFICATE_ARN>
, <SUBNETS_LIST>
et <NGINX_INGRESS_CONTROLLER_SERVICE_NAME>
.
Cette configuration suppose que vous disposez déjà d’un certificat valide, si ça n’est pas le cas créez en un.
Exécutez la commande suivante pour créer cette ressource : kubectl apply -f <path_to_ingress>/<ingress_file_name>.yaml
Nous venons de déployer un ALB qui monitore la ressource ingress définit tout à l’heure et transfère le trafic de l'ALB ingress controller au Nginx ingress controller.
Et voilà, après avoir suivi ce tutoriel, vous avez désormais une instance ALB sur votre infrastructure AWS. Votre instance ALB est prête à être utilisée alors allez la tester !