diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index f8a753bdd2e..7f221509a35 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -5,6 +5,7 @@ on: version: required: false type: string + description: "Main version to build. Does not support base version." release_type: required: true type: string @@ -26,7 +27,7 @@ on: workflow_dispatch: inputs: version: - description: "Version to build" + description: "Main version to build. Does not support base version." required: false type: string release_type: @@ -101,18 +102,49 @@ jobs: with: ref: ${{ inputs.nightly_tag_main || github.ref }} persist-credentials: true - - name: "Setup Environment" - uses: ./.github/actions/setup-uv - - name: Install the project - run: uv sync --dev - name: Get Version from Input if: ${{ inputs.version != '' }} id: get-version-input run: | - version=${{ inputs.version }} - echo version=$version - echo version=$version >> $GITHUB_OUTPUT + # Base version cannot have a version input, since you have to specify a valid main tag to checkout. + if [[ "${{ inputs.release_type }}" == "base" && "${{ inputs.version }}" != '' ]]; then + echo "Cannot specify version for base release." + echo "Build type is 'base' and version is non-empty. Exiting the workflow." + exit 1 + fi + + # If doing a nightly release, just specify the nightly tag. + if [[ "${{ inputs.version }}" != '' && "${{ steps.resolve-nightly-tag.outputs.nightly-tag }}" != '' ]]; then + echo "Cannot specify both version and nightly version." + echo "Version is specified and nightly tag is non-empty. Exiting the workflow." + exit 1 + fi + + if [[ "${{ steps.resolve-nightly-tag.outputs.nightly-tag }}" != '' ]]; then + if [[ "${{ inputs.nightly_tag_main }}" == '' ]]; then + echo "Must specify a main nightly tag to check out when building base image." + echo "Nightly tag main is empty. Exiting the workflow." + exit 1 + fi + echo "main nightly version=${{ inputs.nightly_tag_main }}" + echo "base nightly version=${{ inputs.nightly_tag_base }}" + echo "building image for nightly_version=${{ steps.resolve-nightly-tag.outputs.nightly-tag }}" + + # Strip leading v from nightly tag main if present + version=${{ inputs.nightly_tag_main }} + version=${version#v} + echo version=$version >> $GITHUB_OUTPUT + elif [[ "${{ inputs.version }}" != '' ]]; then + # strip leading v if present + version=${{ inputs.version }} + version=${version#v} + echo version=$version + echo version=$version >> $GITHUB_OUTPUT + else + echo "No version or ref specified. Exiting the workflow." + exit 1 + fi - name: Get Version Base if: ${{ inputs.version == '' && inputs.release_type == 'base' }} id: get-version-base @@ -121,7 +153,7 @@ jobs: echo version=$version echo version=$version >> $GITHUB_OUTPUT - name: Get Version Main - if: ${{ inputs.version == '' && inputs.release_type == 'main' }} + if: ${{ inputs.version == '' && (inputs.release_type == 'main' || inputs.release_type == 'main-ep') }} id: get-version-main run: | version=$(uv tree | grep 'langflow' | grep -v 'langflow-base' | awk '{print $2}' | sed 's/^v//') @@ -135,11 +167,6 @@ jobs: ghcr_tags: ${{ steps.set-vars.outputs.ghcr_tags }} file: ${{ steps.set-vars.outputs.file }} steps: - - name: Check out the code at a specific ref - uses: actions/checkout@v4 - with: - ref: ${{ inputs.nightly_tag_main || github.ref }} - - name: Set Dockerfile and Tags id: set-vars run: | @@ -149,18 +176,30 @@ jobs: fi if [[ "${{ inputs.release_type }}" == "base" ]]; then + # LANGFLOW-BASE RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:base-${{ needs.get-version.outputs.version }},langflowai/langflow${nightly_suffix}:base-latest" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:base-${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow${nightly_suffix}:base-latest" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push_base.Dockerfile" >> $GITHUB_OUTPUT else if [[ "${{ inputs.pre_release }}" == "true" ]]; then + # LANGFLOW-MAIN PRE-RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }}" >> $GITHUB_OUTPUT - else + echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT + elif [[ "${{ inputs.release_type }}" == "main-ep" ]]; then + # LANGFLOW-MAIN (ENTRYPOINT) RELEASE + echo "docker_tags=langflowai/langflow-ep${nightly_suffix}:${{ needs.get-version.outputs.version }},langflowai/langflow-ep${nightly_suffix}:latest" >> $GITHUB_OUTPUT + echo "ghcr_tags=ghcr.io/langflow-ai/langflow-ep${nightly_suffix}:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow-ep${nightly_suffix}:latest" >> $GITHUB_OUTPUT + echo "file=./docker/build_and_push_ep.Dockerfile" >> $GITHUB_OUTPUT + elif [[ "${{ inputs.release_type }}" == "main" ]]; then + # LANGFLOW-MAIN RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }},langflowai/langflow${nightly_suffix}:latest" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow${nightly_suffix}:latest" >> $GITHUB_OUTPUT + echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT + else + echo "Invalid release type. Exiting the workflow." + exit 1 fi - echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT fi build: runs-on: ubuntu-latest @@ -169,15 +208,14 @@ jobs: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ inputs.nightly_tag_main || github.ref }} + ref: ${{ needs.get-version.outputs.version || github.ref }} persist-credentials: true - name: "Setup Environment" uses: ./.github/actions/setup-uv - - name: Install the project run: | if [[ "${{ inputs.release_type }}" == "base" ]]; then - cd src/backend/base && uv sync --no-dev --no-sources + uv sync --directory src/backend/base --no-dev --no-sources else uv sync --no-dev --no-sources fi @@ -246,7 +284,7 @@ jobs: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ inputs.nightly_tag_main || github.ref }} + ref: ${{ needs.get-version.outputs.version || github.ref }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -294,7 +332,7 @@ jobs: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ inputs.nightly_tag_main || github.ref }} + ref: ${{ needs.get-version.outputs.version || github.ref }} - name: "Setup Environment" uses: ./.github/actions/setup-uv diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index afbc0518d57..8048bfc70c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,6 +24,11 @@ on: required: true type: boolean default: false + build_docker_ep: + description: "Build Docker Image for Langflow with Entrypoint" + required: false + type: boolean + default: false pre_release: description: "Pre-release" required: false @@ -203,6 +208,16 @@ jobs: pre_release: ${{ inputs.pre_release }} secrets: inherit + call_docker_build_main_ep: + name: Call Docker Build Workflow for Langflow with Entrypoint + if: inputs.build_docker_ep == true + uses: ./.github/workflows/docker-build.yml + with: + version: needs.release-main.outputs.version + release_type: main-ep + pre_release: False + secrets: inherit + create_release: name: Create Release runs-on: ubuntu-latest diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index 7f4faee8cdb..74ecdf7444a 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -14,6 +14,11 @@ on: required: true type: boolean default: false + build_docker_ep: + description: "Build Docker Image for Langflow Nightly with Entrypoint" + required: false + type: boolean + default: false nightly_tag_main: description: "Tag for the nightly main build" required: true @@ -34,6 +39,11 @@ on: required: true type: boolean default: false + build_docker_ep: + description: "Build Docker Image for Langflow Nightly with Entrypoint" + required: false + type: boolean + default: false nightly_tag_main: description: "Tag for the nightly main build" required: true @@ -197,8 +207,6 @@ jobs: needs: [release-nightly-base, release-nightly-main] uses: ./.github/workflows/docker-build.yml with: - # Version should _not_ contain the leading `v` - version: ${{ needs.release-nightly-base.outputs.version }} release_type: base nightly_tag_base: ${{ inputs.nightly_tag_base }} nightly_tag_main: ${{ inputs.nightly_tag_main }} @@ -210,10 +218,20 @@ jobs: needs: [release-nightly-main] uses: ./.github/workflows/docker-build.yml with: - # Version should _not_ contain the leading `v` - version: ${{ needs.release-nightly-main.outputs.version }} release_type: main nightly_tag_main: ${{ inputs.nightly_tag_main }} secrets: inherit + call_docker_build_main_ep: + name: Call Docker Build Workflow for Langflow with Entrypoint + if: always() && ${{ inputs.build_docker_ep == 'true' }} + needs: [release-nightly-main] + uses: ./.github/workflows/docker-build.yml + with: + release_type: main-ep + nightly_tag_main: ${{ inputs.nightly_tag_main }} + secrets: inherit + + + diff --git a/docker/build_and_push_ep.Dockerfile b/docker/build_and_push_ep.Dockerfile new file mode 100644 index 00000000000..01801e2ff64 --- /dev/null +++ b/docker/build_and_push_ep.Dockerfile @@ -0,0 +1,91 @@ +# syntax=docker/dockerfile:1 +# Keep this syntax directive! It's used to enable Docker BuildKit + +################################ +# BUILDER-BASE +# Used to build deps + create our virtual environment +################################ + +# 1. use python:3.12.3-slim as the base image until https://github.com/pydantic/pydantic-core/issues/1292 gets resolved +# 2. do not add --platform=$BUILDPLATFORM because the pydantic binaries must be resolved for the final architecture +# Use a Python image with uv pre-installed +FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder + +# Install the project into `/app` +WORKDIR /app + +# Enable bytecode compilation +ENV UV_COMPILE_BYTECODE=1 + +# Copy from the cache instead of linking since it's a mounted volume +ENV UV_LINK_MODE=copy + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + # deps for building python deps + build-essential \ + # npm + npm \ + # gcc + gcc \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=README.md,target=README.md \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + --mount=type=bind,source=src/backend/base/README.md,target=src/backend/base/README.md \ + --mount=type=bind,source=src/backend/base/uv.lock,target=src/backend/base/uv.lock \ + --mount=type=bind,source=src/backend/base/pyproject.toml,target=src/backend/base/pyproject.toml \ + uv sync --frozen --no-install-project --no-editable + +ADD ./src /app/src + +COPY src/frontend /tmp/src/frontend +WORKDIR /tmp/src/frontend +RUN --mount=type=cache,target=/root/.npm \ + npm ci \ + && npm run build \ + && cp -r build /app/src/backend/langflow/frontend \ + && rm -rf /tmp/src/frontend + +WORKDIR /app +ADD ./pyproject.toml /app/pyproject.toml +ADD ./uv.lock /app/uv.lock +ADD ./README.md /app/README.md + +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen --no-editable + +################################ +# RUNTIME +# Setup user, utilities and copy the virtual environment only +################################ +FROM python:3.12.3-slim AS runtime + +RUN useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data +COPY --from=builder --chown=1000 /app/.venv /app/.venv + +# Place executables in the environment at the front of the path +ENV PATH="/app/.venv/bin:$PATH" + +LABEL org.opencontainers.image.title=langflow +LABEL org.opencontainers.image.authors=['Langflow'] +LABEL org.opencontainers.image.licenses=MIT +LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow +LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow + +RUN useradd ragstack -u 10000 -g 0 --no-create-home --home-dir /app/data +WORKDIR /app + +RUN mkdir /data +RUN chown -R 10000:0 /data +RUN chown -R 10000:0 /app + +ENV LANGFLOW_HOST=0.0.0.0 +ENV LANGFLOW_PORT=7860 + +USER 10000 + +ENTRYPOINT ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--backend-only"] \ No newline at end of file