Aller au contenu

Installation et configuration

Prerequis

Composant Version minimale Objectif
Gitea 1.21+ Support Actions natif
Podman 4.0+ Runtime pour le runner act
Kubernetes 1.26+ Cluster cible pour Flux v2
Flux CLI 2.3+ Bootstrap et gestion de Flux
Certificat TLS Let's Encrypt ou PKI interne Chiffrement HTTPS

Partie 1 : Gitea Actions runner

Activer Actions dans Gitea

Vérifier que la section [actions] est activee dans app.ini :

# /etc/gitea/app.ini
[actions]
ENABLED = true
DEFAULT_ACTIONS_URL = self

Redemarrer Gitea apres modification :

sudo systemctl restart gitea

Générer le token d'enregistrement

# Via l'API Gitea (admin)
curl -s -X POST \
  -H "Authorization: token ${GITEA_ADMIN_TOKEN}" \
  "https://git.example.com/api/v1/admin/runners/registration-token" \
  | jq -r '.token'

Le token peut aussi etre génère depuis l'interface : Administration > Runners > Créer un runner.

Déployer le runner avec Podman

# Creer l'utilisateur dedie
sudo useradd -r -m -s /sbin/nologin actrunner

# Creer les repertoires
sudo -u actrunner mkdir -p /home/actrunner/{data,cache}

# Generer la configuration par defaut
sudo -u actrunner podman run --rm \
  gitea/act_runner:latest generate-config > /home/actrunner/data/config.yaml

Configuration du runner

# /home/actrunner/data/config.yaml
log:
  level: info

runner:
  file: /data/.runner
  capacity: 4          # jobs en parallele
  timeout: 3h
  labels:
    - "ubuntu-latest:docker://node:20-bookworm"
    - "self-hosted:host"

cache:
  enabled: true
  dir: /cache
  host:
    port: 0            # port aleatoire

container:
  network: host
  privileged: false     # jamais de conteneur privilegie
  options: |
    --memory=4g
    --cpus=2
  valid_volumes:
    - /home/actrunner/cache

Enregistrer le runner

# Enregistrement avec le token
sudo -u actrunner podman run --rm -it \
  -v /home/actrunner/data:/data:Z \
  gitea/act_runner:latest register \
  --instance https://git.example.com \
  --token "${REGISTRATION_TOKEN}" \
  --name runner-01 \
  --labels "ubuntu-latest,self-hosted"

Lancer le runner en service systemd

# /etc/systemd/system/gitea-runner.service
[Unit]
Description=Gitea Actions Runner
After=network.target

[Service]
Type=simple
User=actrunner
Group=actrunner
WorkingDirectory=/home/actrunner

ExecStart=/usr/bin/podman run --rm \
  --name gitea-runner \
  -v /home/actrunner/data:/data:Z \
  -v /home/actrunner/cache:/cache:Z \
  -v /run/podman/podman.sock:/var/run/docker.sock:Z \
  gitea/act_runner:latest daemon --config /data/config.yaml

ExecStop=/usr/bin/podman stop gitea-runner

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-runner

# Verifier le status
sudo systemctl status gitea-runner

Vérifier l'enregistrement

Dans Gitea : Administration > Runners — le runner doit apparaître avec le statut Online.

# Via l'API
curl -s -H "Authorization: token ${GITEA_ADMIN_TOKEN}" \
  "https://git.example.com/api/v1/admin/runners" \
  | jq '.[] | {name, status, labels}'

Partie 2 : Flux v2

Installer le CLI Flux

# Via le script officiel
curl -s https://fluxcd.io/install.sh | sudo bash

# Verifier l'installation
flux --version

# Verifier les prerequis du cluster
flux check --pre

Bootstrap Flux sur le cluster

Le bootstrap installe les controllers Flux dans le cluster et cree un dépôt Git (ou utilise un dépôt existant) pour stocker la configuration Flux.

