GitOps
Skipper supports declarative infrastructure through a skipper.yaml manifest file. Define your entire project (apps, services, volumes, and jobs) in a single file, commit it to Git, and apply it to the cluster.
The skipper.yaml format
project: yourr-name
environment: test
environments:
- test
- acc
- prod
displayName: My Platform
apps:
frontend:
image: registry.example.com/frontend:latest
port: 80
route:
group: yourr-name
path: /
api:
image: registry.example.com/api:latest
port: 8080
replicas: 2
resources:
profile: jvm
env:
LOG_LEVEL: info
serviceBindings:
- name: db
prefix: DB_
autoscale:
enabled: true
minReplicas: 2
maxReplicas: 5
cpuTarget: 70
services:
db:
type: postgres
storage: 5Gi
volumes:
uploads:
size: 10Gi
mounts:
- app: api
mountPath: /data/uploads
functions:
image-resize:
image: registry.example.com/resizer:latest
port: 8080
triggers:
- type: minio
config:
source: storage
jobs:
cleanup:
image: registry.example.com/cleanup:latest
schedule: "0 3 * * *"Each file must have a project field. The environment field determines which namespace the resources are created in (yourr-name-test in this example).
The environments and displayName fields are optional. When present, kip apply creates the Project CR and any missing namespaces automatically, making the manifest self-contained for bootstrapping a new cluster.
Applying a manifest
kip apply -f skipper.yaml ✔ Project yourr-name created (environments: [test acc prod])
✔ Namespace yourr-name-test created
Applying to yourr-name (yourr-name-test)...
✔ App/frontend created
✔ App/api created
✔ Service/db created
✔ Volume/uploads created
✔ Function/image-resize created
✔ Job/cleanup created
Done: 6 created, 0 updatedSkipper creates the Project CR and namespaces if they don't exist, then creates or updates the corresponding Custom Resources. Existing resources are patched, and their spec is merged with the manifest values.
Overriding project and environment
kip apply -f skipper.yaml --project different-project --environment prodDry run
Preview what would change without applying:
kip apply -f skipper.yaml --dry-runExporting from a live cluster
Generate a skipper.yaml from your current cluster state:
kip export --project yourr-name --environment testThis outputs the manifest to stdout. Save it to a file:
kip export --project yourr-name --environment test -o skipper.yamlThe export includes all apps, services, volumes, jobs, functions, project metadata (display name, environments list), resource profiles, autoscale config, service bindings, and routes. Secrets are excluded by design.
Use this to bootstrap a GitOps workflow from an existing cluster, or to replicate a cluster on a new server.
Replicating a cluster
# On the source cluster: export each environment
kip export --project yourr-name --environment test -o test.yaml
kip export --project yourr-name --environment acc -o acc.yaml
kip export --project yourr-name --environment prod -o prod.yaml
# On the new cluster (after kip install)
kip apply -f test.yaml
kip apply -f acc.yaml
kip apply -f prod.yaml
# Recreate secrets (not included in the export)
kip app secret set api DATABASE_URL --project yourr-name --environment testComparing against the cluster
See what would change before applying:
kip diff -f skipper.yaml Comparing yourr-name (yourr-name-test)...
+ App/new-service (new)
~ App/api (exists, will be updated)
~ Service/db (exists, will be updated)+means the resource will be created~means it exists and will be updated
File structure for larger clusters
A single skipper.yaml works for small setups. For larger clusters, split by project and environment:
skipper/
├── yourr-name/
│ ├── test.yaml
│ ├── acc.yaml
│ └── prod.yaml
├── another-project/
│ ├── test.yaml
│ └── prod.yamlApply an entire directory:
kip apply -f skipper/This reads all .yaml and .yml files recursively and applies each one. Each file is self-contained with its own project and environment fields.
Apply a single environment:
kip apply -f skipper/yourr-name/test.yamlGit-based apps
Apps can reference a Git repository instead of a pre-built image:
apps:
api:
port: 8080
git:
url: https://github.com/acme/api.git
branch: mainWhen applied, the app is created with a placeholder image. Use kip app rebuild api or configure a webhook to trigger the first build. See Deploying Apps: From a Git repository for details.
Secrets
Secrets are never stored in skipper.yaml. Manage them separately:
kip app secret set api DATABASE_URL --project yourr-name --environment testThe manifest references services via serviceBindings. Credentials are injected automatically at runtime.
Using with ArgoCD or Flux
Skipper uses standard Kubernetes Custom Resources (getkipper.com/v1alpha1). Any GitOps tool that applies Kubernetes YAML works out of the box:
ArgoCD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: yourr-name
spec:
source:
repoURL: https://github.com/acme/infrastructure.git
path: skipper/yourr-name
destination:
server: https://kubernetes.default.svc
namespace: yourr-name-testFlux:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: infrastructure
spec:
url: https://github.com/acme/infrastructure.git
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: yourr-name
spec:
sourceRef:
kind: GitRepository
name: infrastructure
path: ./skipper/yourr-nameYou can also apply raw CRD YAML directly with kubectl apply -f for full control.
CI/CD integration
Run kip apply in your CI/CD pipeline to deploy on every merge:
# .gitlab-ci.yml
deploy:
script:
- kip apply -f skipper.yaml --environment $CI_ENVIRONMENT_NAME# GitHub Actions
- name: Deploy
run: kip apply -f skipper.yaml --environment productionBlueprints
Blueprints are pre-built skipper.yaml templates for common application stacks. Install a complete stack with one command:
kip blueprint install wordpress --set projectName=my-blogOr generate a manifest to customise before applying:
kip init --blueprint wordpress --set projectName=my-blogSee the Blueprints page for the full catalogue and usage guide.
