# ADR 0020: Docker Build Strategy - Traditional vs Buildx

## Status
**Accepted** ✅

## Context

The DanceLessonsCoach CI/CD pipeline initially used Docker Buildx (`docker buildx build --push`) for building and pushing Docker cache images. However, this approach encountered several issues:

### Issues with Buildx Approach

1. **TLS Certificate Problems**: Buildx had difficulty with self-signed certificates, requiring complex workaround steps
2. **Performance Concerns**: Buildx setup and execution was significantly slower than expected
3. **Complexity**: Buildx introduced additional complexity without providing immediate benefits
4. **Reliability Issues**: Buildx builds were less reliable in the GitHub Actions environment

### Working Solution Analysis

The working webapp CI/CD pipeline uses traditional `docker build` + `docker push` approach:

```yaml
# Working approach from webapp
- name: Build and push image to Gitea Container Registry
  run: |-
    docker build -t app .
    docker tag app gitea.arcodange.lab/${{ github.repository }}:$TAG
    docker push gitea.arcodange.lab/${{ github.repository }}:$TAG
```

This approach is simpler, more reliable, and works consistently with self-signed certificates.

## Decision

**Replace Docker Buildx with traditional docker build + push** for the CI/CD pipeline.

### Implementation

```yaml
# New approach
- name: Build and push Docker cache image
  if: steps.check_cache.outputs.cache_hit == 'false'
  run: |
    IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}-build-cache:${{ steps.calculate_hash.outputs.deps_hash }}"
    echo "Building cache image: $IMAGE_NAME"
    
    # Build the image using traditional docker build
    docker build \
      --file Dockerfile.build \
      --tag "$IMAGE_NAME" \
      .
    
    # Push the image
    docker push "$IMAGE_NAME"
    
    echo "✅ Build cache image pushed successfully"
```

## Benefits

1. **Simplicity**: Traditional approach is easier to understand and debug
2. **Reliability**: Consistent behavior across different environments
3. **Certificate Handling**: Works seamlessly with self-signed certificates
4. **Performance**: Faster execution without Buildx overhead
5. **Compatibility**: Better compatibility with GitHub Actions environment

## Trade-offs

### What We Lose

1. **Multi-platform builds**: Cannot build for multiple architectures simultaneously
2. **BuildKit caching**: Less sophisticated caching mechanism
3. **Advanced features**: No secret mounting, SSH agents, etc.
4. **Parallel processing**: Slower builds without Buildx optimizations

### What We Gain

1. **Stability**: More reliable CI/CD pipeline
2. **Simplicity**: Easier to maintain and troubleshoot
3. **Consistency**: Matches proven patterns from working projects
4. **Faster feedback**: Quicker build times in practice

## Rationale

1. **Current Needs**: We don't need multi-platform builds or advanced BuildKit features
2. **Simple Dockerfile**: Our `Dockerfile.build` doesn't require Buildx-specific features
3. **Proven Pattern**: Traditional approach works reliably in production (webapp project)
4. **CI Stability**: Reliability is more important than advanced features for CI/CD

## Future Considerations

### When to Reconsider Buildx

1. **Multi-platform needs**: If we need ARM/AMD64 builds simultaneously
2. **Complex builds**: If Dockerfile requires BuildKit-specific features
3. **Performance optimization**: If build times become unacceptable
4. **Certificate issues resolved**: If Docker Buildx improves self-signed certificate handling

### Migration Path

If we need to reintroduce Buildx in the future:

1. **Fix certificate issues properly** at the Docker daemon level
2. **Test thoroughly** in staging environment
3. **Monitor performance** impact
4. **Document benefits** clearly for the specific use case

## Alternatives Considered

### Option 1: Keep Buildx with Certificate Workaround
- ❌ Complex setup with questionable reliability
- ❌ Slow performance in GitHub Actions
- ❌ Ongoing maintenance burden

### Option 2: Use Insecure Registry Flag
```yaml
docker buildx build --allow security.insecure --push .
```
- ❌ Security concerns
- ❌ Not recommended for production
- ❌ Temporary workaround, not solution

### Option 3: Traditional Docker Build + Push ✅ **CHOSEN**
- ✅ Simple and reliable
- ✅ Proven in production
- ✅ Better performance in practice
- ✅ Easy to maintain

## Decision Outcome

**Chosen Option**: Traditional docker build + push (Option 3)

This decision prioritizes CI/CD reliability and simplicity over advanced features we don't currently need. The traditional approach has been proven to work consistently in our environment and matches the successful pattern from the webapp project.

## Success Metrics

1. **CI/CD reliability**: No TLS certificate failures
2. **Build consistency**: Predictable build times
3. **Maintenance**: Reduced complexity and debugging time
4. **Compatibility**: Works across all target environments

## References

- [Docker Buildx Documentation](https://docs.docker.com/buildx/working-with-buildx/)
- [Docker Build Documentation](https://docs.docker.com/engine/reference/commandline/build/)
- [GitHub Actions Docker Examples](https://github.com/actions/starter-workflows/tree/main/ci-and-cd)
- [webapp CI/CD Pipeline](https://gitea.arcodange.fr/arcodange-org/webapp/src/branch/main/.gitea/workflows/dockerimage.yaml)

---

**Approved by**: @arcodange
**Date**: 2026-04-07
**Supersedes**: None
**Superseded by**: None