Cette série est également disponible en anglais.
Read in English
Chapitre 5
Home LabTutorialsDevOps & Infrastructure

Comment déployer une application simple sur Kubernetes

7 min de lecture
Comment déployer une application simple sur Kubernetes
Apprenez à déployer une application HTML de base sur votre cluster Kubernetes local. Ce guide couvre la création d'une image Docker, son envoi sur GitHub Container Registry et la rédaction des configurations YAML essentielles.

Pour moi, c’est ce blog même, qui tourne déjà sur Kubernetes sur mon Raspberry Pi au moment où j'écris ces lignes. J'ai essayé de le faire de la manière la plus professionnelle possible. Non seulement pour apprendre mais aussi pour partager avec vous ; laissez-moi vous expliquer comment j'ai déployé ce blog sur Kubernetes.

Comprendre tout le processus (de la création de l'image au DNS et au HTTPS) est un défi de taille. C'est pourquoi nous allons d'abord nous concentrer sur le déploiement d'un site web très simple sur votre réseau local.

Étape 1 : L'application la plus simple possible

Pour simplifier ce tutoriel, créons l'application la plus basique possible : un simple fichier HTML servi par Nginx et construit avec un Dockerfile.

Arborescence des fichiers

Le Dockerfile ressemble à ceci :

FROM nginx:alpine
COPY app/ /usr/share/nginx/html/

Et pour faire encore plus simple, le fichier HTML n'est même pas du "vrai" HTML, mais les navigateurs s'en fichent. Il contient juste ceci :

<h1>Hello from the simplest possible app!</h1>

L'objectif ici est d'apprendre le déploiement, pas le développement. Vous pouvez construire et tester l'image localement avec les commandes suivantes :

docker build -t simple-app .

Et pour tester localement :

docker run -p 80:80 simple-app

Une fois lancé, vous pouvez accéder à votre site en visitant http://localhost dans votre navigateur.

Étape 2 : Comment envoyer votre image sur GitHub Container Registry

Super, nous avons une application : il est temps de la rendre accessible à notre cluster. Pour ce faire, Kubernetes doit pouvoir récupérer l'image depuis un registre. Il y a deux options : soit vous optez pour l'auto-hébergement complet (avec Docker Registry ou Zot), soit vous utilisez GitHub Container Registry (GHCR). Pour que ce tutoriel soit plus accessible à tous, utilisons GitHub, mais n'hésitez pas à essayer d'auto-héberger vos conteneurs également !

D'abord, vous aurez besoin d'un Personal Access Token (PAT). Vous pouvez en créer un sur GitHub en vous rendant dans SettingsDeveloper settingsPersonal access tokens (Tokens classic).

Cochez ces permissions :

  • write:packages
  • read:packages

(Petit conseil : les tokens PAT ont une date d'expiration. S'il expire, Kubernetes finira par perdre la capacité de récupérer vos images. Je vous conseille vivement de vous mettre un rappel dans votre calendrier quelques jours avant l'échéance pour éviter de vous retrouver avec un déploiement bloqué).

Stockez-le dans une variable d'environnement :

export GHCR_TOKEN=ghp_xxxxxxxxxxxxx

Ensuite, connectez-vous à GHCR :

echo $GHCR_TOKEN | docker login ghcr.io -u <VOTRE_NOM_UTILISATEUR_GITHUB> --password-stdin

Maintenant, taguez et envoyez votre image (remplacez <VOTRE_NOM_UTILISATEUR_GITHUB> par votre pseudo).

Notez l'argument --platform linux/arm64 : le Raspberry Pi utilise une architecture ARM, alors que la plupart des PC et ordinateurs portables utilisent du x86. Ce sont des types de processeurs différents, et comme une image x86 ne fonctionnera pas sur un processeur ARM, cette option est indispensable pour construire vers le Pi.

docker build --platform linux/arm64 -t ghcr.io/<VOTRE_NOM_UTILISATEUR_GITHUB>/simple-app:latest .
docker push ghcr.io/<VOTRE_NOM_UTILISATEUR_GITHUB>/simple-app:latest

Votre image devrait maintenant apparaître dans l'onglet Packages de votre profil GitHub.

Onglet Packages

Étape 3 : Comment configurer Kubernetes pour récupérer l'image

Maintenant que l'image est en ligne, Kubernetes doit pouvoir la récupérer pour la déployer. Pour cela, nous devons indiquer à K3s quelles informations d'identification utiliser pour ghcr.io. Sur votre nœud Pi, modifiez le fichier de configuration :

sudo nano /etc/rancher/k3s/registries.yaml

Ajoutez vos identifiants :

configs:
  "ghcr.io":
    auth:
      username: "<VOTRE_NOM_UTILISATEUR_GITHUB>"
      password: "<VOTRE_TOKEN_PAT_GITHUB>"

Important : Pour que K3s prenne en compte ces changements, vous devrez redémarrer le service :

sudo systemctl restart k3s

Étape 4 : Comment rédiger une configuration YAML de base

Nous sommes maintenant prêts à déployer. Pour y parvenir, nous devrons écrire un peu de YAML pour définir l'état souhaité de notre application. Regardons d'un peu plus près les différents blocs nécessaires au déploiement d'un service ou d'un site web de base.

1. Le Namespace

C'est la "boîte" qui contient et organise vos applications. En définissant kind: Namespace avec le nom website-namespace, nous créons une frontière logique. Toutes les autres ressources de notre fichier utilisent ensuite metadata.namespace: website-namespace pour se rattacher à cette boîte.

Plus généralement, cette configuration, comme toutes les autres, partage quelques champs communs : apiVersion (la version de l'API), kind (ce que nous créons) et metadata (le nom de la ressource et son namespace).

Voici comment le namespace est défini :

apiVersion: v1
kind: Namespace
metadata:
  name: website-namespace

Pour en savoir plus sur les namespaces, consultez la documentation officielle.

2. Le déploiement (Deployment)

Le déploiement définit l'état souhaité de votre application. Comme toute autre ressource, il possède un nom défini dans ses métadonnées. Pour des applications plus vastes, vous pourriez avoir plusieurs déploiements dans le même namespace, chacun gérant une partie différente de votre système.

Voici comment le déploiement est défini :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: website
  namespace: website-namespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: website-pod
  template:
    metadata:
      labels:
        app: website-pod
    spec:
      containers:
        - name: website-app
          image: ghcr.io/<VOTRE_NOM_UTILISATEUR_GITHUB>/simple-app:latest

Conteneurs : Cette section définit le conteneur à exécuter dans le pod et l'image à récupérer sur GHCR. Il possède un nom car un pod peut techniquement exécuter plusieurs conteneurs "étroitement liés" (ex: votre application principale accompagnée d'un "sidecar" pour les logs ou les métriques).

Labels (Étiquettes) : Nous marquons nos pods avec spec.template.metadata.labels (ex : app : website-pod). Voyez cela comme des étiquettes pour identifier vos ressources.

Sélecteurs (Selectors) : Le déploiement utilise spec.selector pour savoir de quels pods il est responsable en cherchant ces étiquettes. Dans notre cas simple, le sélecteur et les étiquettes correspondent exactement, ce qui peut sembler redondant, mais cette séparation permet un ciblage très flexible dans des installations plus grandes.

Répliques (Replicas) : Enfin, nous précisons combien de pods exécuter (fixé à 1 ici). Pour en savoir plus sur les déploiements, consultez la documentation officielle.

3. Le service (Service)

Comme les pods sont éphémères et que leurs IPs changent, nous avons besoin d'un point de contact stable pour atteindre notre application. Le service (Service) possède son propre nom unique et agit comme un routeur qui reçoit les requêtes de l'Ingress et les transmet au bon pod. Il fait également office de répartiteur de charge (Load Balancer) en distribuant le trafic vers n'importe quel pod correspondant à son sélecteur. Dans des configurations plus complexes, vous aurez souvent plusieurs services gérant différentes communications internes.

Voici comment le service est défini :

apiVersion: v1
kind: Service
metadata:
  name: website-service
  namespace: website-namespace
spec:
  selector:
    app: website-pod
  ports:
    - port: 80
      targetPort: 80

Mappage de ports : Nous faisons correspondre le port externe (80) au targetPort du conteneur (80).

Cela peut paraître étrange de mapper le port 80 vers 80, mais cette traduction est très utile dans certaines situations. Sous Linux, se lier à des ports inférieurs à 1024 (comme 80 ou 443) nécessite généralement des privilèges root. L'utilisation d'un Service nous permet d'accepter du trafic sur le port 80 et de le renvoyer vers un port sûr et non privilégié (comme 8080) à l'intérieur du conteneur si nécessaire. Pour en savoir plus sur les services, consultez la documentation officielle.

4. L'Ingress

L'Ingress est un routeur HTTP (un sous-module sous networking.k8s.io/v1) qui définit quels noms de domaine mènent à quels services. Comme les autres ressources, il possède un nom spécifique, et vous pouvez en définir plusieurs pour gérer différents domaines ou points d'entrée.

Voici comment l'ingress est défini :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: website-ingress
  namespace: website-namespace
spec:
  rules:
    - host: simple-website.home.arpa
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: website-service
                port:
                  number: 80

Règles : Nous définissons que l'hôte simple-website.home.arpa mène à notre website-service.

Chemins (Paths) : Le chemin / avec pathType: Prefix signifie que tout ce qui se trouve sous ce domaine sera routé vers le même service. Cela inclut simple-website.home.arpa/about ou simple-website.home.arpa/blog/article-1.

Pour en savoir plus sur les ingresses, consultez la documentation officielle.

Voici un schéma montrant comment ces différents composants interagissent :

Architecture Kubernetes

La configuration complète

En concaténant tous ces blocs à l'aide du séparateur ---, nous obtenons notre fichier de configuration final. Bien que vous puissiez les garder dans des fichiers séparés, les combiner dans un seul config.yaml est souvent plus simple pour les petits projets. À mesure que les choses se complexifient, vous finirez peut-être par vouloir les diviser à nouveau en fichiers individuels.

Enregistrez le contenu suivant dans un fichier nommé config.yaml (n'oubliez pas de mettre à jour le chemin de l'image avec votre nom d'utilisateur) :

apiVersion: v1
kind: Namespace
metadata:
  name: website-namespace
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: website
  namespace: website-namespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: website-pod
  template:
    metadata:
      labels:
        app: website-pod
    spec:
      containers:
        - name: website-app
          image: ghcr.io/<VOTRE_NOM_UTILISATEUR_GITHUB>/simple-app:latest
---
apiVersion: v1
kind: Service
metadata:
  name: website-service
  namespace: website-namespace
spec:
  selector:
    app: website-pod
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: website-ingress
  namespace: website-namespace
spec:
  rules:
    - host: simple-website.home.arpa
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: website-service
                port:
                  number: 80

Étape 5 : Comment déployer votre application sur Kubernetes

Une fois votre image envoyée et K3s configuré, appliquez la configuration :

kubectl apply -f config.yaml

Vous pouvez ensuite vérifier que tout tourne correctement en listant les ressources de notre namespace. Puisque nous avons utilisé website-namespace, nous devons le préciser avec l'argument -n :

# Vérifier toutes les ressources (pods, services, déploiements)
kubectl get all -n website-namespace
 
# Vérifier spécifiquement l'ingress
kubectl get ingress -n website-namespace

Attendez quelques secondes que le pod passe en statut "Running". Si vous voyez une erreur ImagePullBackOff, vérifiez bien vos identifiants du registre à l'étape 3 !

Si vous avez suivi l'article précédent sur Pi-Hole et redirigé les domaines *.home.arpa vers votre Pi, votre site devrait être accessible à l'adresse simple-website.home.arpa.

Page web

Vous trouverez le code complet ici : github.com/Local-pie/simple-app

Dans le prochain article, nous verrons comment ouvrir votre cluster sur Internet en toute sécurité.

#kubernetes#docker#devops#k3s#github-container-registry
Judicael Poumay (Ph.D.)

Judicael Poumay (Ph.D.)

Suivez-moi sur LinkedIn pour du contenu hebdomadaire Judicaël Poumay

En tant que chercheur/développeur IA indépendant spécialisé en Traitement du Langage Naturel (NLP), j'ai une expertise complète dans le développement et l'intégration de systèmes d'IA, ainsi que l'analyse de données.

Votre entreprise cherche à intégrer des solutions IA, analyser des données ou renforcer son développement back-end ? Contactez-moi !

Offrez-moi une bière 🍺

Articles Similaires