Container Build Guide
This document explains how to build the OneSelect container image across different environments with intelligent auto-detection.
TL;DR - Quick Start
# Let the Makefile auto-detect your environment:
make container-build
# Or be explicit:
make container-build-standard # Public/standard build
make container-build-proxy # Behind corporate proxy
Overview
The build system intelligently selects between Docker and Podman based on what's running on your system, and automatically detects whether you're behind a corporate proxy. No manual configuration needed in most cases.
Supported Build Modes:
- Standard Build - For public deployments or environments without corporate proxies
- Proxy Build - For corporate environments with SSL-inspecting proxies (e.g., Zscaler)
Container Engine Selection:
The Makefile automatically uses whichever container engine is running: - Checks for Podman first (if engine is running) - Falls back to Docker (if engine is running) - Fails with helpful message if neither is running
Proxy Detection:
Auto-detects proxy environments by checking:
- Proxy environment variables (HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy)
- Presence of CA_proxy_fw_all.pem certificate file with content
Building for Different Environments
Auto-Detection (Recommended)
The simplest approach - let the build system figure everything out:
This automatically: - Selects Podman or Docker based on what's running - Detects if you're behind a proxy - Chooses the appropriate build configuration - Shows what was detected during the build
Standard Build (Explicit)
For public deployments or when you want to explicitly avoid proxy configuration:
# Using Makefile
make container-build-standard
# Or directly with your container engine
podman build -t oneselect-backend:latest .
docker build -t oneselect-backend:latest .
This build: - Uses standard SSL certificate verification - Does not require corporate CA certificates - Works on public cloud platforms (AWS, GCP, Azure, etc.)
Proxy Build (Explicit)
For corporate environments with SSL-inspecting proxies, when auto-detection isn't sufficient:
# First, ensure your CA certificate is in place
cp ~/.config/certs/your-corporate-ca.pem CA_proxy_fw_all.pem
# Using Makefile (recommended)
make container-build-proxy
# Or directly with your container engine
podman build --build-arg USE_PROXY_CA=true -t oneselect-backend:latest .
docker build --build-arg USE_PROXY_CA=true -t oneselect-backend:latest .
Prerequisites:
- Corporate CA certificate file named CA_proxy_fw_all.pem in the project root
- The certificate should contain the root CA used by your corporate proxy
This build: - Installs the corporate CA certificate into the container - Configures Poetry to trust the corporate CA - Enables proper SSL verification for package downloads
Build Arguments
| Argument | Default | Description |
|---|---|---|
USE_PROXY_CA |
false |
Enable corporate CA certificate handling |
Container Engine Selection
The build system automatically selects the appropriate container engine:
Selection Priority: 1. Podman - If Podman is installed and the Podman engine is running 2. Docker - If Docker is installed and the Docker engine is running 3. Error - If neither engine is running
When you run any container-related Makefile target, you'll see a message indicating which engine was selected:
orSwitching Engines: Simply start the engine you want to use and stop the other. The Makefile will automatically detect and use the running engine.
Certificate Management
For Corporate Users
-
Obtain your corporate CA certificate:
-
Copy it to the project root:
-
Build (auto-detection will handle the rest):
-
The certificate is automatically excluded from Git via
.gitignore
Note: If you have proxy environment variables set (HTTP_PROXY, HTTPS_PROXY, etc.), the build will automatically use proxy mode even without the certificate file. However, SSL verification may fail without the proper CA certificate.
Security Notes
- ⚠️ Never commit corporate CA certificates to version control
- The
.gitignoreand.dockerignorefiles excludeCA_proxy_fw_all.pemby default - Proxy builds are only needed during the image build phase
- The certificate is embedded in the image for runtime SSL verification
Publishing to GitHub Container Registry
Once your image is built, you can publish it to GitHub Container Registry (GHCR) for easy distribution and deployment.
Prerequisites
- GitHub Personal Access Token with
write:packagesscope - Generate at: https://github.com/settings/tokens
-
Select scopes:
write:packages,read:packages,delete:packages(optional) -
Environment Variables:
Quick Publish Workflow
# 1. Build your image (auto-detected)
make container-build
# 2. Login to GHCR (cached for 2 hours)
make ghcr-login
# 3. Push to registry
make ghcr-push
Detailed GHCR Commands
Login to GitHub Container Registry:
- RequiresGITHUB_USER and GHCR_TOKEN environment variables
- Login is cached for 2 hours to avoid repeated authentication
- Works with both Podman and Docker (automatically selected)
Push Image to GHCR:
- Tags image with version frompyproject.toml
- Also tags as latest for convenience
- Prevents accidental overwrite of existing version tags
- Format: ghcr.io/<github-user>/oneselect-backend:<version>
Logout from GHCR:
- Removes authentication credentials - Clears login cacheComplete Cleanup:
- Logs out from GHCR - Removes all local oneselect container images - Useful for starting freshExample Publishing Session
# Set credentials once per session
export GITHUB_USER="johndoe"
export GHCR_TOKEN="ghp_abc123xyz..."
# Build and publish
make container-build # Auto-detects environment
make ghcr-login # Authenticate once
make ghcr-push # Upload to registry
# Your image is now available at:
# ghcr.io/johndoe/oneselect-backend:latest
# ghcr.io/johndoe/oneselect-backend:1.2.3 (version from pyproject.toml)
Using Published Images
Pull and run your published image on any machine:
# Login (if private repository)
echo $GHCR_TOKEN | podman login ghcr.io -u $GITHUB_USER --password-stdin
# Pull specific version
podman pull ghcr.io/johndoe/oneselect-backend:1.2.3
# Or pull latest
podman pull ghcr.io/johndoe/oneselect-backend:latest
# Run
podman run -d -p 8000:8000 ghcr.io/johndoe/oneselect-backend:latest
GHCR Access Control
By default, packages inherit repository visibility: - Public repository → Public packages (anyone can pull) - Private repository → Private packages (requires authentication)
To change package visibility:
1. Go to your package page: https://github.com/users/<username>/packages/container/oneselect-backend
2. Navigate to "Package settings"
3. Change visibility as needed
Making a package public: - Allows anyone to pull without authentication - Ideal for open-source projects - Can be done even if the source repository is private
Troubleshooting
Auto-Detection Issues
Wrong engine selected:
- Ensure only one container engine is running
- Stop the unwanted engine: podman machine stop or docker stop (stop Docker Desktop)
- Start the preferred engine
Proxy not detected:
- Check proxy environment variables: env | grep -i proxy
- Verify CA certificate exists and has content: ls -lh CA_proxy_fw_all.pem
- Force proxy build: make container-build-proxy
Proxy incorrectly detected:
- Remove CA certificate file if it exists but shouldn't
- Unset proxy variables: unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy
- Force standard build: make container-build-standard
SSL Certificate Errors
If you see errors like:
Solution: Use the corporate build mode and ensure your CA certificate is correct.
CA Certificate Not Found
If the corporate build fails with "CA_proxy_fw_all.pem not found":
- Verify the certificate file exists in the project root
- Ensure it's named exactly
CA_proxy_fw_all.pem - Check the file is readable:
ls -la CA_proxy_fw_all.pem
Proxy Connection Issues
If builds hang or timeout:
-
Verify proxy settings:
-
Check container engine has proxy configured:
-
Ensure proxy is running and accessible:
GHCR Publishing Issues
"GITHUB_USER not set" error:
"GHCR_TOKEN not set" error:
"Authentication failed" error:
- Verify token has write:packages scope
- Regenerate token if expired
- Check username is correct
"Image already exists" warning:
- This prevents accidental overwrites
- The existing version in the registry is preserved
- Bump version in pyproject.toml to publish a new version
Push fails with "unauthorized":
- Re-run make ghcr-login to refresh authentication
- Verify token has not been revoked
- Check package visibility settings on GitHub
CI/CD Integration
GitHub Actions (Public)
name: Build and Publish
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build container image
run: |
docker build -t oneselect-backend:${{ github.sha }} .
- name: Login to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push to GHCR
run: |
docker tag oneselect-backend:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/oneselect-backend:latest
docker push ghcr.io/${{ github.repository_owner }}/oneselect-backend:latest
Corporate CI/CD (Behind Proxy)
name: Build and Publish (Corporate)
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: self-hosted # Use runner behind corporate firewall
steps:
- uses: actions/checkout@v3
- name: Setup CA certificate
run: |
# Certificate should be injected as a secret
echo "${{ secrets.CORPORATE_CA_CERT }}" > CA_proxy_fw_all.pem
- name: Build container image with proxy support
run: |
docker build --build-arg USE_PROXY_CA=true -t oneselect-backend:${{ github.sha }} .
env:
HTTP_PROXY: ${{ secrets.HTTP_PROXY }}
HTTPS_PROXY: ${{ secrets.HTTPS_PROXY }}
- name: Login to GHCR
run: |
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ secrets.GITHUB_USER }} --password-stdin
- name: Push to GHCR
run: |
docker tag oneselect-backend:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/oneselect-backend:latest
docker push ghcr.io/${{ github.repository_owner }}/oneselect-backend:latest
Using Makefile in CI/CD
For consistency with local development:
- name: Build and publish
run: |
make container-build
make ghcr-login
make ghcr-push
env:
GITHUB_USER: ${{ github.repository_owner }}
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Docker Compose
The standard docker-compose.yml works with auto-detection. For explicit proxy configuration:
Makefile Targets Reference
Build Targets
| Target | Description |
|---|---|
container-build |
Auto-detect environment and build (recommended) |
container-build-auto |
Same as container-build (explicit name) |
container-build-standard |
Force standard build (no proxy) |
container-build-proxy |
Force proxy build with CA certificate |
container-rebuild |
Clean and rebuild from scratch |
Runtime Targets
| Target | Description |
|---|---|
container-up |
Start containers in detached mode |
container-down |
Stop and remove containers |
container-logs |
Follow container logs |
container-restart |
Restart running containers |
container-shell |
Open shell inside running container |
Maintenance Targets
| Target | Description |
|---|---|
container-clean |
Remove all containers and images |
container-clean-container-volumes |
Remove containers, volumes, and prune system |
container-clean-images |
Remove all oneselect images |
container-volume-info |
Inspect volume information |
GitHub Container Registry Targets
| Target | Description |
|---|---|
ghcr-login |
Authenticate with GHCR (cached 2 hours) |
ghcr-push |
Tag and push image to GHCR |
ghcr-logout |
Remove GHCR authentication |
ghcr-clean |
Logout and remove local images |
Environment Detection
When running any container target, the Makefile displays detected configuration:
$ make container-build
Using Podman as the container engine
No proxy detected - will use standard container build
Or in a corporate environment:
$ make container-build
Using Docker as the container engine
Proxy environment detected - will use proxy CA certificate for container builds
Related Documentation
- Dockerfile - Main build configuration
- docker-compose.yml - Service orchestration
- docs/deployment.md - Deployment guide