Cet article est la partie 1 de la serie "Kubernetes deep dive" :
- Déployer un cluster Kubernetes sur AWS avec kube-aws
- Présentation de Torus, un système de fichier distribué cloud natif
- Kubernetes : Introduction aux PetSet et bootstrap d'un cluster Consul
- Kubernetes : Ingress Controller avec Træfɪk et Let's Encrypt
Osones vous propose un dossier sur Kubernetes. Nous allons dans ce premier article déployer un cluster Kubernetes sur AWS, puis tester son fonctionnement de base - en particulier les fonctionnalités liées au Cloud Provider. Le but n'est pas d'installer à la main Kubernetes étape par étape mais de montrer une méthode de déploiement, sur un Cloud Provider que nous utilisons : Amazon Web Services.
Le Choix de CoreOS pour Kubernetes
Kubernetes est un projet Open Source lancé en 2014 par Google. Popularisé en quelques années seulement, ce COE (Container Orchestration Engine) permet de gérer le cycle de vie d'applications de type 12 factor / micro-services à l'aide de conteneurs. Kubernetes propose des fonctionnalités de clustering, de déploiement automatique et de scalabilité ainsi que des API ouvertes. Les configurations se font à l'aide de fichiers JSON ou YAML.
À noter que d'autres COE existent, parmi lesquels Docker Swarm et Apache Mesos.
Nous avons fait ici le choix de la distribution Linux CoreOS, une distribution minimaliste orientée conteneurs dont nous avons déjà parlé dans des précédents articles. Le projet Open Source "CoreOS" est porté par la société CoreOS, Inc, à l'origine de nombre services OpenSource orientés conteneurs tels que :
Membre de l'Open Container Initiative (OCI), CoreOS, Inc a également compté parmi les premiers à pousser l'utilisation de Kubernetes en production, et propose une solution packagée de Kubernetes appelée Tectonic. CoreOS est donc une distribution de choix pour faire fonctionner Kubernetes, même sans avoir recours à la version commerciale.
The "CoreOS way"
Dans le respect des best practices, les fonctionnalités suivantes sont déployées :
- Utilisation de TLS pour sécuriser les communications;
- Utilisation du service de discovery de Kubernetes;
- Utilisation d'un Cloud Provider : AWS.
Kubernetes supporte de multiples Cloud Providers, dont AWS, pour permettre l'utilisation de composants externes mis à disposition. Par exemple, dans le cas de la publication de services, il est possible d'automatiquement provisionner un ELB (Elastic Load Balancer) ainsi que les règles de filtrage (security groups) associées. Nous utiliserons dans cet article un outil de déploiement CoreOS appelé kube-aws, permettant de déployer facilement un cluster dans AWS.
Préparation du cluster
Pour préparer le cluster, nous allons utiliser kube-aws, un outil qui permet de gérer un cluster Kubernetes en mode Infrastructure as Code. À partir d'un template YAML, kube-aws génère un template CloudFormation et le provisionne sur AWS. Les templates générés peuvent par exemple être stockés sur un dépôt Git, comme pour les templates Terraform, afin d'être versionnés.
Pré-requis
Les objets sont multiples dans Kubernetes :
- Pod : plus petit élement unitaire, peut contenir un ou plusieurs conteneurs fonctionnant ensemble, avec des composants partagés et qui doivent former un composant logique
- Replication Controller : contrôle la durée de vie des pods notamment le nombre de pods dans un cluster à un instant T
- Services : permet de fournir un niveau d'abstraction (point d'entrée unique) aux pods qui peuvent physiquement se trouver sur différents hôtes du cluster et être répliqués par les replication controllers
L'installation et la gestion de Kubernetes nécessitent l'installation de 2 binaires, par exemple sur linux dans /usr/local/bin
:
- kube-aws : pré-configurer le cluster et le déployer
- kubectl : contrôle de Kubernetes via les API :
curl -O https://storage.googleapis.com/kubernetes-release/release/v1.2.3/bin/linux/amd64/kubectl
Pour pouvoir se connecter aux instances, si besoin, il est nécessaire de disposer d'une clé SSH sur AWS EC2 ainsi que d'un compte IAM valide afin de pouvoir provisionner l'infrastructure sur AWS. De plus, afin d'assurer la sécurité des communications au sein du cluster ainsi qu'entre les composants d'AWS, AWS Key Management Service (KMS) est utilisé. Pour générer une clé via awscli :
aws --profile osones kms --region=eu-west-1 create-key --description="osones-k8s-clust kms"
{
"KeyMetadata": {
"KeyId": "6d9f59dc-e5c1-441d-8743-4d55c7cd1701",
"KeyState": "Enabled",
"AWSAccountId": "303293004898",
"Arn": "arn:aws:kms:eu-west-1:303293004898:key/6d9f59dc-e5c1-441d-8743-4d55c7cd1701",
"KeyUsage": "ENCRYPT_DECRYPT",
"Enabled": true,
"Description": "osones-k8s-clust kms",
"CreationDate": 1462794561.015
}
}
Initialisation du cluster
Dans un premier temps, il faut exporter les credentials du compte IAM.
$ export AWS_ACCESS_KEY_ID=AKID1234567890
$ export AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY
Puis, dans un répertoire dédié, on initialise le cluster.
kube-aws init --cluster-name=osones-k8s-clust \
--external-dns-name=k8s.osones.io \
--region=eu-west-1 \
--availability-zone=eu-west-1 \
--key-name=klefevre-sorrow \
--kms-key-arn="arn:aws:kms:eu-west-1:303293004898:key/6d9f59dc-e5c1-441d-8743-4d55c7cd1701" -> Correspond à l'ARN de la clé KMS générée précédemment.
Success! Created cluster.yaml
Next steps:
1. (Optional) Edit cluster.yaml to parameterize the cluster.
2. Use the "kube-aws render" command to render the stack template.
Cette commande génère un fichier cluster.yaml
pré-rempli qui définit les options du cluster. Avant de générer la stack CloudFormation, il est possible de la customiser avec par exemple, le nombre de workers par défaut, la zone DNS Route 53, la taille des instances, etc.
Par exemple, le fichier cluster.yaml
pour le cluster Osones :
clusterName: osones-k8s-clust
externalDNSName: k8s.osones.io
releaseChannel: alpha
createRecordSet: true
hostedZone: "osones.io"
keyName: klefevre-sorrow
region: eu-west-1
availabilityZone: eu-west-1a
kmsKeyArn: "arn:aws:kms:eu-west-1:303293004898:key/6d9f59dc-e5c1-441d-8743-4d55c7cd1701"
controllerInstanceType: t2.medium
controllerRootVolumeSize: 30
workerCount: 2
workerInstanceType: t2.small
workerRootVolumeSize: 30
Dans cet exemple, le cluster est déployé dans la région eu-west-1
, dans l'AZ eu-west-1b
. Nous utilisons des instances t2.medium
avec des disques de 30Go pour le contrôleur et des instances t2.small
avec 30 Go de disque pour les nœuds worker. Il y aura au départ 2 workers. Les API seront accessibles à l'adresse k8s.osones.io
et l'enregistrement DNS sera créé au moment de la création de la stack sur la zone osones.io
déjà gérée sur AWS Route53.
Ensuite, à partir du fichier cluster.yaml
on prépare les templates CloudFormation.
kube-aws render
Success! Stack rendered to stack-template.json.
Next steps:
1. (Optional) Validate your changes to cluster.yaml with "kube-aws validate"
2. (Optional) Further customize the cluster by modifying stack-template.json or files in ./userdata.
3. Start the cluster with "kube-aws up".
Une fois le rendu effectué on se retrouve avec l'arborescence suivante :
drwxr-xr-x 4 klefevre klefevre 4.0K May 9 14:57 .
drwxr-xr-x 3 klefevre klefevre 4.0K May 9 11:31 ..
-rw------- 1 klefevre klefevre 3.0K May 9 14:50 cluster.yaml
drwx------ 2 klefevre klefevre 4.0K May 9 14:57 credentials -> contient les ressources pour le TLS
-rw------- 1 klefevre klefevre 540 May 9 14:57 kubeconfig -> fichiers de configuration pour l'utilisation de kubectl
-rw-r--r-- 1 klefevre klefevre 16K May 9 14:57 stack-template.json -> le template CloudFormation géneré
drwxr-xr-x 2 klefevre klefevre 4.0K May 9 14:57 userdata -> contient les fichiers cloud-init pour le master ainsi que les slaves (workers)
Pour information, les userdata générées avec kube-aws sont conformes à la documentation d'installation manuelle.
Enfin on valide les userdata ainsi que la stack CloudFormation :
kube-aws validate
Validating UserData...
UserData is valid.
Validating stack template...
Validation Report: {
Capabilities: ["CAPABILITY_IAM"],
CapabilitiesReason: "The following resource(s) require capabilities: [AWS::IAM::InstanceProfile, AWS::IAM::Role]",
Description: "kube-aws Kubernetes cluster osones-k8s-clust"
}
stack template is valid.
Validation OK!
Déploiement du cluster
Une fois toutes les étapes effectuées, on déploie le cluster avec la simple commande kube-aws up
.
kube-aws up
Creating AWS resources. This should take around 5 minutes.
Success! Your AWS resources have been created:
Cluster Name: osones-k8s-clust
Controller IP: 52.18.58.120
The containers that power your cluster are now being dowloaded.
You should be able to access the Kubernetes API once the containers finish downloading.
Afin de valider le bon fonctionnement du cluster, on peut par exemple lister les nœuds du cluster :
kubectl --kubeconfig=kubeconfig get nodes
NAME STATUS AGE
ip-10-0-0-148.eu-west-1.compute.internal Ready 4m
ip-10-0-0-149.eu-west-1.compute.internal Ready 3m
Le fichier kubeconfig
contient les credentials ainsi que les certificats TLS pour accéder aux API de Kubernetes :
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: credentials/ca.pem
server: https://k8s.osones.io
name: kube-aws-osones-k8s-clust-cluster
contexts:
- context:
cluster: kube-aws-osones-k8s-clust-cluster
namespace: default
user: kube-aws-osones-k8s-clust-admin
name: kube-aws-osones-k8s-clust-context
users:
- name: kube-aws-osones-k8s-clust-admin
user:
client-certificate: credentials/admin.pem
client-key: credentials/admin-key.pem
current-context: kube-aws-osones-k8s-clust-context
L'enregistrement DNS a automatiquement été créé sur Route53, et l'on remarque bien que la connexion aux API s'effectue via HTTPS.
Test d'un simple service
Nous allons tester simplement le fonctionnement du cluster pour terminer cet article. Avec par exemple, un serveur Minecraft, publié automatiquement via un ELB.
Dans un premier temps, on définit le replication controller deployment-minecraft.yaml
.
apiVersion: v1
kind: ReplicationController
metadata:
name: minecraft
spec:
replicas: 1
selector:
app: minecraft
template:
metadata:
name: minecraft
labels:
app: minecraft
spec:
containers:
- name: minecraft
image: vsense/minecraft
ports:
- containerPort: 25565
Dans ce cas, nous avons un seul réplica. Ce qui signifie un seul pod Minecraft. La sélection se fait grâce au label, qui permet au replication controller de matcher le pod avec le même label (ici minecraft). On vérifie avec kubectl :
kubectl --kubeconfig=kubeconfig create -f deployment-minecraft.yaml
replicationcontroller "minecraft" created
kubectl --kubeconfig=kubeconfig get rc
NAME DESIRED CURRENT AGE
minecraft 1 1 1m
kubeectl --kubeconfig=kubeconfig get pods
NAME READY STATUS RESTARTS AGE
minecraft-wj65z 1/1 Running 0 1m
Pour le moment, le pod est accessible uniquement depuis l'intérieur du cluster, pour le rendre accessible depuis l'extérieur nous allons créer un service au sens Kubernetes et utiliser la fonctionnalité de load balancing fournie par le Cloud Provider. Kubernetes va provisionner un ELB sur AWS, ouvrir les security groups et ajouter les nœuds Kubernetes en backend automatiquement.
Le fichier service-minecraft.yaml
:
apiVersion: v1
kind: Service
metadata:
name: minecraft
labels:
app: minecraft
spec:
selector:
app: minecraft
ports:
- port: 25565
type: LoadBalancer
Ici, le load balancer écoute sur le même port que le pod (le port 25565, par défaut pour Minecraft) et forward le trafic vers les workers. Pour avoir le détail :
kubectl --kubeconfig=kubeconfig create -f service-minecraft.yaml
kubectl --kubeconfig=kubeconfig describe service minecraft
Name: minecraft
Namespace: default
Labels: app=minecraft
Selector: app=minecraft
Type: LoadBalancer
IP: 10.3.0.173
LoadBalancer Ingress: a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com
Port: <unset> 25565/TCP
NodePort: <unset> 31846/TCP
Endpoints: 10.2.92.2:25565
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
41m 41m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
41m 41m 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
Pour le moment, Kubernetes ne supporte pas la configuration automatique d'un alias Route53 vers le load balancer. Le service est accessible depuis l'extérieur à l'adresse : a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com sur le port par défaut (25565), ce qui n'est pas très pratique.
Il est possible d'automatiser la création d'un enregistrement DNS en utilisant la CLI AWS. Dans un fichier route53-minecraft.json
:
{
"Comment": "minecraft dns record",
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "minecraft.osones.io",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [
{
"Value": "a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com"
}
]
}
}
]
}
Ensuite via l'awscli :
aws --profile osones route53 change-resource-record-sets --hosted-zone-id Z2BYZVP5DZBBWK --change-batch file://route53-minecraft.json
host minecraft.osones.io
minecraft.osones.io is an alias for a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com.
a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com has address 52.17.242.195
a3b6af5e415f211e6b97202fce3039af-98360.eu-west-1.elb.amazonaws.com has address 52.19.180.100
Le champs hosted-zone-id correspond à l'ID de zone Route53 dans laquelle on ajoute l'enregistrement. On peut ensuite se connecter au service depuis l'extérieur à l'adresse minecraft.osones.io
.
Conclusion
Il existe beaucoup de méthodes de déploiement pour Kubernetes, que ce soit via Ansible, Puppet ou Chef. Elles dépendent également du Cloud Provider utilisé. CoreOS est l'une des premières distributions à s'être intégrée avec Kubernetes, et à supporter complètement AWS. Dans une suite d'articles nous nous détacherons de la partie installation et nous nous intéresserons plus précisément au fonctionnement de Kubernetes ainsi qu'aux differents objets disponibles et leurs cas d'utilisation.
Kevin Lefevre
Découvrez les derniers articles d'alter way
- kubevpn
- Kubernetes 1.32
- re:Invent 2024 : AWS mise tout sur l'IA pour son Cloud
- OVHcloud Summit 2024 : L’innovation au cœur d’un cloud souverain et performant
- Big Data & AI Paris 2024 : L'IA au cœur de toutes les transformations.
- Un retour vers l'open-source ? Vos outils DevOps préférés et leurs equivalents open-source.