- Posted on
- • Artificial Intelligence
Artificial Intelligence GitOps Guide
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence GitOps Guide: Ship Models Like Code from Your Terminal
Ever shipped a model that worked flawlessly in your notebook but drifted in production within days? Or struggled to reproduce “the exact same” environment that scored 92% offline but 78% in prod? GitOps solves this with a simple promise: declare your state in Git, let automation reconcile your cluster to match it, and audit everything through commits.
This guide shows how to run AI the GitOps way—entirely from your Linux shell—so you can version, test, deploy, and roll back models as confidently as application code.
Why GitOps belongs in AI
Reproducibility: Your training parameters, model artifacts, and deployment manifests live in Git. Rebuild and redeploy deterministically at any commit.
Fast rollback and drift control: If latency spikes after a new model, revert the Git commit. The cluster corrects itself—no manual surgery.
Reviewable changes: Models and infra changes go through pull requests. You gain peer review, history, and compliance trails.
Clear separation of concern: Data scientists focus on artifacts and interfaces; platform teams provide safe templates and policies (Helm/Kustomize).
Continuous delivery by default: New model tags update manifests; GitOps controllers roll out, verify, and keep the cluster converged.
Prerequisites: Tools you’ll use
We’ll use:
Git for versioning
Podman (or Docker) for building containers
kubectl and Helm for Kubernetes work
Python for a minimal model service
Flux for GitOps reconciliation
jq for JSON parsing (handy in scripts)
You need a Kubernetes cluster (any distribution; managed or local). If you don’t have one yet, you can still follow along until the “Deploy with Flux” step.
Install on Debian/Ubuntu (apt)
sudo apt-get update
sudo apt-get install -y git curl make jq
# Podman (recommended for rootless builds)
sudo apt-get install -y podman
# Python
sudo apt-get install -y python3 python3-venv python3-pip
# kubectl (official repo)
sudo apt-get install -y apt-transport-https ca-certificates gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
# Helm (official repo)
curl -fsSL https://baltocdn.com/helm/signing.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/helm.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" \
| sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install -y helm
Install on Fedora/RHEL (dnf)
sudo dnf install -y git curl make jq podman python3 python3-pip
# kubectl (official repo)
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://pkgs.k8s.io/core:/stable:/v1.30/rpm/
sudo rpm --import https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key
sudo dnf install -y kubectl
# Helm (official repo)
sudo rpm --import https://baltocdn.com/helm/signing.asc
sudo tee /etc/yum.repos.d/helm.repo <<'EOF'
[helm]
name=Helm
baseurl=https://baltocdn.com/helm/stable/rpm
enabled=1
gpgcheck=1
gpgkey=https://baltocdn.com/helm/signing.asc
EOF
sudo dnf install -y helm
Install on openSUSE (zypper)
sudo zypper refresh
sudo zypper install -y git curl make jq podman python3 python3-pip
# kubectl (official repo)
sudo rpm --import https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key
sudo zypper addrepo https://pkgs.k8s.io/core:/stable:/v1.30/rpm/ kubernetes
sudo zypper refresh
sudo zypper install -y kubectl
# Helm (official repo)
sudo rpm --import https://baltocdn.com/helm/signing.asc
sudo zypper addrepo https://baltocdn.com/helm/stable/rpm helm
sudo zypper refresh
sudo zypper install -y helm
Flux CLI (all distros)
curl -s https://fluxcd.io/install.sh | sudo bash
# or without sudo to install in ~/.local/bin:
# curl -s https://fluxcd.io/install.sh | bash
A minimal, practical AI GitOps flow (5 steps)
We’ll containerize a tiny FastAPI service that loads a toy scikit-learn model, push its image to a registry, commit K8s manifests to Git, and let Flux reconcile the cluster.
1) Create a repo and scaffold files
mkdir -p ai-gitops/apps/ai-svc/manifests
cd ai-gitops
git init
Project layout:
ai-gitops/
apps/ai-svc/
app/ # Python service (model server)
manifests/ # Kubernetes YAMLs deployed by Flux
2) Build a simple model service
Create apps/ai-svc/app/app.py:
from fastapi import FastAPI
from pydantic import BaseModel
import joblib
import os
MODEL_PATH = os.environ.get("MODEL_PATH", "/model/model.joblib")
app = FastAPI()
model = joblib.load(MODEL_PATH)
class Item(BaseModel):
x1: float
x2: float
@app.get("/healthz")
def healthz():
return {"status": "ok"}
@app.post("/predict")
def predict(item: Item):
import numpy as np
X = np.array([[item.x1, item.x2]])
y = model.predict_proba(X)[0].tolist()
return {"proba": y}
Create apps/ai-svc/app/requirements.txt:
fastapi==0.111.0
uvicorn[standard]==0.30.0
scikit-learn==1.5.0
joblib==1.4.2
numpy==1.26.4
Create apps/ai-svc/app/Dockerfile:
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Train a tiny model at build-time (toy example for reproducibility)
RUN python - <<'PY'
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
import joblib, os
X, y = make_classification(n_samples=200, n_features=2, n_informative=2, n_redundant=0, random_state=42)
clf = LogisticRegression().fit(X, y)
os.makedirs("/model", exist_ok=True)
joblib.dump(clf, "/model/model.joblib")
PY
COPY app.py .
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host=0.0.0.0", "--port=8080"]
Build and test locally:
cd apps/ai-svc/app
podman build -t registry.example.com/yourname/ai-svc:0.1.0 .
podman run --rm -p 8080:8080 registry.example.com/yourname/ai-svc:0.1.0
# In another terminal:
curl -s http://localhost:8080/healthz
curl -s -X POST http://localhost:8080/predict -H 'content-type: application/json' \
-d '{"x1":0.1,"x2":-0.2}'
Push to your registry (replace URL with your own; e.g., GHCR, Docker Hub, Harbor):
podman login registry.example.com
podman push registry.example.com/yourname/ai-svc:0.1.0
Tip: Tag models with semver matching your model version (e.g., 0.1.0 → 0.1.1).
3) Declare Kubernetes manifests in Git
Create apps/ai-svc/manifests/namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: ai
Create apps/ai-svc/manifests/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-svc
namespace: ai
spec:
replicas: 2
selector:
matchLabels:
app: ai-svc
template:
metadata:
labels:
app: ai-svc
spec:
containers:
- name: api
image: registry.example.com/yourname/ai-svc:0.1.0
imagePullPolicy: IfNotPresent
env:
- name: MODEL_PATH
value: /model/model.joblib
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
Create apps/ai-svc/manifests/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: ai-svc
namespace: ai
spec:
selector:
app: ai-svc
ports:
- port: 80
targetPort: 8080
Commit and push:
cd ../../../
git add .
git commit -m "AI svc: model service, K8s manifests v0.1.0"
git branch -M main
git remote add origin git@github.com:YOURUSER/ai-gitops.git
git push -u origin main
4) Connect your cluster with Flux (GitOps)
Install Flux controllers in your cluster:
kubectl create namespace flux-system || true
flux install
kubectl -n flux-system get deployments
Tell Flux where your Git repo and manifests live. Create clusters/production/flux.yaml:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: ai-gitops
namespace: flux-system
spec:
interval: 1m
url: https://github.com/YOURUSER/ai-gitops
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: ai-svc
namespace: flux-system
spec:
interval: 1m
targetNamespace: ai
prune: true
sourceRef:
kind: GitRepository
name: ai-gitops
path: ./apps/ai-svc/manifests
wait: true
Apply it:
kubectl apply -f clusters/production/flux.yaml
Within a minute, Flux will:
Create the ai namespace
Deploy the ai-svc Deployment and Service
Verify:
kubectl -n ai get pods,svc
kubectl -n ai port-forward svc/ai-svc 8080:80 &
curl -s http://localhost:8080/healthz
Real-world change flow:
Edit
apps/ai-svc/manifests/deployment.yamltoimage: ...:0.1.1Commit and push to main
Flux detects the commit and rolls out the update automatically
If the new model regresses, revert the commit. Flux reconciles the cluster back to the good version.
Optional: Flux “bootstrap” with GitHub can manage the entire cluster config from Git. If you prefer that model, export GITHUB_TOKEN and run:
export GITHUB_TOKEN=ghp_your_token_here
flux bootstrap github --owner=YOURUSER --repository=ai-gitops --branch=main --path=clusters/production
5) Automate image builds from tags
Simple Makefile to standardize builds:
Create Makefile at repo root:
REGISTRY ?= registry.example.com/yourname
IMAGE ?= $(REGISTRY)/ai-svc
TAG ?= 0.1.0
build:
cd apps/ai-svc/app && podman build -t $(IMAGE):$(TAG) .
push:
podman push $(IMAGE):$(TAG)
release: build push
@echo "Released $(IMAGE):$(TAG)"
Usage:
make TAG=0.1.1 release
# then bump the image tag in apps/ai-svc/manifests/deployment.yaml and git commit/push
You can later add CI (e.g., GitHub Actions) to run make release on tags, sign images, scan, and open a PR to bump the manifest tag.
Production-minded tips
Separate config/data from code:
- Store large model artifacts in a registry or object store. Reference immutable tags or digests in manifests.
Use image digests, not tags, for immutability:
image: registry/...@sha256:...
Add canaries and progressive delivery:
- Use tools like Flagger with Flux to route a percentage of traffic to the new model and roll back on metrics.
Manage secrets safely:
- Pair GitOps with sealed-secrets or external-secrets; never commit raw credentials.
Observe everything:
- Emit metrics (latency, error rate, drift signals) and link rollouts to SLO dashboards.
Conclusion and next steps
GitOps gives AI teams a reliable path from model to production: every change is declarative, audited, and reversible. You just: 1) Build and tag a model image 2) Update a manifest in Git 3) Let Flux handle the rest
Your next step:
- Stand up a branch called “staging,” replicate the Flux Kustomization to
clusters/staging, and practice promoting a model from staging → production via pull requests. When you’re ready, wire in CI to build images on tags and open automated PRs that bump image digests.
If you want a follow-up post with canary deployments, model metrics, and automated rollbacks, tell me which stack you’re using (cloud, registry, cluster) and I’ll tailor the scripts.