Kubernetes complet de zéro sur Raspberry Pi

Kubernetes complet de zéro sur Raspberry Pi

Récemment, une entreprise bien connue a annoncé qu'elle allait migrer sa gamme de portables vers l'architecture ARM. En entendant cette nouvelle, je me suis souvenu : en consultant à nouveau les prix d'EC2 dans AWS, j'ai remarqué les Graviton avec un prix très attractif. L'astuce, bien sûr, était que c'était de l'ARM. À l'époque, je ne réalisais pas que l'ARM était quelque chose de sérieux…

Pour moi, cette architecture a toujours été réservée aux mobiles et autres gadgets IoT. Des « vrais » serveurs sous ARM, c'est un peu étrange, presque sauvage… Cependant, une nouvelle idée m'est venue à l'esprit, et donc un week-end, j'ai décidé de vérifier ce qu'il est possible de faire aujourd'hui sur ARM. Pour cela, j'ai décidé de commencer par quelque chose de familier — un cluster Kubernetes. Et pas juste un « cluster » quelconque, mais un véritable, comme je suis habitué à voir en production.

Selon ma vision, le cluster doit être accessible depuis Internet, exécuter une application Web, et il doit également y avoir au moins une surveillance. Pour réaliser cette idée, il me faudrait quelques Raspberry Pi, au minimum le modèle 3B+. Bien qu'AWS aurait pu servir de plateforme pour les expériences, j'étais plus intéressé par les « framboises » (qui étaient de toute façon inutilisées). Ainsi, nous allons déployer un cluster Kubernetes avec Ingress, Prometheus et Grafana sur ceux-ci.

Préparation des « framboises »

Installation du système d'exploitation et de SSH

Pour le choix du système d'exploitation, je ne me suis pas trop compliqué : j'ai simplement pris la version la plus récente de Raspberry Pi OS Lite avec le site officiel. Une documentation sur l'installation est également disponible , toutes les étapes y figurent et doivent être effectuées sur tous les nœuds du cluster à venir. Ensuite, il faut effectuer les manipulations suivantes (également sur tous les nœuds).Après avoir connecté un moniteur et un clavier, il est nécessaire de configurer au préalable le réseau et SSH :

Pour que le cluster fonctionne, le maître doit avoir une adresse IP statique, tandis que sur les nœuds de travail, c'est à la discrétion de l'utilisateur. J'ai préféré des adresses statiques partout pour des raisons de commodité de configuration.

  1. Une adresse statique peut être configurée dans le système d'exploitation (dans le fichier
  2. , un exemple approprié est disponible) ou en réservant le lease sur le serveur DHCP de votre routeur (dans mon cas, celui de la maison). /etc/dhcpcd.conf Le serveur SSH se configure simplement dans raspi-config (
  3. options d'interface → sshAprès cela, il est possible de se connecter via SSH (par défaut, le login est).

pi , et le mot de passe estraspberry ou celui que vous avez modifié) et de continuer la configuration. Autres configurations

Autres paramètres

  1. Nous allons définir le nom d'hôte. Dans mon exemple, nous allons utiliser pi-control et pi-worker.
  2. Vérifions que le système de fichiers est étendu sur tout le disque (df -h /). Si nécessaire, il peut être étendu à l'aide de raspi-config.
  3. Changer le mot de passe de l'utilisateur par défaut dans raspi-config.
  4. Désactivons le fichier d'échange (c'est une exigence de Kubernetes ; si vous êtes intéressé par les détails à ce sujet, consultez issue #53533):
    dphys-swapfile swapoff
    systemctl disable dphys-swapfile
  5. Mettons à jour les paquets vers les dernières versions :
    apt-get update && apt-get dist-upgrade -y
  6. Installons Docker et des paquets supplémentaires :
    apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistent

    Lors de l'installation iptables-persistent , il sera nécessaire de sauvegarder les paramètres d'iptables pour ipv4, et dans le fichier /etc/iptables/rules.v4 — ajouter des règles dans la chaîne FORWARD, comme ceci :

    # Generated by xtables-save v1.8.2 on Sun Jul 19 00:27:43 2020
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A FORWARD -s 10.1.0.0/16  -j ACCEPT
    -A FORWARD -d 10.1.0.0/16  -j ACCEPT
    COMMIT
  7. Il ne reste plus qu'à redémarrer.

Tout est maintenant prêt pour l'installation du cluster Kubernetes.

Installation de Kubernetes

À ce stade, j'ai délibérément mis de côté tous mes développements d'automatisation d'installation et de configuration du cluster K8s. À la place, nous allons utiliser la documentation officielle sur kubernetes.io (légèrement complétée par des commentaires et des abréviations).

