Vue lecture

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
🔲 ☆

RaspRover – Le kit robot 4×4 pour Raspberry Pi 4 et 5

Vous rêvez de vous initier au monde de la robotique et de l’intelligence artificielle ?

Ca tombe bien puisque ce kit RaspRover va vous permettre de réaliser ce doux rêve ! Ce petit robot 4×4 hyper versatile est le compagnon idéal pour partir à l’aventure car il embarque un Raspberry Pi dernière génération (modèles 4 ou 5) ce qui va vous permettre de laisser libre cours à votre créativité en le programmant vous-même.

Et pas besoin d’être un crack en informatique pour dompter ce robot puisque tout est pensé pour faciliter sa prise en main. En effet, sous le capot, vous trouverez un double contrôleur avec d’un côté le Raspberry Pi qui gère les fonctions IA de haut niveau pendant que de l’autre, un microcontrôleur se charge des opérations basiques à haute fréquence. Comme ça, chaque action que vous lui demandez est précise et fluide.

Côté perception, le RaspRover a du flair grâce à sa caméra mobile grand angle qui lui offre une vision périphérique à 160°. Couplée à l’IA de reconnaissance d’images de OpenCV, cette caméra détecte et piste les visages ou les objets. Bref, de quoi lui permettre d’interagir avec son environnement sans souci.

Et ce n’est pas tout puisqu’il dispose d’une panoplie de capteurs (IMU 9 axes, télémètre laser…) qui décuplent ses talents : cartographie, évitement d’obstacles, localisation précise… et son architecture modulaire et ses nombreuses interfaces (GPIO, USB, I2C, UART…) lui permettent d’accueillir une foule d’accessoires : bras robotique, capteurs environnementaux, module 4G/5G… De quoi l’adapter à une infinité de scénarios comme de l’agriculture de précision, l’inspection de sites industriels, de la télé-surveillance, pour l’éducation, la recherche…

Et bien sûr, il carbure à l’open source ce qui veut dire que vous pouvez personnaliser son code et ajouter vos propres fonctionnalités. De plus, grâce au protocole ESP-NOW, plusieurs RaspRover peuvent même communiquer et collaborer entre eux ! Imaginez l’escouade de robots que vous allez pouvoir programmer avec ce truc.

Si ça vous dit, y’a un super Wiki qui vous explique comment monter et programmer tout ça.

☑️ ⭐

Ce robot dessine sur une ardoise magique comme un artiste digne des années 80

Vous êtes-vous déjà demandé comment dessiner comme un pro sur une ardoise magique, ce jouet iconique des années 80 ? Pas simple, même pour les artistes les plus talentueux, car pour les plus jeunes d’entre nous qui n’ont pas connu ce jouet, le but c’était de tracer des formes complexes d’un seul trait en bougeant les molettes verticalement et horizontalement. !

Mais grâce à la puissance du Raspberry Pi et un peu de bidouille, dessiner comme un vrai artiste sur cet objet est devenu un jeu d’enfant ou presque.

En effet, le maker Micah Tilton a eu l’idée géniale de créer un robot dessinateur pour Ardoise magique, piloté par un Raspberry Pi afin de reproduire n’importe quelle image dessus de manière très précise, sans se prendre la tête. Le principe est assez simple (sur le papier en tout cas…). Un Raspberry Pi 4 commande deux moteurs pas-à-pas, fixés sur les molettes de l’ardoise grâce à des adaptateurs imprimés en 3D.

Ensuite, un logiciel permet de transformer n’importe quelle image en une succession d’instructions pour guider le robot. L’image est d’abord redimensionnée à la résolution du jouet (plus ou moins 300 x 214 pixels), puis convertie en noir et blanc. Cette résolution a été choisie pour s’adapter parfaitement à la taille de l’écran de l’écran magique et un algorithme analyse ensuite comment la reproduire en un seul trait continu, comme en vrai.

