Skip to content

Commit 3e731e7

Browse files
committed
feat(tfroot-runner): layer the actions/runner agent for gha-runner-scale-set
Stay on Alpine + the existing toolchain layer; add the GitHub Actions runner agent and the glibc-compat shims it needs (gcompat / icu / krb5 / lttng-ust). The image now self-registers with a gha-runner-scale-set listener and runs jobs natively, so callers stop nesting tfroot-runner inside a `container:` block. - Add `runner` user (UID 1000), download the runner agent tarball into /home/runner, chown. - Drop ENV HOME=/root; switch USER to `runner` before pre-commit caching so the cache lands under the runtime user's HOME. - Replace CMD with ENTRYPOINT /home/runner/run.sh.
1 parent 4584b75 commit 3e731e7

1 file changed

Lines changed: 142 additions & 89 deletions

File tree

tfroot-runner/Containerfile

Lines changed: 142 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,14 @@
1-
# Builder stage - compile Python packages with C extensions
2-
FROM alpine:3.21 AS builder
1+
# tfroot-runner — GitHub ARC runner image preloaded with the OpenTofu IaC
2+
# toolchain. Self-registers with the gha-runner-scale-set listener; jobs run
3+
# directly in the pod (no nested `container:` block).
4+
#
5+
# Layout follows the hatch1fy/infra-images/terraform-runner pattern:
6+
# Stage 1 (tools) — Ubuntu builder for binary downloads + Python venv
7+
# Stage 2 (final) — ghcr.io/actions/actions-runner base + runtime deps
38

4-
# hadolint ignore=DL3018
5-
RUN apk add --no-cache \
6-
python3 py3-pip python3-dev \
7-
build-base libffi-dev git
8-
9-
# Install Python packages that need compilation
10-
ARG CHECKOV_VERSION=3.2.525
11-
ARG PRECOMMIT_VERSION=4.6.0
12-
RUN pip install --no-cache-dir --break-system-packages --root=/install --prefix=/usr \
13-
pre-commit==${PRECOMMIT_VERSION} checkov==${CHECKOV_VERSION}
14-
15-
# Final stage
16-
FROM alpine:3.21
17-
18-
LABEL description="Alpine-based IaC runner for OpenTofu/Terraform on AMD64 architecture."
19-
20-
# Install runtime dependencies
21-
# cdrkit provides genisoimage equivalent (mkisofs)
22-
# binutils provides strip for binary size reduction
23-
# hadolint ignore=DL3018
24-
RUN apk add --no-cache \
25-
curl unzip gnupg \
26-
python3 py3-pip libffi libstdc++ \
27-
git jq yq \
28-
nodejs npm \
29-
ansible-core \
30-
openssh-client \
31-
cdrkit \
32-
bash \
33-
binutils \
34-
make
35-
36-
# Copy Python packages from builder
37-
COPY --from=builder /install /
38-
39-
# Tool versions
9+
##############################
10+
# Pinned versions — update here
11+
##############################
4012
ARG OPENTOFU_VERSION=1.11.6
4113
ARG SOPS_VERSION=3.12.2
4214
ARG TERRAFORM_DOCS_VERSION=0.22.0
@@ -45,70 +17,151 @@ ARG HCLEDIT_VERSION=0.2.17
4517
ARG TFLINT_VERSION=0.62.0
4618
ARG INFRACOST_VERSION=0.10.44
4719
ARG KUBECTL_VERSION=1.36.0
20+
ARG KUSTOMIZE_VERSION=5.8.0
21+
ARG CHECKOV_VERSION=3.2.525
22+
ARG PRECOMMIT_VERSION=4.6.0
23+
ARG PYTHON_VERSION=3.14
24+
25+
##############################
26+
# Stage 1: Build/download tools
27+
##############################
28+
FROM --platform=linux/amd64 ubuntu:24.04 AS tools
4829

