Skip to content

AWX sur K3s — Déploiement via AWX Operator dans un LXC Proxmox

AWX est l'interface web open-source pour Ansible. À partir de la version 18, AWX ne supporte plus Docker Compose et requiert Kubernetes. Ce guide déploie AWX via l'AWX Operator sur un cluster K3s single-node hébergé dans un conteneur LXC Proxmox — la solution la plus légère pour un homelab.


Architecture

Proxmox VE
└── LXC <CT_ID> — awx.votre-domaine.tld (<CT_IP>) — 6 Go RAM / 4 cores / 32 Go
    └── K3s (single-node)
        └── namespace: awx-operator-system
            ├── awx-operator   ← AWX Operator (controller)
            ├── awx-web        ← Interface web + API REST
            ├── awx-task       ← Exécuteur de jobs Ansible
            ├── awx-redis      ← Cache / file de messages
            └── awx-postgres   ← Base de données (StatefulSet)

Namespace unique

L'instance AWX et l'Operator doivent être dans le même namespace (awx-operator-system). L'Operator ne surveille que son propre namespace par défaut — créer l'instance AWX ailleurs l'empêche de la reconcilier.

Accès : http://<CT_IP>:30080 (NodePort K3s)


Prérequis

Valeurs d'exemple utilisées dans ce guide — à adapter à votre environnement :

Paramètre Valeur d'exemple
ID conteneur 200
Hostname awx.votre-domaine.tld
IP fixe 192.168.1.200/24
Passerelle 192.168.1.254
RAM 6144 Mo (minimum recommandé)
CPU 4 cores
Disque 32 Go
Stockage Proxmox local-lvm
Mode Privilégié (requis par K3s)
Port web 30080 (NodePort)

Conteneur privilégié

K3s nécessite un conteneur privilégié (unprivileged: 0) pour accéder aux namespaces kernel. Ce n'est pas un choix de confort — K3s ne peut pas démarrer dans un LXC non privilégié sans configuration kernel avancée.


Déploiement automatique via le script

cd /root/scripts/awx-lxc
cp vars-example.conf vars.conf   # éditer les valeurs
chmod +x install.sh
bash install.sh

Le script réalise dans l'ordre les étapes décrites ci-dessous.

Durée

Le déploiement complet prend 8 à 12 minutes — la majorité du temps est passée à télécharger les images AWX (~1,5 Go au total).


Déploiement manuel étape par étape

1 — Charger les modules kernel sur l'hôte Proxmox

Ces modules doivent être présents sur l'hôte avant le démarrage de K3s :

modprobe br_netfilter
modprobe overlay

Pour les rendre persistants au redémarrage :

echo -e "br_netfilter\noverlay" >> /etc/modules-load.d/k3s.conf

2 — Créer le conteneur LXC

pveam update
pveam download local debian-12-standard_12.x-x_amd64.tar.zst

pct create 200 local:vztmpl/debian-12-standard_12.x-x_amd64.tar.zst \
    --hostname awx.votre-domaine.tld \
    --memory 6144 \
    --swap 2048 \
    --cores 4 \
    --rootfs local-lvm:32 \
    --net0 name=eth0,bridge=vmbr0,ip=192.168.1.200/24,gw=192.168.1.254 \
    --unprivileged 0 \
    --features nesting=1 \
    --onboot 1

Ajouter la configuration kernel requise par K3s dans /etc/pve/lxc/200.conf :

cat >> /etc/pve/lxc/200.conf << 'EOF'
lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw
EOF

Démarrer le conteneur :

pct start 200

3 — Installer les dépendances

pct exec 200 -- apt-get update -qq
pct exec 200 -- apt-get install -y --no-install-recommends \
    curl ca-certificates git open-iscsi nfs-common

4 — Corriger /dev/kmsg (spécifique LXC)

Le kubelet requiert /dev/kmsg, absent des LXC Proxmox. Ce lien symbolique le recrée automatiquement à chaque démarrage :

pct exec 200 -- bash -c "
    echo 'L /dev/kmsg - - - - /dev/console' > /etc/tmpfiles.d/kmsg.conf &&
    systemd-tmpfiles --create /etc/tmpfiles.d/kmsg.conf
"

5 — Installer K3s

pct exec 200 -- bash -c "
    curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='--disable=traefik' sh -
"

Attendre que le nœud soit prêt :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    until /usr/local/bin/kubectl get nodes 2>/dev/null | grep -q 'Ready'; do sleep 5; done
    /usr/local/bin/kubectl get nodes
"

6 — Déployer l'AWX Operator via kustomize

Récupérer la dernière version stable :

OPERATOR_TAG=$(curl -s https://api.github.com/repos/ansible/awx-operator/releases/latest \
    | grep '"tag_name"' | cut -d'"' -f4)
echo "AWX Operator : $OPERATOR_TAG"

Créer le fichier kustomization et appliquer :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    mkdir -p /tmp/awx-install && cd /tmp/awx-install
    cat > kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - github.com/ansible/awx-operator/config/default?ref=${OPERATOR_TAG}
