Documentation

Application Deployment Guide

Welcome to the Planbok K8s! This guide will walk you through deploying your own applications to the platform, ensuring they are secure, scalable, and compliant with our resource quotas.

1. Environment & Access

As a tenant, you are assigned a dedicated Namespace (e.g., tenant-name). You have full administrative control within this namespace but cannot modify cluster-level resources.

Tip: Always test your deployment in a staging namespace first (if provisioned) before rolling out to production.

2. Secrets Management

Do not commit sensitive data (API keys, passwords) to git. Instead, create Kubernetes Secrets directly in your namespace.

# Example: Creating a database password secret
kubectl create secret generic db-credentials \
  --from-literal=password=super-secret-password \
  --namespace=tenant-name

3. Deployment Configuration

When defining your Deployment YAML, you must adhere to the platform's resource quotas.

Resource Limits (Mandatory)

Every container must specify CPU and Memory limits. Failing to do so will result in a Forbidden error during deployment.

spec:
  containers:
  - name: my-app
    image: my-registry/my-app:latest
    resources:
      requests:
        cpu: "100m"      # 0.1 vCPU
        memory: "128Mi"
      limits:
        cpu: "250m"      # Hard limit
        memory: "256Mi"  # Hard limit

Storage (Persistent Volumes)

Stateful applications (like databases) need persistent storage. Use a PersistentVolumeClaim (PVC). You should set the storageClassName to an empty string "" to use the platform's default high-performance storage.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-app-data
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: "" # Use default storage class
  resources:
    requests:
      storage: 10Gi

4. Exposing Your App (Ingress)

To make your application accessible from the internet, you need an Ingress. We use Traefik and Cert-Manager for automatic SSL.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    kubernetes.io/ingress.class: traefik
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80
  tls:
  - hosts:
    - app.example.com
    secretName: my-app-tls

5. Autoscaling (Production)

For production workloads, we recommend using a Horizontal Pod Autoscaler (HPA).

Crucial: If using HPA, remove the static replicas: X field from your Deployment manifest. Otherwise, your deployment will reset the replica count every time you update it, fighting against the autoscaler.
# Deployment.yaml
spec:
  # replicas: 2  <-- REMOVE THIS LINE if using HPA
  selector: ...

6. Health Checks (Probes)

To ensure zero-downtime updates and correct traffic routing, you must define Liveness and Readiness probes. The Ingress controller will not send traffic to your pod until the Readiness probe passes.

spec:
  containers:
  - name: my-app
    # ...
    livenessProbe:
      httpGet:
        path: /health
        port: http
      initialDelaySeconds: 15
      periodSeconds: 20
    readinessProbe:
      httpGet:
        path: /ready
        port: http
      initialDelaySeconds: 5
      periodSeconds: 10

7. Database Migrations

We recommend running database migrations using an InitContainer within your application Deployment. This ensures the database schema is updated before your application starts accepting traffic.

spec:
  initContainers:
  - name: db-migration
    image: my-registry/my-app:latest
    command: ["npm", "run", "migrate"]
    envFrom:
    - secretRef:
        name: db-credentials
  containers:
  - name: my-app
    # ... application starts after migration succeeds

8. Internal Communication (Service Discovery)

To perform internal communication (e.g., Backend connecting to Database), use Kubernetes Services. Every Service gets a DNS name in the format: service-name.namespace.svc.cluster.local.

# Example: Backend connecting to MongoDB
# Connection String: mongodb://mongo-service:27017/db
apiVersion: v1
kind: Service
metadata:
  name: mongo-service
spec:
  selector:
    app: mongo
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

9. High Availability (PDB)

To protect your application during platform maintenance (node upgrades), use a Pod Disruption Budget (PDB). This ensures a minimum number of replicas are always up.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: my-app

10. Network Security & Isolation

Your namespace is isolated for inbound traffic to prevent unauthorized access from other tenants. However, we have enabled full Egress Access.

  • Ingress: Only traffic from the Ingress Controller and other pods in your namespace is allowed.
  • Egress: You have full access to the internet (e.g., Stripe, SendGrid) and external APIs.
Permissions: As a Tenant Admin, you have full control over your resources, including Events (for debugging), Pod Disruption Budgets, and Leases. You cannot modify Resource Quotas or delete the Namespace, as these protect the platform's stability.

11. Troubleshooting Common Issues

  • ImagePullBackOff: Check if your image registry credentials are correct or if the tag exists. Note: Some public images (like Bitnami) deprecate specific tags over time.
  • Pending PVC: Verify that you haven't requested a specific StorageClass that doesn't exist. Use default.
  • Deployment FailedCreate: Check kubectl get events. It is likely a resource quota violation (missing limits).