feat: multi-image runners — go, node, docker, deploy, godot
Replace single fat image with purpose-built images per workflow type. Each image is lean: base (Alpine+AWS+git) → go/node/deploy extend it. docker image standalone (dind base). godot for future game builds. build-all.sh builds base first, then all others in parallel.
This commit is contained in:
@@ -1,41 +1,57 @@
|
||||
# tinqs/ci
|
||||
|
||||
Tinqs CI toolchain — composite Gitea Actions and runner base image.
|
||||
Tinqs CI toolchain — composite Gitea Actions and purpose-built runner images.
|
||||
|
||||
## Actions
|
||||
|
||||
| Action | Description | Replaces |
|
||||
|--------|-------------|----------|
|
||||
| `tinqs/ci/checkout` | Clone a Gitea repo | `actions/checkout` |
|
||||
| `tinqs/ci/setup-go` | Install Go | `actions/setup-go` |
|
||||
| `tinqs/ci/setup-node` | Install Node.js + pnpm | `actions/setup-node` |
|
||||
| `tinqs/ci/setup-aws` | Install AWS CLI + ECR login | — |
|
||||
|
||||
### Usage
|
||||
| Action | What it does |
|
||||
|--------|-------------|
|
||||
| `tinqs/ci/checkout@v1` | Clone a repo from tinqs.com |
|
||||
| `tinqs/ci/setup-go@v1` | Install Go (skips if pre-baked) |
|
||||
| `tinqs/ci/setup-node@v1` | Install Node.js + pnpm (skips if pre-baked) |
|
||||
| `tinqs/ci/setup-aws@v1` | Install AWS CLI + optional ECR login |
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: tinqs/ci/checkout@v1
|
||||
|
||||
- uses: tinqs/ci/setup-go@v1
|
||||
with:
|
||||
go-version: '1.26.2'
|
||||
|
||||
- uses: tinqs/ci/setup-node@v1
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- uses: tinqs/ci/setup-aws@v1
|
||||
with:
|
||||
ecr-login: 'true'
|
||||
ecr-repo: '149751500842.dkr.ecr.eu-west-1.amazonaws.com/tinqs-git'
|
||||
```
|
||||
|
||||
## Runner Base Image
|
||||
## Runner Images
|
||||
|
||||
`runner-image/` contains the Dockerfile for the CI runner container. Pre-installs Go, Node.js, AWS CLI, Docker, git, and ssh — no per-job install overhead.
|
||||
Each workflow type gets a lean, purpose-built runner image. No fat "everything" image.
|
||||
|
||||
| Image | `runs-on` | Contents | Used by |
|
||||
|-------|-----------|----------|---------|
|
||||
| **base** | — | Alpine + git + AWS CLI + SSH | Foundation for all others |
|
||||
| **go** | `go` | base + Go 1.26 | build-tstudio, deploy-proxy |
|
||||
| **node** | `node` | base + Node 22 + pnpm | deploy-docs |
|
||||
| **docker** | `docker` | docker:dind + Go + AWS CLI | build (platform), deploy-bot |
|
||||
| **deploy** | `deploy` | base only (lightest) | deploy-arikigame, release |
|
||||
| **godot** | `godot` | base + headless Godot 4.6 + export templates | ariki-game builds (future) |
|
||||
|
||||
### Build all images
|
||||
|
||||
```bash
|
||||
cd runner-image
|
||||
./build-push.sh v1
|
||||
cd images
|
||||
./build-all.sh v1
|
||||
```
|
||||
|
||||
Images push to ECR as `tinqs-runner-{name}:v1`.
|
||||
|
||||
### How routing works
|
||||
|
||||
The Lambda dispatcher reads `runs-on:` from the workflow and starts a Fargate task with the matching image:
|
||||
|
||||
```
|
||||
runs-on: go → tinqs-runner-go (Go builds)
|
||||
runs-on: node → tinqs-runner-node (frontend builds)
|
||||
runs-on: docker → tinqs-runner-docker (Docker image builds)
|
||||
runs-on: deploy → tinqs-runner-deploy (S3/ECS deploys)
|
||||
runs-on: godot → tinqs-runner-godot (game exports)
|
||||
runs-on: host → legacy runner (forge-runner, temporary)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# tinqs/ci base — shared foundation for all runner images
|
||||
# Alpine + git + bash + curl + AWS CLI + ssh
|
||||
# Every other image builds FROM this.
|
||||
|
||||
FROM alpine:3.23
|
||||
|
||||
RUN apk add --no-cache \
|
||||
bash git curl wget unzip tar \
|
||||
ca-certificates openssh-client \
|
||||
tzdata
|
||||
|
||||
# AWS CLI (needed by almost every workflow)
|
||||
RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && \
|
||||
unzip -q /tmp/awscli.zip -d /tmp && \
|
||||
/tmp/aws/install && \
|
||||
rm -rf /tmp/awscli.zip /tmp/aws
|
||||
|
||||
RUN git --version && aws --version
|
||||
|
||||
WORKDIR /workspace
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
# Build all Tinqs CI runner images and push to ECR
|
||||
set -euo pipefail
|
||||
|
||||
AWS_REGION="${AWS_REGION:-eu-west-1}"
|
||||
ACCOUNT_ID="${ACCOUNT_ID:-149751500842}"
|
||||
ECR_BASE="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
|
||||
TAG="${1:-latest}"
|
||||
|
||||
echo "=== Logging into ECR ==="
|
||||
aws ecr get-login-password --region "${AWS_REGION}" | \
|
||||
docker login --username AWS --password-stdin "${ECR_BASE}"
|
||||
|
||||
# Ensure ECR repos exist
|
||||
for NAME in tinqs-runner-base tinqs-runner-go tinqs-runner-node tinqs-runner-docker tinqs-runner-deploy tinqs-runner-godot; do
|
||||
aws ecr describe-repositories --repository-names "$NAME" --region "$AWS_REGION" 2>/dev/null || \
|
||||
aws ecr create-repository --repository-name "$NAME" --region "$AWS_REGION" --no-cli-pager
|
||||
done
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# 1. Base (everything depends on this)
|
||||
echo "=== Building base ==="
|
||||
docker build -t "${ECR_BASE}/tinqs-runner-base:${TAG}" -t "${ECR_BASE}/tinqs-runner-base:latest" "$SCRIPT_DIR/base"
|
||||
docker push "${ECR_BASE}/tinqs-runner-base:${TAG}"
|
||||
docker push "${ECR_BASE}/tinqs-runner-base:latest"
|
||||
|
||||
BASE_ARG="--build-arg BASE_IMAGE=${ECR_BASE}/tinqs-runner-base:${TAG}"
|
||||
|
||||
# 2. All others in parallel (they only depend on base)
|
||||
build_and_push() {
|
||||
local name=$1
|
||||
local dir=$2
|
||||
local extra_args="${3:-}"
|
||||
echo "=== Building ${name} ==="
|
||||
docker build $extra_args -t "${ECR_BASE}/tinqs-runner-${name}:${TAG}" -t "${ECR_BASE}/tinqs-runner-${name}:latest" "$SCRIPT_DIR/$dir"
|
||||
docker push "${ECR_BASE}/tinqs-runner-${name}:${TAG}"
|
||||
docker push "${ECR_BASE}/tinqs-runner-${name}:latest"
|
||||
echo "=== Done ${name} ==="
|
||||
}
|
||||
|
||||
build_and_push "go" "go" "$BASE_ARG" &
|
||||
build_and_push "node" "node" "$BASE_ARG" &
|
||||
build_and_push "deploy" "deploy" "$BASE_ARG" &
|
||||
build_and_push "docker" "docker" "" &
|
||||
# godot is optional — uncomment when game CI is ready
|
||||
# build_and_push "godot" "godot" "$BASE_ARG" &
|
||||
|
||||
wait
|
||||
echo "=== All images built and pushed (tag: ${TAG}) ==="
|
||||
@@ -0,0 +1,10 @@
|
||||
# tinqs/ci deploy — lightweight deploy-only runner
|
||||
# Used by: deploy-arikigame, release
|
||||
# runs-on: deploy
|
||||
# Smallest image — just AWS CLI + SSH for S3 sync, CloudFront invalidation, ECS updates.
|
||||
|
||||
ARG BASE_IMAGE=tinqs-runner-base:latest
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
# Nothing extra needed — base already has aws, git, ssh, curl
|
||||
RUN aws --version && ssh -V
|
||||
@@ -0,0 +1,27 @@
|
||||
# tinqs/ci docker — Docker builds (platform image, bot image)
|
||||
# Used by: build (platform), deploy-bot
|
||||
# runs-on: docker
|
||||
# Based on docker:dind for Docker-in-Docker support.
|
||||
|
||||
FROM docker:29-dind
|
||||
|
||||
RUN apk add --no-cache \
|
||||
bash git curl wget unzip tar \
|
||||
ca-certificates openssh-client \
|
||||
build-base s6 tzdata
|
||||
|
||||
# AWS CLI
|
||||
RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && \
|
||||
unzip -q /tmp/awscli.zip -d /tmp && \
|
||||
/tmp/aws/install && \
|
||||
rm -rf /tmp/awscli.zip /tmp/aws
|
||||
|
||||
# Go (needed for platform Docker builds that compile inside container)
|
||||
ARG GO_VERSION=1.26.2
|
||||
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /usr/local -xz
|
||||
ENV PATH="/usr/local/go/bin:/go/bin:${PATH}"
|
||||
ENV GOPATH="/go"
|
||||
|
||||
RUN docker --version && aws --version && go version
|
||||
|
||||
WORKDIR /workspace
|
||||
@@ -0,0 +1,15 @@
|
||||
# tinqs/ci go — Go builds (platform, CLI, proxy)
|
||||
# Used by: build-tstudio, deploy-proxy
|
||||
# runs-on: go
|
||||
|
||||
ARG BASE_IMAGE=tinqs-runner-base:latest
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG GO_VERSION=1.26.2
|
||||
|
||||
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /usr/local -xz
|
||||
|
||||
ENV PATH="/usr/local/go/bin:/go/bin:${PATH}"
|
||||
ENV GOPATH="/go"
|
||||
|
||||
RUN go version
|
||||
@@ -0,0 +1,27 @@
|
||||
# tinqs/ci godot — headless Godot for game builds and export
|
||||
# Used by: ariki-game build pipeline (future)
|
||||
# runs-on: godot
|
||||
# Headless Godot 4.6 + export templates for Windows/Linux/Web.
|
||||
|
||||
ARG BASE_IMAGE=tinqs-runner-base:latest
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG GODOT_VERSION=4.6.2
|
||||
|
||||
# Headless Godot editor (for --headless --export-all)
|
||||
RUN curl -fsSL "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
|
||||
-o /tmp/godot.zip && \
|
||||
unzip -q /tmp/godot.zip -d /tmp && \
|
||||
mv /tmp/Godot_v${GODOT_VERSION}-stable_linux.x86_64 /usr/local/bin/godot && \
|
||||
chmod +x /usr/local/bin/godot && \
|
||||
rm -f /tmp/godot.zip
|
||||
|
||||
# Export templates
|
||||
RUN mkdir -p /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable && \
|
||||
curl -fsSL "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \
|
||||
-o /tmp/templates.tpz && \
|
||||
unzip -q /tmp/templates.tpz -d /tmp/templates && \
|
||||
mv /tmp/templates/templates/* /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable/ && \
|
||||
rm -rf /tmp/templates.tpz /tmp/templates
|
||||
|
||||
RUN godot --headless --version
|
||||
@@ -0,0 +1,13 @@
|
||||
# tinqs/ci node — Node.js builds (docs, frontend)
|
||||
# Used by: deploy-docs
|
||||
# runs-on: node
|
||||
|
||||
ARG BASE_IMAGE=tinqs-runner-base:latest
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG NODE_VERSION=22
|
||||
|
||||
RUN apk add --no-cache nodejs npm && \
|
||||
npm install -g pnpm
|
||||
|
||||
RUN node --version && pnpm --version
|
||||
@@ -1,36 +0,0 @@
|
||||
# Tinqs CI Runner Base Image
|
||||
# Pre-installed: Go, Node.js, AWS CLI, Docker CLI, git, ssh, curl
|
||||
# Used by act_runner with runs-on: host (no per-job install overhead)
|
||||
|
||||
FROM docker:29-dind
|
||||
|
||||
ARG GO_VERSION=1.26.2
|
||||
ARG NODE_VERSION=22
|
||||
|
||||
# System packages
|
||||
RUN apk add --no-cache \
|
||||
bash git curl wget unzip tar \
|
||||
ca-certificates openssh-client \
|
||||
build-base python3 \
|
||||
s6 tzdata
|
||||
|
||||
# Go
|
||||
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /usr/local -xz
|
||||
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||
ENV GOPATH="/go"
|
||||
ENV PATH="${GOPATH}/bin:${PATH}"
|
||||
|
||||
# Node.js + pnpm
|
||||
RUN apk add --no-cache nodejs npm && \
|
||||
npm install -g pnpm
|
||||
|
||||
# AWS CLI
|
||||
RUN curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && \
|
||||
unzip -q /tmp/awscli.zip -d /tmp && \
|
||||
/tmp/aws/install && \
|
||||
rm -rf /tmp/awscli.zip /tmp/aws
|
||||
|
||||
# Verify
|
||||
RUN go version && node --version && pnpm --version && aws --version && docker --version && git --version
|
||||
|
||||
WORKDIR /workspace
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Build and push Tinqs CI runner base image to ECR
|
||||
set -euo pipefail
|
||||
|
||||
AWS_REGION="${AWS_REGION:-eu-west-1}"
|
||||
ACCOUNT_ID="${ACCOUNT_ID:-149751500842}"
|
||||
ECR_REPO="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/tinqs-runner"
|
||||
TAG="${1:-latest}"
|
||||
|
||||
echo "Building tinqs-runner:${TAG}..."
|
||||
docker build -t "${ECR_REPO}:${TAG}" -t "${ECR_REPO}:latest" .
|
||||
|
||||
echo "Logging into ECR..."
|
||||
aws ecr get-login-password --region "${AWS_REGION}" | \
|
||||
docker login --username AWS --password-stdin "${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
|
||||
|
||||
echo "Pushing..."
|
||||
docker push "${ECR_REPO}:${TAG}"
|
||||
docker push "${ECR_REPO}:latest"
|
||||
|
||||
echo "Done: ${ECR_REPO}:${TAG}"
|
||||
Reference in New Issue
Block a user