hero-ocp

OpenShift 4 bare-metal sur Proxmox : le guide Day 1

⏱ 10 min de lecture · 1891 mots
$ oc get nodes
NAME                        STATUS   ROLES           AGE   VERSION
okd4-control-plane-1        Ready    master          42m   v1.33.2+d850f32
okd4-control-plane-2        Ready    master          42m   v1.33.2+d850f32
okd4-control-plane-3        Ready    master          41m   v1.33.2+d850f32
okd4-compute-1              Ready    worker,infra    28m   v1.33.2+d850f32
okd4-compute-2              Ready    worker,infra    27m   v1.33.2+d850f32
okd4-compute-3              Ready    worker,infra    27m   v1.33.2+d850f32

Six nœuds. Tous Ready. C’est la sortie que tu veux voir après un déploiement OpenShift réussi. Voici comment y arriver sur Proxmox.

Sommaire
  1. Contexte
  2. Architecture cible
  3. Prérequis
  4. Le DNS : la partie la plus critique
  5. HAProxy : le load balancer
  6. L’install-config.yaml
  7. Structure du projet Ansible
  8. Le déploiement : étape par étape
  9. Ce que l’automatisation Ansible change
  10. Ressources
  11. Conclusion

Contexte

Quand j’ai voulu monter un cluster OpenShift sur mon homelab en 2022, les options étaient : AWS, vSphere, ou « UPI bare-metal, débrouille-toi ». J’ai choisi la troisième — parce que j’avais Proxmox, du matériel, et l’envie de comprendre ce qui se passe sous le capot.

Le point de départ : le projet Ansible-4-Openshift-on-Proxmox de Hagen Bauer. Un ensemble de playbooks Ansible qui automatisent le déploiement complet d’OCP sur Proxmox. J’ai commencé avec OpenShift 4.10 (mars 2022), et le projet a évolué au fil des versions — aujourd’hui il tourne en 4.20 avec OVN-Kubernetes, ArgoCD pour le GitOps, et FreeIPA pour l’authentification.

Cet article couvre le Day 1 : de zéro à un cluster fonctionnel. Le Day 2 (operators, storage, GitOps, monitoring) viendra dans un prochain article.

Architecture cible

Proxmox VE — Les VMs du cluster

Rôle Nœuds OS Specs
Control Plane okd4-control-plane-{1..3} RHCOS 4 vCPU, 16 Go RAM, 128 Go (ZFS)
Compute / Infra okd4-compute-{1..3} RHCOS 16 vCPU, 40 Go RAM, 128 Go + 256 Go NVMe
Bootstrap okd4-bootstrap (temporaire) RHCOS 4 vCPU, 16 Go RAM, 128 Go
Helper helper node RHEL 4 vCPU, 8 Go RAM, 50 Go

3 masters + 3 workers costauds — chaque worker a 16 cœurs, 40 Go de RAM et un disque NVMe supplémentaire de 256 Go pour le stockage ODF (Ceph). Les workers portent aussi le rôle infra pour l’ingress router et le monitoring.

Le Helper node est la clé de voûte. Sans lui, rien ne boot :

  • DNS (BIND) — résolution des nœuds, api.mycloud.mydomain.com, *.apps.mycloud.mydomain.com
  • DHCP — attribution d’IP fixes par MAC address
  • TFTP — boot PXE des nœuds RHCOS
  • HAProxy — load balancer API (6443), Machine Config (22623), apps (80/443), stats (9000)
  • HTTPD (port 8080) — sert les fichiers ignition et les images RHCOS

Prérequis

Avant de lancer quoi que ce soit :

1. Proxmox VE opérationnel

Un hyperviseur Proxmox avec suffisamment de ressources. Pour 3+3 + helper + bootstrap :

CPU  : 64+ vCPU  (3 masters × 4 + 3 workers × 16 + bootstrap + helper)
RAM  : 180+ Go   (3 × 16 Go + 3 × 40 Go + 2 × 16 Go)
Disk : 2+ To     (7 × 128 Go + 3 × 256 Go NVMe)