Ajoutons le dépôt Kubernetes :

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update

Ensuite, la documentation suggère d'installer le CRI (interface d'exécution de conteneurs). Étant donné que Docker est déjà installé, nous continuons et installez les composants principaux :

sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni

Au moment de l'installation des composants principaux, j'ai immédiatement ajouté kubernetes-cni, qui est nécessaire au fonctionnement du cluster. Et il y a un point important : le paquet kubernetes-cni ne crée pour une raison quelconque pas de répertoire par défaut pour les configurations des interfaces CNI, donc j'ai dû le créer manuellement :

mkdir -p /etc/cni/net.d

Pour le backend de réseau, dont nous parlerons ci-dessous, il est nécessaire d'installer le plugin pour CNI. J'ai choisi le plugin portmap que je connais bien (voir la liste complète dans documentation):

curl -sL https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-arm-v0.7.5.tgz | tar zxvf - -C /opt/cni/bin/ ./portmap

Configuration de Kubernetes

Nœud avec le plan de contrôle

L'installation du cluster lui-même est assez simple. Pour accélérer ce processus et vérifier que les images Kubernetes sont accessibles, vous pouvez préalablement exécuter :

kubeadm config images pull

Nous allons maintenant procéder à l'installation proprement dite — initialisons le plan de contrôle du cluster :

kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certs

Veuillez noter que les sous-réseaux pour les services et les pods ne doivent pas se chevaucher entre eux ni avec les réseaux existants.

À la fin, un message nous montrera que tout va bien et nous expliquera comment connecter les nœuds de travail au plane de contrôle :

Votre plane de contrôle Kubernetes a été initialisé avec succès !
Pour commencer à utiliser votre cluster, vous devez exécuter ce qui suit en tant qu'utilisateur ordinaire :
 mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 sudo chown $(id -u):$(id -g) $HOME/.kube/config
Vous devez maintenant déployer un réseau de pods dans le cluster.
Exécutez "kubectl apply -f [podnetwork].yaml" avec l'une des options répertoriées à :
 https://kubernetes.io/docs/concepts/cluster-administration/addons/
Vous pouvez maintenant rejoindre n'importe quel nombre de nœuds du plane de contrôle en exécutant la commande suivante sur chacun d'eux en tant que root :
 kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050 
   --control-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403
Veuillez noter que la clé de certificat donne accès à des données sensibles du cluster, gardez-la secrète !
En guise de précaution, les certificats téléchargés seront supprimés dans deux heures ; si nécessaire, vous pouvez utiliser
"kubeadm init phase upload-certs --upload-certs" pour recharger les certificats par la suite.
Ensuite, vous pouvez rejoindre n'importe quel nombre de nœuds de travail en exécutant ce qui suit sur chacun d'eux en tant que root :
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

Exécutons les recommandations pour l'ajout de la configuration pour l'utilisateur. Et je recommande également d'ajouter immédiatement l'autocomplétion pour kubectl :

 kubectl completion bash > ~$HOME/.kube/completion.bash.inc
 printf "
 # Complétion de shell Kubectl
 source '$HOME/.kube/completion.bash.inc'
 " >> $HOME/.bash_profile
 source $HOME/.bash_profile

