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 :
Redemarrer Gitea apres modification :
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 :
- Installe les controllers Flux dans le namespace
flux-system - Cree un GitRepository pointant vers le dépôt fleet-infra
- Cree une Kustomization qui reconcilie le chemin
clusters/production - Commit les manifestes Flux dans le dépôt Git
- 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 |