Dev to QA Iteration
This guide explains the recommended workflow for iterating between development and QA environments using SNAPSHOT versions.
Overview
Section titled “Overview”The dev-to-QA workflow in Odin uses SNAPSHOT versions for fast iteration:
- Development: Deploy SNAPSHOT to dev, make changes
- QA: Deploy same SNAPSHOT to staging for testing
- Iteration: Fix issues, redeploy SNAPSHOT
- Release: Create CONCRETE version for production
Step 1: Start Development
Section titled “Step 1: Start Development”Create a service with a SNAPSHOT version:
{ "name": "user-api", "version": "1.0.0-SNAPSHOT", "team": "backend", "components": [ { "name": "api", "type": "webservice", "version": "1.0.0", "depends_on": ["database"] }, { "name": "database", "type": "postgres", "version": "14.5" } ]}Step 2: Deploy to Development
Section titled “Step 2: Deploy to Development”Deploy to your dev environment:
odin deploy service --env dev \ --file service.json \ --provisioning provisioning-dev.jsonprovisioning-dev.json (lightweight resources):
[ { "component_name": "api", "deployment_type": "kubernetes-deployment", "params": { "namespace": "dev", "cpu": "100m", "memory": "256Mi", "replicas": 1, "image": "myregistry/user-api:dev" } }, { "component_name": "database", "deployment_type": "rds-postgres", "params": { "instance_class": "db.t3.micro", "storage": "20" } }]Step 3: Develop and Test
Section titled “Step 3: Develop and Test”Make changes to your application:
- Update code
- Build new Docker image
- Redeploy the SAME SNAPSHOT version
# Build and push new imagedocker build -t myregistry/user-api:dev .docker push myregistry/user-api:dev
# Redeploy (same version)odin deploy service --env dev \ --file service.json \ --provisioning provisioning-dev.jsonStep 4: Pass to QA
Section titled “Step 4: Pass to QA”Once development is stable, deploy to QA/staging:
odin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.jsonprovisioning-staging.json (more production-like):
[ { "component_name": "api", "deployment_type": "kubernetes-deployment", "params": { "namespace": "staging", "cpu": "500m", "memory": "1Gi", "replicas": 2, "image": "myregistry/user-api:staging" } }, { "component_name": "database", "deployment_type": "rds-postgres", "params": { "instance_class": "db.t3.small", "storage": "50", "multi_az": false } }]Step 5: QA Testing
Section titled “Step 5: QA Testing”QA team tests the SNAPSHOT version in staging:
# Check statusodin status env staging --service user-api
# Get service detailsodin describe env staging --service user-apiStep 6: Bug Fixes and Iteration
Section titled “Step 6: Bug Fixes and Iteration”If QA finds issues:
- Fix in code
- Build new image
- Redeploy to dev for verification
- Redeploy to staging for QA retest
# Fix code and rebuilddocker build -t myregistry/user-api:dev .docker push myregistry/user-api:dev
# Test in devodin deploy service --env dev \ --file service.json \ --provisioning provisioning-dev.json
# After verification, update stagingdocker tag myregistry/user-api:dev myregistry/user-api:stagingdocker push myregistry/user-api:staging
odin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.jsonStep 7: Release for Production
Section titled “Step 7: Release for Production”Once QA approves, create a CONCRETE version:
- Update version (remove
-SNAPSHOT) - Build release image
- Tag in Git
{ "name": "user-api", "version": "1.0.0", // Removed -SNAPSHOT "team": "backend", "components": [...]}# Build production imagedocker build -t myregistry/user-api:1.0.0 .docker push myregistry/user-api:1.0.0
# Tag in Gitgit tag v1.0.0git push origin v1.0.0Step 8: Deploy to Production
Section titled “Step 8: Deploy to Production”Deploy the CONCRETE version to production:
provisioning-prod.json (production-grade):
[ { "component_name": "api", "deployment_type": "kubernetes-deployment", "params": { "namespace": "production", "cpu": "2", "memory": "4Gi", "replicas": 5, "image": "myregistry/user-api:1.0.0" } }, { "component_name": "database", "deployment_type": "rds-postgres", "params": { "instance_class": "db.r5.large", "storage": "200", "multi_az": true, "backup_retention_days": 14 } }]odin deploy service --env production \ --file service.json \ --provisioning provisioning-prod.jsonStep 9: Start Next Iteration
Section titled “Step 9: Start Next Iteration”Begin work on the next version:
{ "name": "user-api", "version": "1.1.0-SNAPSHOT", ...}Workflow Diagram
Section titled “Workflow Diagram”┌─────────────┐│ Development ││ 1.0.0-SNAP │└──────┬──────┘ │ Deploy ▼┌─────────────┐│ Dev │ ←─┐│ Environment │ │ Iterate└──────┬──────┘ │ │ Ready │ ▼ │┌─────────────┐ ││ Staging │ ││ Environment │ ───┘ Bug Fixes└──────┬──────┘ │ QA Approved ▼┌─────────────┐│ Release ││ 1.0.0 │└──────┬──────┘ │ Deploy ▼┌─────────────┐│ Production ││ Environment │└─────────────┘Best Practices
Section titled “Best Practices”1. Keep Dev and Staging in Sync
Section titled “1. Keep Dev and Staging in Sync”Ensure staging reflects production as closely as possible:
# Regular sync from dev to stagingodin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.json2. Use Image Tags
Section titled “2. Use Image Tags”Tag Docker images consistently:
dev: Latest development buildstaging: Currently in QA1.0.0: Production releases
3. Automate Image Builds
Section titled “3. Automate Image Builds”Use CI/CD to build images on commits:
name: Buildon: push: branches: [main]jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build and push run: | docker build -t myregistry/user-api:dev . docker push myregistry/user-api:dev4. Document Changes
Section titled “4. Document Changes”Track changes in each SNAPSHOT deployment:
# Keep a changelogecho "$(date): Fixed login bug" >> CHANGELOG-SNAPSHOT.mdgit commit -am "Fix login bug"5. Test Before QA
Section titled “5. Test Before QA”Always test in dev before passing to staging:
# Dev deploymentodin deploy service --env dev \ --file service.json \ --provisioning provisioning-dev.json
# Manual testingcurl https://dev.api.example.com/health
# If OK, deploy to stagingodin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.jsonTroubleshooting
Section titled “Troubleshooting”QA Found a Critical Bug
Section titled “QA Found a Critical Bug”Roll back staging to previous working version:
# Option 1: Redeploy previous Docker image# Update provisioning.json with previous image tagodin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.json
# Option 2: Undeploy and redeployodin undeploy service user-api --env staging# Fix issueodin deploy service --env staging \ --file service.json \ --provisioning provisioning-staging.jsonDifferent Behavior in Staging
Section titled “Different Behavior in Staging”Check provisioning differences:
diff provisioning-dev.json provisioning-staging.jsonEnsure resource limits and configurations match:
{ "env_variables": { "ENVIRONMENT": "staging", // Must match actual environment "DB_HOST": "staging-db.example.com" }}