Et voilà comme ce petit robot peut maintenant dessiner en live des images complexes comme des portraits, des paysages ou des personnages en quelques minutes à peine. Le programme utilise des techniques d’optimisation poussées pour améliorer les performances et la fluidité du tracé et comme par magie, on voit les traits se former progressivement sur la planche, guidés par les mouvements millimétrés des moteurs.

C’est franchement bluffant et un peu comme quand je regarde mon imprimante 3D bosser, ça a un petit côté hypnotique et fascinant.

Micah a partagé le code source ainsi que les plans des pièces nécessaires sur GitHub donc si vous avez un Raspberry Pi qui traîne et une grande sœur qui avait ce joujou, vous pourrez recréer votre propre robot dessinateur à la maison.

Source

☑️ ☆

Le Recovery Kit V2 – Le cyberdeck pour les aventuriers du net

Vous avez vu le Recovery Kit Version 2 ?

En gros, c’est un cyberdeck de compète qui renferme un Raspberry Pi dans une valise Pelican Case. Le genre de bidule qui vous donne envie de partir à l’aventure numérique façon Mad Max.

Alors pour faire simple, un cyberdeck, c’est un ordi portable custom taillé pour les baroudeurs du net. Un truc compact, autonome et qui en a dans le ventre pour pirater la NASA depuis un bunker en plein désert (enfin, façon de parler hein, on est pas là pour finir en taule).

Ce Recovery Kit V2, c’est une version améliorée du premier modèle conçu par Jay Doscher en 2019. À l’époque, le concept avait fait un petit buzz dans la commu des makers et des nerds. Faut dire que l’idée de fourrer un Raspberry Pi dans une mallette antichoc, c’est quand même stylé.

Mais alors, qu’est-ce qui change avec cette V2 ? Déjà, on a droit à un Raspberry Pi 5 qui envoie du gros. Ça va vous permettre de faire tourner des trucs costauds sans avoir l’impression d’être revenu au temps du Minitel. Ensuite, y a une batterie de 25 600 mAh pour tenir la distance (4 à 5h d’autonomie), un écran tactile 7 pouces, un clavier ortholinéaire et même un disque SSD NVMe pour le stockage. De quoi vous concocter une config de guerrier nomade.

La valise Pelican 1300 utilisée pour le boitier offre une protection optimale contre la poussière, l’eau et autres dangers environnementaux, histoire de garder votre matos bien au sec.

Au niveau des composants, la liste est plutôt complète mais il manque quelques détails techniques qui pourraient être utiles, genre un schéma du montage pour voir comment tout se branche car le tuto de montage complet est réservé aux membres premium.

En parlant de switches, les célèbres Cherry MX sont un classique mais pour un kit nomade, des switches low profile type Kailh ou Outemu seraient plus adaptés je trouve. Niveau look, comme vous le voyez, on reste dans un style assez brut de décoffrage qui respire la robustesse. La valise Pelican noire avec ses coins renforcés, ça envoie du lourd. On est clairement pas sur un truc fragile à trimballer avec des gants blancs.

Bon après, faut pas se leurrer, c’est pas non plus le machin le plus ergonomique du monde. Le clavier ortholinéaire, c’est un poil déroutant au début et faut aimer taper sur des touches de la taille d’un timbre poste. Mais bon, c’est le prix à payer pour avoir un truc compact qui rentre dans une valise.

Côté connectique, on est plutôt bien servi avec de l’Ethernet, de l’USB-C, un port GPIO pour brancher des modules et même un switch réseau pour partager la connexion. Par contre, va falloir vous coltiner un adaptateur secteur, parce que la recharge se fait via un port barrel. Un poil old school mais bon, on va pas chipoter.

Pour ce qui est de la config logicielle, Jay propose une image toute prête avec Raspberry Pi OS, mais vous pouvez aussi installer votre distro préférée. Perso, je verrai bien un petit Kali Linux pour partir en mode h@ck3r dans la matrice, mais rassurez-vous, un Windows c’est possible aussi. 😎