# Bootstrap avec Gitea (via token)
flux bootstrap git \
  --url=ssh://git@git.example.com/org/fleet-infra.git \
  --branch=main \
  --path=clusters/production \
  --private-key-file=/path/to/deploy-key \
  --components-extra=image-reflector-controller,image-automation-controller

Le flag --components-extra installe les controllers d'image automation en plus des controllers de base.

Que fait le bootstrap ?

La commande flux bootstrap :

  1. Installe les controllers Flux dans le namespace flux-system
  2. Cree un GitRepository pointant vers le dépôt fleet-infra
  3. Cree une Kustomization qui reconcilie le chemin clusters/production
  4. Commit les manifestes Flux dans le dépôt Git
  5. Flux se gère lui-même via GitOps — les mises a jour passent par Git

Vérifier l'installation

# Verifier que tous les controllers sont prets
flux check

# Lister les controllers
kubectl -n flux-system get pods

# Resultat attendu :
# helm-controller-xxx          1/1     Running
# kustomize-controller-xxx     1/1     Running
# notification-controller-xxx  1/1     Running
# source-controller-xxx        1/1     Running
# image-reflector-controller   1/1     Running (si installe)
# image-automation-controller  1/1     Running (si installe)

Configurer la cle SSH pour le dépôt de manifestes

# Generer une cle SSH dediee
ssh-keygen -t ed25519 -f /tmp/flux-deploy-key -N "" \
  -C "flux@example.com"

# Ajouter la cle publique dans Gitea comme deploy key (lecture seule)
curl -s -X POST \
  -H "Authorization: token ${GITEA_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"title\": \"flux-deploy-key\", \"key\": \"$(cat /tmp/flux-deploy-key.pub)\", \"read_only\": true}" \
  "https://git.example.com/api/v1/repos/org/manifests/keys"

# Creer le GitRepository pour le depot de manifestes
flux create source git manifests \
  --url=ssh://git@git.example.com/org/manifests.git \
  --branch=main \
  --secret-ref=flux-deploy-key \
  --interval=1m

# Supprimer la cle privee locale
rm /tmp/flux-deploy-key

Activer le drift detection

# clusters/production/flux-system/kustomize-controller-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kustomize-controller
  namespace: flux-system
spec:
  template:
    spec:
      containers:
        - name: manager
          args:
            - --events-addr=http://notification-controller.flux-system.svc.cluster.local./
            - --watch-all-namespaces=true
            - --feature-gates=DetectDrift=true,CorrectDrift=true

Partie 3 : Workflow CI complet

Fichier de workflow

# .gitea/workflows/ci.yaml
name: CI Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: harbor.example.com
  IMAGE_NAME: org/myapp

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set image tag
        id: tag
        run: |
          if [ "${{ github.event_name }}" = "push" ]; then
            echo "TAG=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
          else
            echo "TAG=pr-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
          fi

      - name: Build image
        run: |
          podman build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }} .

      - name: Run unit tests
        run: |
          podman run --rm \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }} \
            make test

      - name: Scan with Trivy
        run: |
          trivy image --exit-code 1 --severity HIGH,CRITICAL \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }}

      - name: Login to Harbor
        if: github.event_name == 'push'
        run: |
          podman login ${{ env.REGISTRY }} \
            -u ${{ secrets.HARBOR_USER }} \
            -p ${{ secrets.HARBOR_PASSWORD }}

      - name: Push image
        if: github.event_name == 'push'
        run: |
          podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }}

  update-manifests:
    needs: build
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout manifests
        uses: actions/checkout@v4
        with:
          repository: org/manifests
          token: ${{ secrets.GITEA_DEPLOY_TOKEN }}

      - name: Update image tag
        run: |
          TAG="${GITHUB_SHA::8}"
          cd overlays/production
          kustomize edit set image \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${TAG}

      - name: Commit and push
        run: |
          git config user.name "gitea-actions"
          git config user.email "ci@example.com"
          git add -A
          git commit -m "chore: update myapp image to ${GITHUB_SHA::8}"
          git push

