Posted on
Artificial Intelligence

Artificial Intelligence GitOps for Linux

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence GitOps for Linux: Ship Models with Pull Requests

What if deploying your machine learning model was as safe and repeatable as upgrading your Linux kernel? That’s the promise of GitOps for AI: treat everything (code, models, infra) as code, reviewed and merged via pull requests, then reconciled continuously and automatically on your clusters.

The problem many teams hit is the “works on my machine” gap: training on a laptop, serving in a container, hand-deploying YAML—reproducibility fades, and drift creeps in. GitOps fixes this by making Git the single source of truth for desired state. Combined with Linux-friendly tools (Podman, kubectl, Helm), you can create an AI delivery pipeline that is auditable, repeatable, and fast.

This article shows a minimal, end-to-end example you can run on a Linux workstation:

  • Build a small sentiment API backed by a trained model

  • Containerize training and serving

  • Declare Kubernetes manifests

  • Deploy via Argo CD using Git as the control plane

Along the way you’ll get actionable setup commands (apt, dnf, zypper), bash-friendly snippets, and a path to production.


Why AI + GitOps on Linux?

  • Reproducibility: Containers and pinned dependencies ensure training and serving behave the same locally and in-cluster.

  • Auditability: Models, data pointers, and deployments live in Git—every change is reviewed and traceable.

  • Speed with safety: Automated reconciliation (Argo CD/Flux) closes the gap between commit and cluster while keeping rollbacks trivial.

  • Linux-native: The whole toolchain (Podman/Buildah/Skopeo, kubectl, Helm) thrives on Linux—no workarounds required.


Actionable Step 1: Prepare your Linux GitOps workstation

Install core tooling. Use your distro’s package manager. Then we’ll add kubectl, Helm, kind, and Argo CD using vendor-provided scripts/binaries for up-to-date versions.

Base packages (apt)

sudo apt update
sudo apt install -y \
  git python3 python3-pip python3-venv \
  podman buildah skopeo \
  make curl gnupg ca-certificates \
  git-lfs

Base packages (dnf)

sudo dnf -y install \
  git python3 python3-pip \
  podman buildah skopeo \
  make curl gnupg2 ca-certificates \
  git-lfs

Base packages (zypper)

sudo zypper refresh
sudo zypper install -y \
  git python3 python3-pip \
  podman buildah skopeo \
  make curl gpg2 ca-certificates \
  git-lfs

Tip: If you prefer Docker, you can use it; this guide sticks to Podman (rootless by default and widely available).

Install kubectl (binary)

curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client

Install Helm (script)

curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version

Install kind (local Kubernetes)

curl -Lo kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
chmod +x kind
sudo mv kind /usr/local/bin/kind
kind version

Create a local cluster

kind create cluster --name ai-gitops
kubectl get nodes

Install Argo CD on the cluster

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Wait until components are available
kubectl -n argocd rollout status deploy/argocd-server
kubectl -n argocd rollout status deploy/argocd-repo-server

# Access Argo CD UI (optional, for visibility)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Retrieve initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

Actionable Step 2: Create a minimal AI repo ready for GitOps

We’ll scaffold a simple project that:

  • Trains a scikit-learn model

  • Serves predictions via FastAPI

  • Packages everything into a container

  • Declares manifests for Kubernetes

Recommended structure:

ai-gitops/
  model/
    train.py
    requirements.txt
  service/
    serve.py
  docker/
    Dockerfile
  k8s/
    ns.yaml
    deployment.yaml
    service.yaml
  argo/
    app.yaml
  Makefile

Initialize the repo:

mkdir -p ai-gitops/{model,service,docker,k8s,argo}
cd ai-gitops
git init

requirements.txt:

fastapi
uvicorn[standard]
scikit-learn
joblib

model/train.py (toy sentiment-ish classifier using scikit-learn):

#!/usr/bin/env python3
import joblib
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression

X = [
  "i love this product",
  "this is great",
  "awesome experience",
  "i hate this",
  "this is terrible",
  "awful service",
]
y = [1,1,1,0,0,0]

vec = CountVectorizer()
Xv = vec.fit_transform(X)
clf = LogisticRegression(max_iter=200).fit(Xv, y)

joblib.dump({"vec": vec, "clf": clf}, "service/model.pkl")
print("Saved model to service/model.pkl")

service/serve.py (FastAPI service):

from fastapi import FastAPI
from pydantic import BaseModel
import joblib

app = FastAPI()
bundle = joblib.load("model.pkl")
vec = bundle["vec"]
clf = bundle["clf"]

class Inp(BaseModel):
    text: str

@app.get("/healthz")
def healthz():
    return {"ok": True}

@app.post("/predict")
def predict(inp: Inp):
    X = vec.transform([inp.text])
    proba = clf.predict_proba(X)[0][1]
    return {"positive_prob": float(proba)}

docker/Dockerfile:

FROM python:3.11-slim

WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1

COPY model/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Copy service code and the trained model file later
COPY service/ /app/service/
WORKDIR /app/service

EXPOSE 8000
CMD ["uvicorn", "serve:app", "--host", "0.0.0.0", "--port", "8000"]

k8s/ns.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: ai