En vrai, ce Recovery Kit V2, c’est clairement pas un truc pour madame Michu qui veut surfer sur Facebook. C’est plutôt une machine pour les passionnés de bidouille qui kiffent l’idée d’avoir un ordi portable custom qui sort de l’ordinaire. Et puis faudra quand même mettre la main au portefeuille parce qu’entre la valise Pelican, le matos électronique et les accessoires, vous allez vite dépasser les 500 balles. Mais bon, c’est le prix à payer pour avoir un cyberdeck qui en jette.

En attendant, si vous voulez en savoir plus sur ce projet, je vous invite à checker le site de Jay Doscher. Vous y trouverez plein de photos et des détails sur les composants utilisés.

☑️ ⭐

MoOde – Le lecteur audio Raspberry Pi préféré des audiophiles

Vous cherchez un lecteur audio open source de qualité pour votre Raspberry Pi ? Ne cherchez plus, moOde audio est là pour vous !

Ce lecteur audio totalement gratuit et distribué sous licence GPL permet d’avoir un véritable serveur musical sur votre Rpi pour en faire profiter toute la famille. C’est un peu comme Volumio dont je vous ai déjà parlé, mais en beaucoup plus abouti. En plus, les gars derrière moOde sont des vrais. Pas de pubs intrusives, pas d’abonnements à la noix, zéro cookies ou tracking à la Google. Toutes vos données restent bien au chaud sur votre Raspberry Pi, et ne sont refilées à personne d’autre. Bon, après si vous voulez les soutenir, vous pouvez toujours faire un petit don…

Pour installer moOde, c’est facile. Vous chopez l’img et vous allez suivre le guide d’installation qui est juste là. En gros, vous préparez votre image avec le Raspberry Pi Imager, vous pouvez même configurer le SSH et le WiFi direct, et après vous balancez le tout sur votre carte SD. C’est du classique pour les utilisateurs de Raspberry Pi. Rien de plus simple !

La dernière version, la 8.3.9, est dispo pour les modèles 3B, 3B+, 3A+, 4, 400, les Compute Module 3, 3+ et 4, et même le petit dernier le Zero 2 W et elle tourne sur une debian Bullseye 64 bits. Autant dire que ça va envoyer du lourd côté performances audio.

D’ailleurs, parlons-en de l’audio. moOde gère une flopée de périphériques compatibles avec les Raspberry Pi. Que vous ayez une enceinte Bluetooth ou quelque chose de plus « filaire » comme un DAC USB (Digital Audio Converter), une carte d’extension Hat ou carrément un streamer réseau, y a de fortes chances que ça fonctionne direct. Et niveau réglages, les audiophiles vont être aux anges puisqu’il y a de quoi faire du réglage fin sur votre son comme jamais !

Le top du top, c’est l’interface web. Super bien foutue, responsive, elle s’adapte parfaitement à votre appareil, que ce soit un pc, une tablette, un smartphone ou même une TV. Pas besoin d’installer quoi que ce soit, un simple navigateur suffit. Vous pourrez lancer la lecture d’un album, écouter la radio, taguer vos morceaux, accéder à des partages de fichiers via SMB et NFS, balancer le son en AirPlay ou avec Spotify Connect, faire du multiroom synchronisé et profiter de fonctionnalités audiophiles comme le support des formats hi-res, un égaliseur paramétrique, et divers algorithmes de rééchantillonnage. Pour les devs, y a même une API REST pour faire mumuse.

Et si vous avez besoin d’aide ou que vous voulez causer son entre passionnés, le forum moOde est là pour vous. Les devs sont ultra réactifs et la communauté est au taquet. Vous pouvez même choper les dernières news sur le développement du player.

Côté technique, si vous voulez mettre les mains dans le cambouis, un guide du développeur est dispo. Vous pourrez gérer les paquets et générer vos propres images.

Ah et j’allais oublier, les gars de moOde vous ont même concocté un petit DAC NOS (Non-Oversampling) à monter vous-même : le ProtoDAC. Il paraît que le son est d’enfer, surtout si vous utilisez des composants de qualité. Les plans et le guide sont dispos, vous avez juste à commander vos PCB et sortir votre fer à souder.

