This repository demonstrates how to deploy a SaaS application to a self-hosted k3s cluster. It's designed to work with the infrastructure created by self-host-saas-k3s.
This repository contains:
- Kubernetes deployment configurations that work with the self-hosted infrastructure
- Traefik ingress setup with proper caching strategies
- ArgoCD configuration for GitOps deployment
- Example application (Next.js) that can be replaced with any other framework
- A k3s cluster set up using self-host-saas-k3s
- ArgoCD installed in your cluster
- A container registry (the infrastructure provides Harbor)
- A domain name pointing to your cluster
.
├── deployment/ # Kubernetes manifests
│ ├── deployment.yaml # Application deployment
│ ├── service.yaml # Kubernetes service
│ ├── ingress.yaml # Traefik ingress configuration
│ ├── middleware.yaml # Traefik middleware for caching
│ └── kustomization.yaml # Kustomize configuration
└── Dockerfile # Container definition
Replace the Dockerfile with one appropriate for your application:
# Example for a Python application
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
# Example for a Node.js application
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]Modify k8s/deployment.yaml:
- Update the container image name
- Adjust resource limits based on your application's needs
- Add any required environment variables
- Configure health checks for your application
# Example for a Python application
spec:
containers:
- name: your-app
image: your-registry/your-app:latest
ports:
- containerPort: 8000 # Adjust to your app's port
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: your-app-secrets
key: database-url
livenessProbe:
httpGet:
path: /health # Adjust to your health check endpoint
port: 8000The k8s/ingress.yaml and k8s/middleware.yaml files are framework-agnostic. You only need to:
- Update the domain name
- Adjust the paths if your application uses different routes
- Modify caching strategies based on your needs
The current setup uses Traefik middleware for caching. Adjust the caching rules in k8s/middleware.yaml based on your application's needs:
# Example for a static-heavy application
spec:
headers:
customResponseHeaders:
Cache-Control: "public, max-age=86400" # 1 day
# Example for a dynamic application
spec:
headers:
customResponseHeaders:
Cache-Control: "no-cache, must-revalidate"-
Build and push your container:
docker build -t your-registry/your-app:latest . docker push your-registry/your-app:latest -
Update the image reference in
k8s/deployment.yaml -
Apply the configuration:
kubectl apply -k k8s/
-
Register your application manifests in ArgoCD
- Create an ArgoCD Application resource pointing to this repository and the
k8s/directory. - ArgoCD will automatically sync the changes to your cluster.
- Create an ArgoCD Application resource pointing to this repository and the
Your application will automatically benefit from:
- Traefik: For ingress and TLS termination
- cert-manager: For automatic SSL certificate management
- ArgoCD: For GitOps-based deployment
- Harbor: For container registry
- Longhorn: For persistent storage
- Prometheus/Grafana: For monitoring
- AlertManager: For notifications
- All traffic is encrypted with TLS
- Security headers are configured through Traefik middleware
- Management interfaces are not exposed directly
- Proper caching headers prevent stale content
- Secrets should be managed through Kubernetes secrets
Feel free to submit issues and enhancement requests!
This project is licensed under the MIT License - see the LICENSE file for details.