This guide shows how to use pycontainer-build in GitHub Actions workflows to build and push container images without Docker.
pycontainer-build provides a reusable GitHub Actions workflow that makes it easy to integrate container builds into your CI/CD pipeline.
name: Build Container
on:
push:
branches: [main]
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
tag: ghcr.io/${{ github.repository }}:${{ github.sha }}
push: true
permissions:
contents: read
packages: writeThis will:
- Check out your code
- Set up Python 3.11
- Install pycontainer-build
- Build your container image
- Push to GitHub Container Registry (ghcr.io)
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
# Python version for the build environment
python-version: '3.11'
# Container image tag (required)
tag: 'ghcr.io/myorg/myapp:v1.0.0'
# Base image for the container
base-image: 'python:3.11-slim'
# Build context directory
context: '.'
# Push to registry (true/false)
push: true
# Include dependencies from venv/requirements.txt
include-deps: true
# Generate SBOM (spdx or cyclonedx)
sbom: 'spdx'
# Container registry
registry: 'ghcr.io'
secrets:
# Optional: Custom registry credentials
# If not provided, uses GITHUB_TOKEN for ghcr.io
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}name: Build Container
on:
push:
branches: [main, develop]
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
tag: ghcr.io/${{ github.repository }}:${{ github.sha }}
push: true
permissions:
contents: read
packages: writename: Release Container
on:
release:
types: [published]
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
tag: ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}
base-image: 'python:3.11-slim'
include-deps: true
sbom: 'spdx'
push: true
permissions:
contents: read
packages: writename: Multi-Version Build
on:
push:
branches: [main]
jobs:
build:
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
python-version: ${{ matrix.python-version }}
tag: ghcr.io/${{ github.repository }}:py${{ matrix.python-version }}
base-image: python:${{ matrix.python-version }}-slim
push: true
permissions:
contents: read
packages: writename: PR Build
on:
pull_request:
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
tag: ghcr.io/${{ github.repository }}:pr-${{ github.event.pull_request.number }}
push: false # Just build, don't push
permissions:
contents: readIf you need more control, you can use pycontainer-build directly:
name: Custom Build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install pycontainer-build
run: pip install pycontainer-build
- name: Build and push container
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pycontainer build \
--tag ghcr.io/${{ github.repository }}:${{ github.sha }} \
--base-image python:3.11-slim \
--include-deps \
--sbom spdx \
--push \
--verbose
- name: Run tests on container (optional)
run: |
# Example: pull and test the image
# Note: Requires Docker for testing, but not for building
docker pull ghcr.io/${{ github.repository }}:${{ github.sha }}
docker run ghcr.io/${{ github.repository }}:${{ github.sha }} python -c "import myapp; print('OK')"The workflow automatically uses GITHUB_TOKEN for authentication to ghcr.io. No additional configuration needed.
For Docker Hub, Azure Container Registry, or private registries:
jobs:
build:
uses: spboyer/pycontainer-build/.github/workflows/pycontainer-build.yml@main
with:
tag: 'myregistry.azurecr.io/myapp:latest'
registry: 'myregistry.azurecr.io'
push: true
secrets:
REGISTRY_USERNAME: ${{ secrets.ACR_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.ACR_PASSWORD }}The workflow sets these environment variables automatically:
GITHUB_TOKEN- For ghcr.io authenticationREGISTRY_USERNAME- Custom registry username (if provided)REGISTRY_PASSWORD- Custom registry password (if provided)
The workflow generates a build summary in the GitHub Actions UI showing:
- Image tag
- Base image used
- Python version
- Build context
- Whether the image was pushed
- SBOM generation status
Ensure your dependencies are properly specified:
- Include a
requirements.txtorpyproject.toml - Use
--include-depsflag - Or pre-install dependencies in your workflow
Check:
- Workflow has
packages: writepermission - For custom registries,
REGISTRY_USERNAMEandREGISTRY_PASSWORDsecrets are set - Registry URL is correct
Optimize your base image:
- Use slim images:
python:3.11-sliminstead ofpython:3.11 - Consider distroless:
gcr.io/distroless/python3-debian12 - Exclude unnecessary files in your project
- No Docker daemon required - Works in any CI environment
- Faster builds - No Docker layer caching overhead
- Simpler workflows - No Docker setup or Docker-in-Docker
- Better security - No privileged containers needed
- Cloud-native - Works in GitHub Codespaces, Azure DevOps, etc.
- See example-build.yml.example for complete examples
- Read Configuration for all build options
- Explore IMPLEMENTATION_PLAN.md for roadmap