Skip to content

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:

  1. Standard Build - For public deployments or environments without corporate proxies
  2. 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

The simplest approach - let the build system figure everything out:

make container-build

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:

Using Podman as the container engine
or
Using Docker as the container engine

Switching 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

  1. Obtain your corporate CA certificate:

    # Usually located in:
    # - macOS: ~/.config/certs/
    # - Linux: /etc/ssl/certs/
    # - Windows: Contact your IT department
    

  2. Copy it to the project root:

    cp ~/.config/certs/your-corporate-ca.pem CA_proxy_fw_all.pem
    

  3. Build (auto-detection will handle the rest):

    make container-build
    

  4. 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 .gitignore and .dockerignore files exclude CA_proxy_fw_all.pem by 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

  1. GitHub Personal Access Token with write:packages scope
  2. Generate at: https://github.com/settings/tokens
  3. Select scopes: write:packages, read:packages, delete:packages (optional)

  4. Environment Variables:

    export GITHUB_USER="your-github-username"
    export GHCR_TOKEN="ghp_your_personal_access_token"
    

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:

make ghcr-login
- Requires GITHUB_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:

make ghcr-push
- Tags image with version from pyproject.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:

make ghcr-logout
- Removes authentication credentials - Clears login cache

Complete Cleanup:

make ghcr-clean
- Logs out from GHCR - Removes all local oneselect container images - Useful for starting fresh

Example 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:

SSL: CERTIFICATE_VERIFY_FAILED

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":

  1. Verify the certificate file exists in the project root
  2. Ensure it's named exactly CA_proxy_fw_all.pem
  3. Check the file is readable: ls -la CA_proxy_fw_all.pem

Proxy Connection Issues

If builds hang or timeout:

  1. Verify proxy settings:

    env | grep -i proxy
    

  2. Check container engine has proxy configured:

    # For Podman (macOS)
    podman machine ssh "env | grep -i proxy"
    
    # For Docker
    # Check Docker Desktop settings → Resources → Proxies
    

  3. Ensure proxy is running and accessible:

    curl -I https://google.com  # Should work if proxy is configured
    

GHCR Publishing Issues

"GITHUB_USER not set" error:

export GITHUB_USER="your-github-username"

"GHCR_TOKEN not set" error:

export GHCR_TOKEN="ghp_your_token_here"

"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:

services:
  backend:
    build:
      context: .
      args:
        USE_PROXY_CA: "true"

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