gitdevops is a study project for practicing Rust backend development, database migrations, containers, Kubernetes, and GitOps delivery.
The project is intentionally small: one Actix API, SeaORM migrations, local Docker Compose infrastructure, and k3s deployments managed with Helm, Argo CD, Kargo, and CloudNativePG.
- Build a Rust monorepo with Cargo workspaces.
- Create an Actix Web API with health endpoints, product CRUD, and Swagger UI.
- Manage PostgreSQL schema changes with SeaORM migrations.
- Run local development infrastructure with Docker Compose.
- Publish a Docker image to Docker Hub with GitHub Actions.
- Deploy the app to k3s using Helm and Argo CD.
- Manage PostgreSQL in Kubernetes with CloudNativePG.
- Practice GitOps delivery with Argo CD and Kargo.
apps/api/ Rust Actix Web API
migrations/ SeaORM migration workspace
infrastructure/argocd/ Argo CD AppProject and ApplicationSet
infrastructure/helm/gitdevops/ Helm chart and environment values
infrastructure/kargo/ Kargo Project, Warehouse, and Stage
infrastructure/k3s/operators/ k3s operator manifests
docker-compose.yaml Local development stack
Dockerfile Production image build
The root Cargo.toml defines a workspace with two members:
apps/api
migrations
Useful commands:
cargo fmt --all
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
cargo check --locked --workspace
cargo test --locked --workspace
cargo build --release --locked --workspaceThe API uses Actix Web and exposes:
GET /health
GET /health/ready
GET /docs/
GET /api-docs/openapi.json
The readiness endpoint checks both database connections:
DATABASE_URL write connection
DATABASE_READ_URL read connection
Public product endpoints:
GET /products
GET /products/{id}
POST /products
PUT /products/{id}
DELETE /products/{id}
Product request body:
{
"name": "Keyboard",
"description": "Mechanical keyboard",
"price_cents": 19900
}Migrations are a separate workspace member under migrations/.
Run migrations locally against the configured database:
cargo run --locked -p migrations -- upThe final schema contains the products table:
products
The latest migration creates products and drops old user or users tables if they exist.
Copy and edit the local environment file if needed:
cp .env.example .envStart the local stack:
docker compose up --buildDocker Compose runs:
postgres-write primary PostgreSQL instance
postgres-read-1 read replica
postgres-read-2 read replica
migrations runs /app/migrations up
api runs the Actix API
Local database service aliases mirror k3s:
postgres-rw write endpoint
postgres-ro read endpoint
The image is published to Docker Hub:
docker.io/nathan3boss/gitdevops
GitHub Actions expects these repository secrets:
DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
The app deploy manifests are generated from a Helm chart:
infrastructure/helm/gitdevops
PostgreSQL uses CloudNativePG with three instances:
1 primary writer
2 read replicas per environment
Each environment has its own namespace, CloudNativePG Cluster, Services, Secrets, and PVCs:
gitdevops-sit
gitdevops-hlg
gitdevops-prd
That means SIT, HLG, and PRD do not share database volumes.
Install the platform controllers before applying the GitOps resources:
kubectl apply --server-side -k infrastructure/k3s/operators/argocd
kubectl rollout status deployment/argocd-server -n argocd
kubectl apply --server-side -k infrastructure/k3s/operators/cloudnative-pg
kubectl rollout status deployment/cnpg-controller-manager -n cnpg-system
kubectl apply -k infrastructure/k3s/operators/cert-manager
kubectl rollout status deployment/cert-manager -n cert-manager
kubectl rollout status deployment/cert-manager-cainjector -n cert-manager
kubectl rollout status deployment/cert-manager-webhook -n cert-manager
# Install Kargo with Helm. See infrastructure/k3s/helm/kargo/README.md.
kubectl apply -k infrastructure/argocd
kubectl apply -k infrastructure/kargoAccess Argo CD and Kargo with port-forwarding:
kubectl port-forward svc/argocd-server -n argocd 8080:443
kubectl port-forward svc/kargo-api -n kargo 8081:443Open:
https://localhost:8080
https://localhost:8081
If a previous failed apply created a migration job first, reset it in the affected environment namespace:
kubectl delete job gitdevops-migrations -n gitdevops-sit --ignore-not-foundUseful checks:
kubectl get applications -n argocd
kubectl get applicationsets -n argocd
kubectl get all -n gitdevops-sit
kubectl get cluster -n gitdevops-sit
kubectl logs -n gitdevops-sit job/gitdevops-migrations
kubectl logs -n gitdevops-sit deploy/gitdevopsArgo CD application manifests live in:
infrastructure/argocd
Kargo promotion manifests live in:
infrastructure/kargo
The app Helm chart lives in:
infrastructure/helm/gitdevops
Environment values live in:
infrastructure/helm/gitdevops/values-sit.yaml
infrastructure/helm/gitdevops/values-hlg.yaml
infrastructure/helm/gitdevops/values-prd.yaml
Argo CD uses an ApplicationSet to generate one Application per environment. Kargo tracks the Docker image through a declarative Warehouse and promotes Freight through sit -> hlg -> prd stages.