Dans un article de blog précédent, vous avez vu comment utiliser cdk8s avec AWS Controllers for Kubernetes (également connu sous le nom ACK), grâce au fait que vous pouvez importer des définitions de ressources personnalisées Kubernetes existantes à l’aide de cdk8s
! Cela a permis de déployer DynamoDB
avec une application cliente, en utilisant cdk8s
et Kubernetes.
Mais que se passe-t-il si vous continuez à utiliser AWS CDK pour l’infrastructure AWS et exploitez la puissance cdk8s
(et cdk8s-plus
!) pour définir les ressources Kubernetes à l’aide de code normal ? Grâce à l’intégration native entre le module AWS EKS et cdk8s, vous pouvez avoir le meilleur des deux mondes !
Le but de cet article de blog est de le démontrer avec quelques exemples. Nous commencerons par un exemple simple (basé sur nginx) avant de passer à une pile d’applications complète (y compris DynamoDB
etc.). Les deux utiliseront le langage de programmation Go qui est bien pris en charge dans AWS CDK ainsi que dans cdk8s.
Tout le code discuté dans ce blog est disponible dans ce dépôt GitHub
Conditions préalables
Pour suivre étape par étape, en plus d’un compte AWS, vous aurez besoin des CLI suivantes : AWS CLI, cdk8s CLI et kubectl. N’oubliez pas non plus d’installer AWS CDK, le langage de programmation Go (v1.16 ou supérieur) ainsi que Docker, si vous ne les avez pas déjà.
Rester simple avec Nginx sur EKS
Comme pour la plupart des choses dans la vie, il y a deux manières – la manière facile ou la manière difficile 😉 Vous verrez les deux ! Essayons d’abord les choses, voyons-les fonctionner, puis regardons le code.
Pour commencer, clonez le référentiel et accédez au bon répertoire :
git clone https://github.com/abhirockzz/cdk8s-for-go-developers
cd cdk8s-for-go-developers/part6-cdk-eks-cdk8s/cdk-cdk8s-nginx-eks
Pour tout configurer, il vous suffit d’une seule commande :
vous pouvez aussi utiliser
cdk synth
pour générer et inspecter le modèle Cloud Formation en premier
Vous serez invité à confirmer. Une fois que vous aurez fait cela, le processus démarrera – cela prendra un certain temps car de nombreuses ressources AWS seront créées, y compris VPC, cluster EKS, etc.
N’hésitez pas à consulter la console AWS Cloud Formation pour suivre la progression.
Une fois le processus terminé, vous devez vous connecter au cluster EKS à l’aide de kubectl
. La commande requise pour cela sera disponible à la suite de la cdk deploy
processus (dans le terminal) ou vous pouvez vous référer au Les sorties section de la pile AWS Cloud Formation.
Une fois que vous avez configuré kubectl
pour pointer vers votre cluster EKS, vous pouvez vérifier le Nginx Deployment
et Service
.
kubectl get deployment
# output
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment-cdk8s 1/1 1 1 1m
nginx-deployment-cdk 1/1 1 1 1m
Vous verrez que deux Deployment
s ont été créés – plus à ce sujet bientôt. De même, si vous cochez la case Service
(kubectl get svc
), vous devriez en voir deux – nginx-service-cdk
et nginx-service-cdk8s
.
Pour accéder à Nginx, sélectionnez EXTERNAL-IP
de l’un des deux Service
s. Par exemple:
APP_URL=$(kubectl get service/nginx-service-cdk -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")
echo $APP_URL
# to access nginx (notice we are using port 9090)
curl -i http://$APP_URL:9090
Si vous obtenez un
Could not resolve host
erreur lors de l’accès à l’URL LB, attendez environ une minute et réessayez
Dans les coulisses
Regardons le code maintenant – cela clarifiera pourquoi nous avons deux Nginx Deployment
s.
Grâce à AWS CDK, la création de VPC est une ligne avec la fonction awsec2.NewVpc et la création d’un cluster EKS n’est pas trop difficile non plus !
func NewNginxOnEKSStack(scope constructs.Construct, id string, props *CdkStackProps) awscdk.Stack {
//...
vpc := awsec2.NewVpc(stack, jsii.String("demo-vpc"), nil)
eksSecurityGroup := awsec2.NewSecurityGroup(stack, jsii.String("eks-demo-sg"),
&awsec2.SecurityGroupProps{
Vpc: vpc,
SecurityGroupName: jsii.String("eks-demo-sg"),
AllowAllOutbound: jsii.Bool(true)})
eksCluster := awseks.NewCluster(stack, jsii.String("demo-eks"),
&awseks.ClusterProps{
ClusterName: jsii.String("demo-eks-cluster"),
Version: awseks.KubernetesVersion_V1_21(),
Vpc: vpc,
SecurityGroup: eksSecurityGroup,
VpcSubnets: &[]*awsec2.SubnetSelection{
{Subnets: vpc.PrivateSubnets()}},
DefaultCapacity: jsii.Number(2),
DefaultCapacityInstance: awsec2.InstanceType_Of(awsec2.InstanceClass_BURSTABLE3, awsec2.InstanceSize_SMALL), DefaultCapacityType: awseks.DefaultCapacityType_NODEGROUP,
OutputConfigCommand: jsii.Bool(true),
EndpointAccess: awseks.EndpointAccess_PUBLIC()})
//...
Nginx sur Kubernetes, à la dure !
Nous examinons maintenant deux manières différentes de créer Nginx, en commençant par la manière « difficile ». Dans ce cas, nous utilisons AWS CDK (ne pas cdk8s
) pour définir la Deployment
et Service
Ressources.
func deployNginxUsingCDK(eksCluster awseks.Cluster) {
appLabel := map[string]*string{
"app": jsii.String("nginx-eks-cdk"),
}
deployment := map[string]interface{}{
"apiVersion": jsii.String("apps/v1"),
"kind": jsii.String("Deployment"),
"metadata": map[string]*string{
"name": jsii.String("nginx-deployment-cdk"),
},
"spec": map[string]interface{}{
"replicas": jsii.Number(1),
"selector": map[string]map[string]*string{
"matchLabels": appLabel,
},
"template": map[string]interface{}{
"metadata": map[string]map[string]*string{
"labels": appLabel,
},
"spec": map[string][]map[string]interface{}{
"containers": {
{
"name": jsii.String("nginx"),
"image": jsii.String("nginx"),
"ports": []map[string]*float64{
{
"containerPort": jsii.Number(80),
},
},
},
},
},
},
},
}
service := map[string]interface{}{
"apiVersion": jsii.String("v1"),
"kind": jsii.String("Service"),
"metadata": map[string]*string{
"name": jsii.String("nginx-service-cdk"),
},
"spec": map[string]interface{}{
"type": jsii.String("LoadBalancer"),
"ports": []map[string]*float64{
{
"port": jsii.Number(9090),
"targetPort": jsii.Number(80),
},
},
"selector": appLabel,
},
}
eksCluster.AddManifest(jsii.String("app-deployment"), &service, &deployment)
Enfin, pour le créer dans EKS, nous invoquons AddManifest (considérez-le comme l’équivalent programmatique de kubectl apply
). Cela fonctionne, mais il y a quelques lacunes dans cette approche :
- Nous ne sommes pas en mesure de récolter les bénéfices du Go qui est un fortement typé Langue. C’est parce que l’API est librement tapé, grâce à
map[string]interface{}
partout. Cela le rend très sujet aux erreurs (j’ai aussi fait quelques erreurs !) - La verbosité est également évidente. Il semble que nous écrivions
YAML
dansGo
– pas trop d’amélioration !
Existe-t-il un meilleur moyen ..?
Regardons la deuxième fonction deployNginxUsingCDK8s
– par le nom, il est évident que nous avons utilisé cdk8s
pas seulement CDK)
func deployNginxUsingCDK8s(eksCluster awseks.Cluster) {
app := cdk8s.NewApp(nil)
eksCluster.AddCdk8sChart(jsii.String("nginx-eks-chart"), NewNginxChart(app, "nginx-cdk8s", nil), nil)
}
Cela semble « trop facile » pour être vrai ! Mais c’est rendu possible grâce à l’interopérabilité entre CDK et cdk8s
. Cela implique que vous pouvez utiliser définir Ressources Kubernetes utilisant cdk8s
Chart
s et appliquez-les à un cluster EKS créé avec CDK (cela en fait une sorte de système hybride).
Le héros de notre histoire est la fonction AddCdk8sChart, qui accepte une construction. Construire (rappelez-vous, tout est une construction !). Dans ce cas, le Construct
se trouve être un cdk8s.Chart renvoyé par NewNginxChart
fonction – alors jetons un coup d’œil à cela.
func NewNginxChart(scope constructs.Construct, id string, props *MyChartProps) cdk8s.Chart {
//....
dep := cdk8splus22.NewDeployment(chart, jsii.String("nginx-deployment"),
&cdk8splus22.DeploymentProps{
Metadata: &cdk8s.ApiObjectMetadata{
Name: jsii.String("nginx-deployment-cdk8s")}})
dep.AddContainer(&cdk8splus22.ContainerProps{
Name: jsii.String("nginx-container"),
Image: jsii.String("nginx"),
Port: jsii.Number(80)})
dep.ExposeViaService(&cdk8splus22.DeploymentExposeViaServiceOptions{
Name: jsii.String("nginx-service-cdk8s"),
ServiceType: cdk8splus22.ServiceType_LOAD_BALANCER,
Ports: &[]*cdk8splus22.ServicePort{{
Port: jsii.Number(9090),
TargetPort: jsii.Number(80)}}})
return chart
}
Si vous avez travaillé avec cdk8s
(and Go) ou lisez certains de mes blogs précédents sur ce sujet, cela devrait vous sembler familier – une API fortement typée, compacte et expressive ! Je n’ai même pas besoin de vous expliquer cela car c’est tellement lisible – nous utilisons cdk8s-plus
pour créer un Nginx Deployment
ajoutez les informations sur le conteneur et enfin exposez-le via un Service
afin que nous puissions accéder au Nginx depuis l’extérieur d’EKS.
C’était un exemple assez simple pour aider à faire ressortir la différence entre les deux approches. Le scénario suivant est différent – en plus du cluster EKS, il a…