49-
# Install all binary tools in a single layer, strip debug symbols, clean up
30+
ARG OPENTOFU_VERSION
31+
ARG SOPS_VERSION
32+
ARG TERRAFORM_DOCS_VERSION
33+
ARG TFUPDATE_VERSION
34+
ARG HCLEDIT_VERSION
35+
ARG TFLINT_VERSION
36+
ARG INFRACOST_VERSION
37+
ARG KUBECTL_VERSION
38+
ARG KUSTOMIZE_VERSION
39+
ARG CHECKOV_VERSION
40+
ARG PRECOMMIT_VERSION
41+
ARG PYTHON_VERSION
42+
43+
ENV DEBIAN_FRONTEND=noninteractive
44+
45+
# Build-time dependencies (Python + add-apt-repository)
46+
# hadolint ignore=DL3008
47+
RUN apt-get update && apt-get install -y --no-install-recommends \
48+
ca-certificates curl gnupg lsb-release software-properties-common unzip \
49+
&& add-apt-repository -y ppa:deadsnakes/ppa \
50+
&& apt-get update && apt-get install -y --no-install-recommends \
51+
python${PYTHON_VERSION} python${PYTHON_VERSION}-venv python${PYTHON_VERSION}-dev \
52+
build-essential libffi-dev git \
53+
&& rm -rf /var/lib/apt/lists/*
54+
55+
# Python venv with the pip-managed tools.
56+
RUN python${PYTHON_VERSION} -m venv /opt/venv \
57+
&& /opt/venv/bin/pip install --no-cache-dir \
58+
pre-commit==${PRECOMMIT_VERSION} \
59+
checkov==${CHECKOV_VERSION}
60+
61+
# Binary downloads — single layer, strip debug symbols at the end.
5062
# hadolint ignore=DL3003,DL4006
5163
RUN set -eux; \
52-
# SOPS
53-
curl -Lo /usr/local/bin/sops \
54-
"https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64"; \
55-
chmod +x /usr/local/bin/sops; \
56-
# OpenTofu (and symlink as terraform)
57-
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh | sh -s -- --install-method standalone --opentofu-version "${OPENTOFU_VERSION}"; \
64+
# OpenTofu
65+
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh \
66+
| sh -s -- --install-method standalone --opentofu-version "${OPENTOFU_VERSION}"; \
67+
# Symlink as terraform for tooling that hardcodes that name.
5868
ln -s /usr/local/bin/tofu /usr/local/bin/terraform; \
69+
# SOPS
70+
curl -fsSL "https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64" \
71+
-o /usr/local/bin/sops && chmod +x /usr/local/bin/sops; \
5972
# kubectl
60-
curl -fsSL "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl" -o /usr/local/bin/kubectl; \
61-
chmod +x /usr/local/bin/kubectl; \
62-
# Kustomize (script outputs to current directory)
63-
cd /tmp && curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash; \
64-
mv /tmp/kustomize /usr/local/bin/; \
73+
curl -fsSL "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl" \
74+
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl; \
75+
# kustomize
76+
curl -fsSL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz" \
77+
| tar xz -C /usr/local/bin kustomize; \
6578
# terraform-docs
66-
curl -sSL "https://terraform-docs.io/dl/v${TERRAFORM_DOCS_VERSION}/terraform-docs-v${TERRAFORM_DOCS_VERSION}-linux-amd64.tar.gz" | \
67-
tar xz -C /usr/local/bin terraform-docs; \
68-
chmod +x /usr/local/bin/terraform-docs; \
79+
curl -fsSL "https://terraform-docs.io/dl/v${TERRAFORM_DOCS_VERSION}/terraform-docs-v${TERRAFORM_DOCS_VERSION}-linux-amd64.tar.gz" \
80+
| tar xz -C /usr/local/bin terraform-docs && chmod +x /usr/local/bin/terraform-docs; \
6981
# tfupdate
70-
curl -sSL "https://github.com/minamijoyo/tfupdate/releases/download/v${TFUPDATE_VERSION}/tfupdate_${TFUPDATE_VERSION}_linux_amd64.tar.gz" | \
71-
tar xz -C /usr/local/bin tfupdate; \
72-
chmod +x /usr/local/bin/tfupdate; \
82+
curl -fsSL "https://github.com/minamijoyo/tfupdate/releases/download/v${TFUPDATE_VERSION}/tfupdate_${TFUPDATE_VERSION}_linux_amd64.tar.gz" \
83+
| tar xz -C /usr/local/bin tfupdate && chmod +x /usr/local/bin/tfupdate; \
7384
# hcledit
74-
curl -sSL "https://github.com/minamijoyo/hcledit/releases/download/v${HCLEDIT_VERSION}/hcledit_${HCLEDIT_VERSION}_linux_amd64.tar.gz" | \
75-
tar xz -C /usr/local/bin hcledit; \
76-
chmod +x /usr/local/bin/hcledit; \
85+
curl -fsSL "https://github.com/minamijoyo/hcledit/releases/download/v${HCLEDIT_VERSION}/hcledit_${HCLEDIT_VERSION}_linux_amd64.tar.gz" \
86+
| tar xz -C /usr/local/bin hcledit && chmod +x /usr/local/bin/hcledit; \
7787
# tflint
78-
curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | TFLINT_VERSION="v${TFLINT_VERSION}" bash; \
88+
curl -fsSL "https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/tflint_linux_amd64.zip" \
89+
-o /tmp/tflint.zip && unzip /tmp/tflint.zip -d /usr/local/bin/ && rm -f /tmp/tflint.zip; \
7990
# infracost
80-
curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | INFRACOST_VERSION="v${INFRACOST_VERSION}" sh; \
81-
# Strip debug symbols from all Go/Rust binaries
82-
strip /usr/local/bin/sops \
83-
/usr/local/bin/tofu \
91+
curl -fsSL "https://github.com/infracost/infracost/releases/download/v${INFRACOST_VERSION}/infracost-linux-amd64.tar.gz" \
92+
| tar xz -C /tmp && mv /tmp/infracost-linux-amd64 /usr/local/bin/infracost && chmod +x /usr/local/bin/infracost; \
93+
strip /usr/local/bin/tofu \
94+
/usr/local/bin/sops \
8495
/usr/local/bin/kubectl \
8596
/usr/local/bin/kustomize \
8697
/usr/local/bin/terraform-docs \
8798
/usr/local/bin/tfupdate \
8899
/usr/local/bin/hcledit \
89100
/usr/local/bin/tflint \
90-
/usr/local/bin/infracost 2>/dev/null || true; \
91-
# Clean up
92-
rm -rf /tmp/* /var/cache/apk/*
93-
94-
# Remove binutils (only needed for strip)
95-
# hadolint ignore=DL3018
96-
RUN apk del binutils
97-
98-
# Configure git safe.directory globally to handle mounted workspaces
99-
# Set in both system and user config for maximum compatibility
100-
ENV HOME=/root
101-
RUN git config --system --add safe.directory '*' && \
102-
git config --global --add safe.directory '*'
103-
104-
# Pre-cache pre-commit hooks
105-
WORKDIR /pre-commit-init
106-
COPY pre-commit-config.yaml .pre-commit-config.yaml
107-
RUN git init && \
108-
git config user.email "builder@localhost" && \
109-
git config user.name "Builder" && \
110-
pre-commit install-hooks && \
111-
rm -rf /tmp/*
112-
113-
WORKDIR /
114-
CMD ["/bin/bash"]
101+
/usr/local/bin/infracost 2>/dev/null || true
102+
103+
##############################
104+
# Stage 2: Final runner image
105+
##############################
106+
FROM --platform=linux/amd64 ghcr.io/actions/actions-runner:latest
107+
108+
ARG PYTHON_VERSION
109+
110+
LABEL org.opencontainers.image.title="tfroot-runner" \
111+
org.opencontainers.image.description="GitHub ARC runner with OpenTofu, kubectl, kustomize, sops, ansible, pre-commit, and friends." \
112+
org.opencontainers.image.source="https://github.com/makeitworkcloud/images"
113+
114+
USER root
115+
116+
ENV DEBIAN_FRONTEND=noninteractive
117+
118+
# Runtime dependencies: Python (no -dev), ansible, openssh-client, jq/yq,
119+
# genisoimage (cdrkit equivalent), gnupg, make, shellcheck, libatomic1.
120+
# libatomic1 is needed by the Node.js binary pre-commit downloads for some hooks.
121+
# hadolint ignore=DL3008
122+
RUN apt-get update && apt-get install -y --no-install-recommends \
123+
ca-certificates curl unzip software-properties-common \
124+
&& add-apt-repository -y ppa:deadsnakes/ppa \
125+
&& apt-get update && apt-get install -y --no-install-recommends \
126+
python${PYTHON_VERSION} python${PYTHON_VERSION}-venv \
127+
ansible-core openssh-client \
128+
jq genisoimage gnupg make shellcheck libatomic1 \
129+
&& update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTHON_VERSION} 1 \
130+
&& curl -fsSL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 \
131+
-o /usr/local/bin/yq && chmod +x /usr/local/bin/yq \
132+
&& apt-get clean \
133+
&& rm -rf /var/lib/apt/lists/* /usr/share/doc/* /usr/share/man/*
134+
135+
# Copy pre-built tools and the Python venv from the builder stage.
136+
COPY --from=tools /usr/local/bin/tofu /usr/local/bin/tofu
137+
COPY --from=tools /usr/local/bin/terraform /usr/local/bin/terraform
138+
COPY --from=tools /usr/local/bin/sops /usr/local/bin/sops
139+
COPY --from=tools /usr/local/bin/kubectl /usr/local/bin/kubectl
140+
COPY --from=tools /usr/local/bin/kustomize /usr/local/bin/kustomize
141+
COPY --from=tools /usr/local/bin/terraform-docs /usr/local/bin/terraform-docs
142+
COPY --from=tools /usr/local/bin/tfupdate /usr/local/bin/tfupdate
143+
COPY --from=tools /usr/local/bin/hcledit /usr/local/bin/hcledit
144+
COPY --from=tools /usr/local/bin/tflint /usr/local/bin/tflint
145+
COPY --from=tools /usr/local/bin/infracost /usr/local/bin/infracost
146+
COPY --from=tools /opt/venv /opt/venv
147+
148+
ENV PATH="/opt/venv/bin:${PATH}"
149+
150+
# git safe.directory for mounted _work volumes — system-wide covers all users.
151+
RUN git config --system --add safe.directory '*'
152+
153+
# Pre-cache pre-commit hook environments under the runner user so the cache
154+
# is owned correctly at runtime.
155+
COPY --chown=runner:runner pre-commit-config.yaml /home/runner/.pre-commit-default-config.yaml
156+
157+
USER runner
158+
159+
RUN cd /home/runner \
160+
&& git init pre-commit-cache \
161+
&& cd pre-commit-cache \
162+
&& git config user.email "builder@localhost" \
163+
&& git config user.name "Builder" \
164+
&& cp /home/runner/.pre-commit-default-config.yaml .pre-commit-config.yaml \
165+
&& pre-commit install-hooks \
166+
&& cd /home/runner \
167+
&& rm -rf pre-commit-cache

0 commit comments

Comments
 (0)