Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
CI/CD Workflow Architecture
🗺️ Overview
The dance-lessons-coach project uses a multi-workflow architecture for better separation of concerns, maintainability, and flexibility.
📁 Workflow Files
1. ci-cd.yaml - Main CI/CD Pipeline
Purpose: Run tests, build binaries, and generate documentation
Triggers:
- Push to
main,ci/**,feature/**,fix/**,refactor/**branches - Pull requests to
mainbranch - Manual workflow dispatch
Jobs:
- build-cache - Build and cache Docker build environment
- ci-pipeline - Run tests, build binaries, generate Swagger docs
- trigger-docker-push - Trigger separate Docker workflow on main branch
Key Features:
- Runs in container environment with all build tools
- Generates Swagger documentation
- Runs BDD and unit tests with PostgreSQL
- Updates badges and version information
- Triggers Docker workflow only on main branch
2. docker-push.yaml - Docker Image Publishing
Purpose: Build and push Docker images to registry
Triggers:
- Manual workflow dispatch only (no automatic triggers)
- Triggered by
ci-cd.yamlon main branch
Jobs:
- docker-push - Build production Docker image and push to registry
Key Features:
- Runs on host environment (access to Docker daemon)
- Uses dependency hash from build-cache
- Builds minimal Alpine-based production image
- Pushes multiple tags (version, latest, commit SHA)
🔧 Architecture Benefits
1. Clear Separation of Concerns
- CI/CD Pipeline: Testing and artifact generation
- Docker Publishing: Image building and registry operations
2. Proper Environment Isolation
- CI jobs run in container: Consistent build environment
- Docker jobs run on host: Access to Docker daemon
3. Flexible Testing
- Can trigger Docker workflow independently for testing
- No complex conditional logic in main workflow
- Easier to debug and maintain
4. Better Security
- Docker operations isolated in separate workflow
- Clear dependency between test success and deployment
- Manual trigger capability for emergency situations
🚀 Usage Examples
Trigger Full CI/CD Pipeline
# Automatically triggered on push to main branch
# Or manually:
./scripts/gitea-client.sh trigger-workflow arcodange dance-lessons-coach ci-cd.yaml main
Trigger Docker Push Manually
# Get dependency hash from build-cache job first
DEPS_HASH="abc123def456"
# Trigger Docker workflow manually
./scripts/gitea-client.sh trigger-workflow arcodange dance-lessons-coach docker-push.yaml main --deps_hash $DEPS_HASH
Workflow Dispatch Parameters (docker-push.yaml)
deps_hash(required): Dependency hash from build-cache jobref(optional): Git reference (branch/tag), defaults to current
🔗 Workflow Dependencies
graph TD
A[Push to main] --> B[ci-cd.yaml]
B --> C[build-cache job]
B --> D[ci-pipeline job]
D --> E[trigger-docker-push job]
E --> F[docker-push.yaml]
F --> G[docker-push job]
G --> H[Docker Registry]
📋 Best Practices
1. Always Run CI First
- Docker workflow should only be triggered after CI passes
- Maintains quality gate before deployment
2. Use Dependency Hash
- Ensures consistent builds across workflows
- Pass hash from build-cache to docker-push
3. Manual Testing
- Use separate Docker workflow for testing image builds
- Avoids polluting main branch with test images
4. Monitor Both Workflows
- CI/CD workflow for test results and artifacts
- Docker workflow for image build and push status
🎯 Docker Build Strategy Decision
🏆 Chosen Approach: Attempt 2 (Standard Dockerfile)
After extensive testing of multiple approaches, we selected Attempt 2 as the optimal Docker build strategy.
⚡ Why Attempt 2 Won:
1. Simplicity (60% smaller workflow)
- 73 lines vs 158 lines in complex approaches
- No inline Dockerfile generation
- Standard
docker build -f docker/Dockerfile .command
2. Better Performance
- No artifact/cache action overhead
- Natural Docker layer caching works optimally
- Faster execution without complex variable substitutions
3. Superior Reliability
- Proven standard Docker build process
- Easier to debug and maintain
- Fewer moving parts = fewer failures
4. Better Maintainability
- Uses standard Dockerfile (easier to understand)
- No complex YAML templating
- Clear separation of concerns
🗑️ Why We Rejected Other Approaches:
Attempt 1 (Inline Dockerfile):
- Complex YAML templating
- Harder to debug and maintain
- No significant performance benefit
Attempt 3 (Build Cache Image):
- Added complexity with cache management
- Slower due to artifact actions overhead
- More prone to cache invalidation issues
Attempt 4 (Template File):
- Added unnecessary file management
- No clear advantage over standard Dockerfile
- More complex workflow
📊 Performance Comparison:
| Approach | Lines of Code | Complexity | Reliability | Maintainability |
|---|---|---|---|---|
| Attempt 2 | 73 | Low | High | Excellent |
| Attempt 1 | 158 | High | Medium | Poor |
| Attempt 3 | 125 | Medium | Medium | Fair |
| Attempt 4 | 110 | Medium | High | Good |
🔧 Implementation Details:
Standard Dockerfile Approach:
- name: Build and push Docker image
run: |
docker build -t dance-lessons-coach -f docker/Dockerfile .
docker tag dance-lessons-coach "$IMAGE_NAME"
docker push "$IMAGE_NAME"
Key Benefits:
- Uses multi-stage builds for optimization
- Standard Docker layer caching works naturally
- Easy to understand and modify
- Proven reliability in production
🎯 Future Enhancements
Potential Improvements:
- Add workflow status badges to README
- Implement workflow chaining with outputs
- Add matrix builds for multiple architectures
- Implement canary deployment workflow
- Add rollback capability
Architecture Considerations:
- Keep workflows focused on single responsibilities
- Maintain clear separation between test and deploy
- Document all workflow triggers and conditions
- Monitor workflow execution times and optimize
📝 Maintenance
Adding New Jobs:
- Add to appropriate workflow based on responsibility
- CI-related jobs →
ci-cd.yaml - Docker-related jobs →
docker-push.yaml
Modifying Triggers:
- Update trigger conditions in respective workflow files
- Test changes thoroughly before merging
Debugging:
- Check workflow logs in Gitea Actions
- Use
gitea-client.sh diagnose-jobfor detailed analysis - Monitor workflow dependencies and execution order
🔒 Security
Secrets Management:
- Docker registry credentials stored in Gitea secrets
- Never hardcode credentials in workflow files
- Use GitHub token for workflow dispatch
Access Control:
- Only authorized users can trigger workflows
- Manual approval required for production deployments
- Audit logs available for all workflow executions
This architecture provides a clean, maintainable, and secure CI/CD pipeline that scales well with project growth while maintaining clear separation of concerns.