À ce stade, vous pouvez déjà voir le premier nœud dans le cluster (bien qu'il ne soit pas encore prêt) :

root@pi-control:~# kubectl get no
NOM         STATUT     RÔLES    ÂGE   VERSION
pi-control   NotReady   maitre   29s   v1.18.6

Configuration du réseau

Ensuite, comme mentionné dans le message après l'installation, il sera nécessaire d'installer un réseau dans le cluster. La documentation propose le choix entre Calico, Cilium, contiv-vpp, Kube-router et Weave Net… Ici, j'ai dévié des instructions officielles et choisi une option qui m'est plus familière et compréhensible : flannel en mode host-gw (plus de détails sur les backends disponibles dans la documentation du projet).

L'installer dans le cluster est assez simple. Pour commencer - téléchargeons les manifestes :

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Ensuite, nous changeons dans les paramètres le type de vxlan sur host-gw:

sed -i 's/vxlan/host-gw/' kube-flannel.yml

… et le sous-réseau des pods - de la valeur par défaut à celle indiquée lors de l'initialisation du cluster :

sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.yml

Après cela, nous créons les ressources :

kubectl create -f kube-flannel.yml

C'est fait ! Après un certain temps, le premier nœud K8s passera au statut Prêt:

NOM         STATUT   RÔLES    ÂGE   VERSION
pi-control   Prêt    maitre   2m    v1.18.6

Ajout d'un nœud de travail

Vous pouvez maintenant ajouter un worker. Pour ce faire, sur celui-ci — après avoir installé Kubernetes selon le scénario décrit ci-dessus — il suffit simplement d'exécuter la commande précédemment obtenue :

kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
    --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

À ce stade, nous pouvons considérer que le cluster est prêt :

root@pi-control:~# kubectl get no
NAME         STATUS   ROLES    AGE    VERSION
pi-control   Ready    master   28m    v1.18.6
pi-worker    Ready       2m8s   v1.18.6

Je n'avais que deux Raspberry Pi à portée de main, donc je ne voulais pas en donner une pour le control plane. uniquement Ainsi, j'ai supprimé le taint automatiquement attribué du nœud pi-control en exécutant :

root@pi-control:~# kubectl edit node pi-control

… et en supprimant les lignes :

 - effect: NoSchedule
   key: node-role.kubernetes.io/master

Remplissage du cluster avec le minimum nécessaire

Tout d'abord, nous aurons besoin de Helm. Bien sûr, il est possible de tout faire sans lui, mais Helm permet de configurer littéralement certains composants à votre goût sans modifier de fichiers. Et en fait, c'est juste un fichier binaire qui « ne demande rien ».

Alors, rendez-vous sur helm.sh dans la section docs/installation et exécutez la commande depuis là :

curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

Ensuite, ajoutons le dépôt de charts :

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

Maintenant, installons les composants d'infrastructure selon le plan :

  • Ingress controller ;
  • Prometheus ;
  • Grafana ;
  • cert-manager.

Ingress controller

Le premier composant — Ingress controller — s'installe assez facilement et est prêt à l'emploi « dès la sortie de la boîte ». Pour ce faire, il suffit d'aller dans la section bare-metal sur le site et d'exécuter la commande d'installation depuis là :

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml

Cependant, à ce moment-là, la « framboise » a commencé à se mettre à ramer et à s'opposer aux IOPS disques. Le problème est que l'Ingress controller installe un grand nombre de ressources, effectue beaucoup de requêtes à l'API et, par conséquent, beaucoup de données sont écrites dans etcd. En général, soit la carte mémoire de classe 10 n'est pas très performante, soit les cartes SD ne sont pas suffisantes pour une telle charge. Néanmoins, après environ 5 minutes, tout s'est lancé.

Un namespace a été créé et un contrôleur avec tout ce dont il avait besoin est apparu en son sein :

root@pi-control:~# kubectl -n ingress-nginx get pod
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-2hwdx        0/1     Completed   0          31s
ingress-nginx-admission-patch-cp55c         0/1     Completed   0          31s
ingress-nginx-controller-7fd7d8df56-68qp5   1/1     Running     0          48s

Prometheus

Les deux composants suivants sont assez simples à installer via Helm à partir du dépôt chart.

Trouvons Prometheus, créons un espace de noms et installons-y :

helm search repo stable | grep prometheus
kubectl create ns monitoring
helm install prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"}

Par défaut, Prometheus demande 2 disques : un pour les données de Prometheus et un pour les données d'AlertManager. Comme aucune classe de stockage n'a été créée dans le cluster, les disques ne seront pas demandés et les pods ne démarreront pas. Pour les installations bare metal de Kubernetes, nous utilisons généralement Ceph rbd, mais dans le cas de Raspberry Pi, c'est clairement excessif.

Nous allons donc créer un stockage local simple sur hostpath. Les manifestes PV (volume permanent) pour prometheus-server et prometheus-alertmanager sont regroupés dans le fichier prometheus-pv.yaml dans Les dépôts Git avec des exemples pour l'article. Le répertoire pour le PV doit être préparé à l'avance sur le disque de l'hôte auquel nous voulons lier Prometheus : dans l'exemple, il est précisé nodeAffinity par le hostname pi-worker et des répertoires y ont été créés /data/localstorage/prometheus-server et /data/localstorage/prometheus-alertmanager.

Téléchargeons (clonons) le manifeste et ajoutons-le à Kubernetes :

kubectl create -f prometheus-pv.yaml

À ce stade, j'ai rencontré pour la première fois un problème d'architecture ARM. Kube-state-metrics, qui est installé par défaut dans le chart Prometheus, a refusé de démarrer. Il a renvoyé l'erreur :

root@pi-control:~# kubectl -n monitoring logs prometheus-kube-state-metrics-c65b87574-l66d8
standard_init_linux.go:207: exec user process caused "exec format error"

En fait, l'image utilisée pour kube-state-metrics provient du projet CoreOS, qui n'est pas compatible avec ARM :

kubectl -n monitoring get deployments.apps prometheus-kube-state-metrics -o=jsonpath={.spec.template.spec.containers[].image}
quay.io/coreos/kube-state-metrics:v1.9.7

J'ai dû faire quelques recherches et trouver, par exemple, cette image. Pour l'utiliser, nous mettrons à jour le release en spécifiant quelle image utiliser pour kube-state-metrics :

helm upgrade prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"} --set kube-state-metrics.image.repository=carlosedp/kube-state-metrics --set kube-state-metrics.image.tag=v1.9.6

Vérifions que tout a démarré :

root@pi-control:~# kubectl -n monitoring get po
NAME                                             READY   STATUS              RESTARTS   AGE
prometheus-alertmanager-df65d99d4-6d27g          2/2     Running             0          5m56s
prometheus-kube-state-metrics-5dc5fd89c6-ztmqr   1/1     Running             0          5m56s
prometheus-node-exporter-49zll                   1/1     Running             0          5m51s
prometheus-node-exporter-vwl44                   1/1     Running             0          4m20s
prometheus-pushgateway-c547cfc87-k28qx           1/1     Running             0          5m56s
prometheus-server-85666fd794-z9qnc               2/2     Running             0          4m52s

Grafana et cert-manager

Pour les graphiques et les tableaux de bord, nous installons Grafana:

helm install grafana --namespace monitoring stable/grafana  --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

À la fin de la sortie, ils nous montreront comment obtenir le mot de passe d'accès :

kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

Pour commander des certificats, nous installerons cert-manager. Pour son installation, nous nous référerons à documentation, qui propose les commandes correspondantes pour Helm :

helm repo add jetstack https://charts.jetstack.io

helm install 
  cert-manager jetstack/cert-manager 
  --namespace cert-manager 
  --version v0.16.0 
  --set installCRDs=true

Pour des certificats auto-signés à usage domestique, cela suffit. Cependant, si vous devez obtenir le même Let's Encrypt, il est nécessaire de configurer un cluster issuer supplémentaire. Les détails peuvent être trouvés dans notre article «Certificats SSL de Let’s Encrypt avec cert-manager dans Kubernetes».

J'ai moi-même opté pour l'option du exemple dans la documentation, pensant que l'option staging de LE serait suffisante. Modifions l'email dans l'exemple, enregistrons-le dans un fichier et ajoutons-le au cluster (cert-manager-cluster-issuer.yaml):

kubectl create -f cert-manager-cluster-issuer.yaml

Nous pouvons maintenant commander un certificat, par exemple, pour Grafana. Pour cela, un domaine et un accès au cluster de l'extérieur sont nécessaires. J'ai un domaine, et j'ai configuré le transfert de trafic des ports 80 et 443 sur mon routeur domestique conformément au service ingress-controller créé :

kubectl -n ingress-nginx get svc
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
 ingress-nginx-controller             NodePort    10.2.206.61            80:31303/TCP,443:30498/TCP   23d

Le port 80 est ici traduit en 31303, et le 443 en 30498. (Les ports sont générés de manière aléatoire, donc vous en aurez d'autres.)

Voici un exemple de certificat (cert-manager-grafana-certificate.yaml):

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: grafana
  namespace: monitoring
spec:
  dnsNames:
    - grafana.home.pi
  secretName: grafana-tls
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-staging

Ajoutons-le au cluster :

kubectl create -f cert-manager-grafana-certificate.yaml

Après cela, une ressource Ingress apparaîtra, à travers laquelle la validation avec Let’s Encrypt se fera :

root@pi-control:~# kubectl -n monitoring get ing
NAME                        CLASS    HOSTS                        ADDRESS         PORTS   AGE
cm-acme-http-solver-rkf8l      grafana.home.pi      192.168.88.31   80      72s
grafana                        grafana.home.pi      192.168.88.31   80      6d17h
prometheus-server              prometheus.home.pi   192.168.88.31   80      8d

Après la validation, nous verrons que la ressource certificate est prête, et dans le secret mentionné ci-dessus grafana-tls se trouvent le certificat et la clé. Nous pouvons immédiatement vérifier qui a émis le certificat :

root@pi-control:~# kubectl -n monitoring get certificate
NAME      READY   SECRET        AGE
grafana   True    grafana-tls   13m

root@pi-control:~# kubectl -n monitoring get secrets grafana-tls -ojsonpath="{.data['tls.crt']}" | base64 -d | openssl x509 -issuer -noout
issuer=CN = Fake LE Intermediate X1

Revenons à Grafana. Nous devrons légèrement modifier son lancement Helm, en ajustant les paramètres TLS conformément au certificat créé.

Pour cela, téléchargeons le chart, modifions-le et le mettons à jour depuis le répertoire local :

helm pull --untar stable/grafana

Modifions le fichier grafana/values.yaml les paramètres TLS :

  tls:
    - secretName: grafana-tls
      hosts:
        - grafana.home.pi

Ici, nous pouvons également configurer Prometheus installé comme datasource:

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
    - name: Prometheus
      type: prometheus
      url: http://prometheus-server:80
      access: proxy
      isDefault: true

Nous mettons maintenant à jour le chart Grafana depuis le répertoire local :

helm upgrade grafana --namespace monitoring ./grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

Vérifions que dans l'Ingress grafana le port 443 a été ajouté et qu'il y a un accès via HTTPS :

root@pi-control:~# kubectl -n monitoring get ing grafana
NAME CLASS HOSTS ADDRESS PORTS AGE
grafana  grafana.home.pi 192.168.88.31 80, 443 63m

root@pi-control:~# curl -kI https://grafana.home.pi
HTTP/2 302
server: nginx/1.19.1
date: Tue, 28 Jul 2020 19:01:31 GMT
content-type: text/html; charset=utf-8
cache-control: no-cache
expires: -1
location: /login
pragma: no-cache
set-cookie: redirect_to=; Path=/; HttpOnly; SameSite=Lax
x-frame-options: deny
strict-transport-security: max-age=15724800; includeSubDomains

Pour démontrer Grafana en action, vous pouvez télécharger et ajouter un tableau de bord pour kube-state-metrics. Voici à quoi cela ressemble :

Kubernetes complet de zéro sur Raspberry Pi

Je recommande également d'ajouter un tableau de bord pour le node exporter : il montrera en détail ce qui se passe avec les « framboises » (charge CPU, utilisation de la mémoire, réseau, disque, etc.).

Après cela, je considère que le cluster est prêt à accepter et à exécuter des applications !

Remarque sur la construction

Pour assembler des applications pour l'architecture ARM, il existe au moins deux options. Tout d'abord, on peut assembler sur un appareil ARM. Cependant, après avoir examiné l'utilisation actuelle de deux Raspberry Pi, j'ai réalisé qu'ils ne peuvent même pas supporter l'assemblage. J'ai donc commandé un nouveau Raspberry Pi 4 (qui est plus puissant et dispose de 4 Go de mémoire) — je prévois de l'utiliser pour l'assemblage.

La deuxième option consiste à assembler une image Docker multi-architecture sur une machine plus puissante. Pour cela, il y a l'extension docker buildx. Si l'application est dans un langage compilé, une cross-compilation pour ARM sera nécessaire. Je ne vais pas décrire tous les réglages nécessaires pour cette approche, car cela nécessiterait un article à part. En mettant en œuvre cette méthode, on peut obtenir des images « universelles » : Docker, exécuté sur un appareil ARM, téléchargera automatiquement l'image correspondant à l'architecture.

Conclusion

L'expérience menée a dépassé toutes mes attentes : [au moins] un Kubernetes « vanille » avec la base nécessaire se comporte plutôt bien sur ARM, et lors de sa configuration, seuls quelques détails ont posé problème.

Les Raspberry Pi 3B+ supportent la charge du CPU, cependant leurs cartes SD constituent un réel goulet d'étranglement. Des collègues m'ont suggéré que dans certaines versions, il est possible de démarrer à partir d'USB, où l'on peut connecter un SSD : dans ce cas, la situation devrait s'améliorer.

Voici un exemple de charge CPU lors de l'installation de Grafana :

Kubernetes complet de zéro sur Raspberry Pi

Pour des expériences et « à essayer », à mon avis, un cluster Kubernetes sur des « framboises » transmet bien mieux les sensations d'exploitation que Minikube, car tous les composants du cluster sont installés et fonctionnent de manière « professionnelle ».

À terme, j'ai l'idée d'ajouter à ce cluster tout le cycle CI/CD, entièrement réalisé sur Raspberry Pi. Je serais également heureux si quelqu'un pouvait partager son expérience de configuration de K8s sur AWS Graviton.

P.S. Oui, « production » peut être plus proche que je ne le pensais :

Kubernetes complet de zéro sur Raspberry Pi

P.P.S.

Lisez aussi dans notre blog :

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster