Skip to main content
CleanStart

Knowledge Hub

Test Environment Setup Guide

Purpose

Get a working CleanStart test environment running locally or in staging so your QA team can start testing immediately. This guide walks through four options:

  1. Local with Docker Desktop (15 minutes) — fastest for developers
  2. Local Kubernetes with kind (20 minutes) — matches production K8s more closely
  3. Local Kubernetes with minikube (20 minutes) — alternative to kind
  4. Cloud staging cluster (30-60 minutes) — realistic infrastructure

Pick the option that matches your needs. Docker Desktop is fastest for getting started; Kubernetes options better simulate production.

Prerequisites (All Options)

Required Tools

Install these before starting:

# Check if already installedwhich dockerwhich gitwhich jq

If any are missing:

macOS (Homebrew):

brew install docker git jqbrew install --cask docker  # Docker Desktop

Linux (Ubuntu/Debian):

sudo apt-get updatesudo apt-get install -y docker.io git jq # Non-root Docker access (optional, but recommended)sudo usermod -aG docker $USER

Windows: Docker Desktop for Windows (from docker.com) Git (from git-scm.com) WSL 2 backend (Docker Desktop setup).

Registry Authentication

You need to authenticate to CleanStart's registry to pull images:

# Create Docker credentials file (if needed)docker login registry.cleanstart.com# Username: (your CleanStart account)# Password: (your API token) # Verify authenticationdocker pull registry.cleanstart.com/python:3.12-stable# Should succeed without "unauthorized" error

If you don't have credentials:

  1. Contact your CleanStart administrator
  2. Create an account at registry.cleanstart.com (if public signup available)
  3. Generate API token in account settings

Option 1: Local with Docker Desktop (15 minutes)

Best for: Developers, quick testing, learning the basics.

Step 1: Verify Docker Installation

docker version# Output shows both client and server docker info | grep "Total Memory"# Note available memory (need at least 2GB for testing)

Step 2: Pull Your First CleanStart Image

# Pull Python imagedocker pull registry.cleanstart.com/python:3.12-stable # Verify the image existsdocker images | grep python# Output: cleanstart.../python  3.12-stable  abc123...  150MB

Step 3: Run a Container

# Start a container and interact with itdocker run --rm -it registry.cleanstart.com/python:3.12-stable # You should see Python promptPython 3.12.0 (main, ...)>>> # Test basic operations>>> import requests>>> print("CleanStart working!")CleanStart working!>>> exit()

Step 4: Create docker-compose.yml for Multi-Service Testing

Use case: Test your app with a database and cache.

# docker-compose.ymlversion: '3.8' services:  app:    image: registry.cleanstart.com/python:3.12-stable    build:      context: .      dockerfile: Dockerfile    ports:      - "8000:8000"    environment:      DATABASE_URL: postgresql://user:password@postgres:5432/testdb      REDIS_URL: redis://redis:6379/0    depends_on:      - postgres      - redis    volumes:      - .:/app      - /app/__pycache__    command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload   postgres:    image: postgres:15-alpine    environment:      POSTGRES_USER: user      POSTGRES_PASSWORD: password      POSTGRES_DB: testdb    ports:      - "5432:5432"    volumes:      - postgres_data:/var/lib/postgresql/data   redis:    image: redis:7-alpine    ports:      - "6379:6379" volumes:  postgres_data:

Start the stack:

docker-compose up --build # In another terminal, test the APIcurl http://localhost:8000/health# Output: {"status": "ok"} # View logsdocker-compose logs appdocker-compose logs postgres # Stop everythingdocker-compose down

Step 5: Test Basic Security Properties

# Test 1: No shell in imagedocker run --rm registry.cleanstart.com/python:3.12-stable /bin/bash# Should fail: "no such file or directory" # Test 2: Non-root userdocker run --rm registry.cleanstart.com/python:3.12-stable id# Output: uid=65532 (non-root) # Test 3: Read-only filesystemdocker run --rm registry.cleanstart.com/python:3.12-stable touch /test# Should fail: "Read-only file system"

Verification Checklist

[ ] Docker Desktop is running (check system tray) [ ] Can authenticate to registry.cleanstart.com [ ] Can pull images without errors [ ] Can start containers [ ] Basic Python/Node/etc operations work [ ] docker-compose stack starts successfully [ ] Can access app on localhost:8000. Troubleshooting Docker Desktop:

Problem

Solution

"Cannot connect to Docker daemon"

Start Docker Desktop, wait 30 seconds

"denied: unauthorized"

Run docker login registry.cleanstart.com

"image not found"

Check image name spelling (case-sensitive)

"port already in use"

Change port in docker-compose (8001:8000)

"out of memory"

Increase Docker Desktop memory limit (preferences → resources)

Option 2: Local Kubernetes with kind (20 minutes)

Best for: K8s testing, admission controller testing, pod security policies.

What is kind?

kind = Kubernetes in Docker. It runs a full Kubernetes cluster inside Docker containers. Perfect for testing K8s features like networking, RBAC, and operators.

Step 1: Install kind

# macOSbrew install kind # Linuxcurl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64chmod +x ./kindsudo mv ./kind /usr/local/bin/kind # Windowschoco install kind  # if using chocolatey # Verifykind version# Output: kind v0.20.0 go1.21.0

Step 2: Install kubectl

# macOSbrew install kubectl # Linuxcurl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"chmod +x kubectlsudo mv kubectl /usr/local/bin/ # Verifykubectl version --client

Step 3: Create a kind Cluster

# Create cluster named "cleanstart-test"kind create cluster --name cleanstart-test # Verify cluster is runningkubectl get nodes# Output: KIND-CONTROL-PLANE  Ready  master  2m

Step 4: Load CleanStart Images into kind

kind runs Kubernetes in Docker. Docker images are isolated. You must load images into kind's Docker instance.

# Pull image locally firstdocker pull registry.cleanstart.com/python:3.12-stable # Load into kind clusterkind load docker-image registry.cleanstart.com/python:3.12-stable --name cleanstart-test # Verify image is in kind clusterkubectl run test-python --image=registry.cleanstart.com/python:3.12-stable --image-pull-policy=Neverkubectl get pod test-python# STATUS: Running # Cleanup test podkubectl delete pod test-python

Step 5: Configure Registry Access for kind

For a more production-like setup, configure kind to pull directly from registry.cleanstart.com:

# Create kind cluster with registry configcat > /tmp/kind-config.yaml <<EOFkind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane  kubeadmConfigPatches:  - |    kind: KubeletConfiguration    registryMirrors:      registry.cleanstart.com:        endpoint:        - "https://registry.cleanstart.com"containerdConfigPatches:- |-  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.cleanstart.com"]    endpoint = ["https://registry.cleanstart.com"]  [plugins."io.containerd.grpc.v1.cri".registry.configs."registry.cleanstart.com".auth]    username = "<your_username>"    password = "<your_api_token>"EOF kind create cluster --name cleanstart-registry --config /tmp/kind-config.yaml

Step 6: Deploy a Test Application

# test-app-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: test-appspec:  replicas: 2  selector:    matchLabels:      app: test-app  template:    metadata:      labels:        app: test-app    spec:      securityContext:        runAsNonRoot: true        runAsUser: 65532      containers:      - name: app        image: registry.cleanstart.com/python:3.12-stable        imagePullPolicy: Never  # Use local image loaded with kind load        ports:        - containerPort: 8000        securityContext:          allowPrivilegeEscalation: false          readOnlyRootFilesystem: true          capabilities:            drop:            - ALL        volumeMounts:        - name: tmp          mountPath: /tmp        - name: run          mountPath: /run        livenessProbe:          exec:            command:            - /usr/bin/python3            - -c            - "import sys; sys.exit(0)"          initialDelaySeconds: 5          periodSeconds: 10      volumes:      - name: tmp        emptyDir: {}      - name: run        emptyDir: {}---apiVersion: v1kind: Servicemetadata:  name: test-appspec:  type: LoadBalancer  ports:  - port: 8000    targetPort: 8000  selector:    app: test-app

Deploy:

kubectl apply -f test-app-deployment.yaml # Check deploymentkubectl get deployment test-app# STATUS: 2/2 ready # Check podskubectl get pods# Both pods should be Running # View logskubectl logs -l app=test-app # Port forward to testkubectl port-forward svc/test-app 8000:8000# In another terminal: curl http://localhost:8000 # Cleanupkubectl delete -f test-app-deployment.yaml

Verification Checklist

[ ] kind cluster created successfully [ ] kubectl can connect to cluster [ ] CleanStart images loaded into kind [ ] Can deploy pods using CleanStart images [ ] Security context properly enforced (non-root, read-only FS) [ ] Port forwarding works. Troubleshooting kind:

Problem

Solution

"could not connect to kind cluster"

Cluster may be down: kind get clusters

"image not found in kind"

Load image: kind load docker-image IMAGE --name CLUSTER

"ImagePullBackOff"

Check image exists in kind, set imagePullPolicy: Never

"out of memory"

Reduce kind cluster size or increase Docker memory

Clean up kind:

kind delete cluster --name cleanstart-test# Removes all data and container

Option 3: Local Kubernetes with minikube (20 minutes)

Alternative to kind. Some teams prefer minikube.

Step 1: Install minikube

# macOSbrew install minikube # Linuxcurl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64chmod +x minikube-linux-amd64sudo mv minikube-linux-amd64 /usr/local/bin/minikube # Windowschoco install minikube # Verifyminikube version

Step 2: Start minikube Cluster

# Start default clusterminikube start --cpus=4 --memory=4096 # Verifykubectl get nodes# Output: minikube  Ready  master/worker # Check minikube statusminikube status

Step 3: Configure Registry Authentication

# Create secret for registry.cleanstart.comkubectl create secret docker-registry cleanstart-secret \  --docker-server=registry.cleanstart.com \  --docker-username=<your_username> \  --docker-password=<your_api_token> \  --docker-email=<your_email> # Verifykubectl get secrets# Should show: cleanstart-secret  docker-registry

Step 4: Configure Minikube's Docker Daemon

minikube has its own Docker daemon. You can either:

Option A: Pull images via minikube (easier)

# Use minikube's Dockereval $(minikube docker-env) # Now 'docker pull' uses minikube's Dockerdocker pull registry.cleanstart.com/python:3.12-stable # Deploy without imagePullPolicy override

Option B: Use ImagePullSecrets in pods

apiVersion: apps/v1kind: Deploymentmetadata:  name: test-appspec:  template:    spec:      imagePullSecrets:      - name: cleanstart-secret      containers:      - name: app        image: registry.cleanstart.com/python:3.12-stable

Step 5: Deploy and Test

Same as kind (Option 2, Step 6). Only difference is which cluster is running.

Option 4: Cloud Staging Cluster (30-60 minutes)

Best for: Realistic infrastructure, team testing, pre-production validation.

Subheading: AWS EKS

Prerequisites: AWS account with permissions to create EKS clusters aws-cli installed and configured eksctl installed (EKS control tool). Create cluster:

# Simple cluster (creates security groups, VPC, etc.)eksctl create cluster \  --name cleanstart-staging \  --region us-east-1 \  --node-type t3.medium \  --nodes 3 # Wait 15-20 minutes for cluster creation # Verifykubectl get nodes# Should show 3 nodes ready

