Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions 03_container_layer/docker/admin/gitea-registry/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.env
*.env
*.key
*.pem
*.p12
*.pfx
README.md
29 changes: 29 additions & 0 deletions 03_container_layer/docker/admin/gitea-registry/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# ISSUE 142
#
# Copy to .env and fill in values before running: cp .env.example .env
# .env is gitignored — never commit real secrets.
#

# ── Gitea ──────────────────────────────────────────────────────────────────
# Registry domain (used for docker login)
GITEA_DOMAIN=localhost
GITEA_BASE_URL=http://localhost:3000

# Generate with: openssl rand -hex 32
GITEA_SECRET_KEY=CHANGEME_generate_with_openssl_rand_hex_32
# Generate with: gitea generate secret INTERNAL_TOKEN
GITEA_INTERNAL_TOKEN=CHANGEME_generate_with_gitea_generate_secret

# ── Initial admin (must match admins[0] in provisioning/users.yml) ─────────
GITEA_ADMIN_USER=gitea-admin
GITEA_ADMIN_PASS=Admin1234!

# ── PostgreSQL ──────────────────────────────────────────────────────────────
POSTGRES_USER=gitea
POSTGRES_PASSWORD=CHANGEME_replace_before_deploying
POSTGRES_DB=gitea

# ── Host ports ──────────────────────────────────────────────────────────────
HTTP_PORT=3000
SSH_PORT=2222
30 changes: 30 additions & 0 deletions 03_container_layer/docker/admin/gitea-registry/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#
# ISSUE 142
#

#
# BUILDER — golang:alpine (same base as official Gitea Dockerfile)
# Installs yq for YAML parsing; copies and pre-validates provisioning scripts.
#
FROM golang:alpine AS builder

RUN apk add --no-cache jq && \
wget -q https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_amd64 \
-O /usr/bin/yq && chmod +x /usr/bin/yq

COPY provisioning/ /provisioning/
RUN chmod +x /provisioning/init.sh

#
# RUNTIME — gitea/gitea:latest (Alpine-based, ships the gitea CLI)
# Copies tooling and provisioning scripts from builder.
# Acts as the provisioner sidecar: creates users via CLI + SSH keys via REST API
# and generates personal access tokens for Docker registry usage.
#
FROM gitea/gitea:latest AS runtime

COPY --from=builder /usr/bin/yq /usr/bin/yq
COPY --from=builder /usr/bin/jq /usr/bin/jq
COPY --from=builder /provisioning/ /provisioning/

ENTRYPOINT ["/provisioning/init.sh"]
94 changes: 94 additions & 0 deletions 03_container_layer/docker/admin/gitea-registry/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#
# ISSUE 142
#

SERVICE = gitea-registry
PROVISIONER = gitea-registry-provisioner
DEBUG_SERVICE = $(SERVICE)-debug

.PHONY: help up down stop build rebuild build-up rebuild-up reprovision logs-provisioner tokens term term-debug-build clean print

help:
@echo ""
@echo ""
@echo " Available : "
@echo ""
@echo " make up - run the full stack (db + gitea + provisioner) in background"
@echo " make down - stop and remove all containers"
@echo " make stop - stop $(SERVICE) only"
@echo ""
@echo " make build - build the provisioner image"
@echo " make build-up - build provisioner image then start the full stack"
@echo ""
@echo " make rebuild - full rebuild without cache"
@echo " make rebuild-up - full rebuild without cache then start"
@echo ""
@echo " make reprovision - remove the provisioning stamp and restart provisioner"
@echo " make logs-provisioner - tail provisioner output"
@echo ""
@echo " make tokens - display generated registry tokens"
@echo ""
@echo " make term - open shell in $(SERVICE) container"
@echo " make term-debug-build - build and open shell in $(DEBUG_SERVICE)"
@echo " make clean - delete all containers, images, volumes and unused network"
@echo " make print - print this help"
@echo ""
@echo ""

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

up:
docker compose up -d
down:
docker compose down
stop:
docker compose stop $(SERVICE)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

build:
docker compose build

rebuild:
docker compose down
docker compose build --no-cache

# # # # # # # # # # # #

build-up:
docker compose build
docker compose up -d

rebuild-up:
docker compose down
docker compose build --no-cache
docker compose up -d

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

reprovision:
docker exec $(SERVICE) rm -f /data/gitea/.provisioned
docker compose restart $(PROVISIONER)

logs-provisioner:
docker compose logs -f $(PROVISIONER)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tokens:
docker run --rm -v gitea-registry-tokens:/tokens alpine cat /tokens/tokens.txt

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

clean:
docker compose down -v --rmi all

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

term:
docker exec -it $(SERVICE) /bin/sh

term-debug-build:
@echo "Uncomment the 'debug' service in compose.yml first, then re-run."

print: help
179 changes: 179 additions & 0 deletions 03_container_layer/docker/admin/gitea-registry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# gitea-registry

