This guide walks you through setting up the Platform in a Box from scratch. It assumes you have a Kubernetes cluster ready and Argo CD installed in your ops cluster.
Before starting, ensure you have:
argocd)kubectl v1.27+ configured with cluster accesshelm v3.8+ installedkubeseal CLI installed (for sealed secrets)yq v4+ installed (for value file manipulation)# Clone the repository
git clone <your-repo-url>
cd k8s
# Verify structure
ls -la charts/
ls -la argocd-bootstrap-apps/
Each environment has its own values file. Start with the ops cluster configuration:
# Review the ops cluster values
cat charts/app-of-apps/values.ops-01.yaml
cluster:
name: ops-01
server: https://ops-cluster.example.com
source:
repoURL: git@github.com:YourOrg/k8s.git
targetRevision: stable # or HEAD for dev
sealedSecrets:
enable: true
certManager:
enable: true
envoyGateway:
enable: true
monitoring:
enable: true
logging:
enable: true
Edit charts/app-of-apps/values.ops-01.yaml and update:
Sealed Secrets allow you to commit encrypted secrets to Git. You’ll need to seal credentials before deployment.
If you don’t have a sealing key yet:
# Option 1: Generate new key pair
mkdir -p sealing-key && cd sealing-key
openssl req -x509 -days 3650 -nodes -newkey rsa:4096 \
-keyout platform-sealing.key \
-out platform-sealing.crt \
-subj "/CN=sealed-secret/O=sealed-secret"
# Option 2: Fetch public cert from existing controller
kubeseal --fetch-cert \
--controller-name=sealed-secrets \
--controller-namespace=sealed-secrets \
> pub-cert.pem
Important: Store the private key (platform-sealing.key) securely. Without it, you cannot decrypt existing sealed secrets.
Create and seal secrets for:
DNS Provider Credentials (for cert-manager and external-dns):
# Create secret manifest (DO NOT COMMIT THIS)
cat > dns-credentials.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: clouddns-dns01-solver-svc-acct
namespace: cert-manager
type: Opaque
stringData:
key.json: |
{
"type": "service_account",
"project_id": "your-project",
...
}
EOF
# Seal it
kubeseal --cert=pub-cert.pem --scope=namespace-wide \
--namespace=cert-manager \
--format=yaml < dns-credentials.yaml > sealed-dns-credentials.yaml
# Clean up unsealed file
rm dns-credentials.yaml
Object Storage Credentials (for Thanos, if enabling monitoring):
# Create secret for GCS
cat > thanos-gcs-credentials.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: thanos-gcs-credentials
namespace: monitoring
type: Opaque
stringData:
thanos.yaml: |
type: GCS
config:
bucket: thanos-ops-01
service_account: |
{
"type": "service_account",
...
}
EOF
# Seal it
kubeseal --cert=pub-cert.pem --scope=namespace-wide \
--namespace=monitoring \
--format=yaml < thanos-gcs-credentials.yaml > sealed-thanos-gcs.yaml
rm thanos-gcs-credentials.yaml
Elasticsearch Credentials (for logging, if enabling):
# Similar process for ES credentials
# See charts/logging/README.md for details
Add sealed secrets to the appropriate chart directories:
# DNS credentials go to cert-manager or external-dns chart
# Object storage goes to monitoring chart
# ES credentials go to logging/jaeger charts
git add charts/*/sealed-*.yaml
git commit -m "Add sealed secrets for ops-01"
The bootstrap application is the entry point that creates the App-of-Apps root.
cat argocd-bootstrap-apps/ops-01.yaml
Edit argocd-bootstrap-apps/ops-01.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ops-01-bootstrap-apps
namespace: argocd
spec:
project: operations
source:
repoURL: git@github.com:YourOrg/k8s.git # Update this
path: charts/app-of-apps
targetRevision: stable # or HEAD for initial dev setup
helm:
valueFiles:
- values.ops-01.yaml
destination:
namespace: argocd
server: https://kubernetes.default.svc
syncPolicy:
automated:
selfHeal: true
allowEmpty: true
prune: true
git add argocd-bootstrap-apps/ops-01.yaml
git commit -m "Configure ops-01 bootstrap application"
git push
Apply the bootstrap application to your ops cluster:
# Ensure you're connected to the ops cluster
kubectl cluster-info
# Apply the bootstrap application
kubectl apply -f argocd-bootstrap-apps/ops-01.yaml
# Verify it was created
kubectl get application -n argocd ops-01-bootstrap-apps
Wait for Argo CD to sync the bootstrap application:
# Watch application status
kubectl get application -n argocd ops-01-bootstrap-apps -w
# Or check via Argo CD CLI
argocd app get ops-01-bootstrap-apps
# Or use Argo CD UI
# Navigate to: https://argocd.your-domain.com
# List all applications
kubectl get applications -n argocd
# Check specific component
kubectl get application -n argocd ops-01-sealed-secrets
kubectl get application -n argocd ops-01-cert-manager
kubectl get application -n argocd ops-01-envoy-gateway
Once components are synced, verify they’re running:
kubectl get pods -n sealed-secrets
kubectl get sealedsecrets -A
kubectl get pods -n cert-manager
kubectl get clusterissuers
kubectl get pods -n envoy-gateway-system
kubectl get gateways -A
kubectl get pods -n monitoring
kubectl get prometheus -n monitoring
kubectl get pods -n logging
kubectl get elasticsearch -n logging
To add workload clusters (dev, staging, prod):
cp charts/app-of-apps/values.ops-01.yaml charts/app-of-apps/values.dev-01.yaml
Edit values.dev-01.yaml:
targetRevision: HEAD or dev for developmentcp argocd-bootstrap-apps/ops-01.yaml argocd-bootstrap-apps/dev-01.yaml
Edit dev-01.yaml:
values.dev-01.yaml# Get cluster kubeconfig
kubectl config view --minify --raw > dev-cluster-kubeconfig.yaml
# Register in Argo CD
argocd cluster add dev-cluster-context \
--kubeconfig dev-cluster-kubeconfig.yaml \
--name dev-01 \
--server https://dev-cluster.example.com
# Or manually create cluster secret
kubectl create secret generic dev-01-cluster \
--from-file=config=dev-cluster-kubeconfig.yaml \
-n argocd \
--type=Opaque
kubectl label secret dev-01-cluster -n argocd argocd.argoproj.io/secret-type=cluster
kubectl apply -f argocd-bootstrap-apps/dev-01.yaml
# Check certificate status
kubectl get certificates -A
kubectl describe certificate <cert-name> -n <namespace>
# Verify DNS challenge
dig _acme-challenge.your-domain.com TXT
# Create a test HTTPRoute
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: test-route
spec:
hostnames:
- test.your-domain.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: test-service
port: 80
EOF
# Check DNS record was created
dig test.your-domain.com
# Access Grafana (if exposed)
curl https://grafana.your-domain.com
# Check Prometheus targets
kubectl port-forward -n monitoring svc/prometheus 9090:9090
# Visit http://localhost:9090/targets
# Check Elasticsearch health
kubectl port-forward -n logging svc/elasticsearch-es-http 9200:9200
curl -u elastic:password https://localhost:9200/_cluster/health
Edit your values file to enable more components:
kyverno:
enable: true
redis:
enable: true
jaeger:
enable: true
charts/monitoring/configs/alert-rules/# Check application status
kubectl describe application <app-name> -n argocd
# Check Argo CD logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller
# Force refresh
argocd app get <app-name> --refresh
# Check pod status
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
# Check for resource constraints
kubectl top nodes
kubectl top pods -A
# Check certificate status
kubectl describe certificate <cert-name>
# Check challenges
kubectl get challenges -A
kubectl describe challenge <challenge-name>
# Verify DNS
dig _acme-challenge.your-domain.com TXT
# Check sealed secret status
kubectl get sealedsecrets -A
kubectl describe sealedsecret <name> -n <namespace>
# Verify controller is running
kubectl get pods -n sealed-secrets
# Check controller logs
kubectl logs -n sealed-secrets -l app.kubernetes.io/name=sealed-secrets
For more troubleshooting help, see the Troubleshooting Guide (when available) or component-specific documentation.
Solution: Ensure repository credentials are configured in Argo CD:
argocd repo add <repo-url> --ssh-private-key-path ~/.ssh/id_rsa
Solution: Use sync waves in values files:
sealedSecrets:
enable: true
annotations:
argocd.argoproj.io/sync-wave: "-1"
certManager:
enable: true
annotations:
argocd.argoproj.io/sync-wave: "0"
Solution:
If you encounter issues not covered in this guide:
charts/<component>/README.mddocs/