Stateful Services
Skipper manages stateful services (databases, caches) separately from apps. Services use StatefulSets with persistent storage. They survive restarts and keep their data.
Adding a service
kip service add postgres --name mydb
kip service add mysql --name mydb
kip service add mongodb --name mydb
kip service add redis --name cache
kip service add rabbitmq --name queue
kip service add opensearch --name search
kip service add minio --name storageSupported types: postgres, mysql, mongodb, redis, rabbitmq, opensearch, minio
Per-environment services
Each environment can have its own database with separate credentials and storage:
kip service add postgres --name db --project yourr-name --environment test --storage 1Gi
kip service add postgres --name db --project yourr-name --environment acc --storage 2Gi
kip service add postgres --name db --project yourr-name --environment prod --storage 10GiEach environment's database is fully isolated. Test data never touches production. Test and acc can use smaller storage allocations to save resources.
What this creates
Options
| Flag | Default | Description |
|---|---|---|
--name | Required | Service name |
--project | default | Project name |
--environment | — | Target environment (e.g. test, acc, prod) |
--storage | 5Gi (postgres/mysql/mongodb/opensearch), 1Gi (redis/rabbitmq), 10Gi (minio) | Storage size |
Connection details
After creating a service, the connection details are displayed:
Host: mydb.default.svc.cluster.local
Port: 5432
Username: skipper
Password: a1b2c3d4e5f6...
Database: appRetrieve them later:
kip service info mydbThe hostname (mydb.default.svc.cluster.local) is a Kubernetes internal DNS name. Apps running on the same cluster can connect to it directly.
MinIO (S3-compatible object storage)
MinIO provides S3-compatible object storage for file uploads, media, documents, and other binary data.
kip service add minio --name storage --project yourr-name --environment test Host: storage.yourr-name-test.svc.cluster.local
Port: 9000
Username: skipper
Password: a1b2c3d4e5f6...
Endpoint: http://storage.yourr-name-test.svc.cluster.local:9000
Console: http://storage.yourr-name-test.svc.cluster.local:9001Bind MinIO to your app to inject credentials automatically:
kip service bind storage api --project yourr-name --environment testThis injects S3_HOST, S3_PORT, S3_USERNAME, and S3_PASSWORD into the app. Use them with any S3-compatible SDK (AWS SDK, MinIO SDK, boto3). See the Storage page for mc CLI examples and SDK code samples.
File explorer
MinIO services include a built-in file explorer in the web console. Navigate to Storage in the sidebar to browse buckets, upload and download files, delete objects, and generate share links (presigned URLs). See the Storage page for full details.
Connecting from your machine
Services run inside the cluster and are not exposed to the internet. To connect with a desktop database client (DBeaver, TablePlus, pgAdmin, RedisInsight, or any other tool), use kip tunnel to open a secure connection from your machine to the service:
kip tunnel mydb ✔ Tunnel open: localhost:5432 → mydb (postgres)
Press Ctrl+C to closeOpen your database client and connect to localhost:5432 with the credentials from kip service info mydb.
If the default port is already in use on your machine, pick a different one:
kip tunnel mydb --local-port 15432For services in a specific environment:
kip tunnel db --project yourr-name --environment stagingSee Team Access for the full tunnel documentation, including Redis examples and troubleshooting.
Binding to apps
Bind a service to an app to inject connection details as environment variables:
kip service bind db domain-service --project yourr-name --environment testPer-app databases
For database services (PostgreSQL, MySQL, MongoDB), Skipper automatically creates a dedicated database for each app. The database name is derived from the app name and environment:
| App | Environment | Database name |
|---|---|---|
domain-service | test | domain_service_test |
identity-service | prod | identity_service_prod |
exchange-service | acc | exchange_service_acc |
api | (none) | api |
This means multiple microservices can share a single PostgreSQL instance while keeping their data completely isolated.
Injected environment variables
The binding injects individual connection components with a type-based prefix. The prefix depends on the service type:
Database services (PostgreSQL, MySQL, MongoDB), prefix DB_:
| Variable | Example value |
|---|---|
DB_HOST | db.yourr-name-test.svc.cluster.local |
DB_PORT | 5432 |
DB_USERNAME | skipper |
DB_PASSWORD | a1b2c3d4e5f6... |
DB_NAME | domain_service_test |
MinIO, prefix S3_:
| Variable | Example value |
|---|---|
S3_HOST | storage.yourr-name-test.svc.cluster.local |
S3_PORT | 9000 |
S3_USERNAME | skipper |
S3_PASSWORD | a1b2c3d4e5f6... |
Redis, prefix REDIS_. RabbitMQ, prefix AMQP_. OpenSearch, prefix OPENSEARCH_.
Your app constructs a connection URL from these components in whatever format your framework needs:
- Node.js / Python / Ruby / Go:
postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} - Java / Spring Boot (JDBC):
jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME} - S3 endpoint (MinIO):
http://${S3_HOST}:${S3_PORT}
Unbinding
Remove a binding from the console (env tab → click X on the service) or the CLI:
kip service unbind db domain-service --project yourr-name --environment testDeleting a service automatically unbinds it from all apps. The per-app databases are not dropped. They remain in the PostgreSQL instance for manual cleanup if needed.
The app restarts automatically when a binding is added or removed.
Listing services
kip service list NAME TYPE STATUS READY STORAGE
mydb postgres running 1/1 5Gi
cache redis running 1/1 1GiServices also appear in the web console under the Services sidebar item, where you can view connection details with a masked URL and copy-to-clipboard.
Deleting a service
Deleting a service permanently destroys all data. Skipper requires an explicit flag to prevent accidents:
# This will be rejected
kip service delete mydb
# This works, data is permanently destroyed
kip service delete mydb --delete-dataDANGER
--delete-data is irreversible. The persistent volume and all data are permanently deleted. There is no undo.
Resource limits
Configure CPU and memory limits for your services from the Resources tab in the service detail panel. Click a service in the web console, switch to the Resources tab, and adjust the CPU and memory requests and limits.
Resource limits control how much CPU and memory the service pod is allowed to consume. Databases under heavy query load or caches handling high throughput may need higher limits than the defaults.
WARNING
Changing resource limits on a service triggers a pod restart. For databases (PostgreSQL, MySQL, MongoDB), this means a brief period of downtime while the pod restarts with the new limits. Plan resource changes during a maintenance window or low-traffic period.
How services differ from apps
| Apps | Services | |
|---|---|---|
| Kubernetes resource | Deployment | StatefulSet |
| Storage | None (stateless) | PersistentVolumeClaim |
| Restart | Rolling restart, safe | Warns, requires --force |
| Delete | Immediate | Requires --delete-data |
| Scaling | kip app scale | Single replica (MVP) |
| External access | Via Ingress (public URL) | Internal only (cluster DNS) |