Bref, vous l’aurez compris, moOde c’est que du bon fait par des pro du son pour les audiophiles geeks qui aiment faire les choses eux-mêmes. Alors, n’attendez plus, foncez sur le site, chopez l’img et transformez votre Raspberry Pi en un lecteur audio de compèt’ !

Merci à François pour le partage !

🔲 ☆

Déploiement Kubernetes sur Raspberry Pi

Aujourd’hui, nous procéderons au déploiement d’un cluster Kubernetes sur Raspberry PI.

On ne présente plus Kubernetes, solution de conteneurisation open-source, simplifiant le déploiement, la mise à l’échelle, et la gestion en général, d’applications conteneurisées. Ni Raspberry-Pi, ordinateur ARM, de la taille d’une carte de crédit, idéal pour vos projets domotique, IoT, rétro-gaming, …

Notre cluster sera composé d’une douzaine de noeuds, et d’un LoadBalancer. Nous le déploierons à l’aide de Kubespray, outil de déploiement faisant partie de l’écosystème Kubernetes, modulaire, fiable, et relativement exhaustif.

Préparatifs Raspbian

Commençons par télécharger Raspbian.

Pour les noeuds master, il est impératif d’utiliser une image 64b, sans quoi Kubespray ne sait pas installer etcd. Nous retrouverons une image beta du projet Raspbian, fournissant une version arm64. Le problème étant que les mainteneurs du projet etcd ne publient pas de version 32b. Notons qu’il reste possible d’installer une version 32b d’etcd, fournie par Debian, quoi que Kubespray ne supporte pas cette combinaison.

Pour nos autres noeuds, nous pourrons utiliser la dernière image officiel Raspbian.

Une fois ces archives téléchargées et extraites, nous pourrons flasher les cartes micro-sd de nos Raspberry Pi :

$ dd if=./2020-08-20-raspios-buster-arm64-lite.img | pv | dd of=/dev/mmcblk0

Cluster-rapsi

Démarrer le Raspberry, avec écran et clavier, afin d’y configurer un mot de passe root :

$ sudo -i
# passwd

Une addresse IP statique :

# cat <<EOF >/etc/network/interfaces
auto eth0
iface eth0 inet static
    address x.y.z.a
    netmask 255.255.255.0
    gateway x.y.z.b
EOF

Serveur DNS :

# cat <<EOF >/etc/resolv.conf
nameserver 10.255.255.255
domain friends.intra.example.com
search friends.intra.example.com
EOF

Désactiver le fichier d’échange swap :

# sed -i 's|CONF_SWAPSIZE=.*|CONF_SWAPSIZE=0|' /etc/dphys-swapfile
# systemctl disable dphys-swapfile

Configurer le serveur SSH :

# sed -i -e 's|#PermitRootLog.*|PermitRootLogin yes|' -e 's|#PasswordAuth|PasswordAuthentication yes|' /etc/ssh/sshd_config
# systemctl enable ssh

Désactiver les services réseaux que nous n’utiliserons pas :

# systemctl disable dhcpcd
# systemctl disable wpa_supplicant
# systemctl disable bluetooth

Configurer le nom de la machine :

# cat <<EOF >/etc/hostname
EOF
# cat <<EOF >/etc/hosts
x.y.z.a <fqdn> <hostname>
127.0.0.1 <fqdn> <hostname>
127.0.0.1 localhost
::1 localhost6 localhost6.localdomain
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF

Activer les cgroups mémoire :

# sed -i 's|rootwait$|rootwait cgroup_enable=cpuset cgroup_enable=memory|' /boot/cmdline.txt
# cat /boot/cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=dcca89ee-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait cgroup_enable=cpuset cgroup_enable=memory

Redémarrer, et vérifier les mots de passe root, IP, gateway, groups mémoire, … puis mettre le système à jour :

# cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
...
memory 9 186 1
....
# hostname -s
# hostname -f
# ip a
# ip r
# apt-get update --allow-releaseinfo-change
# apt-get install python-apt cgroupfs-mount ceph-common rbd-nbd
# apt-get upgrade
# apt-get dist-upgrade

