1 - Vue d'ensemble de l'administration d'un cluster

Administration cluster Kubernetes

La vue d'ensemble de l'administration d'un cluster est destinée à toute personne créant ou administrant un cluster Kubernetes. Il suppose une certaine familiarité avec les concepts de Kubernetes.

Planifier le déploiement d'un cluster

Voir le guide: choisir la bonne solution pour des exemples de planification, de mise en place et de configuration de clusters Kubernetes. Les solutions répertoriées dans cet article s'appellent des distributions.

Avant de choisir un guide, voici quelques considérations:

  • Voulez-vous simplement essayer Kubernetes sur votre machine ou voulez-vous créer un cluster haute disponibilité à plusieurs nœuds? Choisissez les distributions les mieux adaptées à vos besoins.
  • Si vous recherchez la haute disponibilité, apprenez à configurer des clusters multi zones.
  • Utiliserez-vous un cluster Kubernetes hébergé, comme Google Kubernetes Engine, ou hébergerez-vous votre propre cluster?
  • Votre cluster sera-t-il on-premises, ou sur un cloud (IaaS)? Kubernetes ne prend pas directement en charge les clusters hybrides. Cependant, vous pouvez configurer plusieurs clusters.
  • Si vous configurez Kubernetes on-premises, choisissez le modèle réseau qui vous convient le mieux.
  • Voulez-vous faire tourner Kubernetes sur du bare metal ou sur des machines virtuelles (VMs)?
  • Voulez-vous simplement faire tourner un cluster, ou vous attendez-vous à faire du développement actif sur le code du projet Kubernetes? Dans ce dernier cas, choisissez une distribution activement développée. Certaines distributions n’utilisent que des versions binaires, mais offrent une plus grande variété de choix.
  • Familiarisez-vous avec les composants nécessaires pour faire tourner un cluster.

A noter: Toutes les distributions ne sont pas activement maintenues. Choisissez des distributions qui ont été testées avec une version récente de Kubernetes.

Gérer un cluster

  • Gérer un cluster décrit plusieurs rubriques relatives au cycle de vie d’un cluster: création d’un nouveau cluster, mise à niveau des nœuds maître et des workers de votre cluster, maintenance des nœuds (mises à niveau du noyau, par exemple) et mise à niveau de la version de l’API Kubernetes d’un cluster en cours d’exécution.

  • Apprenez comment gérer les nœuds.

  • Apprenez à configurer et gérer les quotas de ressources pour les clusters partagés.

Sécuriser un cluster

Sécuriser la Kubelet

Services de cluster optionnels

2 - Certificats

Certifications cluster Kubernetes

Lorsque vous utilisez l'authentification par certificats client, vous pouvez générer des certificats manuellement grâce à easyrsa, openssl ou cfssl.

easyrsa

easyrsa peut générer manuellement des certificats pour votre cluster.

  1. Téléchargez, décompressez et initialisez la version corrigée de easyrsa3.

    curl -LO https://dl.k8s.io/easy-rsa/easy-rsa.tar.gz
    tar xzf easy-rsa.tar.gz
    cd easy-rsa-master/easyrsa3
    ./easyrsa init-pki
    
  2. Générez une CA. (--batch pour le mode automatique. --req-cn CN par défaut à utiliser)

    ./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
    
  3. Générer un certificat de serveur et une clé. L' argument --subject-alt-name définit les adresses IP et noms DNS possibles par lesquels l'API serveur peut être atteind. La MASTER_CLUSTER_IP est généralement la première adresse IP du CIDR des services qui est spécifié en tant qu'argument --service-cluster-ip-range pour l'API Server et le composant controller manager. L'argument --days est utilisé pour définir le nombre de jours après lesquels le certificat expire. L’exemple ci-dessous suppose également que vous utilisez cluster.local par défaut comme nom de domaine DNS.

    ./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
    "IP:${MASTER_CLUSTER_IP},"\
    "DNS:kubernetes,"\
    "DNS:kubernetes.default,"\
    "DNS:kubernetes.default.svc,"\
    "DNS:kubernetes.default.svc.cluster,"\
    "DNS:kubernetes.default.svc.cluster.local" \
    --days=10000 \
    build-server-full server nopass
    
  4. Copiez pki/ca.crt, pki/issued/server.crt, et pki/private/server.key dans votre répertoire.

  5. Personnalisez et ajoutez les lignes suivantes aux paramètres de démarrage de l'API Server:

    --client-ca-file=/yourdirectory/ca.crt
    --tls-cert-file=/yourdirectory/server.crt
    --tls-private-key-file=/yourdirectory/server.key
    

