Skip to content

Versioning Guide

1. Git SHA (Commit Hash)

Format: image:git-sha
Example: myapp:a1b2c3d

Pros:

  • Precise tracking to source code
  • Immutable and unique
  • Easy to debug and rollback
  • Perfect for development environments

Cons:

  • Not human-readable
  • Difficult to determine version order
  • No immediate indication of stability level

Detailed Explanation:

Git SHA versioning uses the unique hash identifier that Git generates for each commit in your repository. When you build a Docker image using this approach, you take the first few characters (usually 7-8) of the commit hash and use it as your image tag. This method creates an unbreakable link between your source code and the Docker image, making it extremely useful for debugging and traceability. For instance, if you discover an issue in production, you can immediately identify the exact code commit that produced that image. However, these hashes are not human-friendly - you can't tell at a glance which version came first or what changes it contains. This makes it less ideal for release management but perfect for development and testing environments where precise code tracking is crucial.

2. Semantic Versioning

Format: image:MAJOR.MINOR.PATCH
Example: myapp:1.2.3

Pros:

  • Clear indication of change magnitude
  • Well understood by developers
  • Good for stable releases
  • Easy to automate with conventional commits

Cons:

  • Can be subjective (what constitutes a breaking change?)
  • Multiple tags might point to same image

Detailed Explanation:

Semantic Versioning follows a structured numbering system with three components: MAJOR.MINOR.PATCH. Each component has a specific meaning - MAJOR versions indicate breaking changes that might require users to modify their code, MINOR versions add new features while maintaining backward compatibility, and PATCH versions represent bug fixes. This system is particularly valuable when your Docker image contains an application or service that other systems depend on. Users can quickly understand the impact of upgrading to a new version. For example, if you're currently using version 1.2.3 and see version 1.2.4, you know it's safe to upgrade since it's just a patch. However, if you see version 2.0.0, you know to carefully review the changes as it contains breaking changes. The main challenge with SemVer is maintaining discipline in version number assignment - teams need to consistently agree on what constitutes a breaking change versus a minor feature addition.

3. Git Tag Based

Format: image:v1.2.3
Example: myapp:v1.2.3

Pros:

  • Direct correlation with Git releases
  • Good for release automation
  • Clear release history

Cons:

  • Requires disciplined tag management
  • May need additional CI/CD configuration
  • Can be confusing with multiple release branches

Detailed Explanation:

Git tag based versioning aligns your Docker image versions with your Git repository's release tags. This approach creates a natural workflow where creating a Git tag automatically triggers a new Docker image build with the same version. It's particularly powerful when combined with semantic versioning - for example, tagging a release as v1.2.3 in Git automatically produces a Docker image tagged 1.2.3. This method works exceptionally well with automated release processes and provides clear documentation of your release history. The challenge comes when managing multiple release branches or when hotfixes need to be applied to older versions. You need robust processes to handle these scenarios and ensure tags are created consistently across branches.

4. Environment Based

Format: image:env-timestamp
Example: myapp:prod-20250302

Pros:

  • Clear deployment target
  • Easy to track when image was built
  • Good for environment-specific configurations

Cons:

  • Less precise source tracking
  • Potential confusion with multiple deployments per day
  • Additional storage overhead

Detailed Explanation:

Environment based versioning adds context about where and when an image is intended to be used. This approach often combines an environment identifier with a timestamp or build number, such as prod-20250302 or staging-build123. This strategy is particularly useful in organizations with complex deployment pipelines involving multiple environments (development, staging, QA, production). It makes it immediately clear which images are approved for which environments and when they were built. The timestamp component helps track the age of deployments and can be crucial for compliance requirements. However, this approach can lead to image proliferation and doesn't inherently track the relationship between images across environments. You might need additional tooling to know that prod-20250302 and dev-20250301 contain the same code.

5. Latest Tag

Format: image:latest
Example: myapp:latest

Pros:

  • Simple to use
  • Always points to newest version
  • Good for development

Cons:

  • Unreliable for production
  • Can lead to inconsistent deployments
  • Hard to track actual version deployed

Detailed Explanation:

The 'latest' tag is a special convention in Docker that typically points to the most recent version of an image. While simple and convenient, especially during development, it's considered an anti-pattern for production use. The main issue is its mutability - the 'latest' tag can point to different images at different times, making it impossible to guarantee consistency across deployments. For example, if two developers pull 'latest' at different times, they might get different versions. This can lead to the "it works on my machine" problem and make debugging extremely difficult. Latest tags are best reserved for development environments or automated testing where having the newest version is more important than version stability.

Best Practices

For CI/CD Pipeline:

  1. Always use immutable tags
  2. Include build metadata (e.g., myapp:1.2.3-a1b2c3d)
  3. Implement automated version bumping
  4. Use multi-stage builds to reduce image size

For Production:

  1. Never use :latest tag
  2. Always specify exact version
  3. Implement image scanning
  4. Keep image history for rollbacks

For ArgoCD:

  1. Use specific versions in manifests
  2. Implement automatic image updater
  3. Configure image pull policies
  4. Set up proper RBAC for image repositories

For a robust production setup, combine multiple approaches:

myapp:1.2.3-a1b2c3d-20250302
│     │     │      └─ Build timestamp
│     │     └──────── Git SHA (short)
│     └─────────────── Semantic version
└───────────────────── Image name

This provides: - Clear version tracking - Easy rollbacks - Build traceability - Deployment history

Combined Strategy Explanation:

Many organizations adopt a hybrid approach that combines multiple versioning strategies to get the best of each. A common pattern is to tag each image with both a semantic version and a Git SHA (e.g., myapp:1.2.3-a1b2c3d). This provides both human-readable version information and precise code traceability. Some teams also add build metadata like timestamps or CI build numbers. While this approach provides comprehensive information, it requires more sophisticated build and deployment automation to manage the multiple tags correctly.

Automation Tips

  1. Use GitHub Actions to automatically:
  2. Generate versions based on conventional commits
  3. Tag Docker images
  4. Push to registry
  5. Update deployment manifests

  6. Use ArgoCD to:

  7. Monitor image repositories
  8. Auto-sync new versions
  9. Maintain deployment history
  10. Enable easy rollbacks

Key Stakeholder Considerations

The key to successful Docker image versioning is choosing a strategy that balances the needs of different stakeholders: - Developers need to quickly identify and debug issues - Operations teams need stable, traceable deployments - Release managers need clear version progression - Security teams need audit capabilities - End users need clear upgrade paths

Back to top