argo-workflows Docker & Self-Hosted Deployment

GitHub

Workflow Engine for Kubernetes

1. Pull Image (DOCKERHUB) docker pull argoproj/argo-workflows:latest
2. Docker Run (1-Click Launch) docker run -d --name argo-workflows --restart always argoproj/argo-workflows:latest
3. Podman Run podman run -d --name argo-workflows --restart always argoproj/argo-workflows:latest
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://docker.io/argoproj/argo-workflows:latest
5. ORAS Pull (OCI Artifact) oras pull argoproj/argo-workflows:latest
Dockerfile
#syntax=docker/dockerfile:1.28
ARG GIT_COMMIT=unknown
ARG GIT_TAG=unknown
ARG GIT_TREE_STATE=unknown

FROM golang:1.27.3-alpine3.23 AS builder

# libc-dev to build openapi-gen
RUN apk update && apk add --no-cache \
    git \
    make \
    ca-certificates \
    wget \
    curl \
    gcc \
    libc-dev \
    bash \
    mailcap

WORKDIR /go/src/github.com/argoproj/argo-workflows
COPY go.mod .
COPY go.sum .
RUN --mount=type=cache,target=/go/pkg/mod go mod download

COPY . .

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

# Delve debugger, copied into the `-dev` images so the controller/server/executor
# can be run under `dlv exec` when Tilt is invoked with `--debug=...`. Pinned to a
# release that supports the builder's Go toolchain. Dev-only: never used by the
# distroless production targets.
FROM builder AS dlv-build
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
    go install github.com/go-delve/delve/cmd/[email protected]

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

FROM node:20-alpine AS argo-ui

RUN apk update && apk add --no-cache git

COPY ui/package.json ui/yarn.lock ui/

RUN --mount=type=cache,target=/root/.yarn \
  YARN_CACHE_FOLDER=/root/.yarn JOBS=max \
  yarn --cwd ui install --network-timeout 1000000

COPY ui ui
COPY api api

RUN --mount=type=cache,target=/root/.yarn \
  YARN_CACHE_FOLDER=/root/.yarn JOBS=max \
  NODE_OPTIONS="--max-old-space-size=2048" JOBS=max yarn --cwd ui build

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

FROM builder AS argoexec-build

ARG GIT_COMMIT
ARG GIT_TAG
ARG GIT_TREE_STATE

RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build make dist/argoexec GIT_COMMIT=${GIT_COMMIT} GIT_TAG=${GIT_TAG} GIT_TREE_STATE=${GIT_TREE_STATE}

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

FROM builder AS workflow-controller-build

ARG GIT_COMMIT
ARG GIT_TAG
ARG GIT_TREE_STATE

RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build make dist/workflow-controller GIT_COMMIT=${GIT_COMMIT} GIT_TAG=${GIT_TAG} GIT_TREE_STATE=${GIT_TREE_STATE}

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

FROM builder AS argocli-build

ARG GIT_COMMIT
ARG GIT_TAG
ARG GIT_TREE_STATE

RUN mkdir -p ui/dist
COPY --from=argo-ui ui/dist/app ui/dist/app
# update timestamp so that `make` doesn't try to rebuild this -- it was already built in the previous stage
RUN touch ui/dist/app/index.html

RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build STATIC_FILES=true make dist/argo GIT_COMMIT=${GIT_COMMIT} GIT_TAG=${GIT_TAG} GIT_TREE_STATE=${GIT_TREE_STATE}

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

FROM gcr.io/distroless/static-debian13:latest@sha256:034df5c1737e8241f6ed6423a12e720ee0f6d6f088609ee172f98f6f2166ef5d AS argoexec-base

COPY --from=argoexec-build /etc/mime.types /etc/mime.types
COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/

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

FROM argoexec-base AS argoexec-nonroot

USER 8737

COPY --chown=8737 --from=argoexec-build /go/src/github.com/argoproj/argo-workflows/dist/argoexec /bin/

ENTRYPOINT [ "argoexec" ]

####################################################################################################
FROM argoexec-base AS argoexec

COPY --from=argoexec-build /go/src/github.com/argoproj/argo-workflows/dist/argoexec /bin/

ENTRYPOINT [ "argoexec" ]

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

FROM gcr.io/distroless/static-debian13:latest@sha256:034df5c1737e8241f6ed6423a12e720ee0f6d6f088609ee172f98f6f2166ef5d AS workflow-controller

USER 8737

COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/
COPY --chown=8737 --from=workflow-controller-build /go/src/github.com/argoproj/argo-workflows/dist/workflow-controller /bin/

ENTRYPOINT [ "workflow-controller" ]

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

FROM gcr.io/distroless/static-debian13:latest@sha256:034df5c1737e8241f6ed6423a12e720ee0f6d6f088609ee172f98f6f2166ef5d AS argocli

USER 8737

WORKDIR /home/argo

COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/
COPY --from=argocli-build /go/src/github.com/argoproj/argo-workflows/dist/argo /bin/

ENTRYPOINT [ "argo" ]

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

FROM registry.k8s.io/kubectl:v1.36.3@sha256:6e4fce3c83651edb91b74bc67701c5cd263dd8aa3cd4254b1798d6425a5ab789 AS argo-workflows-crdinstaller

USER 8737

# The base image sets no HOME, so kubectl would put its discovery cache in
# /.kube/cache, which UID 8737 cannot write. /tmp is world-writable (1777).
ENV HOME=/tmp

COPY manifests/base/crds/full/argoproj.io_*.yaml /crds/full/

CMD [ "apply", "--server-side", "--force-conflicts", "-v=6", "-f", "/crds/full/" ]

####################################################################################################
# Dev-only stages for Tilt. Small alpine base; NOT shipped to users. The
# binaries are compiled on the host (by Tilt local_resources) and COPYed from
# the build context, so each binary is built exactly once. On change Tilt
# rebuilds these (trivial COPY) and recreates the pod.

FROM alpine:3.24 AS workflow-controller-dev
RUN apk add --no-cache ca-certificates
COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/
COPY dist/workflow-controller /bin/workflow-controller
# Delve, for `tilt up -- --debug=controller` (the Tiltfile wraps the entrypoint).
COPY --from=dlv-build /go/bin/dlv /bin/dlv
# Match the prod image's non-root user so runAsNonRoot is satisfied.
USER 8737
ENTRYPOINT [ "workflow-controller" ]

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

FROM alpine:3.24 AS argocli-dev
RUN apk add --no-cache ca-certificates
WORKDIR /home/argo
COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/
COPY dist/argo /bin/argo
# Delve, for `tilt up -- --debug=server` (the Tiltfile wraps the entrypoint).
COPY --from=dlv-build /go/bin/dlv /bin/dlv
USER 8737
ENTRYPOINT [ "argo" ]

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

FROM alpine:3.24 AS argoexec-dev
RUN apk add --no-cache ca-certificates mailcap
COPY hack/ssh_known_hosts /etc/ssh/
COPY hack/nsswitch.conf /etc/
COPY dist/argoexec /bin/argoexec
USER 8737
ENTRYPOINT [ "argoexec" ]