Un Threadripper avec 256 Go de RAM, c’est confortable.

2. Red Hat Pull Secret

Disponible sur console.redhat.com. C’est un JSON qui autorise le téléchargement des images de conteneurs Red Hat. Gratuit avec un compte développeur.

3. Ansible sur une machine de contrôle

Le projet utilise Ansible pour orchestrer tout le déploiement. Les playbooks s’exécutent depuis le helper node ou une machine séparée.

4. Réseau dédié

Un réseau (ou VLAN) dédié au cluster, avec un plan d’adressage défini. Exemple :

Réseau       : 192.168.x.0/24
Helper       : 192.168.x.169
Bootstrap    : 192.168.x.220
Masters      : 192.168.x.221-223
Workers      : 192.168.x.224-226
API VIP      : api.mycloud.mydomain.com  HAProxy (helper)
Apps wildcard: *.apps.mycloud.mydomain.com  HAProxy

Le DNS : la partie la plus critique

Si le déploiement OpenShift échoue, 9 fois sur 10 c’est le DNS. L’installeur est extrêmement pointilleux :

; Forward zone — mycloud.mydomain.com
api.mycloud.mydomain.com.        A    <HELPER_IP>
api-int.mycloud.mydomain.com.    A    <HELPER_IP>
*.apps.mycloud.mydomain.com.     A    <HELPER_IP>

okd4-bootstrap.mydomain.com.     A    192.168.x.220
okd4-control-plane-1.mydomain.com.  A  192.168.x.221
okd4-control-plane-2.mydomain.com.  A  192.168.x.222
okd4-control-plane-3.mydomain.com.  A  192.168.x.223
okd4-compute-1.mydomain.com.     A    192.168.x.224
okd4-compute-2.mydomain.com.     A    192.168.x.225
okd4-compute-3.mydomain.com.     A    192.168.x.226

; SRV records pour etcd
_etcd-server-ssl._tcp.mycloud.mydomain.com. SRV 0 10 2380 etcd-0.mycloud.mydomain.com.
_etcd-server-ssl._tcp.mycloud.mydomain.com. SRV 0 10 2380 etcd-1.mycloud.mydomain.com.
_etcd-server-ssl._tcp.mycloud.mydomain.com. SRV 0 10 2380 etcd-2.mycloud.mydomain.com.

etcd-0.mycloud.mydomain.com.  A   192.168.x.221
etcd-1.mycloud.mydomain.com.  A   192.168.x.222
etcd-2.mycloud.mydomain.com.  A   192.168.x.223

Les enregistrements reverse DNS (PTR) sont aussi obligatoires. Sans eux, les nœuds ne pourront pas se résoudre mutuellement.

Le projet Ansible génère automatiquement tous ces enregistrements via des templates Jinja2 — c’est un gain de temps énorme.

HAProxy : le load balancer

HAProxy distribue le trafic vers les bons nœuds :

# API Server (6443)
frontend api
    bind *:6443
    default_backend api_backend

backend api_backend
    balance source
    server bootstrap  192.168.x.220:6443 check  # retiré après bootstrap
    server cp-1       192.168.x.221:6443 check
    server cp-2       192.168.x.222:6443 check
    server cp-3       192.168.x.223:6443 check

# Machine Config (22623)
frontend mcs
    bind *:22623
    default_backend mcs_backend

backend mcs_backend
    balance source
    server bootstrap  192.168.x.220:22623 check
    server cp-1       192.168.x.221:22623 check
    server cp-2       192.168.x.222:22623 check
    server cp-3       192.168.x.223:22623 check

# HTTP (80) - Apps ingress
frontend http
    bind *:80
    default_backend http_backend

backend http_backend
    balance source
    server compute-1  192.168.x.224:80 check
    server compute-2  192.168.x.225:80 check
    server compute-3  192.168.x.226:80 check

# HTTPS (443) - Apps ingress
frontend https
    bind *:443
    default_backend https_backend