namespace: awx-operator-system
EOF
    /usr/local/bin/kubectl create namespace awx-operator-system --dry-run=client -o yaml \
        | /usr/local/bin/kubectl apply -f -
    /usr/local/bin/kubectl apply -k .
"

Correctif kube-rbac-proxy

L'image gcr.io/kubebuilder/kube-rbac-proxy a été retirée de Google Container Registry. Patcher le déploiement pour utiliser l'image de remplacement sur quay.io :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl patch deployment awx-operator-controller-manager \
        -n awx-operator-system \
        --type='json' \
        -p='[
            {\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/image\", \"value\": \"quay.io/brancz/kube-rbac-proxy:v0.15.0\"},
            {\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/1/image\", \"value\": \"quay.io/ansible/awx-operator:${OPERATOR_TAG}\"}
        ]'
"

Attendre que l'Operator soit opérationnel (2/2 Running) :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    until /usr/local/bin/kubectl get pods -n awx-operator-system \
        | grep controller-manager | grep -q '2/2'; do sleep 5; done
    echo 'Operator prêt'
"

7 — Déployer l'instance AWX

Namespace

L'instance AWX doit impérativement être créée dans awx-operator-system, le même namespace que l'Operator.

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    cat <<'EOF' | /usr/local/bin/kubectl apply -f -
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
  name: awx
  namespace: awx-operator-system
spec:
  service_type: nodeport
  nodeport_port: 30080
  postgres_storage_class: local-path
EOF
"

Attendre que les pods AWX soient en Running (8 à 12 min) :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    until /usr/local/bin/kubectl get pods -n awx-operator-system \
        | grep 'awx-web' | grep -q 'Running'; do
        /usr/local/bin/kubectl get pods -n awx-operator-system
        sleep 15
    done
    echo 'AWX opérationnel'
"

8 — Exposer le NodePort via iptables

CT_IP=192.168.1.200

iptables -t nat -A PREROUTING -p tcp --dport 30080 -j DNAT --to-destination ${CT_IP}:30080
iptables -I FORWARD -p tcp -d ${CT_IP} --dport 30080 -j ACCEPT
iptables-save > /etc/iptables.rules

Vérification post-installation

État des pods

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl get pods -n awx-operator-system
"

Résultat attendu :

NAME                                               READY   STATUS    RESTARTS
awx-operator-controller-manager-...               2/2     Running   0
awx-postgres-15-0                                  1/1     Running   0
awx-redis-...                                      1/1     Running   0
awx-task-...                                       4/4     Running   0
awx-web-...                                        3/3     Running   0

Logs de l'Operator

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl logs -n awx-operator-system \
        deploy/awx-operator-controller-manager -c awx-manager -f
"

Accès à l'interface

http://192.168.1.200:30080

Récupérer le mot de passe admin (généré automatiquement à l'installation) :

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl get secret awx-admin-password \
        -n awx-operator-system \
        -o jsonpath='{.data.password}' | base64 --decode && echo
"
  • Utilisateur : admin
  • Mot de passe : résultat de la commande ci-dessus

Mise à jour

La mise à jour d'AWX passe par la mise à jour de l'Operator via kustomize — l'Operator se charge ensuite de mettre à jour l'instance automatiquement.

cd /root/scripts/awx-lxc
bash update.sh

Ou manuellement :

NEW_TAG=$(curl -s https://api.github.com/repos/ansible/awx-operator/releases/latest \
    | grep '"tag_name"' | cut -d'"' -f4)

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    mkdir -p /tmp/awx-update && cd /tmp/awx-update
    cat > kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - github.com/ansible/awx-operator/config/default?ref=${NEW_TAG}
namespace: awx-operator-system
EOF
    /usr/local/bin/kubectl apply -k .
"

Points d'administration

État général

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl get pods -n awx-operator-system
    /usr/local/bin/kubectl top pods -n awx-operator-system
"

Redémarrer AWX sans recréer les données

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl rollout restart \
        deployment/awx-web deployment/awx-task \
        -n awx-operator-system
"

Sauvegarde des données

pct exec 200 -- bash -c "
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    /usr/local/bin/kubectl exec -n awx-operator-system deploy/awx-web -- \
        awx-manage dumpdata --natural-foreign --natural-primary \
        -e contenttypes -e auth.Permission \
        --indent 4 > /tmp/awx-backup-\$(date +%Y%m%d).json
"

Désinstallation complète

cd /root/scripts/awx-lxc
bash uninstall.sh

Comparaison avec l'ancienne installation Docker Compose

AWX 17 (Docker Compose) AWX actuel (K3s + Operator)
Support ❌ Abandonné depuis v18 ✅ Actif
Mise à jour Manuelle et complexe kustomize apply + Operator
Ressources ~2 Go RAM ~4-6 Go RAM
Complexité opérationnelle Faible Modérée
RBAC
Workflows
API REST