LoadBalancer Kubernetes

Raspberry 3 et 4 conviendront parfaitement au déploiement de Kubernetes. En revanche, les modèles plus anciens seront incapables de lancer certaines composantes Kubernetes, faute d’images adaptées à leur ARM v6.

Profitons d’un Raspberry 2b, pour y déployer le LoadBalancer, qui se trouvera devant le service API des masters Kubernetes :

# apt-get install haproxy hatop
# cat <<EOF >/etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3

defaults
    log global
    option dontlognull
    timeout connect 5000
    timeout client 50000
    timeout server 50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

listen kubernetes-apiserver-https
    bind 0.0.0.0:6443
    mode tcp
    option log-health-checks
    timeout client 3h
    timeout server 3h
    server master1 10.42.253.40:6443 check check-ssl verify none inter 10s
    server master2 10.42.253.41:6443 check check-ssl verify none inter 10s
    server master3 10.42.253.42:6443 check check-ssl verify none inter 10s
    balance roundrobin
EOF
# cat <<EOF >/etc/profile.d/haproxy.sh
alias hatop='hatop -s /run/haproxy/admin.sock'
EOF
# systemctl start haproxy
# systemctl enable haproxy
# . /etc/profile.d/haproxy.sh
# hatop

Préparatifs Ansible

Il nous faudra ensuite préparer le noeud Ansible.

Nous pourrions déployer depuis un laptop, ou n’importe quel poste. L’utilisation d’une machine dédié simplifiera les interventions futures sur le cluster, s’assurant que les mêmes versions de kubespray, python, ansible, … soient utilisées, si l’on veut, par exemple, rajouter un noeud.

Commençons par installer les playbooks Kubespray, et Ansible :

$ sudo apt-get install python-pip git ca-certificates
$ git clone https://github.com/kubernetes-sigs/kubespray
$ cd kubespray
$ sudo pip install -r requirements.txt

Nous devrons alors préparer l’inventaire, listant les machines composant notre cluster :

$ mkdir -p inventory/rpi/group_vars/all inventory/rpi/group_vars/all/k8s-cluster
$ cat <<EOF >inventory/rpi/hosts.yaml
all:
  hosts:
    pandore.friends.intra.example.com:
      etcd_member_name: pandore
      node_labels:
        my.topology/rack: rpi-rack1
        my.topology/row: rpi-row2
    hellenes.friends.intra.example.com:
      etcd_member_name: hellenes
      node_labels:
        my.topology/rack: rpi-rack2
        my.topology/row: rpi-row2
    epimethee.friends.intra.example.com:
      etcd_member_name: epimethee
      node_labels:
        my.topology/rack: rpi-rack3
        my.topology/row: rpi-row2
    pyrrha.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack1
        my.topology/row: rpi-row3
        node-role.kubernetes.io/infra: "true"
    calliope.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack2
        my.topology/row: rpi-row3
        node-role.kubernetes.io/infra: "true"
    clio.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack3
        my.topology/row: rpi-row3
        node-role.kubernetes.io/infra: "true"
    erato.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack1
        my.topology/row: rpi-row4
        node-role.kubernetes.io/worker: "true"
    euterpe.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack2
        my.topology/row: rpi-row4
        node-role.kubernetes.io/worker: "true"
    melpomene.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack3
        my.topology/row: rpi-row4
        node-role.kubernetes.io/worker: "true"
    polyhymnia.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack3
        my.topology/row: rpi-row1
        node-role.kubernetes.io/worker: "true"
    terpsichore.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack2
        my.topology/row: rpi-row1
        node-role.kubernetes.io/worker: "true"
    thalia.friends.intra.example.com:
      node_labels:
        my.topology/rack: rpi-rack1
        my.topology/row: rpi-row1
        node-role.kubernetes.io/worker: "true"
  children:
    calico-rr:
      hosts: {}
    etcd:
      hosts:
        pandore.friends.intra.example.com:
        hellenes.friends.intra.example.com:
        epimethee.friends.intra.example.com:
    kube-infra:
      hosts:
        pyrrha.friends.intra.example.com:
        calliope.friends.intra.example.com:
        clio.friends.intra.example.com:
    kube-master:
      hosts:
        pandore.friends.intra.example.com:
        hellenes.friends.intra.example.com:
        epimethee.friends.intra.example.com:
    kube-workers:
      hosts:
        erato.friends.intra.example.com:
        euterpe.friends.intra.example.com:
        melpomene.friends.intra.example.com:
        polyhymnia.friends.intra.example.com:
        terpsichore.friends.intra.example.com:
        thalia.friends.intra.example.com:
    kube-node:
      children:
        kube-master:
        kube-infra:
        kube-workers:
    k8s-cluster:
      children:
        calico-rr:
        kube-node:
