From 4be33e33f19d8efec551632884f51aa604ff435d Mon Sep 17 00:00:00 2001 From: tinqs-limited Date: Fri, 22 May 2026 18:00:57 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20multi-image=20runners=20=E2=80=94=20go,?= =?UTF-8?q?=20node,=20docker,=20deploy,=20godot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- README.md | 58 ++++++++++++++++++++++++-------------- images/base/Dockerfile | 20 +++++++++++++ images/build-all.sh | 50 ++++++++++++++++++++++++++++++++ images/deploy/Dockerfile | 10 +++++++ images/docker/Dockerfile | 27 ++++++++++++++++++ images/go/Dockerfile | 15 ++++++++++ images/godot/Dockerfile | 27 ++++++++++++++++++ images/node/Dockerfile | 13 +++++++++ runner-image/Dockerfile | 36 ----------------------- runner-image/build-push.sh | 21 -------------- 10 files changed, 199 insertions(+), 78 deletions(-) create mode 100644 images/base/Dockerfile create mode 100644 images/build-all.sh create mode 100644 images/deploy/Dockerfile create mode 100644 images/docker/Dockerfile create mode 100644 images/go/Dockerfile create mode 100644 images/godot/Dockerfile create mode 100644 images/node/Dockerfile delete mode 100644 runner-image/Dockerfile delete mode 100644 runner-image/build-push.sh diff --git a/README.md b/README.md index 9ae82e8..15f55fa 100644 --- a/README.md +++ b/README.md @@ -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) ``` diff --git a/images/base/Dockerfile b/images/base/Dockerfile new file mode 100644 index 0000000..b8200d7 --- /dev/null +++ b/images/base/Dockerfile @@ -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 diff --git a/images/build-all.sh b/images/build-all.sh new file mode 100644 index 0000000..7f65d97 --- /dev/null +++ b/images/build-all.sh @@ -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}) ===" diff --git a/images/deploy/Dockerfile b/images/deploy/Dockerfile new file mode 100644 index 0000000..79a1be5 --- /dev/null +++ b/images/deploy/Dockerfile @@ -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 diff --git a/images/docker/Dockerfile b/images/docker/Dockerfile new file mode 100644 index 0000000..eca3fa0 --- /dev/null +++ b/images/docker/Dockerfile @@ -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 diff --git a/images/go/Dockerfile b/images/go/Dockerfile new file mode 100644 index 0000000..45f5a97 --- /dev/null +++ b/images/go/Dockerfile @@ -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 diff --git a/images/godot/Dockerfile b/images/godot/Dockerfile new file mode 100644 index 0000000..555ef28 --- /dev/null +++ b/images/godot/Dockerfile @@ -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 diff --git a/images/node/Dockerfile b/images/node/Dockerfile new file mode 100644 index 0000000..fa3da71 --- /dev/null +++ b/images/node/Dockerfile @@ -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 diff --git a/runner-image/Dockerfile b/runner-image/Dockerfile deleted file mode 100644 index ec85e3f..0000000 --- a/runner-image/Dockerfile +++ /dev/null @@ -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 diff --git a/runner-image/build-push.sh b/runner-image/build-push.sh deleted file mode 100644 index 69d3f33..0000000 --- a/runner-image/build-push.sh +++ /dev/null @@ -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}"