k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sentiment-api
  namespace: ai
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sentiment-api
  template:
    metadata:
      labels:
        app: sentiment-api
    spec:
      containers:
      - name: api
        image: ghcr.io/your-org/sentiment-api:0.1.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8000
        readinessProbe:
          httpGet: { path: /healthz, port: 8000 }
          initialDelaySeconds: 3
        livenessProbe:
          httpGet: { path: /healthz, port: 8000 }
          initialDelaySeconds: 10

k8s/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: sentiment-svc
  namespace: ai
spec:
  selector:
    app: sentiment-api
  ports:
  - name: http
    port: 80
    targetPort: 8000

argo/app.yaml (Argo CD Application pointing at your Git repo):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: sentiment-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/ai-gitops.git
    targetRevision: main
    path: k8s
  destination:
    server: https://kubernetes.default.svc
    namespace: ai
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Makefile (quality-of-life targets):

IMAGE=ghcr.io/your-org/sentiment-api
TAG?=0.1.0

venv:
    python3 -m venv .venv && . .venv/bin/activate && pip install -r model/requirements.txt

train:
    . .venv/bin/activate && python3 model/train.py

build:
    podman build -f docker/Dockerfile -t $(IMAGE):$(TAG) .

run:
    podman run --rm -p 8000:8000 $(IMAGE):$(TAG)

push:
    podman push $(IMAGE):$(TAG)

Commit your work:

git add .
git commit -m "Bootstrap AI GitOps example"

Actionable Step 3: Train, containerize, and test locally

Create a virtual environment and train:

make venv
make train

Build and run the container:

make build
make run

Test the API:

curl -s localhost:8000/healthz
curl -s -X POST localhost:8000/predict -H "content-type: application/json" -d '{"text":"i love this"}'

Tag and push to a registry (GHCR shown; log in first):

echo $GITHUB_TOKEN | podman login ghcr.io -u YOUR_GH_USER --password-stdin
make push

Update k8s/deployment.yaml to reference the pushed image tag if needed.


Actionable Step 4: GitOps your deployment with Argo CD

Apply the namespace and Argo CD Application. Argo CD will watch your repo and sync to the cluster.

kubectl apply -f k8s/ns.yaml
kubectl apply -f argo/app.yaml

Argo CD will pull the manifests under k8s/, create your Deployment and Service, and reconcile ongoing changes.

Verify resources:

kubectl -n ai get deploy,po,svc

Port-forward and test in-cluster:

kubectl -n ai port-forward svc/sentiment-svc 8081:80
curl -s localhost:8081/healthz
curl -s -X POST localhost:8081/predict -H "content-type: application/json" -d '{"text":"this is great"}'

From now on:

  • Change code → build/push a new image → bump the tag in k8s/deployment.yaml → git commit/push

  • Argo CD detects the new commit and syncs automatically (per syncPolicy.automated)


Actionable Step 5: Evolve to production (CI, data, and policy)

  • Automate builds with CI:

    • On each PR merge, build and push the image, then update the image tag in the manifest path (k8s/deployment.yaml). A simple approach is to run a script that commits the new tag to main, or generate manifests from a Helm chart with a values file holding the tag.
  • Version data/models:

    • Use Git LFS for binary model artifacts or adopt DVC to track large datasets and model files in remote storage while keeping pointers in Git.
  • Add guardrails:

    • Validate Kubernetes manifests with kubeconform, policy-check with Conftest/OPA, and scan images in CI.
  • Secrets:

    • Store API keys or registry creds with Sealed Secrets or External Secrets; never commit plaintext secrets.

A minimal GitHub Actions outline (pseudo):

name: build-and-deploy
on:
  push:
    branches: [ "main" ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: podman build -f docker/Dockerfile -t ghcr.io/your-org/sentiment-api:${{ github.sha }} .
      - name: Login GHCR
        run: echo $CR_PAT | podman login ghcr.io -u $GITHUB_ACTOR --password-stdin
        env:
          CR_PAT: ${{ secrets.GITHUB_TOKEN }}
      - name: Push
        run: podman push ghcr.io/your-org/sentiment-api:${{ github.sha }}
      - name: Bump manifest tag
        run: |
          sed -i "s#ghcr.io/your-org/sentiment-api:.*#ghcr.io/your-org/sentiment-api:${{ github.sha }}#g" k8s/deployment.yaml
          git config user.name "ci-bot"
          git config user.email "ci@example.com"
          git add k8s/deployment.yaml
          git commit -m "chore: update image tag to ${{ github.sha }}"
          git push

Argo CD will pick up the commit and roll out the new version.


Real-world fit

  • Startups: Move from notebook-to-API in a day, with reproducible containers and safe rollbacks.

  • Enterprises: Enforce change control and audit trails for regulated models (finance, healthcare).

  • Edge/Hybrid: GitOps lets you sync multiple clusters or edge nodes consistently.


Conclusion and Call to Action

AI without delivery discipline stalls. GitOps gives you a Linux-native way to standardize how models move from “it works” to “it runs everywhere.” You now have a working baseline: train a model, containerize it, declare it, and let Argo CD reconcile the cluster to what’s in Git.

Next steps:

  • Fork this structure and adapt it to your org’s registry and CI

  • Add data/model versioning (DVC or Git LFS)

  • Introduce policies and security scans in CI

  • Grow to Helm or Kustomize overlays for environments (dev/stage/prod)

Have questions or improvements? Open a PR on your team’s template repo or start a discussion thread—then ship your next model with a pull request.