--- - name: Installation et configuration du Gitea Act Runner hosts: infra become: false gather_facts: true vars: act_runner_version: "0.2.11" act_runner_binary: /usr/local/bin/act_runner act_runner_workdir: /opt/gitea-runner act_runner_config: /opt/gitea-runner/.runner gitea_instance_url: "https://gitea.uber-stup.club" runner_name: "{{ inventory_hostname }}-runner" runner_labels: "ubuntu-latest:docker://catthehacker/ubuntu:act-22.04,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04" # ── Utilisateur CI/CD ──────────────────────────────── ci_cd_user: "ci-cd" ci_cd_user_shell: "/bin/bash" ci_cd_user_groups: - docker ci_cd_ssh_pubkey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICJ4COozE+71IvOhzK7ijeQY5lmoDxYTA0+B0lEAO0tG xor_fakers@AsusXor" # ex: "ssh-ed25519 AAAAC3Nza... ci-cd@gitea" tasks: # ── Verrou dpkg (unattended-upgrades / cloud-init au boot) ── - name: Attendre la libération du verrou dpkg/apt become: true shell: | while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \ || fuser /var/lib/dpkg/lock >/dev/null 2>&1 \ || fuser /var/lib/apt/lists/lock >/dev/null 2>&1 \ || fuser /var/cache/apt/archives/lock >/dev/null 2>&1; do sleep 5 done changed_when: false args: executable: /bin/bash tags: always # ── Prérequis ────────────────────────────────────────── - name: Installer les paquets requis become: true apt: name: - curl - ca-certificates state: present update_cache: yes register: apt_prereqs_result until: apt_prereqs_result is succeeded retries: 10 delay: 15 # ── Docker (requis pour exécuter les jobs) ───────────── - name: Vérifier si Docker est installé become: true command: docker --version register: docker_check changed_when: false failed_when: false - name: Installer Docker si absent become: true block: - name: Ajouter la clé GPG Docker apt_key: url: https://download.docker.com/linux/ubuntu/gpg keyring: /etc/apt/keyrings/docker.gpg state: present - name: Ajouter le dépôt Docker apt_repository: repo: "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" state: present filename: docker - name: Installer Docker apt: name: - docker-ce - docker-ce-cli - containerd.io state: present update_cache: yes register: apt_docker_result until: apt_docker_result is succeeded retries: 10 delay: 15 - name: Démarrer et activer Docker systemd: name: docker state: started enabled: yes when: docker_check.rc != 0 # ── Utilisateur dédié CI/CD ───────────────────────────── - name: Vérifier que ci_cd_ssh_pubkey est fourni fail: msg: "La variable 'ci_cd_ssh_pubkey' est requise. Relancez avec : -e ci_cd_ssh_pubkey='ssh-ed25519 AAAA...'" when: ci_cd_ssh_pubkey is not defined or ci_cd_ssh_pubkey == "" tags: ["ci-cd-user"] - name: Créer l'utilisateur CI/CD become: true user: name: "{{ ci_cd_user }}" shell: "{{ ci_cd_user_shell }}" groups: "{{ ci_cd_user_groups }}" append: true create_home: true state: present tags: ["ci-cd-user"] - name: Créer le répertoire .ssh de l'utilisateur CI/CD become: true file: path: "/home/{{ ci_cd_user }}/.ssh" state: directory owner: "{{ ci_cd_user }}" group: "{{ ci_cd_user }}" mode: "0700" tags: ["ci-cd-user"] - name: Déployer la clé publique SSH de l'utilisateur CI/CD become: true authorized_key: user: "{{ ci_cd_user }}" key: "{{ ci_cd_ssh_pubkey }}" state: present exclusive: false tags: ["ci-cd-user"] - name: Autoriser l'utilisateur CI/CD à utiliser Docker sans mot de passe (sudo ciblé, optionnel) become: true copy: dest: "/etc/sudoers.d/{{ ci_cd_user }}-docker" content: "{{ ci_cd_user }} ALL=(ALL) NOPASSWD: /usr/bin/docker\n" mode: "0440" validate: "visudo -cf %s" tags: ["ci-cd-user"] # ── Téléchargement act_runner ────────────────────────── - name: Vérifier si act_runner est déjà installé become: true stat: path: "{{ act_runner_binary }}" register: runner_bin tags: ["runner", "register-runner"] - name: Récupérer la version installée become: true command: "{{ act_runner_binary }} --version" register: installed_version changed_when: false failed_when: false when: runner_bin.stat.exists tags: ["runner", "register-runner"] - name: Télécharger act_runner v{{ act_runner_version }} become: true get_url: url: "https://dl.gitea.com/act_runner/{{ act_runner_version }}/act_runner-{{ act_runner_version }}-linux-amd64" dest: "{{ act_runner_binary }}" mode: "0755" force: yes tags: ["runner", "register-runner"] when: > not (runner_bin.stat.exists | default(false)) or (installed_version.stdout is defined and act_runner_version not in installed_version.stdout) # ── Répertoire de travail ────────────────────────────── - name: Créer le répertoire de travail become: true file: path: "{{ act_runner_workdir }}" state: directory mode: "0750" tags: ["register-runner"] # ── Enregistrement du runner ─────────────────────────── - name: Vérifier que gitea_runner_token est fourni become: true fail: msg: "La variable 'gitea_runner_token' est requise. Relancez avec : -e gitea_runner_token=" when: gitea_runner_token is not defined or gitea_runner_token == "" tags: ["register-runner"] - name: Vérifier si le runner est déjà enregistré become: true stat: path: "{{ act_runner_config }}" register: runner_config tags: ["register-runner"] - name: Arrêter le service avant re-enregistrement become: true systemd: name: gitea-runner state: stopped failed_when: false when: gitea_runner_token is defined and runner_config.stat.exists tags: ["register-runner"] - name: Supprimer l'ancienne configuration du runner become: true file: path: "{{ act_runner_config }}" state: absent when: gitea_runner_token is defined and runner_config.stat.exists tags: ["register-runner"] - name: Enregistrer le runner auprès de Gitea become: true command: > {{ act_runner_binary }} register --instance {{ gitea_instance_url }} --token {{ gitea_runner_token }} --name {{ runner_name }} --labels {{ runner_labels }} --no-interactive args: chdir: "{{ act_runner_workdir }}" no_log: true tags: ["register-runner"] # ── Service systemd ──────────────────────────────────── - name: Créer le service systemd gitea-runner become: true copy: dest: /etc/systemd/system/gitea-runner.service mode: "0644" content: | [Unit] Description=Gitea Act Runner After=network.target docker.service Requires=docker.service [Service] ExecStart={{ act_runner_binary }} daemon WorkingDirectory={{ act_runner_workdir }} Restart=always RestartSec=5 User=root StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target notify: Recharger systemd tags: ["register-runner"] - name: Activer et démarrer le service gitea-runner become: true systemd: name: gitea-runner state: started enabled: yes daemon_reload: yes tags: ["register-runner"] # ── Vérification ─────────────────────────────────────── - name: Vérifier le statut du runner become: true command: systemctl status gitea-runner register: runner_status changed_when: false failed_when: false tags: ["register-runner"] - name: Afficher le statut become: true debug: msg: "{{ runner_status.stdout_lines }}" tags: ["register-runner"] - name: Check if swap is already active become: true ansible.builtin.command: swapon --show register: swap_status changed_when: false tags: ["register-runner"] - name: Create swapfile become: true ansible.builtin.command: "fallocate -l {{ swap_size }} {{ swap_file }}" args: creates: "{{ swap_file }}" tags: ["register-runner"] when: swap_status.stdout == "" - name: Set swapfile permissions become: true ansible.builtin.file: path: "{{ swap_file }}" mode: "0600" owner: root group: root tags: ["register-runner"] - name: Format swap become: true ansible.builtin.command: mkswap {{ swap_file }} tags: ["register-runner"] when: swap_status.stdout == "" - name: Enable swap become: true ansible.builtin.command: swapon {{ swap_file }} tags: ["register-runner"] when: swap_status.stdout == "" - name: Ensure swap in fstab become: true ansible.builtin.lineinfile: path: /etc/fstab line: "{{ swap_file }} none swap sw 0 0" state: present tags: ["register-runner"] - name: Set swappiness become: true ansible.builtin.sysctl: name: vm.swappiness value: "{{ swap_swappiness }}" state: present reload: yes tags: ["register-runner"] handlers: - name: Recharger systemd become: true systemd: daemon_reload: yes