EOF

Cet inventaire décrit un cluster composé de 3 noeuds masters+etcd, 3 noeuds “infra”, et 6 noeuds “workers”.

Ensuite, nous voudrons créer un premier fichier de variables globales :

$ cat <<EOF >inventory/rpi/group_vars/all/all.yaml
ansible_user: root
etcd_data_dir: /var/lib/etcd
etcd_kubeadm_enabled: false
bin_dir: /usr/local/bin
apiserver_loadbalancer_domain_name: api-k8s-arm.intra.example.com
loadbalancer_apiserver:
address: 10.42.253.52
port: 6443
loadbalancer_apiserver_localhost: false
loadbalancer_apiserver_port: 6443
upstream_dns_servers:
- 10.255.255.255
no_proxy_exclude_workers: false
cert_management: script
download_container: true
deploy_container_engine: true
EOF

Nous désignons ici le ou les serveurs DNS existants que Kubernetes devra interroger pour la résolution de noms hors clusters. Ainsi que la VIP d’un LoadBalancer, et le nom DNS correspondant, ceux-ci pointant sur l’HAProxy que nous venons de déployer.

Il faudra ensuite créer un fichier de configuration avec les variables relatives au cluster etcd :

$ cat <<EOF >inventory/rpi/group_vars/etcd.yaml
etcd_compaction_retention: 8
etcd_metrics: basic
etcd_memory_limit: 2GB
etcd_quota_backend_bytes: "2147483648"
etcd_peer_client_auth: true
etcd_deployment_type: host
EOF

On rajoute une limite mémoire et un quota de 2GB, pour etcd, qui doit rentrer sur nos masters, disposant de 4GB de mémoire. Si l’on ne veut pas utiliser docker, comme container runtime, alors on devra changer le type déploiement etcd. Par défaut conteneurisé, son déploiement dépend de commandes docker. Le déploiement de type host permettant l’utilisation d’un runtime crio, ou containerd.

Nous devrons alors créer un nouveau de fichier de variables :

