Files
homelab-design/decisions/0020-internal-registry-for-cicd.md
Billy D. 8f4df84657 chore: Consolidate ADRs into decisions/ directory
- Added ADR-0016: Affine email verification strategy
- Moved ADRs 0019-0024 from docs/adr/ to decisions/
- Renamed to consistent format (removed ADR- prefix)
2026-02-04 08:28:12 -05:00

4.7 KiB

ADR-0020: Internal Registry URLs for CI/CD

Status

Accepted

Date

2026-02-02

Context

Factor Details
Problem Cloudflare proxying limits uploads to 100MB per request
Impact Docker images (20GB+) and large packages fail to push
Current Setup Gitea at git.daviestechlabs.io behind Cloudflare
Internal Access registry.lab.daviestechlabs.io bypasses Cloudflare

Our Gitea instance is accessible via two URLs:

  • External: git.daviestechlabs.io - proxied through Cloudflare (DDoS protection, caching)
  • Internal: registry.lab.daviestechlabs.io - direct access from cluster network

Cloudflare's free tier enforces a 100MB upload limit per request. This blocks:

  • Docker image pushes (multi-GB layers)
  • Large Python package uploads
  • Any artifact exceeding 100MB

Decision

Use internal registry URLs for all CI/CD artifact uploads.

CI/CD workflows running on Gitea Actions runners (which are inside the cluster) should use registry.lab.daviestechlabs.io for:

  • Docker image pushes
  • PyPI package uploads
  • Any large artifact uploads

External URLs remain for:

  • Git operations (clone, push, pull)
  • Package downloads (pip install, docker pull)
  • Human access via browser

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         INTERNET                                 │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    ┌─────────────────┐
                    │   Cloudflare    │
                    │  (100MB limit)  │
                    └────────┬────────┘
                             │
                             ▼
              ┌──────────────────────────────┐
              │  git.daviestechlabs.io       │
              │  (external access)           │
              └──────────────────────────────┘
                             │
                             │  same Gitea instance
                             │
              ┌──────────────────────────────┐
              │  registry.lab.daviestechlabs │
              │  (internal, no limits)       │
              └──────────────────────────────┘
                             ▲
                             │ direct upload
                             │
              ┌──────────────────────────────┐
              │     Gitea Actions Runner     │
              │     (in-cluster)             │
              └──────────────────────────────┘

Consequences

Positive

  • No upload size limits for CI/CD artifacts
  • Faster uploads (no Cloudflare proxy overhead)
  • Lower latency for in-cluster operations
  • Cost savings (reduced Cloudflare bandwidth)

Negative

  • Two URLs to maintain in workflow configurations
  • Runners must be in-cluster (cannot use external runners for uploads)
  • DNS split-horizon required if accessing from outside

Neutral

  • External users can still pull packages/images via Cloudflare URL
  • Git operations continue through external URL (small payloads)

Implementation

Docker Registry Login

- name: Login to Internal Registry
  uses: docker/login-action@v3
  with:
    registry: registry.lab.daviestechlabs.io
    username: ${{ secrets.REGISTRY_USER }}
    password: ${{ secrets.REGISTRY_TOKEN }}

PyPI Upload

- name: Publish to Gitea PyPI
  run: |
    twine upload \
      --repository-url https://registry.lab.daviestechlabs.io/api/packages/daviestechlabs/pypi \
      dist/*

Environment Variable Pattern

For consistency across workflows:

env:
  REGISTRY_EXTERNAL: git.daviestechlabs.io
  REGISTRY_INTERNAL: registry.lab.daviestechlabs.io