Standalone [Gitea](https://gitea.io) instance configured as an OCI Docker registry, with automated user provisioning and personal access token generation.

Gitea's built-in [Packages / Container Registry](https://docs.gitea.io/en-us/packages/container/) feature is enabled via `GITEA__packages__ENABLED=true`. Each provisioned user receives a `registry-token` personal access token that can be used directly with `docker login`.

---

## Quick Start

```bash
# 1. Copy and fill in secrets
cp .env.example .env
# Edit .env — replace all CHANGEME_ values

# 2. Declare users in provisioning/users.yml

# 3. Build and start
make build-up

# 4. Retrieve generated tokens
make tokens
```

---

## Build & Push (Makefile targets)

| Target | Description |
|---|---|
| `make up` | Start full stack in background |
| `make down` | Stop and remove all containers |
| `make build` | Build provisioner image |
| `make build-up` | Build then start |
| `make rebuild-up` | Full rebuild without cache then start |
| `make reprovision` | Remove stamp and re-run provisioner |
| `make logs-provisioner` | Tail provisioner logs |
| `make tokens` | Print generated registry tokens |
| `make term` | Shell into gitea-registry container |
| `make clean` | Destroy all containers, images, volumes |

---

## Declaring Users

Edit `provisioning/users.yml` before the first `make up`:

```yaml
admins:
- username: gitea-admin
email: admin@range42.local
password: "StrongPassw0rd!"
ssh_keys:
- "ssh-ed25519 AAAA... admin@host"

users:
- username: trainee01
email: trainee01@range42.local
password: "TraineePass1!"
ssh_keys: []
```

The provisioner is **idempotent** — running it again on an already-provisioned stack exits immediately (stamp at `/data/gitea/.provisioned`).

To re-provision: `make reprovision`

---

## SSH Key Format

SSH keys must be valid OpenSSH public keys. Supported types:

- `ssh-ed25519 AAAA...`
- `ssh-rsa AAAA...`
- `ecdsa-sha2-nistp256 AAAA...`

Set `ssh_keys: []` for users who do not need SSH access.

---

## Docker Registry Usage

Gitea acts as an OCI-compatible registry at `DOMAIN:PORT`.

### Login

```bash
# Using a personal access token (recommended)
docker login localhost:3000 -u trainee01 -p TOKEN

# Or use your Gitea password
docker login localhost:3000 -u trainee01 -p Trainee1234!
```

### Push an image

```bash
docker tag myimage:latest localhost:3000/trainee01/myimage:latest
docker push localhost:3000/trainee01/myimage:latest
```

### Pull an image

```bash
docker pull localhost:3000/trainee01/myimage:latest
```

### List packages via API

```bash
curl -s http://localhost:3000/api/v1/packages/trainee01 \
-u trainee01:TOKEN | jq .
```

---

## Token Retrieval

Personal access tokens (`registry-token`) are generated for every user during provisioning and written to a named volume.

```bash
# Print all tokens
make tokens

# Or directly
docker exec gitea-registry-provisioner cat /tokens/tokens.txt
```

Token file format:
```
# Generated by gitea-registry provisioner
# docker login usage: docker login DOMAIN:PORT -u USERNAME -p TOKEN
gitea-admin:abc123...sha1
trainee01:def456...sha1
```

---

## Environment Variables

| Variable | Default | Description |
|---|---|---|
| `GITEA_DOMAIN` | `localhost` | Domain for Gitea server and SSH |
| `GITEA_BASE_URL` | `http://localhost:3000` | Full root URL |
| `GITEA_SECRET_KEY` | `please-change-me-in-production` | App secret key (`openssl rand -hex 32`) |
| `GITEA_INTERNAL_TOKEN` | `please-change-me-in-production` | Internal token (`gitea generate secret INTERNAL_TOKEN`) |
| `GITEA_ADMIN_USER` | `gitea-admin` | Admin username (must match `admins[0]` in users.yml) |
| `GITEA_ADMIN_PASS` | `Admin1234!` | Admin password |
| `POSTGRES_USER` | `gitea` | Database user |
| `POSTGRES_PASSWORD` | `gitea` | Database password |
| `POSTGRES_DB` | `gitea` | Database name |
| `HTTP_PORT` | `3000` | Host port mapped to Gitea HTTP |
| `SSH_PORT` | `2222` | Host port mapped to Gitea SSH |

---

## Troubleshooting

**Provisioner exits before Gitea is ready**

The provisioner retries for up to 180 s. If Gitea takes longer (cold pull), increase `start_period` in `compose.yml` or run `make reprovision` after Gitea is healthy.

**Token shows `ERROR`**

The Gitea API returned an empty response. Check provisioner logs:

```bash
make logs-provisioner
```

Common causes: Gitea not yet fully initialized, or the user creation step failed silently. Run `make reprovision` after verifying Gitea is up.

**`docker login` fails with 401**

Ensure the Packages feature is enabled. Check the Gitea admin panel at `http://localhost:3000/-/admin/self` or verify `GITEA__packages__ENABLED=true` is set in `compose.yml`.

**Port conflict**

Change `HTTP_PORT` or `SSH_PORT` in `.env` and run `make down && make up`.
Loading