backend https_backend
    balance source
    server compute-1  192.168.x.224:443 check
    server compute-2  192.168.x.225:443 check
    server compute-3  192.168.x.226:443 check

L’install-config.yaml

Le cœur de la configuration OpenShift :

apiVersion: v1
baseDomain: mydomain.com
compute:
- architecture: amd64
  hyperthreading: Enabled
  name: worker
  replicas: 3          # Nombre de workers
controlPlane:
  architecture: amd64
  hyperthreading: Enabled
  name: master
  replicas: 3
metadata:
  name: mycloud         # Cluster ID → mycloud.mydomain.com
networking:
  clusterNetwork:
  - cidr: 10.128.0.0/14
    hostPrefix: 23
  networkType: OVNKubernetes    # OVN plutôt que OpenShiftSDN
  serviceNetwork:
  - 172.30.0.0/16
platform:
  none: {}              # UPI bare-metal
pullSecret: '<pull-secret>'
sshKey: '<ssh-pub-key>'

Points notables :
OVN-Kubernetes comme réseau — plus moderne et performant que l’ancien OpenShiftSDN
platform: none — c’est la clé du déploiement UPI. OpenShift ne connaît pas Proxmox, il traite les VMs comme du bare-metal
– Le pull secret vient de console.redhat.com

Structure du projet Ansible

OCP4_Install/
├── main.yml                              # Entry point
├── inventory                             # helper + proxmox
├── vars/main.yml                         # Nodes, réseau, versions
├── tasks/
   ├── cluster-helper-nodes-setup.yml    # DNS, DHCP, HAProxy, TFTP
   ├── cluster-config.yml                # Génération ignition
   ├── cluster-proxmox-server-setup.yml  # Création VMs Proxmox
   └── cluster-post-install.yml          # Bootstrap, CSR, day-2
├── templates/                            # Jinja2 (named, haproxy, PXE, install-config)
├── files/                                # Configs statiques
└── handlers/                             # Handlers Ansible

Toute la magie est dans les templates Jinja2 : les fichiers de zone DNS, la config HAProxy, les menus PXE — tout est généré automatiquement à partir des variables définies dans vars/main.yml. Changer un nœud ou une IP, c’est modifier une variable et relancer le playbook.

Le déploiement : étape par étape

Étape 1 — Préparer le Helper node

Les playbooks Ansible installent et configurent tout sur le helper :

ansible-playbook -i inventory tasks/helper-node-setup.yml

Ce playbook :
– Installe DNS (named), DHCP, TFTP, HAProxy, HTTPD
– Configure les zones DNS (forward + reverse)
– Génère les fichiers PXE pour chaque nœud
– Configure le DHCP avec les MAC addresses fixes
– Télécharge les images RHCOS (kernel, initramfs, bios)

Étape 2 — Générer les fichiers d’installation

ansible-playbook -i inventory tasks/cluster-generate-install-files.yml

Ce playbook :
– Crée le install-config.yaml avec le pull secret
– Génère les manifests Kubernetes
– Patch les manifests (mastersSchedulable: false)
– Crée les fichiers ignition (bootstrap.ign, master.ign, worker.ign)
– Copie les ignition sur le serveur HTTP du helper

Les fichiers ignition sont le cœur du déploiement UPI. Chaque nœud RHCOS boot, récupère son fichier ignition via HTTP, et se configure automatiquement.

Étape 3 — Créer les VMs sur Proxmox

ansible-playbook -i inventory tasks/cluster-proxmox-server-setup.yml

Ce playbook utilise le module proxmox_kvm d’Ansible pour :
– Créer les VMs avec les specs définies (CPU, RAM, disque)
– Assigner des MAC addresses fixes (cruciales pour le PXE/DHCP)
– Configurer le boot réseau (PXE)
– Démarrer les VMs

Chaque VM boot en PXE → le DHCP lui assigne une IP basée sur sa MAC → le TFTP lui sert le bon menu PXE → RHCOS démarre et récupère le fichier ignition correspondant (bootstrap, master ou worker) via HTTP.

Étape 4 — Attendre le bootstrap

