$ 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
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
- Projet Ansible : github.com/hagen-bauer/Ansible-4-Openshift-on-Proxmox
- Documentation UPI bare-metal : docs.openshift.com
- Red Hat Pull Secret : console.redhat.com
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.

Laisser un commentaire