Container: - Dockerfile → Containerfile; drop gosu, entrypoint, PUID/PGID user-switching - HOME=/config so Path.home()/.aws resolves to runtime-mounted credentials - docker-compose.yml → compose.yml with userns_mode: keep-id for Podman rootless - .dockerignore → .containerignore - boto3 unpinned from 1.34.0 to >=1.34.0 CI: - Remove Woodpecker (.woodpecker.yml, .woodpecker/) - Add Forgejo Actions (.forgejo/workflows/ci.yml, publish.yml) - CI: syntax check, security scan, container lint (hadolint), build test - Publish: build and push to Quay.io on main push and version tags Cleanup: - Remove entrypoint.sh (no longer needed) - Remove scripts/build-and-push.sh and PUBLISHING.md (superseded by CI) - All docker → podman command references updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
406 lines
8.5 KiB
Markdown
406 lines
8.5 KiB
Markdown
# Building and Publishing to Quay.io
|
|
|
|
This guide covers how to build and publish SGO container images to Quay.io.
|
|
|
|
## Prerequisites
|
|
|
|
1. **Quay.io account**: Create account at https://quay.io
|
|
2. **Repository created**: Create a repository (e.g., `yourusername/sgo`)
|
|
3. **Docker or Podman installed**: For building and pushing images
|
|
|
|
## Manual Build and Push
|
|
|
|
### Step 1: Login to Quay.io
|
|
|
|
```bash
|
|
# Using Docker
|
|
docker login quay.io
|
|
|
|
# Using Podman
|
|
podman login quay.io
|
|
|
|
# You'll be prompted for:
|
|
# Username: your_quay_username
|
|
# Password: your_quay_password (or robot account token)
|
|
```
|
|
|
|
### Step 2: Build the Image
|
|
|
|
```bash
|
|
cd /home/eduardo_figueroa/Dev/sgo
|
|
|
|
# Build with Docker
|
|
docker build -t quay.io/yourusername/sgo:latest .
|
|
|
|
# Build with Podman
|
|
podman build -t quay.io/yourusername/sgo:latest .
|
|
```
|
|
|
|
### Step 3: Tag for Version (Optional)
|
|
|
|
```bash
|
|
# Tag with version number
|
|
docker tag quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:v1.0.0
|
|
|
|
# Tag with git commit
|
|
docker tag quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:$(git rev-parse --short HEAD)
|
|
```
|
|
|
|
### Step 4: Push to Quay.io
|
|
|
|
```bash
|
|
# Push latest tag
|
|
docker push quay.io/yourusername/sgo:latest
|
|
|
|
# Push version tag
|
|
docker push quay.io/yourusername/sgo:v1.0.0
|
|
|
|
# Push all tags
|
|
docker push quay.io/yourusername/sgo --all-tags
|
|
```
|
|
|
|
## Using Robot Accounts (Recommended for CI/CD)
|
|
|
|
Robot accounts provide scoped credentials for automation.
|
|
|
|
### Create Robot Account
|
|
|
|
1. Go to your repository on Quay.io
|
|
2. Click **Settings** → **Robot Accounts**
|
|
3. Click **Create Robot Account**
|
|
4. Name it (e.g., `sgo_builder`)
|
|
5. Grant **Write** permissions
|
|
6. Save the credentials (username and token)
|
|
|
|
### Login with Robot Account
|
|
|
|
```bash
|
|
# Format: quay.io+username+robotname
|
|
docker login quay.io
|
|
Username: yourusername+sgo_builder
|
|
Password: <robot-token>
|
|
```
|
|
|
|
## Automated Build with Woodpecker CI
|
|
|
|
### Step 1: Add Secrets to Woodpecker
|
|
|
|
Add these secrets to your Woodpecker CI configuration:
|
|
|
|
- `QUAY_USERNAME` - Your quay.io username or robot account
|
|
- `QUAY_PASSWORD` - Your quay.io password or robot token
|
|
|
|
### Step 2: Create Woodpecker Pipeline
|
|
|
|
Create `.woodpecker/docker-publish.yml`:
|
|
|
|
```yaml
|
|
pipeline:
|
|
docker-build-and-push:
|
|
image: docker:dind
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
environment:
|
|
- QUAY_USERNAME
|
|
- QUAY_PASSWORD
|
|
commands:
|
|
# Login to Quay.io
|
|
- echo "$QUAY_PASSWORD" | docker login quay.io -u "$QUAY_USERNAME" --password-stdin
|
|
|
|
# Build image
|
|
- docker build -t quay.io/yourusername/sgo:latest .
|
|
- docker tag quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:${CI_COMMIT_SHA}
|
|
|
|
# Push images
|
|
- docker push quay.io/yourusername/sgo:latest
|
|
- docker push quay.io/yourusername/sgo:${CI_COMMIT_SHA}
|
|
|
|
when:
|
|
branch:
|
|
- main
|
|
event:
|
|
- push
|
|
- tag
|
|
```
|
|
|
|
### Step 3: Update Main Woodpecker Config
|
|
|
|
Add to `.woodpecker.yml`:
|
|
|
|
```yaml
|
|
when:
|
|
event: [push, pull_request, tag]
|
|
|
|
pipeline:
|
|
dependencies:
|
|
image: python:3.11-slim
|
|
commands:
|
|
- pip install -r requirements.txt
|
|
|
|
syntax-check:
|
|
image: python:3.11-slim
|
|
commands:
|
|
- python -m py_compile app.py
|
|
- python -m py_compile import_from_aws.py
|
|
- python -m py_compile import_data.py
|
|
|
|
docker-build:
|
|
image: docker:dind
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
commands:
|
|
- docker build -t sgo:${CI_COMMIT_SHA} .
|
|
|
|
security-scan:
|
|
image: python:3.11-slim
|
|
commands:
|
|
- pip install bandit safety
|
|
- bandit -r . -ll || true
|
|
- safety check --file requirements.txt || true
|
|
|
|
# Only push on main branch
|
|
publish-to-quay:
|
|
image: docker:dind
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
secrets: [quay_username, quay_password]
|
|
commands:
|
|
- echo "$QUAY_PASSWORD" | docker login quay.io -u "$QUAY_USERNAME" --password-stdin
|
|
- docker build -t quay.io/yourusername/sgo:latest .
|
|
- docker tag quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:${CI_COMMIT_SHA}
|
|
- docker push quay.io/yourusername/sgo:latest
|
|
- docker push quay.io/yourusername/sgo:${CI_COMMIT_SHA}
|
|
when:
|
|
branch: main
|
|
event: push
|
|
```
|
|
|
|
## Multi-Architecture Builds
|
|
|
|
Build for multiple architectures (amd64, arm64):
|
|
|
|
### Using Docker Buildx
|
|
|
|
```bash
|
|
# Create builder
|
|
docker buildx create --name multiarch --use
|
|
|
|
# Build and push multi-arch image
|
|
docker buildx build \
|
|
--platform linux/amd64,linux/arm64 \
|
|
-t quay.io/yourusername/sgo:latest \
|
|
--push \
|
|
.
|
|
```
|
|
|
|
### Using Podman
|
|
|
|
```bash
|
|
# Build for amd64
|
|
podman build --platform linux/amd64 -t quay.io/yourusername/sgo:latest-amd64 .
|
|
|
|
# Build for arm64
|
|
podman build --platform linux/arm64 -t quay.io/yourusername/sgo:latest-arm64 .
|
|
|
|
# Create and push manifest
|
|
podman manifest create quay.io/yourusername/sgo:latest
|
|
podman manifest add quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:latest-amd64
|
|
podman manifest add quay.io/yourusername/sgo:latest quay.io/yourusername/sgo:latest-arm64
|
|
podman manifest push quay.io/yourusername/sgo:latest
|
|
```
|
|
|
|
## Tagging Strategy
|
|
|
|
### Recommended Tags
|
|
|
|
```bash
|
|
# Latest - always points to newest build
|
|
quay.io/yourusername/sgo:latest
|
|
|
|
# Version tags - for releases
|
|
quay.io/yourusername/sgo:v1.0.0
|
|
quay.io/yourusername/sgo:v1.0
|
|
quay.io/yourusername/sgo:v1
|
|
|
|
# Git commit SHA - for specific commits
|
|
quay.io/yourusername/sgo:abc1234
|
|
|
|
# Branch name - for development branches
|
|
quay.io/yourusername/sgo:dev
|
|
quay.io/yourusername/sgo:feature-xyz
|
|
```
|
|
|
|
### Applying Multiple Tags
|
|
|
|
```bash
|
|
IMAGE_NAME="quay.io/yourusername/sgo"
|
|
VERSION="v1.0.0"
|
|
COMMIT=$(git rev-parse --short HEAD)
|
|
|
|
# Build once
|
|
docker build -t ${IMAGE_NAME}:${VERSION} .
|
|
|
|
# Apply multiple tags
|
|
docker tag ${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:latest
|
|
docker tag ${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${COMMIT}
|
|
|
|
# Push all tags
|
|
docker push ${IMAGE_NAME}:${VERSION}
|
|
docker push ${IMAGE_NAME}:latest
|
|
docker push ${IMAGE_NAME}:${COMMIT}
|
|
```
|
|
|
|
## Verifying the Published Image
|
|
|
|
### Pull and Test
|
|
|
|
```bash
|
|
# Pull the image
|
|
docker pull quay.io/yourusername/sgo:latest
|
|
|
|
# Test it works
|
|
docker run --rm \
|
|
-e AWS_CONFIG_PATH=/tmp/aws-host \
|
|
-e PUID=1000 \
|
|
-e PGID=1000 \
|
|
-v $HOME/.aws:/tmp/aws-host:ro \
|
|
-v sgo-data:/app/data \
|
|
-p 5000:5000 \
|
|
quay.io/yourusername/sgo:latest
|
|
```
|
|
|
|
### Check Image Details
|
|
|
|
```bash
|
|
# Inspect image
|
|
docker inspect quay.io/yourusername/sgo:latest
|
|
|
|
# Check image size
|
|
docker images quay.io/yourusername/sgo
|
|
|
|
# View image history
|
|
docker history quay.io/yourusername/sgo:latest
|
|
```
|
|
|
|
## Making Repository Public
|
|
|
|
By default, Quay.io repositories are private.
|
|
|
|
To make public:
|
|
1. Go to repository on Quay.io
|
|
2. Click **Settings**
|
|
3. Change **Repository Visibility** to **Public**
|
|
4. Click **Save**
|
|
|
|
## Updating docker-compose.yml for Quay.io
|
|
|
|
Users can pull from Quay.io by updating their `docker-compose.yml`:
|
|
|
|
```yaml
|
|
services:
|
|
sgo:
|
|
image: quay.io/yourusername/sgo:latest
|
|
# rest of configuration...
|
|
```
|
|
|
|
Or pull specific version:
|
|
|
|
```yaml
|
|
services:
|
|
sgo:
|
|
image: quay.io/yourusername/sgo:v1.0.0
|
|
# rest of configuration...
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Authentication Failed
|
|
|
|
```bash
|
|
# Clear old credentials
|
|
rm ~/.docker/config.json
|
|
|
|
# Login again
|
|
docker login quay.io
|
|
```
|
|
|
|
### Push Denied
|
|
|
|
- Verify repository exists on Quay.io
|
|
- Check robot account has **Write** permissions
|
|
- Ensure you're logged in to correct account
|
|
|
|
### Build Fails
|
|
|
|
```bash
|
|
# Check Dockerfile syntax
|
|
docker build --no-cache -t test .
|
|
|
|
# View build logs
|
|
docker build -t test . 2>&1 | tee build.log
|
|
```
|
|
|
|
### Image Too Large
|
|
|
|
```bash
|
|
# Check image size
|
|
docker images quay.io/yourusername/sgo
|
|
|
|
# Use .dockerignore to exclude files
|
|
# Already configured in project
|
|
|
|
# Use multi-stage builds (if applicable)
|
|
# Current Dockerfile is already optimized
|
|
```
|
|
|
|
## Complete Build Script
|
|
|
|
Create `scripts/build-and-push.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
# Configuration
|
|
REGISTRY="quay.io"
|
|
USERNAME="yourusername"
|
|
REPO="sgo"
|
|
IMAGE="${REGISTRY}/${USERNAME}/${REPO}"
|
|
|
|
# Get version from git tag or use dev
|
|
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev")
|
|
COMMIT=$(git rev-parse --short HEAD)
|
|
|
|
echo "Building ${IMAGE}:${VERSION}"
|
|
|
|
# Build image
|
|
docker build -t ${IMAGE}:${VERSION} .
|
|
|
|
# Tag with multiple tags
|
|
docker tag ${IMAGE}:${VERSION} ${IMAGE}:latest
|
|
docker tag ${IMAGE}:${VERSION} ${IMAGE}:${COMMIT}
|
|
|
|
echo "Pushing to ${REGISTRY}"
|
|
|
|
# Push all tags
|
|
docker push ${IMAGE}:${VERSION}
|
|
docker push ${IMAGE}:latest
|
|
docker push ${IMAGE}:${COMMIT}
|
|
|
|
echo "Successfully pushed:"
|
|
echo " - ${IMAGE}:${VERSION}"
|
|
echo " - ${IMAGE}:latest"
|
|
echo " - ${IMAGE}:${COMMIT}"
|
|
```
|
|
|
|
Make it executable:
|
|
|
|
```bash
|
|
chmod +x scripts/build-and-push.sh
|
|
```
|
|
|
|
Run it:
|
|
|
|
```bash
|
|
./scripts/build-and-push.sh
|
|
```
|