Partie 4 : Kustomization Flux

Kustomization pour l'application

# clusters/production/myapp.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: myapp-production
  namespace: flux-system
spec:
  interval: 5m
  retryInterval: 2m
  timeout: 3m
  prune: true
  force: false

  sourceRef:
    kind: GitRepository
    name: manifests

  path: ./overlays/production

  targetNamespace: app-production

  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: myapp
      namespace: app-production

  patches:
    - patch: |
        apiVersion: kustomize.config.k8s.io/v1beta1
        kind: Kustomization
        metadata:
          name: not-used
      target:
        kind: Namespace

Kustomizations multi-environnement

# clusters/production/myapp-staging.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: myapp-staging
  namespace: flux-system
spec:
  interval: 5m
  prune: true
  sourceRef:
    kind: GitRepository
    name: manifests
  path: ./overlays/staging
  targetNamespace: app-staging
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: myapp
      namespace: app-staging
---
# clusters/production/myapp-production.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: myapp-production
  namespace: flux-system
spec:
  interval: 10m
  prune: true
  sourceRef:
    kind: GitRepository
    name: manifests
  path: ./overlays/production
  targetNamespace: app-production
  # Production : depend du staging
  dependsOn:
    - name: myapp-staging
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: myapp
      namespace: app-production

HelmRelease (alternative Helm)

# clusters/production/myapp-helm.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: myapp-charts
  namespace: flux-system
spec:
  interval: 1h
  url: https://harbor.example.com/chartrepo/org
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: myapp
  namespace: app-production
spec:
  interval: 10m
  chart:
    spec:
      chart: myapp
      version: ">=1.0.0 <2.0.0"
      sourceRef:
        kind: HelmRepository
        name: myapp-charts
        namespace: flux-system
  values:
    image:
      repository: harbor.example.com/org/myapp
      tag: latest
    replicas: 3
  upgrade:
    remediation:
      retries: 3

Image automation (optionnel)

# clusters/production/myapp-image-automation.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: myapp
  namespace: flux-system
spec:
  image: harbor.example.com/org/myapp
  interval: 5m
  secretRef:
    name: harbor-credentials
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: myapp
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: myapp
  policy:
    semver:
      range: ">=1.0.0 <2.0.0"
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
  name: myapp
  namespace: flux-system
spec:
  interval: 5m
  sourceRef:
    kind: GitRepository
    name: manifests
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        name: flux-automation
        email: flux@example.com
      messageTemplate: "chore: update myapp image to {{.NewTag}}"
    push:
      branch: main
  update:
    path: ./overlays/production
    strategy: Setters

Puis annoter les manifestes avec des marqueurs de setter :

# overlays/production/deployment.yaml
spec:
  containers:
    - name: myapp
      image: harbor.example.com/org/myapp:1.0.0 # {"$imagepolicy": "flux-system:myapp"}

Appliquer les manifestes

# Committer les fichiers dans le depot fleet-infra
git add clusters/production/myapp.yaml
git commit -m "feat: add myapp kustomization"
git push

# Flux detecte le changement et reconcilie automatiquement
# Verifier le statut
flux get kustomizations
flux get sources git

# Forcer une reconciliation immediate
flux reconcile kustomization myapp-production --with-source

Vérification post-installation

Vérification Commande Résultat attendu
Runner Gitea enregistre Gitea UI > Administration > Runners Status Online
Workflow declenche au push git push + vérifier Actions dans le dépôt Pipeline vert
Flux controllers prets flux check All checks passed
GitRepository connecte flux get sources git Ready: True
Kustomization synchronisee flux get kustomizations Ready: True, Applied rev
Image déployée kubectl -n app-production get pods -o jsonpath='{..image}' Image attendue