cat <<EOF >inventory/rpi/group_vars/k8s-cluster/k8s-cluster.yaml
kube_config_dir: /etc/kubernetes
kube_script_dir: "{{ bin_dir }}/kubernetes-scripts"
kube_manifest_dir: "{{ kube_config_dir }}/manifests"
kube_cert_dir: "{{ kube_config_dir }}/ssl"
kube_token_dir: "{{ kube_config_dir }}/tokens"
kube_api_anonymous_auth: true
kube_version: v1.19.5
local_release_dir: /tmp/releases
retry_stagger: 5
kube_cert_group: kube-cert
kube_log_level: 2
credentials_dir: "{{ inventory_dir }}/credentials"
kube_oidc_auth: false
kube_token_auth: true
kube_network_plugin: flannel
kube_network_plugin_multus: false
kube_service_addresses: 10.233.128.0/18
kube_pods_subnet: 10.233.192.0/18
kube_network_node_prefix: 24
kube_apiserver_ip: "{{ kube_service_addresses|ipaddr('net')|ipaddr(1)|ipaddr('address') }}"
kube_apiserver_port: 6443
kube_apiserver_insecure_port: 0
kube_proxy_mode: ipvs
authorization_modes: ['Node', 'RBAC']
kube_proxy_strict_arp: false
kube_encrypt_secret_data: false
cluster_name: cluster.local
ndots: 2
dns_mode: coredns
enable_nodelocaldns: true
nodelocaldns_ip: 169.254.25.10
nodelocaldns_health_port: 9254
enable_coredns_k8s_external: false
enable_coredns_k8s_endpoint_pod_names: false
resolvconf_mode: none
deploy_netchecker: false
skydns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(3)|ipaddr('address') }}"
skydns_server_secondary: "{{ kube_service_addresses|ipaddr('net')|ipaddr(4)|ipaddr('address') }}"
dns_domain: "{{ cluster_name }}"
container_manager: containerd
kata_containers_enabled: false
kubeadm_certificate_key: "{{ lookup('password', credentials_dir + '/kubeadm_certificate_key.creds length=64 chars=hexdigits') | lower }}"
k8s_image_pull_policy: IfNotPresent
kubernetes_audit: false
dynamic_kubelet_configuration: false
default_kubelet_config_dir: "{{ kube_config_dir }}/dynamic_kubelet_dir"
dynamic_kubelet_configuration_dir: "{{ kubelet_config_dir | default(default_kubelet_config_dir) }}"
podsecuritypolicy_enabled: true
kubeconfig_localhost: true
kubectl_localhost: false
system_reserved: true
system_memory_reserved: 128Mi
system_cpu_reserved: 250m
system_master_memory_reserved: 256Mi
system_master_cpu_reserved: 250m
volume_cross_zone_attachment: false
persistent_volumes_enabled: false
event_ttl_duration: 1h0m0s
force_certificate_regeneration: false
minimal_node_memory_mb: 896
kube_proxy_nodeport_addresses: >-

Beaucoup de variables ci-dessus reprennent des défaults. Entre autre changements, notons le plugin réseau, “flannel“, et la définition des “kube_service_addresses” et “kube_pods_subnet” ou le “resolvconf_mode“. Le runtime conteneur : “containerd“. L’activation des PodSecurityPolicy. Les “system_*” vont réserver un peu de CPU et mémoire pour l’OS des noeuds. Le “minimal_node_memory” sera indispensable, lorsque certains noeuds ont moins d’1Gi de mémoire – les RPI 3b+ remontent 924Mi.

Il sera possible de configurer le runtime conteneur du cluster, en créant un fichier tel que le suivant :

$ cat <<EOF >inventory/rpi/group_vars/all/containerd.yaml
containerd_config:
  grpc:
    max_recv_message_size: 16777216
    max_send_message_size: 16777216
  debug:
    level: ""
  registries:
    docker.io: "https://registry-1.docker.io"
    katello: "https://katello.vms.intra.example.com:5000"
    "registry.registry.svc.cluster.local:5000": "http://registry.registry.svc.cluster.local:5000"
  max_container_log_line_size: -1
  metrics:
    address: ""
    grpc_histogram: false
EOF

Kubespray permet le déploiement de diverses applications optionnelles :

$ cat <<EOF >inventory/rpi/group_vars/k8s-cluster/addons.yaml
helm_enabled: false
registry_enabled: false
metrics_server_enabled: true
metrics_server_kubelet_insecure_tls: true
metrics_server_metric_resolution: 60s
metrics_server_kubelet_preferred_address_types: "InternalIP"
local_path_provisioner_enabled: false
local_volume_provisioner_enabled: false
cephfs_provisioner_enabled: false
rbd_provisioner_enabled: false
ingress_nginx_enabled: true
ingress_ambassador_enabled: false
ingress_alb_enabled: false
cert_manager_enabled: false
metallb_enabled: false
EOF

Dans notre cas, nous activerons le metrics server, et l’Ingress Controller Nginx.

Enfin, générer une clé SSH sur le noeud Ansible, et l’installer sur tous les noeuds composant le cluster :

$ ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa
$ for i in pandore hellenes .... terpsichore thalia
do ssh-copy-id -i ~/.ssh/id_rsa.pub root@$i.friends.intra.example.com; done
...
$ ansible -m ping -i inventory/rpi/hosts.yaml all