openssl

openssl peut générer manuellement des certificats pour votre cluster.

  1. Générez ca.key en 2048bit:

    openssl genrsa -out ca.key 2048
    
  2. A partir de la clé ca.key générez ca.crt (utilisez -days pour définir la durée du certificat):

    openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
    
  3. Générez server.key en 2048bit:

    openssl genrsa -out server.key 2048
    
  4. Créez un fichier de configuration pour générer une demande de signature de certificat (CSR). Assurez-vous de remplacer les valeurs marquées par des "< >" (par exemple, <MASTER_IP>) avec des valeurs réelles avant de l'enregistrer dans un fichier (par exemple, csr.conf). Notez que la valeur de MASTER_CLUSTER_IP est celle du service Cluster IP pour l' API Server comme décrit dans la sous-section précédente. L’exemple ci-dessous suppose également que vous utilisez cluster.local par défaut comme nom de domaine DNS.

    [ req ]
    default_bits = 2048
    prompt = no
    default_md = sha256
    req_extensions = req_ext
    distinguished_name = dn
    
    [ dn ]
    C = <country>
    ST = <state>
    L = <city>
    O = <organization>
    OU = <organization unit>
    CN = <MASTER_IP>
    
    [ req_ext ]
    subjectAltName = @alt_names
    
    [ alt_names ]
    DNS.1 = kubernetes
    DNS.2 = kubernetes.default
    DNS.3 = kubernetes.default.svc
    DNS.4 = kubernetes.default.svc.cluster
    DNS.5 = kubernetes.default.svc.cluster.local
    IP.1 = <MASTER_IP>
    IP.2 = <MASTER_CLUSTER_IP>
    
    [ v3_ext ]
    authorityKeyIdentifier=keyid,issuer:always
    basicConstraints=CA:FALSE
    keyUsage=keyEncipherment,dataEncipherment
    extendedKeyUsage=serverAuth,clientAuth
    subjectAltName=@alt_names
    
  5. Générez la demande de signature de certificat basée sur le fichier de configuration:

    openssl req -new -key server.key -out server.csr -config csr.conf
    
  6. Générez le certificat de serveur en utilisant ca.key, ca.crt et server.csr:

    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out server.crt -days 10000 \
    -extensions v3_ext -extfile csr.conf -sha256
    
  7. Vérifiez le certificat:

    openssl x509  -noout -text -in ./server.crt
    

Enfin, ajoutez les mêmes paramètres aux paramètres de démarrage de l'API Server.

cfssl

