1- # Dockerfile template for Droq nodes
2- # This is an agnostic template - customize as needed for your node
1+ # syntax=docker/dockerfile:1
2+ # Dockerfile for LFX Tool Executor Node
3+ # Build from repo root: docker build -f Dockerfile -t droqai/lfx-tool-executor-node:latest .
34
4- FROM python:3.11-slim
5+ # ###############################
6+ # BUILDER STAGE
7+ # Build dependencies and Langflow
8+ # ###############################
9+ FROM ghcr.io/astral-sh/uv:python3.12-alpine AS builder
10+
11+ # Install build dependencies
12+ # Retry on failure to handle transient network issues
13+ RUN set -e; \
14+ for i in 1 2 3; do \
15+ apk update && \
16+ apk add --no-cache \
17+ build-base \
18+ libaio-dev \
19+ linux-headers && \
20+ break || sleep 5; \
21+ done
522
6- # Set working directory
723WORKDIR /app
824
9- # Install system dependencies
10- # Uncomment and add system packages as needed:
11- # RUN apt-get update && apt-get install -y \
12- # gcc \
13- # g++ \
14- # make \
15- # curl \
16- # && rm -rf /var/lib/apt/lists/*
17-
18- # Install uv
19- COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
20-
21- # Copy dependency files and source code
22- COPY pyproject.toml README.md ./
23- COPY uv.lock* ./
24- COPY src/ ./src/
25- COPY lfx /app/lfx
25+ # Enable bytecode compilation
26+ ENV UV_COMPILE_BYTECODE=1
27+ ENV UV_LINK_MODE=copy
28+
29+ # Copy dependency files first (for better caching)
30+ # Copy uv.lock file to use the same dependency resolution as local setup
31+ COPY uv.lock /app/uv.lock
32+ COPY pyproject.toml /app/pyproject.toml
33+ COPY README.md /app/README.md
34+
35+ # Copy Langflow dependency files
36+ COPY lfx/pyproject.toml /app/lfx/pyproject.toml
37+ COPY lfx/README.md /app/lfx/README.md
38+
39+ # Copy Langflow source (needed for installation)
40+ COPY lfx/src /app/lfx/src
41+
42+ # Copy executor node source
43+ COPY src/node /app/src/node
44+
45+ # Create venv first
46+ RUN --mount=type=cache,target=/root/.cache/uv \
47+ uv venv
48+
49+ # Install lfx package FIRST to pin langchain-core<1.0.0 (which has langchain_core.memory)
50+ # This ensures langchain_core.memory is available before any other packages
51+ RUN --mount=type=cache,target=/root/.cache/uv \
52+ cd /app/lfx && \
53+ uv pip install --python /app/.venv/bin/python --no-cache -e .
54+
55+ # Explicitly pin langchain-core to <1.0.0 to prevent any upgrades
56+ # This is critical - langchain-core>=1.0.0 doesn't have langchain_core.memory
57+ RUN --mount=type=cache,target=/root/.cache/uv \
58+ uv pip install --python /app/.venv/bin/python --no-cache \
59+ "langchain-core>=0.3.66,<1.0.0" --force-reinstall
60+
61+ # Install langchain package which provides langchain_core.memory
62+ RUN --mount=type=cache,target=/root/.cache/uv \
63+ uv pip install --python /app/.venv/bin/python --no-cache \
64+ "langchain~=0.3.23"
65+
66+ # Now sync other dependencies from lock file (executor node dependencies)
67+ RUN --mount=type=cache,target=/root/.cache/uv \
68+ uv sync --frozen --no-dev || echo "Warning: Some dependencies may conflict, continuing..."
69+
70+ # Install the executor node package itself (editable install like local)
71+ # Note: langchain-chroma and langchain-docling may fail on Alpine aarch64 due to missing wheels
72+ # Install package without these problematic dependencies first, then try to install them separately (allow failure)
73+ RUN --mount=type=cache,target=/root/.cache/uv \
74+ cd /app && \
75+ uv pip install --python /app/.venv/bin/python --no-cache -e . --no-deps && \
76+ uv pip install --python /app/.venv/bin/python --no-cache \
77+ "fastapi>=0.115.0,<1.0.0" \
78+ "uvicorn[standard]>=0.34.0,<1.0.0" \
79+ "pydantic>=2.0.0,<3.0.0" \
80+ "python-dotenv>=1.0.0,<2.0.0" \
81+ "structlog>=25.0.0,<26.0.0" \
82+ "nats-py>=2.6.0,<3.0.0" \
83+ "httpx>=0.27.0,<1.0.0" \
84+ "langchain-core>=0.3.79,<0.4.0" \
85+ "langchain==0.3.23" \
86+ "langchain-anthropic==0.3.14" \
87+ "langchain-astradb>=0.6.1,<1.0.0" \
88+ "langchain-aws==0.2.33" \
89+ "langchain-cohere==0.3.3" \
90+ "langchain-community>=0.3.21,<1.0.0" \
91+ "langchain-elasticsearch==0.3.0" \
92+ "langchain-google-calendar-tools==0.0.1" \
93+ "langchain-google-community==2.0.3" \
94+ "langchain-google-genai==2.0.6" \
95+ "langchain-google-vertexai>=2.0.7,<3.0.0" \
96+ "langchain-graph-retriever==0.8.0" \
97+ "langchain-groq==0.2.1" \
98+ "langchain-huggingface==0.3.1" \
99+ "langchain-milvus==0.1.7" \
100+ "langchain-mistralai==0.2.3" \
101+ "langchain-mongodb==0.7.0" \
102+ "langchain-nvidia-ai-endpoints==0.3.8" \
103+ "langchain-ollama==0.2.1" \
104+ "langchain-openai>=0.2.12,<1.0.0" \
105+ "langchain-pinecone>=0.2.8,<1.0.0" \
106+ "langchain-sambanova==0.1.0" \
107+ "langchain-unstructured>=0.1.5" \
108+ "langchain-ibm>=0.3.8" \
109+ "nanoid>=2.0.0" && \
110+ (uv pip install --python /app/.venv/bin/python --no-cache "langchain-chroma>=0.2.6,<1.0.0" || \
111+ echo "Warning: langchain-chroma installation failed (onnxruntime may not have Python 3.12 wheels for Alpine aarch64)" ) && \
112+ (uv pip install --python /app/.venv/bin/python --no-cache "langchain-docling>=1.1.0" || \
113+ echo "Warning: langchain-docling installation failed (torch may not have Python 3.12 wheels for Alpine aarch64)" )
114+
115+ # Install langchain integration packages compatible with langchain-core<1.0.0
116+ # Pin versions to match local working installation (langchain-core 0.3.79, pydantic 2.12.4)
117+ RUN --mount=type=cache,target=/root/.cache/uv \
118+ uv pip install --python /app/.venv/bin/python --no-cache \
119+ "langchain-openai==0.2.14" \
120+ "langchain-anthropic>=0.1.13,<0.2.0" \
121+ "langchain-community>=0.0.38,<0.1.0" \
122+ "langchain-google-genai>=0.0.6,<0.1.0" \
123+ "langchain-ollama>=0.3.5,<0.4.0" || echo "Warning: Some langchain packages failed to install"
124+
125+ # Re-pin langchain-core after installing integration packages (they might try to upgrade it)
126+ RUN --mount=type=cache,target=/root/.cache/uv \
127+ uv pip install --python /app/.venv/bin/python --no-cache \
128+ "langchain-core>=0.3.66,<1.0.0" --force-reinstall
129+
130+ # Re-install langchain package after re-pinning langchain-core (uv sync or re-pin might have removed it)
131+ RUN --mount=type=cache,target=/root/.cache/uv \
132+ uv pip install --python /app/.venv/bin/python --no-cache \
133+ "langchain~=0.3.23" || echo "Warning: langchain installation failed"
134+
135+ # Re-install langchain-openai after re-pinning to ensure compatibility with langchain-core<1.0.0
136+ RUN --mount=type=cache,target=/root/.cache/uv \
137+ uv pip install --python /app/.venv/bin/python --no-cache \
138+ "langchain-openai==0.2.14" --force-reinstall || echo "Warning: langchain-openai re-installation failed"
139+
140+ # Ensure all lfx dependencies are installed (some might not be in the lock file)
141+ # NOTE: aiofile and aiofiles are DIFFERENT packages - both are required!
142+ # Also ensure langchain is installed (required by AgentComponent and other components)
143+ RUN --mount=type=cache,target=/root/.cache/uv \
144+ uv pip install --python /app/.venv/bin/python --no-cache \
145+ "langchain~=0.3.23" \
146+ "nanoid>=2.0.0,<3.0.0" \
147+ "platformdirs>=4.3.8,<5.0.0" \
148+ "aiofile>=3.8.0,<4.0.0" \
149+ "aiofiles>=24.1.0,<25.0.0" \
150+ "pillow>=10.0.0,<13.0.0" \
151+ "emoji>=2.0.0,<3.0.0" \
152+ "asyncer>=0.0.8,<1.0.0" \
153+ "cachetools>=5.5.2,<6.0.0" \
154+ "chardet>=5.2.0,<6.0.0" \
155+ "defusedxml>=0.7.1,<1.0.0" \
156+ "docstring-parser>=0.16,<1.0.0" \
157+ "json-repair>=0.30.3,<1.0.0" \
158+ "loguru>=0.7.3,<1.0.0" \
159+ "networkx>=3.4.2,<4.0.0" \
160+ "orjson>=3.10.15,<4.0.0" \
161+ "passlib>=1.7.4,<2.0.0" \
162+ "pydantic>=2.12.4,<3.0.0" \
163+ "pydantic-settings>=2.10.1,<3.0.0" \
164+ "rich>=13.0.0,<14.0.0" \
165+ "tomli>=2.2.1,<3.0.0" \
166+ "typer>=0.16.0,<1.0.0" \
167+ "typing-extensions>=4.14.0,<5.0.0" \
168+ "validators>=0.34.0,<1.0.0" \
169+ "qdrant-client>=1.15.1,<2.0.0"
170+
171+ # Install langchain-experimental for PythonREPLComponent and other experimental features
172+ RUN --mount=type=cache,target=/root/.cache/uv \
173+ uv pip install --python /app/.venv/bin/python --no-cache \
174+ "langchain-experimental>=0.0.50,<1.0.0" || echo "Warning: langchain-experimental installation failed"
175+
176+ # Re-pin langchain-core after langchain-experimental (it might have upgraded langchain-core to >=1.0.0)
177+ RUN --mount=type=cache,target=/root/.cache/uv \
178+ uv pip install --python /app/.venv/bin/python --no-cache \
179+ "langchain-core>=0.3.66,<1.0.0" --force-reinstall
180+
181+ # Copy node.json mapping file and startup script
26182COPY node.json /app/node.json
183+ COPY start-local.sh /app/start-local.sh
184+
185+ # ###############################
186+ # RUNTIME STAGE
187+ # Minimal runtime image
188+ # ###############################
189+ FROM python:3.12-alpine AS runtime
27190
28- # Install project dependencies
29- RUN uv pip install --system --no-cache -e .
191+ # Install runtime dependencies with retry (including bash for start-local.sh)
192+ RUN set -e; \
193+ for i in 1 2 3; do \
194+ apk update && \
195+ apk add --no-cache curl bash && \
196+ break || sleep 5; \
197+ done
30198
31- # Create non-root user for security
32- RUN useradd -m -u 1000 nodeuser && chown -R nodeuser:nodeuser /app
33- USER nodeuser
199+ # Create non-root user
200+ RUN adduser -D -u 1000 -G root -h /app -s /sbin/nologin executor
201+
202+ WORKDIR /app
203+
204+ # Copy the virtual environment from builder (created by uv sync)
205+ # This ensures all dependencies are installed exactly as in local setup
206+ COPY --from=builder --chown=executor:root /app/.venv /app/.venv
207+
208+ # Copy application code
209+ # Copy node package to /app/node (so "import node" works)
210+ COPY --from=builder --chown=executor:root /app/src/node /app/node
211+ COPY --from=builder --chown=executor:root /app/lfx/src /app/lfx/src
212+ COPY --from=builder --chown=executor:root /app/node.json /node.json
213+ COPY --from=builder --chown=executor:root /app/README.md /app/README.md
214+ COPY --from=builder --chown=executor:root /app/pyproject.toml /app/pyproject.toml
215+ COPY --from=builder /app/start-local.sh /app/start-local.sh
216+
217+ # Add venv to PATH so Python uses the venv's packages
218+ ENV PATH="/app/.venv/bin:$PATH"
219+
220+ # Make startup script executable and verify it exists (as root, before switching users)
221+ RUN chmod +x /app/start-local.sh && \
222+ chown executor:root /app/start-local.sh && \
223+ ls -la /app/start-local.sh
34224
35225# Set environment variables
36- ENV PYTHONPATH=/app/lfx/src :/app/src
226+ ENV PYTHONPATH=/app:/app/lfx /src
37227ENV PYTHONUNBUFFERED=1
228+ ENV HOST=0.0.0.0
229+ ENV PORT=8005
230+ ENV LANGFLOW_EXECUTOR_NODE_URL=http://localhost:8005
231+ ENV DOCKER_CONTAINER=1
232+ ENV RELOAD=false
233+
234+ # Switch to non-root user
235+ USER executor
38236
39- # Optional: Health check
40- # Uncomment and customize as needed:
41- # HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
42- # CMD python -c "import sys; sys.exit(0)"
237+ # Expose port
238+ EXPOSE 8005
43239
44- # Run the node
45- CMD ["uv" , "run" , "lfx-tool-executor-node" ]
240+ # Health check
241+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
242+ CMD curl -f http://localhost:8005/health || exit 1
46243
244+ # Run the executor node using start-local.sh
245+ CMD ["/bin/bash" , "./start-local.sh" ]
0 commit comments