mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
ci: Build and publish the n8n-io/runners image on Docker hub (#19035)
This commit is contained in:
177
.github/workflows/docker-build-push.yml
vendored
177
.github/workflows/docker-build-push.yml
vendored
@@ -1,8 +1,9 @@
|
||||
# This workflow is used to build and push the Docker image for n8n
|
||||
# This workflow is used to build and push the Docker image for n8nio/n8n and n8nio/runners
|
||||
# - determine-build-context: Determines what needs to be built based on the trigger
|
||||
# - build-and-push-docker: This builds on both an ARM64 and AMD64 runner so the builds are native to the platform. Uses blacksmith native runners and build-push-action
|
||||
# - create_multi_arch_manifest: This creates the multi-arch manifest for the Docker image. Needed to recombine the images from the build-and-push-docker job since they are separate runners.
|
||||
# - security-scan: This scans the Docker image for security vulnerabilities using Trivy.
|
||||
# - security-scan: This scans the n8nio/n8n Docker image for security vulnerabilities using Trivy.
|
||||
# - security-scan-runners: This scans the n8nio/runners Docker image for security vulnerabilities using Trivy.
|
||||
|
||||
name: 'Docker: Build and Push'
|
||||
|
||||
@@ -49,6 +50,7 @@ on:
|
||||
paths:
|
||||
- '.github/workflows/docker-build-push.yml'
|
||||
- 'docker/images/n8n/Dockerfile'
|
||||
- 'docker/images/runners/Dockerfile'
|
||||
|
||||
jobs:
|
||||
determine-build-context:
|
||||
@@ -168,6 +170,7 @@ jobs:
|
||||
outputs:
|
||||
image_ref: ${{ steps.determine-tags.outputs.primary_ghcr_manifest_tag }}
|
||||
primary_ghcr_manifest_tag: ${{ steps.determine-tags.outputs.primary_ghcr_manifest_tag }}
|
||||
runners_primary_ghcr_manifest_tag: ${{ steps.determine-runners-tags.outputs.primary_ghcr_manifest_tag }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
@@ -260,6 +263,69 @@ jobs:
|
||||
echo "primary_ghcr_manifest_tag=${PRIMARY_GHCR_MANIFEST_TAG_VALUE}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Determine Docker tags (runners)
|
||||
id: determine-runners-tags
|
||||
run: |
|
||||
RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}"
|
||||
N8N_VERSION_TAG="${{ needs.determine-build-context.outputs.n8n_version }}"
|
||||
GHCR_BASE="ghcr.io/${{ github.repository_owner }}/runners"
|
||||
DOCKER_BASE="${{ secrets.DOCKER_USERNAME }}/runners"
|
||||
PLATFORM="${{ matrix.platform }}"
|
||||
|
||||
GHCR_TAGS_FOR_PUSH=""
|
||||
DOCKER_TAGS_FOR_PUSH=""
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE=""
|
||||
|
||||
case "$RELEASE_TYPE" in
|
||||
"stable")
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE="${GHCR_BASE}:${N8N_VERSION_TAG}"
|
||||
GHCR_TAGS_FOR_PUSH="${PRIMARY_GHCR_MANIFEST_TAG_VALUE}-${PLATFORM}"
|
||||
DOCKER_TAGS_FOR_PUSH="${DOCKER_BASE}:${N8N_VERSION_TAG}-${PLATFORM}"
|
||||
;;
|
||||
"nightly")
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE="${GHCR_BASE}:nightly"
|
||||
GHCR_TAGS_FOR_PUSH="${PRIMARY_GHCR_MANIFEST_TAG_VALUE}-${PLATFORM}"
|
||||
DOCKER_TAGS_FOR_PUSH="${DOCKER_BASE}:nightly-${PLATFORM}"
|
||||
;;
|
||||
"branch")
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE="${GHCR_BASE}:${N8N_VERSION_TAG}"
|
||||
GHCR_TAGS_FOR_PUSH="${PRIMARY_GHCR_MANIFEST_TAG_VALUE}-${PLATFORM}"
|
||||
DOCKER_TAGS_FOR_PUSH="" # mirror n8n logic: no Docker Hub for branch
|
||||
;;
|
||||
"dev"|*)
|
||||
if [[ "$N8N_VERSION_TAG" == pr-* ]]; then
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE="${GHCR_BASE}:${N8N_VERSION_TAG}"
|
||||
GHCR_TAGS_FOR_PUSH="${PRIMARY_GHCR_MANIFEST_TAG_VALUE}-${PLATFORM}"
|
||||
DOCKER_TAGS_FOR_PUSH=""
|
||||
else
|
||||
PRIMARY_GHCR_MANIFEST_TAG_VALUE="${GHCR_BASE}:dev"
|
||||
GHCR_TAGS_FOR_PUSH="${PRIMARY_GHCR_MANIFEST_TAG_VALUE}-${PLATFORM}"
|
||||
DOCKER_TAGS_FOR_PUSH="${DOCKER_BASE}:dev-${PLATFORM}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
ALL_TAGS="${GHCR_TAGS_FOR_PUSH}"
|
||||
if [[ -n "$DOCKER_TAGS_FOR_PUSH" ]]; then
|
||||
ALL_TAGS="${ALL_TAGS}\n${DOCKER_TAGS_FOR_PUSH}"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "tags<<EOF"
|
||||
echo -e "$ALL_TAGS"
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
{
|
||||
echo "ghcr_platform_tag=${GHCR_TAGS_FOR_PUSH}"
|
||||
echo "dockerhub_platform_tag=${DOCKER_TAGS_FOR_PUSH}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Only output manifest tags from the first platform to avoid duplicates
|
||||
if [[ "$PLATFORM" == "amd64" ]]; then
|
||||
echo "primary_ghcr_manifest_tag=${PRIMARY_GHCR_MANIFEST_TAG_VALUE}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
|
||||
@@ -271,14 +337,16 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: needs.determine-build-context.outputs.push_enabled == 'true' && steps.determine-tags.outputs.dockerhub_platform_tag != ''
|
||||
- name: Login to Docker Hub
|
||||
if: needs.determine-build-context.outputs.push_enabled == 'true' && (
|
||||
steps.determine-tags.outputs.dockerhub_platform_tag != '' ||
|
||||
steps.determine-runners-tags.outputs.dockerhub_platform_tag != '')
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
- name: Build and push n8n Docker image
|
||||
uses: useblacksmith/build-push-action@574eb0ee0b59c6a687ace24192f0727dfb65d6d7 # v1.2
|
||||
with:
|
||||
context: .
|
||||
@@ -293,6 +361,22 @@ jobs:
|
||||
push: ${{ needs.determine-build-context.outputs.push_enabled == 'true' }}
|
||||
tags: ${{ steps.determine-tags.outputs.tags }}
|
||||
|
||||
- name: Build and push task runners Docker image
|
||||
uses: useblacksmith/build-push-action@574eb0ee0b59c6a687ace24192f0727dfb65d6d7 # v1.2
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/images/runners/Dockerfile
|
||||
build-args: |
|
||||
NODE_VERSION=22.19
|
||||
PYTHON_VERSION=3.13
|
||||
N8N_VERSION=${{ needs.determine-build-context.outputs.n8n_version }}
|
||||
N8N_RELEASE_TYPE=${{ needs.determine-build-context.outputs.release_type }}
|
||||
platforms: ${{ matrix.docker_platform }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
push: ${{ needs.determine-build-context.outputs.push_enabled == 'true' }}
|
||||
tags: ${{ steps.determine-runners-tags.outputs.tags }}
|
||||
|
||||
create_multi_arch_manifest:
|
||||
name: Create Multi-Arch Manifest
|
||||
needs: [determine-build-context, build-and-push-docker]
|
||||
@@ -347,8 +431,45 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Determine Docker Hub manifest tag (runners)
|
||||
id: dockerhub_runners_check
|
||||
run: |
|
||||
RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}"
|
||||
N8N_VERSION="${{ needs.determine-build-context.outputs.n8n_version }}"
|
||||
DOCKER_BASE="${{ secrets.DOCKER_USERNAME }}/runners"
|
||||
|
||||
# Determine if Docker Hub manifest is needed and construct the tag
|
||||
case "$RELEASE_TYPE" in
|
||||
"stable")
|
||||
{
|
||||
echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:${N8N_VERSION}"
|
||||
echo "CREATE_DOCKERHUB_MANIFEST=true"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"nightly")
|
||||
{
|
||||
echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:nightly"
|
||||
echo "CREATE_DOCKERHUB_MANIFEST=true"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"dev")
|
||||
if [[ "$N8N_VERSION" != pr-* ]]; then
|
||||
{
|
||||
echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:dev"
|
||||
echo "CREATE_DOCKERHUB_MANIFEST=true"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true'
|
||||
if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true' ||
|
||||
steps.dockerhub_runners_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true'
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
@@ -374,6 +495,26 @@ jobs:
|
||||
${MANIFEST_TAG}-arm64
|
||||
fi
|
||||
|
||||
- name: Create GHCR multi-arch manifest (runners)
|
||||
if: needs.build-and-push-docker.outputs.runners_primary_ghcr_manifest_tag != ''
|
||||
run: |
|
||||
MANIFEST_TAG="${{ needs.build-and-push-docker.outputs.runners_primary_ghcr_manifest_tag }}"
|
||||
RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}"
|
||||
|
||||
echo "Creating GHCR runners manifest: $MANIFEST_TAG"
|
||||
|
||||
# For branch builds, only AMD64 is built
|
||||
if [[ "$RELEASE_TYPE" == "branch" ]]; then
|
||||
docker buildx imagetools create \
|
||||
--tag $MANIFEST_TAG \
|
||||
${MANIFEST_TAG}-amd64
|
||||
else
|
||||
docker buildx imagetools create \
|
||||
--tag $MANIFEST_TAG \
|
||||
${MANIFEST_TAG}-amd64 \
|
||||
${MANIFEST_TAG}-arm64
|
||||
fi
|
||||
|
||||
- name: Create Docker Hub multi-arch manifest
|
||||
if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true'
|
||||
run: |
|
||||
@@ -386,6 +527,18 @@ jobs:
|
||||
${MANIFEST_TAG}-amd64 \
|
||||
${MANIFEST_TAG}-arm64
|
||||
|
||||
- name: Create Docker Hub multi-arch manifest (runners)
|
||||
if: steps.dockerhub_runners_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true'
|
||||
run: |
|
||||
MANIFEST_TAG="${{ steps.dockerhub_runners_check.outputs.DOCKER_MANIFEST_TAG }}"
|
||||
|
||||
echo "Creating Docker Hub manifest: $MANIFEST_TAG"
|
||||
|
||||
docker buildx imagetools create \
|
||||
--tag $MANIFEST_TAG \
|
||||
${MANIFEST_TAG}-amd64 \
|
||||
${MANIFEST_TAG}-arm64
|
||||
|
||||
call-success-url:
|
||||
name: Call Success URL
|
||||
needs: [create_multi_arch_manifest]
|
||||
@@ -412,3 +565,15 @@ jobs:
|
||||
with:
|
||||
image_ref: ${{ needs.build-and-push-docker.outputs.image_ref }}
|
||||
secrets: inherit
|
||||
|
||||
security-scan-runners:
|
||||
name: Security Scan (runners)
|
||||
needs: [determine-build-context, build-and-push-docker]
|
||||
if: |
|
||||
success() &&
|
||||
(needs.determine-build-context.outputs.release_type == 'stable' ||
|
||||
needs.determine-build-context.outputs.release_type == 'nightly')
|
||||
uses: ./.github/workflows/security-trivy-scan-callable.yml
|
||||
with:
|
||||
image_ref: ${{ needs.build-and-push-docker.outputs.runners_primary_ghcr_manifest_tag }}
|
||||
secrets: inherit
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
ARG PYTHON_IMAGE=python:3.13-slim
|
||||
ARG NODE_VERSION=22.19
|
||||
ARG PYTHON_VERSION=3.13
|
||||
|
||||
# ==============================================================================
|
||||
# STAGE 1: JavaScript runner (@n8n/task-runner) artifact from CI
|
||||
@@ -8,25 +9,21 @@ COPY ./dist/task-runner-javascript /app/task-runner-javascript
|
||||
|
||||
# ==============================================================================
|
||||
# STAGE 2: Python runner build (@n8n/task-runner-python) with uv
|
||||
# Produces a relocatable venv tied to PYTHON_IMAGE
|
||||
# Produces a relocatable venv tied to the python version used
|
||||
# ==============================================================================
|
||||
FROM ${PYTHON_IMAGE} AS python-runner-builder
|
||||
FROM python:${PYTHON_VERSION}-alpine AS python-runner-builder
|
||||
ARG TARGETPLATFORM
|
||||
ARG UV_VERSION=0.8.14
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl ca-certificates build-essential pkg-config git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN set -e; \
|
||||
case "$TARGETPLATFORM" in \
|
||||
"linux/amd64") UV_ARCH="x86_64-unknown-linux-gnu" ;; \
|
||||
"linux/arm64") UV_ARCH="aarch64-unknown-linux-gnu" ;; \
|
||||
"linux/amd64") UV_ARCH="x86_64-unknown-linux-musl" ;; \
|
||||
"linux/arm64") UV_ARCH="aarch64-unknown-linux-musl" ;; \
|
||||
*) echo "Unsupported platform: $TARGETPLATFORM" >&2; exit 1 ;; \
|
||||
esac; \
|
||||
mkdir -p /tmp/uv && cd /tmp/uv; \
|
||||
curl -fsSLO "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${UV_ARCH}.tar.gz"; \
|
||||
curl -fsSLO "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${UV_ARCH}.tar.gz.sha256"; \
|
||||
wget -q "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${UV_ARCH}.tar.gz"; \
|
||||
wget -q "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${UV_ARCH}.tar.gz.sha256"; \
|
||||
sha256sum -c "uv-${UV_ARCH}.tar.gz.sha256"; \
|
||||
tar -xzf "uv-${UV_ARCH}.tar.gz"; \
|
||||
install -m 0755 "uv-${UV_ARCH}/uv" /usr/local/bin/uv; \
|
||||
@@ -74,10 +71,14 @@ RUN set -e; \
|
||||
cd / && rm -rf /launcher-temp
|
||||
|
||||
# ==============================================================================
|
||||
# STAGE 4: Runtime
|
||||
# STAGE 4: Node alpine base for JS task runner
|
||||
# ==============================================================================
|
||||
FROM ${PYTHON_IMAGE} AS runtime
|
||||
ARG NODE_VERSION=22
|
||||
FROM node:${NODE_VERSION}-alpine AS node-alpine
|
||||
|
||||
# ==============================================================================
|
||||
# STAGE 5: Runtime
|
||||
# ==============================================================================
|
||||
FROM python:${PYTHON_VERSION}-alpine AS runtime
|
||||
ARG N8N_VERSION=snapshot
|
||||
ARG N8N_RELEASE_TYPE=dev
|
||||
|
||||
@@ -85,20 +86,17 @@ ENV NODE_ENV=production
|
||||
ENV N8N_RELEASE_TYPE=${N8N_RELEASE_TYPE}
|
||||
ENV SHELL=/bin/sh
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl gnupg ca-certificates tini \
|
||||
&& mkdir -p /etc/apt/keyrings \
|
||||
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
|
||||
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_VERSION}.x nodistro main" \
|
||||
> /etc/apt/sources.list.d/nodesource.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& apt-get remove curl -y \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb
|
||||
# Copy over node from node alpine
|
||||
COPY --from=node-alpine /usr/local/bin/node /usr/local/bin/node
|
||||
COPY --from=node-alpine /usr/local/bin/npm /usr/local/bin/npm
|
||||
COPY --from=node-alpine /usr/local/bin/npx /usr/local/bin/npx
|
||||
COPY --from=node-alpine /usr/local/lib/node_modules /usr/local/lib/node_modules
|
||||
|
||||
RUN useradd -m -u 1000 runner
|
||||
# Node needs libstdc++
|
||||
RUN apk add --no-cache ca-certificates tini libstdc++
|
||||
|
||||
RUN addgroup -g 1000 -S runner \
|
||||
&& adduser -u 1000 -S -G runner -h /home/runner -D runner
|
||||
WORKDIR /home/runner
|
||||
|
||||
COPY --from=app-artifact-processor /app/task-runner-javascript /opt/runners/task-runner-javascript
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"runner-type": "javascript",
|
||||
"workdir": "/home/runner",
|
||||
"command": "/usr/bin/node",
|
||||
"command": "/usr/local/bin/node",
|
||||
"args": [
|
||||
"--disallow-code-generation-from-strings",
|
||||
"--disable-proto=delete",
|
||||
@@ -13,8 +13,10 @@
|
||||
"allowed-env": [
|
||||
"PATH",
|
||||
"GENERIC_TIMEZONE",
|
||||
"N8N_RUNNERS_MAX_CONCURRENCY",
|
||||
"NODE_OPTIONS",
|
||||
"N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT",
|
||||
"N8N_RUNNERS_TASK_TIMEOUT",
|
||||
"N8N_RUNNERS_MAX_CONCURRENCY",
|
||||
"N8N_SENTRY_DSN",
|
||||
"N8N_VERSION",
|
||||
"ENVIRONMENT",
|
||||
@@ -35,13 +37,18 @@
|
||||
"allowed-env": [
|
||||
"PATH",
|
||||
"N8N_RUNNERS_LAUNCHER_LOG_LEVEL",
|
||||
"N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT",
|
||||
"N8N_RUNNERS_TASK_TIMEOUT",
|
||||
"N8N_RUNNERS_MAX_CONCURRENCY",
|
||||
"N8N_SENTRY_DSN",
|
||||
"N8N_VERSION",
|
||||
"ENVIRONMENT",
|
||||
"DEPLOYMENT_NAME"
|
||||
],
|
||||
"env-overrides": {
|
||||
"PYTHONPATH": "/opt/runners/task-runner-python"
|
||||
"PYTHONPATH": "/opt/runners/task-runner-python",
|
||||
"N8N_RUNNERS_STDLIB_ALLOW": "",
|
||||
"N8N_RUNNERS_EXTERNAL_ALLOW": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user