cfssl est un autre outil pour la génération de certificat.

  1. Téléchargez, décompressez et préparez les outils de ligne de commande comme indiqué ci-dessous. Notez que vous devrez peut-être adapter les exemples de commandes en fonction du matériel, de l'architecture et de la version de cfssl que vous utilisez.

    curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o cfssl
    chmod +x cfssl
    curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o cfssljson
    chmod +x cfssljson
    curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o cfssl-certinfo
    chmod +x cfssl-certinfo
    
  2. Créez un répertoire pour contenir les artefacts et initialiser cfssl:

    mkdir cert
    cd cert
    ../cfssl print-defaults config > config.json
    ../cfssl print-defaults csr > csr.json
    
  3. Créez un fichier JSON pour générer le fichier d'autorité de certification, par exemple, ca-config.json:

    {
      "signing": {
        "default": {
          "expiry": "8760h"
        },
        "profiles": {
          "kubernetes": {
            "usages": [
              "signing",
              "key encipherment",
              "server auth",
              "client auth"
            ],
            "expiry": "8760h"
          }
        }
      }
    }
    
  4. Créez un fichier JSON pour la demande de signature de certificat de l'autorité de certification, par exemple, ca-csr.json. Assurez-vous de remplacer les valeurs marquées par des "< >" par les vraies valeurs que vous voulez utiliser.

    {
      "CN": "kubernetes",
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names":[{
        "C": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    
  5. Générez la clé de CA (ca-key.pem) et le certificat (ca.pem):

    ../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
    
  6. Créer un fichier JSON pour générer des clés et des certificats pour l'API Server, par exemple, server-csr.json. Assurez-vous de remplacer les valeurs entre "< >" par les vraies valeurs que vous voulez utiliser. MASTER_CLUSTER_IP est le service Cluster IP de l'API Server, comme décrit dans la sous-section précédente. L’exemple ci-dessous suppose également que vous utilisez cluster.local par défaut comme nom de domaine DNS.

    {
      "CN": "kubernetes",
      "hosts": [
        "127.0.0.1",
        "<MASTER_IP>",
        "<MASTER_CLUSTER_IP>",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
      ],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [{
        "C": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    
  7. Générez la clé et le certificat pour l'API Server, qui sont par défaut sauvegardés respectivement dans les fichiers server-key.pem et server.pem:

    ../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
    --config=ca-config.json -profile=kubernetes \
    server-csr.json | ../cfssljson -bare server
    

Distribuer un certificat auto-signé

Un client peut refuser de reconnaître un certificat auto-signé comme valide. Pour un déploiement hors production ou pour un déploiement exécuté derrière un pare-feu d'entreprise, vous pouvez distribuer un certificat auto-signé à tous les clients et actualiser la liste locale pour les certificats valides.

Sur chaque client, effectuez les opérations suivantes:

$ sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
done.

API pour les certificats

Vous pouvez utiliser l’API certificates.k8s.io pour faire créer des Certificats x509 à utiliser pour l'authentification, comme documenté ici.

3 - Architecture de Journalisation d'évènements (logging)

La journalisation des évènements systèmes et d'applications peut aider à comprendre ce qui se passe dans un cluster. Les journaux sont particulièrement utiles pour débogguer les problèmes et surveiller l'activité du cluster. La plupart des applications modernes ont un mécanisme de journalisation d'évènements, et la plupart des environnements d'exécution de conteneurs ont été conçus pour supporter la journalisation des évènements. La méthode de journalisation la plus facile et la plus répandue pour des applications conteneurisées est d'écrire dans les flux de sortie standard et d'erreur (stdout et stderr).

Malgré cela, la fonctionnalité de journalisation fournie nativement par l'environnement d'exécution de conteneurs n'est pas suffisante comme solution complète de journalisation. Quand un conteneur crashe, quand un Pod est expulsé ou quand un nœud disparaît, il est utile de pouvoir accéder au journal d'événements de l'application. C'est pourquoi les journaux doivent avoir leur propre espace de stockage et un cycle de vie indépendamment des nœuds, Pods ou conteneurs. Ce concept est appelé journalisation des évènements au niveau du cluster (cluster-level-logging). Un backend dédié pour stocker, analyser et faire des requêtes est alors nécessaire. Kubernetes n'offre pas nativement de solution de stockage pour les journaux mais il est possible d'intégrer de nombreuses solutions de journalisation d'évènements dans un cluster Kubernetes.

L'architecture de journalisation des évènements au niveau du cluster est décrite en considérant qu'un backend de journalisation est présent à l'intérieur ou à l'extérieur du cluster. Même sans avoir l'intention de journaliser les évènements au niveau du cluster, il est intéressant de savoir comment les journaux sont conservés et gérés au niveau d'un nœud.

Journalisation simple d'évènements dans Kubernetes

Dans cette section, on va utiliser un exemple simple de journalisation d'évènements avec le flux de sortie standard. Cette démonstration utilise un manifeste pour un Pod avec un seul conteneur qui écrit du texte sur le flux de sortie standard toutes les secondes.

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

Pour lancer ce Pod, utilisez la commande suivante :

kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml

Le résultat est :

pod/counter created

Pour récupérer les événements du conteneur d'un pod, utilisez la commande kubectl logs de la manière suivante :

kubectl logs counter

Le résultat est :

0: Mon Jan  1 00:00:00 UTC 2001
1: Mon Jan  1 00:00:01 UTC 2001
2: Mon Jan  1 00:00:02 UTC 2001
...

Utilisez kubectl logs pour récupérer les évènements de l'instanciation précédente d'un Pod en utilisant l'option --previous quand par exemple le conteneur a crashé.

Si le Pod a plusieurs conteneurs, il faut spécifier le nom du conteneur dont on veut récupérer le journal d'évènement. Dans notre exemple le conteneur s'appelle count donc vous pouvez utiliser kubectl logs counter count. Plus de détails dans la [documentation de kubectl logs] (/docs/reference/generated/kubectl/kubectl-commands#logs)

Journalisation d'évènements au niveau du nœud

Journalisation d'évènements au niveau du
nœud

Tout ce qu'une application conteneurisée écrit sur stdout ou stderr est pris en compte et redirigé par l'environnement d'exécution des conteneurs. Par exemple, Docker redirige ces deux flux vers un driver de journalisation (EN) qui est configuré dans Kubernetes pour écrire dans un fichier au format json.

Par défaut quand un conteneur redémarre, le kubelet ne conserve le journal que du dernier conteneur terminé. Quand un Pod est expulsé d'un nœud, tous ses conteneurs sont aussi expulsés avec leurs journaux d'évènements.

Quand on utilise la journalisation d'évènements au niveau du nœud, il faut prendre garde à mettre en place une politique de rotation des journaux adéquate afin qu'ils n'utilisent pas tout l'espace de stockage du nœud. Kubernetes n'a pas en charge la rotation des journaux, c'est à l'outil de déploiement de le prendre en compte.

Par exemple, dans les clusters Kubernetes déployés avec le script kube-up.sh logrotate est configuré pour s'exécuter toutes les heures. Il est aussi possible de configurer l'environnement d'exécution des conteneurs pour que la rotation des journaux s'exécute automatiquement, e.g. en utilisant le paramètre log-opt de Docker. Dans le script kube-up.sh, c'est cette méthode qui est utilisée pour des images COS sur GCP et sinon c'est la première méthode dans tous les autres cas. Quelle que soit la méthode choisie par kube-up.sh la rotation est configurée par défaut quand la taille d'un journal atteint 10 Mo.

Ce script montre de manière détaillée comment kube-up.sh met en place la journalisation d'évènements pour des images COS sur GCP.

Quand kubectl logs s'exécute comme dans le premier exemple de journalisation simple le kubelet du nœud gère la requête et lit directement depuis le fichier de journal et retourne son contenu dans la réponse.

Journalisation des évènements des composants système

Il y a deux types de composants système selon qu'ils s'exécutent dans un conteneur ou pas.

Par exemple :

  • Le scheduler Kubernetes et kube-proxy s'exécutent dans un conteneur.
  • Kubelet et l'environnement d'exécution de conteneurs, comme par exemple Docker, ne s'exécutent pas dans un conteneur.

Sur les systèmes avec systemd, kubelet et l'environnement d'exécution de conteneurs écrivent dans journald. Si systemd n'est pas présent, ils écrivent dans un fichier .log dans le répertoire /var/log.

Les composants système qui s'exécutent dans un conteneur écrivent toujours dans le répertoire /var/log, en contournant le mécanisme de journalisation par défaut. Ils utilisent la bibliothèque de journalisation klog. Les conventions pour la sévérité des évènements pour ces composants se trouvent dans cette [documentation sur les conventions de journalisation des évènements dans kubernetes] (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md).

De la même manière que les journaux des conteneurs, les journaux des composants systèmes doivent avoir une politique de rotation. Dans un cluster créé avec le script kube-up.sh, les journaux ont une rotation journalière ou quand leur taille atteint 100 Mo.

Architecture de journalisation des évènements au niveau du cluster

Kubernetes ne fournit pas de solution native pour la journalisation des évènements au niveau du cluster. Mais il y a différentes approches qui peuvent être considérées :

  • Utiliser un agent de journalisation au niveau du nœud sur chacun des nœuds.
  • Inclure un conteneur side-car pour journaliser les évènements du Pod applicatif.
  • Envoyer les évènements directement a un backend depuis l'application.

Utiliser un agent de journalisation au niveau du nœud

Utiliser un agent de journalisation au niveau du
nœud

Vous pouvez implémenter une journalisation au niveau du cluster en incluant un agent de journalisation au niveau du nœud sur chacun des nœuds. L'agent de journalisation est un outil dédié qui met à disposition ou envoie les journaux à un backend. Communément l'agent de journalisation est un conteneur qui a accès au répertoire qui contient les journaux des conteneurs applicatifs sur ce nœud.

Comme l'agent de journalisation doit s'exécuter sur chacun des nœuds, on utilise soit un DaemonSet, soit un manifeste de Pod, soit un processus dédié natif sur le nœud. Ces deux dernières options sont obsolètes et fortement découragées.

Utiliser un agent de journalisation au niveau du nœud est l'approche la plus commune et recommandée pour un cluster Kubernetes parce qu'un seul agent par nœud est créé et qu'aucune modification dans l'application n'est nécessaire. Mais cette approche ne fonctionne correctement que pour les flux standards de sortie et d'erreurs des applications.

Kubernetes ne définit pas d'agent de journalisation, mais deux agents de journalisation optionnels sont fournis avec la version de Kubernetes : Stackdriver (EN) pour utiliser sur Google Cloud Platform, et Elasticsearch (EN). Les deux utilisent fluentd avec une configuration spécifique comme agent sur le nœud. Les liens précédents fournissent plus d'informations et les instructions pour les utiliser et configurer.

Inclure un conteneur side-car pour journaliser les évènements du Pod applicatif

Vous pouvez utiliser un conteneur side-car d'une des manières suivantes :

  • Le conteneur side-car diffuse les journaux de l'application sur son propre stdout.
  • Le conteneur side-car exécute un agent de journalisation qui est configuré pour récupérer les journaux du conteneur applicatif.

Conteneur side-car diffusant (Streaming sidecar container)

Conteneur side-car
diffusant

Comme le conteneur side-car diffuse les journaux sur ses propres flux stdout et stderr, on peut bénéficier du kubelet et de l'agent de journalisation qui s'exécute déjà sur chaque nœud. Les conteneurs side-car lisent les journaux depuis un fichier, un socket ou bien journald. Chaque conteneur side-car écrit son journal sur son propre flux stdout ou stderr.

Cette méthode permet de séparer les flux de journaux de différentes parties de votre application même si elles ne supportent pas d'écrire sur stdout ou stderr. La logique de rediriger les journaux est minime et le surcoût est non significatif. De plus comme les flux standards stdout et stderr sont gérés par kubelet, les outils natifs comme kubectl logs peuvent être utilisés.

Regardez l'exemple qui suit.

Un Pod exécute un unique conteneur et ce conteneur écrit dans deux fichiers de journaux différents en utilisant deux format différents. Voici le manifeste du Pod :

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

Il serait très désordonné d'avoir des évènements avec des formats différents dans le même journal en redirigeant les évènements dans le flux de sortie stdout d'un seul conteneur. Il est plutôt souhaitable d'utiliser deux conteneurs side-car, un pour chaque type de journaux. Chaque conteneur side-car suit un des fichiers et renvoie les évènements sur son propre stdout.

Ci-dessous se trouve le manifeste pour un Pod avec deux conteneurs side-car.

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-1
    image: busybox
    args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-2
    image: busybox
    args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

Quand ce Pod s'exécute, chaque journal peut être diffusé séparément en utilisant les commandes suivantes :

kubectl logs counter count-log-1
0: Mon Jan  1 00:00:00 UTC 2001
1: Mon Jan  1 00:00:01 UTC 2001
2: Mon Jan  1 00:00:02 UTC 2001
...
kubectl logs counter count-log-2
Mon Jan  1 00:00:00 UTC 2001 INFO 0
Mon Jan  1 00:00:01 UTC 2001 INFO 1
Mon Jan  1 00:00:02 UTC 2001 INFO 2
...

L'agent au niveau du nœud installé dans le cluster récupère les deux flux de journaux sans aucune configuration supplémentaire. Il est possible de configurer l'agent pour qu'il analyse syntaxiquement les évènements en fonction du conteneur source.

Notez que bien que la consommation en CPU et mémoire soit faible ( de l'ordre de quelques milicores pour la CPU et quelques mégaoctets pour la mémoire), ecrire les évènements dans un fichier et les envoyer ensuite dans stdout peut doubler l'espace disque utilisé. Quand une application écrit dans un seul fichier de journal, il est préférable de configurer /dev/stdout comme destination plutôt que d'implémenter un conteneur side-car diffusant.

Les conteneurs side-car peuvent être utilisés pour faire la rotation des journaux quand l'application n'en est pas capable elle-même. Un exemple serait un petit conteneur side-car qui effectuerait cette rotation périodiquement. Toutefois, il est recommandé d'utiliser stdout et stderr directement et de laisser la rotation et les politiques de rétentions au kubelet.

Conteneur side-car avec un agent de journalisation

Conteneur side-car avec un agent de
journalisation

Quand un agent de journalisation au niveau du nœud n'est pas assez flexible pour votre utilisation, vous pouvez créer un conteneur side-car avec un agent de journalisation séparé que vous avez configuré spécialement pour qu'il s'exécute avec votre application.

Comme exemple, vous pouvez utiliser Stackdriver où fluentd est l'agent de journalisation. Ci-dessous se trouvent deux configurations qui implémentent cette méthode.

Le premier fichier contient un ConfigMap pour configurer fluentd.

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
data:
  fluentd.conf: |
    <source>
      type tail
      format none
      path /var/log/1.log
      pos_file /var/log/1.log.pos
      tag count.format1
    </source>

    <source>
      type tail
      format none
      path /var/log/2.log
      pos_file /var/log/2.log.pos
      tag count.format2
    </source>

    <match **>
      type google_cloud
    </match>    

Le second fichier est un manifeste pour un Pod avec un conteneur side-car qui exécute fluentd. Le Pod monte un volume où fluentd peut récupérer sa configuration.

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-agent
    image: registry.k8s.io/fluentd-gcp:1.30
    env:
    - name: FLUENTD_ARGS
      value: -c /etc/fluentd-config/fluentd.conf
    volumeMounts:
    - name: varlog
      mountPath: /var/log
    - name: config-volume
      mountPath: /etc/fluentd-config
  volumes:
  - name: varlog
    emptyDir: {}
  - name: config-volume
    configMap:
      name: fluentd-config

Apres quelques minutes, les évènements apparaîtront dans l'interface de Stackdriver.

Ce n'est qu'un exemple et vous pouvez remplacer fluentd par n'importe quel agent de journalisation qui lit depuis n'importe quelle source de votre application.

Envoyer les évènements directement depuis l'application.

Envoyer les évènements directement a un backend depuis
l'application.

Vous pouvez implémenter la journalisation au niveau cluster en mettant à disposition ou en envoyant les journaux directement depuis chaque application; Toutefois l'implémentation de ce mécanisme de journalisation est hors du cadre de Kubernetes.