Configure ECR (AWS's registry):

# Create registry (if needed)aws ecr create-repository \  --repository-name cleanstart/python \  --region us-east-1 # Tag CleanStart image for ECRdocker tag registry.cleanstart.com/python:3.12-stable \  123456789.dkr.ecr.us-east-1.amazonaws.com/cleanstart/python:3.12-stable # Push to ECRaws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.comdocker push 123456789.dkr.ecr.us-east-1.amazonaws.com/cleanstart/python:3.12-stable

Deploy:

# Same as kind/minikube, but use ECR image URLapiVersion: apps/v1kind: Deploymentmetadata:  name: test-appspec:  template:    spec:      containers:      - name: app        image: 123456789.dkr.ecr.us-east-1.amazonaws.com/cleanstart/python:3.12-stable

Subheading: Google Cloud GKE

Prerequisites: Google Cloud account gcloud CLI installed and configured kubectl installed. Create cluster:

# Create GKE clustergcloud container clusters create cleanstart-staging \  --zone us-central1-a \  --num-nodes 3 \  --machine-type n1-standard-2 # Configure kubectlgcloud container clusters get-credentials cleanstart-staging --zone us-central1-a # Verifykubectl get nodes

Configure Artifact Registry:

# Create repositorygcloud artifacts repositories create cleanstart \  --location us-central1 \  --repository-format docker # Tag imagedocker tag registry.cleanstart.com/python:3.12-stable \  us-central1-docker.pkg.dev/PROJECT-ID/cleanstart/python:3.12-stable # Pushgcloud auth configure-docker us-central1-docker.pkg.devdocker push us-central1-docker.pkg.dev/PROJECT-ID/cleanstart/python:3.12-stable

Subheading: Microsoft Azure AKS

Prerequisites: Azure account az CLI installed and configured kubectl installed. Create cluster:

# Create resource groupaz group create --name cleanstart-rg --location eastus # Create AKS clusteraz aks create \  --resource-group cleanstart-rg \  --name cleanstart-staging \  --node-count 3 \  --vm-set-type VirtualMachineScaleSets # Configure kubectlaz aks get-credentials \  --resource-group cleanstart-rg \  --name cleanstart-staging # Verifykubectl get nodes

Cloud Cluster: Verification Checklist

[ ] Cluster created and nodes are ready [ ] kubectl connected to cluster [ ] Container registry (ECR/Artifact Registry/ACR) created [ ] CleanStart image pushed to registry [ ] Network policies allow pod-to-pod communication [ ] Can deploy pods successfully [ ] Can access pods via port-forward or load balancer. Cleanup cloud resources (to avoid costs):

# EKSeksctl delete cluster --name cleanstart-staging # GKEgcloud container clusters delete cleanstart-staging --zone us-central1-a # AKSaz aks delete --resource-group cleanstart-rg --name cleanstart-staging --yes

Test Fixtures (Sample Applications)

Ready-to-use configurations for common stacks:

Fixture 1: Python + PostgreSQL + Redis

# fixtures/python-web-stack.yamlversion: '3.8'services:  app:    image: registry.cleanstart.com/python:3.12-stable    build:      context: .      dockerfile: Dockerfile.python    environment:      DATABASE_URL: postgresql://user:password@postgres:5432/testdb      REDIS_URL: redis://redis:6379/0    depends_on:      - postgres      - redis  postgres:    image: postgres:15-alpine    environment:      POSTGRES_USER: user      POSTGRES_PASSWORD: password      POSTGRES_DB: testdb  redis:    image: redis:7-alpine

Fixture 2: Node.js + MongoDB

# fixtures/node-mongodb-stack.yamlversion: '3.8'services:  app:    image: registry.cleanstart.com/node:20-stable    build:      context: .      dockerfile: Dockerfile.node    environment:      MONGODB_URL: mongodb://mongo:27017/testdb    depends_on:      - mongo  mongo:    image: mongo:6    environment:      MONGO_INITDB_ROOT_USERNAME: root      MONGO_INITDB_ROOT_PASSWORD: password

Fixture 3: Java + MySQL + Kafka

# fixtures/java-kafka-stack.yamlversion: '3.8'services:  app:    image: registry.cleanstart.com/java:21-stable    build:      context: .      dockerfile: Dockerfile.java    environment:      DATABASE_URL: jdbc:mysql://mysql:3306/testdb      KAFKA_BROKERS: kafka:9092    depends_on:      - mysql      - kafka  mysql:    image: mysql:8    environment:      MYSQL_ROOT_PASSWORD: root      MYSQL_DATABASE: testdb  kafka:    image: confluentinc/cp-kafka:7.5.0    environment:      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181  zookeeper:    image: confluentinc/cp-zookeeper:7.5.0    environment:      ZOOKEEPER_CLIENT_PORT: 2181

Sample Applications

Sample 1: Simple Python Flask App

# Dockerfile.pythonFROM registry.cleanstart.com/python:3.12-stable WORKDIR /appCOPY requirements.txt .RUN pip install -r requirements.txt COPY . . EXPOSE 8000CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]
# app.pyfrom flask import Flask, jsonify app = Flask(__name__) @app.route('/health')def health():    return jsonify({'status': 'ok'}) @app.route('/api/test')def test():    return jsonify({'message': 'CleanStart works!'}) if __name__ == '__main__':    app.run(debug=False)
# requirements.txtFlask==3.0.0Gunicorn==21.2.0Requests==2.31.0

Sample 2: Simple Node.js Express App

# Dockerfile.nodeFROM registry.cleanstart.com/node:20-stable WORKDIR /appCOPY package*.json ./RUN npm ci --only=production COPY . . EXPOSE 8000CMD ["node", "app.js"]
// app.jsconst express = require('express');const app = express(); app.get('/health', (req, res) => {  res.json({ status: 'ok' });}); app.get('/api/test', (req, res) => {  res.json({ message: 'CleanStart works!' });}); app.listen(8000, () => {  console.log('Server running on :8000');});
// package.json{  "name": "cleanstart-test",  "version": "1.0.0",  "main": "app.js",  "dependencies": {    "express": "^4.18.2"  }}

Complete Setup Script

For fastest setup, use this script (works for Docker Desktop and local K8s):

#!/bin/bash# setup-cleanstart-test-env.sh set -e echo "╔════════════════════════════════════════════╗"echo "║  CleanStart Test Environment Setup         ║"echo "╚════════════════════════════════════════════╝"echo "" # Ask user for environment typeecho "Choose environment:"echo "1) Docker Desktop (local, fast)"echo "2) kind (local K8s)"echo "3) minikube (local K8s)"read -p "Enter choice (1-3): " choice # Verify prerequisitesecho ""echo "Checking prerequisites..."which docker > /dev/null || { echo "❌ Docker not found"; exit 1; }which git > /dev/null || { echo "❌ Git not found"; exit 1; }echo "✓ Docker and Git found" # Create test directoryTEST_DIR="$HOME/cleanstart-test"mkdir -p "$TEST_DIR"cd "$TEST_DIR" # Clone sample apps (if not already cloned)if [ ! -d "sample-apps" ]; then  echo ""  echo "Cloning sample applications..."  git clone https://github.com/cleanstart/sample-apps.git || truefi # Docker Desktop optionif [ "$choice" = "1" ]; then  echo ""  echo "Setting up Docker Desktop environment..."   echo "Pulling CleanStart images..."  docker pull registry.cleanstart.com/python:3.12-stable  docker pull registry.cleanstart.com/node:20-stable   echo "Creating docker-compose.yml..."  cp sample-apps/docker-compose.yml .   echo ""  echo "✓ Setup complete!"  echo ""  echo "Next steps:"  echo "  docker-compose up --build"  echo "  curl http://localhost:8000/health" # kind optionelif [ "$choice" = "2" ]; then  echo ""  echo "Setting up kind Kubernetes cluster..."   which kind > /dev/null || { echo "❌ kind not found. Install: brew install kind"; exit 1; }  which kubectl > /dev/null || { echo "❌ kubectl not found. Install: brew install kubectl"; exit 1; }   kind create cluster --name cleanstart-test || true   echo "Loading CleanStart images into kind..."  docker pull registry.cleanstart.com/python:3.12-stable  kind load docker-image registry.cleanstart.com/python:3.12-stable --name cleanstart-test   echo "Creating test deployment..."  kubectl apply -f sample-apps/k8s/deployment.yaml   echo ""  echo "✓ Setup complete!"  echo ""  echo "Next steps:"  echo "  kubectl get pods"  echo "  kubectl port-forward svc/test-app 8000:8000" # minikube optionelif [ "$choice" = "3" ]; then  echo ""  echo "Setting up minikube Kubernetes cluster..."   which minikube > /dev/null || { echo "❌ minikube not found. Install: brew install minikube"; exit 1; }  which kubectl > /dev/null || { echo "❌ kubectl not found. Install: brew install kubectl"; exit 1; }   minikube start --cpus=4 --memory=4096 || true   echo "Creating registry secret..."  read -p "Enter CleanStart username: " username  read -sp "Enter CleanStart API token: " token  echo ""   kubectl create secret docker-registry cleanstart-secret \    --docker-server=registry.cleanstart.com \    --docker-username="$username" \    --docker-password="$token" \    --docker-email="$username@example.com" || true   echo "Creating test deployment..."  kubectl apply -f sample-apps/k8s/deployment-with-imagepullsecret.yaml   echo ""  echo "✓ Setup complete!"  echo ""  echo "Next steps:"  echo "  kubectl get pods"  echo "  kubectl port-forward svc/test-app 8000:8000"fi echo ""echo "Documentation:"echo "  - Security Testing: docs/security-testing-playbook.md"echo "  - Compatibility: docs/compatibility-testing-matrix.md"

Run:

chmod +x setup-cleanstart-test-env.sh./setup-cleanstart-test-env.sh

Verification Checklist (All Options)

After setup, verify your environment:

# 1. Can pull imagesdocker pull registry.cleanstart.com/python:3.12-stable# Should complete without errors # 2. Can run containers (Docker Desktop)docker run --rm registry.cleanstart.com/python:3.12-stable python -c "print('works')"# Should output: works # 3. Can deploy to Kubernetes (if using kind/minikube)kubectl create deployment test --image=registry.cleanstart.com/python:3.12-stablekubectl wait --for=condition=available --timeout=60s deployment/test# Should deploy successfully # 4. Can verify security propertiesdocker run --rm registry.cleanstart.com/python:3.12-stable id# Should output uid=65532 (non-root)

Troubleshooting Common Setup Issues

Problem

Symptom

Solution

Registry auth fails

"denied: unauthorized"

Run docker login registry.cleanstart.com

Image not found

"manifest not found"

Check image name (case-sensitive), verify registry URL

No internet

"name resolution failed"

Check network connectivity, proxy settings

Port conflicts

"port already in use"

Change port in docker-compose or kill existing process

Out of memory

"OOMKilled" or crashes

Increase Docker/minikube memory allocation

k8s cluster won't start

kind/minikube hangs

Docker Desktop may need restart

Can't connect to Docker

"cannot connect to daemon"

Start Docker Desktop, wait 30 seconds

Images too large

"disk space"

Delete unused images: docker image prune

Next Steps

  1. Run security tests: See Security Testing Playbook
  2. Test your app: Copy your app into a sample fixture, test locally
  3. Test in Kubernetes: Deploy to kind/minikube to verify K8s behavior
  4. Move to staging: If using cloud option, test with real infrastructure
  5. Automate testing: Create CI pipeline that uses these environments

What to Read Next

Security Testing: Security Testing Playbook — verify security properties Compatibility: Compatibility Testing Matrix — ensure your frameworks work Kubernetes Operations: Kubernetes-Helm Operations — scale testing to teams.