Le bootstrap est le moment critique. Le nœud bootstrap démarre un cluster etcd temporaire et lance l’installation du control plane :

# Surveiller la progression
openshift-install wait-for bootstrap-complete --log-level=info

# Pendant ce temps, on peut observer :
ssh core@bootstrap "journalctl -b -f -u bootkube.service"

Ce processus prend 15-30 minutes. Quand c’est terminé :

INFO It is now safe to remove the bootstrap resources

Étape 5 — Retirer le bootstrap

ansible-playbook -i inventory tasks/cluster-after-bootstrap.yml

Ce playbook retire le nœud bootstrap de la configuration HAProxy. La VM bootstrap peut ensuite être arrêtée et supprimée — elle n’est plus nécessaire.

Étape 6 — Approuver les CSR des workers

Les workers ont boot avec leur ignition, mais ils attendent une approbation manuelle pour rejoindre le cluster :

# Lister les CSR en attente
oc get csr | grep Pending

# Approuver tous les CSR
oc get csr -o name | xargs oc adm certificate approve

Il faut parfois approuver deux vagues de CSR (la première pour le kubelet, la seconde pour le serving certificate).

Étape 7 — Configurer le registry

Pour un environnement bare-metal sans stockage partagé, le registry interne est configuré en mode emptyDir :

oc patch configs.imageregistry.operator.openshift.io cluster \
  --type merge \
  --patch '{"spec":{"managementState":"Managed","storage":{"emptyDir":{}}}}'

C’est suffisant pour un lab. En production, on utiliserait un PV NFS ou du stockage objet.

Étape 8 — Vérifier le cluster

# Tous les nœuds sont Ready ?
oc get nodes

# Tous les cluster operators sont Available ?
oc get co

# La console est accessible ?
oc get routes -n openshift-console

Quand tous les cluster operators sont Available=True et que la console web répond, le Day 1 est terminé.

Ce que l’automatisation Ansible change

Sans les playbooks de Hagen Bauer, le déploiement UPI d’OpenShift sur Proxmox serait un parcours du combattant. Manuellement, il faut :

  • Écrire les fichiers de zone DNS à la main
  • Configurer le DHCP avec chaque MAC
  • Créer les fichiers PXE par nœud
  • Créer les VMs une par une dans Proxmox
  • Gérer les fichiers ignition

Avec Ansible, tout est déclaratif : on renseigne les variables (noms, IPs, MACs) et les playbooks font le reste. Un ansible-playbook et 30 minutes plus tard, le cluster est debout.

Le projet a bien évolué depuis le fork initial de Hagen Bauer :

  • OCP 4.2 → 4.20 : passage de RHCOS BIOS à UEFI, OpenShiftSDN à OVN-Kubernetes
  • FreeIPA/IdM intégré pour l’authentification OAuth + LDAP group sync
  • ArgoCD (GitOps) pour le Day 2 : les operators, le storage, le monitoring sont déployés automatiquement depuis un repo Gitea
  • ODF (Ceph) pour le stockage persistant, sur les disques NVMe des workers
  • GPU Operator + NFD pour les workloads IA
  • OADP pour les backups du cluster

Ressources

Conclusion

$ oc whoami
system:admin
$ oc get co | grep -c "True.*False.*False"
32
$ echo "32/32 operators — cluster stable."
32/32 operators  cluster stable.

Déployer OpenShift en bare-metal sur Proxmox, c’est possible et reproductible grâce à Ansible. Le secret : un DNS impeccable, un helper node bien configuré, et de la patience pendant le bootstrap.

Le Day 2 arrive bientôt : ArgoCD, ODF (Ceph), FreeIPA, GPU Operator, et les vrais workloads. Tout ça est déjà en GitOps — mais c’est une autre histoire.


Déployé sur un Threadripper 3970X / 256 Go RAM / Proxmox VE — parce qu’un homelab sans OpenShift, c’est juste un hyperviseur ennuyeux.

← Précédent Déployer un blog WordPress piloté par Claude Code

Comments

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *