HAProxy¶
Dépôt non versionné
Contrairement à tous les autres dépôts IaC d'Indio (nsx, proxy, aws-s3, etc., tous sous indio/iac/* sur GitLab), /root/haproxy ne contient aucun .git — ni local, ni distant (git status échoue avec « n'est un dépôt git »). Il n'existe donc aucun historique de commits ni aucune sauvegarde GitLab pour ce code : seule la copie locale sous /root/haproxy fait foi.
Rôle¶
Cluster HAProxy à 3 nœuds avec IP virtuelle flottante (keepalived), servant de façade unique multi-services pour plusieurs briques internes de l'infrastructure : un frontend/backend distinct par service, sur des ports différents de la même VIP. Au 2026-07-17, 8 services sont exposés : le dépôt Nexus, HashiCorp Vault, l'API Kubernetes, et 5 registries Docker à port dédié.
Architecture¶
Structure du dépôt¶
haproxy/
├── terraform/ infra : 3 VM Rocky 9.6 + génération de l'inventaire Ansible
│ ├── main.tf data sources vSphere/NetBox, vsphere_virtual_machine.hap (for_each), local_file inventory.ini
│ ├── variables.tf nodes (3× INDSERV00x), vm_cpu/vm_ram, vip, ansible_user...
│ ├── outputs.tf vms, vip, ansible_inventory_path
│ └── templates/inventory.ini.tftpl
└── ansible/ applicatif : HAProxy + keepalived
├── site.yml rôles common, keepalived, haproxy
├── ansible.cfg vault_password_file = /root/.hap_vault_pass (hors dépôt)
├── group_vars/haproxy.yml haproxy_services (8 entrées), keepalived_*
└── roles/{common,keepalived,haproxy}
Nœuds et VIP¶
| Rôle | Hôte | IP | Priorité keepalived |
|---|---|---|---|
| VIP (keepalived) | — | 10.100.2.130 |
— |
| MASTER | INDSERV002 | 10.100.2.131 |
110 |
| BACKUP | INDSERV003 | 10.100.2.132 |
100 |
| BACKUP | INDSERV004 | 10.100.2.133 |
90 |
VRRP virtual_router_id = 51, interface détectée automatiquement (ansible_default_ipv4.interface). Segment seg-service (10.100.2.128/26, zone admin — voir NSX).
Services exposés (un frontend/backend par entrée de haproxy_services)¶
| Service | Port frontend | Mode | SSL (HAProxy) | Backend(s) |
|---|---|---|---|---|
repo |
443 | http | oui | Nexus 10.100.2.178:8081 |
vault |
8200 | tcp | non (passthrough) | 3× Vault :8200 |
k8s-api |
6443 | tcp | non (passthrough) | 3× control-plane k8s :6443 |
docker-proxy |
8083 | http | oui | Nexus 10.100.2.178:8083 |
k8s-proxy |
8084 | http | oui | Nexus 10.100.2.178:8084 |
ghcr-proxy |
8085 | http | oui | Nexus 10.100.2.178:8085 |
quay-proxy |
8086 | http | oui | Nexus 10.100.2.178:8086 |
docker-internal |
8087 | http | oui | Nexus 10.100.2.178:8087 |
Deux logiques distinctes cohabitent :
- Terminaison SSL (
repo+ 5 services Docker) : HAProxy déchiffre le TLS avec le certificatroles/haproxy/files/repo.pem(cert+clé concaténés, déployé en/etc/haproxy/certs/repo.pem, mode0640, groupehaproxy) puis parle HTTP en clair au backend Nexus ; un en-têteX-Forwarded-Proto: httpsinforme le backend de l'origine HTTPS. Les 5 services Docker vérifient le backend viaGET /v2/en attendant un401(unhttpchkgénérique renvoie400sur un connecteur Docker Nexus). - TCP passthrough (
vault,k8s-api) : chaque backend termine son propre TLS. Pourvault, le health-check (GET /v1/sys/health,expect status 200) ne réussit que sur le leader actif du cluster Vault — les standby renvoient un autre code, donc un seul des 3 nœuds apparaît « up » en fonctionnement normal. Pourk8s-api, simple vérification TCP : les 3 apiserver sont actifs simultanément (pas de notion de leader HTTP), pas besoin de health-check applicatif.
Page de statistiques HAProxy sur le port 8404 (tous les nœuds).
flowchart TD
CLIENTS["Flotte admin/SOC + proxies DMZ<br/>(règles dmz-to-repo / soc-to-repo côté NSX)"] --> VIP
VIP(["VIP keepalived 10.100.2.130<br/>VRRP 51"])
subgraph NODES[" seg-service 10.100.2.128/26 — 1 seul nœud actif porte la VIP "]
N1["INDSERV002 · .131<br/>prio 110"]
N2["INDSERV003 · .132<br/>prio 100"]
N3["INDSERV004 · .133<br/>prio 90"]
N1 -.failover.-> N2 -.failover.-> N3
end
VIP === N1
N1 --> FE["8 frontends HAProxy (config identique sur les 3 nœuds)<br/>443 repo · 8200 vault · 6443 k8s-api<br/>8083-8087 registries Docker · 8404 stats"]
FE -->|"443, SSL termination"| NEXUS1["Nexus 10.100.2.178:8081"]
FE -->|"8083-8087, SSL termination"| NEXUS2["Nexus 10.100.2.178:8083-8087"]
FE -->|"8200, TCP passthrough"| VAULT["Vault ×3 — 10.100.2.146-148:8200<br/>(seul le leader répond 200 au health-check)"]
FE -->|"6443, TCP passthrough"| K8S["k8s control-plane ×3 — 10.100.2.149-151:6443"]
Provisioning Terraform¶
Le sous-dossier terraform/ ne déploie que l'infrastructure (3 VM) — aucune configuration applicative.
- Data sources vSphere (datacenter, cluster, datastore, réseau
seg-service, VM template) +netbox_ip_addresses(résolution d'IP par nom DNS). resource "vsphere_virtual_machine" "hap"enfor_eachsurvar.nodes— une validation Terraform impose exactement 3 nœuds.- Génère automatiquement
../ansible/inventory.inivialocal_file+templatefile(inventory.ini.tftpl): l'état MASTER/BACKUP et la priorité keepalived sont calculés depuis l'ordre de la liste (index 0= MASTER prio 110, puis-10par nœud suivant). - Variables clés (
variables.tf) :template_name(défauttmpl-rocky96-hardened),nodes(défautINDSERV002/003/004),vm_cpu=2,vm_ram=4096,vm_domain=infra.indio,vm_gateway=10.100.2.190,vip=10.100.2.130,ansible_user=indio-adm. - Providers :
hashicorp/vsphere >= 2.6.0,e-breuninger/netbox >= 5.0.0, < 6.0.0,hashicorp/local >= 2.4.0. Terraform>= 1.5.0. - Sorties (
outputs.tf) :vms(nom → IP),vip,ansible_inventory_path.
README partiellement daté
README.md décrit encore l'état d'origine du dépôt : hostnames haproxy-01/02/03 (renommés INDSERV002/003/004 depuis, cf. Convention de nommage) et un unique service (le dépôt Nexus, via une variable haproxy_backends qui n'existe plus). Le modèle réel actuel est multi-services (haproxy_services, 8 entrées) — cette page reflète le contenu réel de group_vars/haproxy.yml au 2026-07-17, pas le README.
Configuration Ansible¶
site.yml applique 3 rôles sur le groupe haproxy : common, keepalived, haproxy.
common:net.ipv4.ip_nonlocal_bind=1(permet au nœud passif de bind la VIP avant de la porter), booléen SELinuxhaproxy_connect_any, ouverture firewalld d'un port par service (haproxy_services) + le port stats + une règle riche autorisant le protocole VRRP.keepalived: installekeepalived, déploiekeepalived.conf(état/priorité/interface venant de l'inventaire généré par Terraform), redémarre le service au changement.haproxy: installehaproxy, déploie le certificatrepo.pem, déploiehaproxy.cfg(template généré depuishaproxy_services, validé parhaproxy -c -f %savant application), démarre/active le service.
Variables (group_vars/haproxy.yml) : keepalived_vrid=51, keepalived_auth_pass (voir point d'attention), haproxy_stats_port=8404, haproxy_ssl_cert_src/haproxy_ssl_cert, et la liste complète haproxy_services détaillée en Architecture.
ansible.cfg référence un vault_password_file = /root/.hap_vault_pass (hors dépôt) pour le déchiffrement automatique de futurs secrets ansible-vault. requirements.yml installe la collection ansible.posix (modules sysctl, seboolean, firewalld).
Procédure de déploiement¶
cd terraform
cp terraform.tfvars.example terraform.tfvars # vCenter + placement + IP
terraform init
terraform plan
terraform apply # crée les 3 VM et écrit ../ansible/inventory.ini
cd ../ansible
ansible-galaxy collection install -r requirements.yml
ansible-playbook site.yml
Prérequis : template tmpl-rocky96-hardened présent dans vCenter, accès SSH indio-adm (sudo), règles DFW autorisant VRRP entre les 3 nœuds et le flux VIP → backends (voir NSX).
Pour ajouter un service : ajouter une entrée à haproxy_services dans group_vars/haproxy.yml puis rejouer site.yml (le port frontend est automatiquement ouvert dans firewalld par la boucle du rôle common) — la règle DFW correspondante côté NSX doit être ajoutée séparément si le backend n'est pas déjà couvert.
Points d'attention¶
- Absence totale de dépôt git (voir encadré en tête de page) : aucune traçabilité de version, aucune sauvegarde distante. À considérer en priorité si une politique de versionnage systématique est décidée pour ce projet.
keepalived_auth_passest actuellement une valeur en clair dansgroup_vars/haproxy.yml(gérée séparément, non reproduite ici) — le fichier lui-même porte la note « à déplacer dans un ansible-vault en prod », non encore appliquée.- Le certificat
repo.pem(cert + clé concaténés) est un fichier déployé tel quel depuisroles/haproxy/files/: son contenu n'a pas été lu ni reproduit dans cette page (règle de sécurité du projet), à traiter avec la même rigueur qu'un secret. - Cette VIP HAProxy (
10.100.2.130) est indépendante des VIP keepalived du proxy Squid (10.100.10.4) et du proxy DNS (10.100.10.12) — voir Proxy Squid & DNS. HAProxy ne relaie ni Squid ni le DNS proxy : ce sont des clusters HA distincts avec leur propre mécanisme VRRP. - Le health-check Vault (
GET /v1/sys/health,expect status 200) ne cible que le leader : ne pas s'étonner qu'un seul des 3 backendsvault-*apparaisse « up » dans la page de stats en fonctionnement normal — c'est le comportement attendu, pas une panne. - Ajouter un backend Nexus/registry nécessite de vérifier le bon connecteur côté Nexus selon le format (le piège
httpchkgénérique → 400 sur un connecteur Docker déjà rencontré est résolu parGET /v2/+expect status 401, déjà en place pour les 5 services Docker existants — à reproduire pour tout nouveau registry).