Déploiement Kubernetes

Nous pourrons enfin procéder au déploiement :

$ ansible-playbook -i inventory/rpi/hosts.yaml cluster.yml 2>&&1 | tee -a deploy.$(date +%s).log

Si le déploiement échoue, nous pourrons corriger notre inventaire et relancer cette même commande, à moins que l’erreur ne se soit produite lorsqu’ansible lance l’initialisation du cluster Kubernetes (kubeadm init), auquel cas nous devrions d’abord lancer le playbook de reset, pour réinitialiser les noeuds :

$ ansible-playbook -i inventory/rpi/hosts.yaml reset.yml

Si tout se passe bien, le déploiement ne prendra pas plus d’une trentaine de minutes.

...
PLAY RECAP *******************************************
calliope.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
clio.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
epimethee.friends.intra.example.com : ok=440 changed=67 unreachable=0 failed=0 skipped=864 rescued=0 ignored=1
erato.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
euterpe.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
hellenes.friends.intra.example.com : ok=442 changed=68 unreachable=0 failed=0 skipped=862 rescued=0 ignored=1
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
melpomene.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
pandore.friends.intra.example.com : ok=497 changed=86 unreachable=0 failed=0 skipped=924 rescued=0 ignored=1
pyrrha.friends.intra.example.com : ok=308 changed=30 unreachable=0 failed=0 skipped=604 rescued=0 ignored=1
polyhymnia.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
terpsichore.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1
thalia.friends.intra.example.com : ok=285 changed=29 unreachable=0 failed=0 skipped=514 rescued=0 ignored=1


$ kubectl get nodes
NAME                                    STATUS   ROLES    AGE     VERSION
calliope.friends.intra.example.com      Ready    infra    7m14s   v1.19.5
clio.friends.intra.example.com          Ready    infra    7m14s   v1.19.5
epimethee.friends.intra.example.com     Ready    master   9m26s   v1.19.5
erato.friends.intra.example.com         Ready    worker   7m14s   v1.19.5
euterpe.friends.intra.example.com       Ready    worker   7m1s    v1.19.5
hellenes.friends.intra.example.com      Ready    master   9m24s   v1.19.5
melpomene.friends.intra.example.com     Ready    worker   7m1s    v1.19.5
pandore.friends.intra.example.com       Ready    master   9m59s   v1.19.5
pyrrha.friends.intra.example.com        Ready    infra    7m14s   v1.19.5
polyhimnia.friends.intra.example.com    Ready    worker   7m1s    v1.19.5
terpsichore.friends.intra.example.com   Ready    worker   7m13s   v1.19.5
thalia.friends.intra.example.com        Ready    worker   7m      v1.19.5

A ce stade, nous pourrions intégrer le cluster avec une solution de stockage externe – au plus simple, un serveur NFS. Notons en revanche que l’on reste limité par les modules kernels fournis avec Raspbian : pour s’interfacer avec avec un cluster Ceph, il faudra recompiler votre kernel, ou s’intéresser à rbd-ndb. Nous reviendrons sur ce point dans un article ultérieur.

Conclusion

Cluster-raspi2

Le support ARM par Kubespray est relativement récent, mais fonctionne bien, contrairement à ce que l’on peut lire sur quelques articles de blogs, plus anciens. Il faudra en revanche s’assurer qu’au moins vos noeuds disposent de processeurs armv7, et qu’au moins vos master puissent lancer des binaires 64b.

En règle générale, il faudra s’assurer que les applications que l’on compte déployer dans notre cluster offrent bien des images ARM, ce qui n’est pas toujours le cas. Ceci dit, libre à vous d’assembler vous-mêmes vos images.

Contrairement à OpenShift 4, un cluster Kubernetes demande moins de ressources, offre une plus grande portabilitée, tandis que Kubespray n’a rien à envier aux outils de déploiements d’OpenShift que sont openshift-ansible, ou openshift-install.

❌