Skip to content

Commit 2bf6564

Browse files
committed
code cleanup
Signed-off-by: Niels Bantilan <niels.bantilan@gmail.com>
1 parent 04f5cfa commit 2bf6564

File tree

5 files changed

+81
-133
lines changed

5 files changed

+81
-133
lines changed

examples/genai/n8n/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ Create postgres database credentials
77
```bash
88
flyte create secret n8n_postgres_password --value <password>
99
flyte create secret n8n_postgres_host --value <host>
10+
flyte create secret n8n_encryption_key --value <encryption_key>
1011
```

examples/genai/n8n/n8n_app.py

Lines changed: 74 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,166 +1,109 @@
11
import flyte
22
import flyte.app
3-
from flyte.app.extras import FastAPIAppEnvironment
43
import pathlib
54

65
import kubernetes
76

8-
from fastapi import FastAPI
9-
10-
11-
N8N_VERSION = "2.4.8"
12-
N8N_RUNNERS_AUTH_TOKEN = "your-secret-here"
13-
14-
n8n_with_runner_pod_template = flyte.PodTemplate(
15-
primary_container_name="app",
16-
pod_spec=kubernetes.client.V1PodSpec(
17-
containers=[
18-
# Primary container: n8n main server
19-
kubernetes.client.V1Container(
20-
name="app",
21-
image=f"n8nio/n8n:{N8N_VERSION}",
22-
ports=[
23-
kubernetes.client.V1ContainerPort(container_port=5678),
24-
],
25-
env=[
26-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_ENABLED", value="true"),
27-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_MODE", value="external"),
28-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_BROKER_LISTEN_ADDRESS", value="0.0.0.0"),
29-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_AUTH_TOKEN", value=N8N_RUNNERS_AUTH_TOKEN),
30-
kubernetes.client.V1EnvVar(name="N8N_NATIVE_PYTHON_RUNNER", value="true"),
31-
],
32-
# volume_mounts=[
33-
# kubernetes.client.V1VolumeMount(
34-
# name="n8n-data",
35-
# mount_path="/home/node/.n8n",
36-
# ),
37-
# ],
38-
),
39-
# Sidecar container: task runners
40-
kubernetes.client.V1Container(
41-
name="task-runners",
42-
# image=f"n8nio/runners:{N8N_VERSION}",
43-
image="ghcr.io/flyteorg/n8n-task-runner-image:896c4478822858a314074b1a3caf882a",
44-
env=[
45-
# Connect to n8n broker via localhost since they're in the same pod
46-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_TASK_BROKER_URI", value="http://localhost:5679"),
47-
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_AUTH_TOKEN", value=N8N_RUNNERS_AUTH_TOKEN),
48-
],
49-
),
50-
],
51-
# volumes=[
52-
# kubernetes.client.V1Volume(
53-
# name="n8n-data",
54-
# empty_dir=kubernetes.client.V1EmptyDirVolumeSource(),
55-
# ),
56-
# ],
7+
8+
def n8n_pod_template(version: str, runner_auth_token: str, runner_image_uri: str | None = None) -> flyte.PodTemplate:
9+
return flyte.PodTemplate(
10+
primary_container_name="app",
11+
pod_spec=kubernetes.client.V1PodSpec(
12+
containers=[
13+
# Primary container: n8n main server
14+
kubernetes.client.V1Container(name="app", image=f"n8nio/n8n:{version}"),
15+
# Sidecar container: task runners
16+
kubernetes.client.V1Container(
17+
name="task-runners",
18+
image=runner_image_uri or f"n8nio/runners:{version}",
19+
env=[
20+
# Connect to n8n broker via localhost since they're in the same pod
21+
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_TASK_BROKER_URI", value="http://127.0.0.1:5679"),
22+
kubernetes.client.V1EnvVar(name="N8N_RUNNERS_AUTH_TOKEN", value=runner_auth_token),
23+
],
24+
),
25+
],
26+
)
5727
)
58-
)
5928

6029

61-
# TODO:
62-
# - ✅ Add postgres database for user data persistence
63-
# - Set up external runners here: https://docs.n8n.io/hosting/configuration/task-runners/#setting-up-external-mode
64-
# - Support python nodes: https://docs.n8n.io/code/code-node/#python-native
65-
# - Add support for Flyte nodes: https://docs.n8n.io/hosting/configuration/task-runners/#adding-extra-dependencies
66-
n8n_app_image = (
67-
flyte.Image.from_base("node:24-slim")
68-
.clone(name="n8n-app-image")
69-
.with_pip_packages("flyte==2.0.0b54", "fastapi", "uvicorn")
70-
.with_apt_packages("ca-certificates", "curl", "gnupg", "npm")
71-
.with_commands(["npm install -g n8n@2.4.8"])
72-
)
73-
74-
# launcher_url = "https://github.com/n8n-io/task-runner-launcher/releases/download/1.4.2/task-runner-launcher-1.4.2-linux-amd64.tar.gz"
75-
76-
# n8n_task_runner_image = (
77-
# flyte.Image.from_base("node:24-slim")
78-
# .clone(name="n8n-task-runner-image")
79-
# .with_pip_packages("flyte==2.0.0b54", "kubernetes")
80-
# .with_apt_packages("ca-certificates", "curl", "gnupg", "npm")
81-
# # install the task-runner-launcher: https://github.com/n8n-io/task-runner-launcher
82-
# .with_commands([
83-
# f"curl -L -o /tmp/task-runner-launcher.tar.gz {launcher_url}",
84-
# "tar -xzf /tmp/task-runner-launcher.tar.gz -C /usr/local/bin",
85-
# "chmod +x /usr/local/bin/task-runner-launcher",
86-
# "rm /tmp/task-runner-launcher.tar.gz",
87-
# ])
88-
# .with_source_file(pathlib.Path(__file__).parent / "n8n-task-runners.json", "/etc/n8n-task-runners.json")
89-
# )
90-
91-
bump = "4"
9230
n8n_app = flyte.app.AppEnvironment(
9331
name="n8n-app",
94-
image=n8n_app_image,
95-
# pod_template=n8n_with_runner_pod_template,
96-
resources=flyte.Resources(cpu=2, memory="2Gi"),
32+
resources=flyte.Resources(cpu=4, memory="8Gi"),
33+
scaling=flyte.app.Scaling(replicas=(0, 1)),
9734
port=5678,
9835
command=["n8n", "start"],
9936
secrets=[
10037
flyte.Secret("n8n_postgres_password", as_env_var="DB_POSTGRESDB_PASSWORD"),
38+
flyte.Secret("n8n_encryption_key", as_env_var="N8N_ENCRYPTION_KEY"),
10139
],
10240
requires_auth=False,
10341
env_vars={
104-
"N8N_ENCRYPTION_KEY": "abc123",
105-
106-
# db config
107-
# https://docs.n8n.io/hosting/installation/docker/#using-with-postgresql
42+
"N8N_RUNNERS_ENABLED": "true",
43+
"N8N_RUNNERS_MODE": "external",
44+
"N8N_RUNNERS_BROKER_LISTEN_ADDRESS": "0.0.0.0",
45+
"N8N_NATIVE_PYTHON_RUNNER": "true",
46+
47+
# db config: https://docs.n8n.io/hosting/installation/docker/#using-with-postgresql
10848
"DB_TYPE": "postgresdb",
10949
"DB_POSTGRESDB_HOST": "aws-0-us-west-2.pooler.supabase.com",
11050
"DB_POSTGRESDB_DATABASE": "postgres",
11151
"DB_POSTGRESDB_USER": "postgres.qcfcidgymclxvslgphyb",
11252
"DB_POSTGRESDB_PORT": "6543",
11353
"DB_POSTGRESDB_SCHEMA": "public",
114-
115-
"BUMP": bump,
11654
}
11755
)
11856

11957

120-
app = FastAPI()
58+
def build_runner_image() -> flyte.Image:
59+
flyte.init_from_config(image_builder="local")
12160

122-
@app.get("/")
123-
async def root():
124-
import os
61+
image = flyte.Image.from_dockerfile(
62+
pathlib.Path(__file__).parent / "task_runner.dockerfile",
63+
registry="ghcr.io/flyteorg",
64+
name="n8n-task-runner-image",
65+
)
66+
return flyte.build(image, wait=True)
12567

126-
return {"message": "Hello World", "n8n_app_endpoint": os.getenv("N8N_APP_URL")}
12768

128-
n8n_debugger = FastAPIAppEnvironment(
129-
app=app,
130-
name="n8n-debugger",
131-
image=flyte.Image.from_debian_base().with_pip_packages("fastapi", "uvicorn", "kubernetes"),
132-
resources=flyte.Resources(cpu=2, memory="2Gi"),
133-
port=8080,
134-
requires_auth=False,
135-
depends_on=[n8n_app],
136-
parameters=[
137-
flyte.app.Parameter(
138-
name="n8n_app_endpoint",
139-
value=flyte.app.AppEndpoint(app_name="n8n-app", public=False),
140-
env_var="N8N_APP_URL",
141-
),
142-
],
143-
)
69+
def get_webhook_url(subdomain: str) -> str:
70+
cfg = get_init_config()
71+
return f"https://{subdomain}.apps.{cfg.client.endpoint.replace('dns:///', '').rstrip('/')}/"
14472

145-
# n8n_task_runner = flyte.app.AppEnvironment(
146-
# name="n8n-task-runner",
147-
# image="ghcr.io/flyteorg/n8n-task-runner-image:896c4478822858a314074b1a3caf882a",
148-
# resources=flyte.Resources(cpu=2, memory="2Gi"),
149-
# port=5678,
150-
# command=["/usr/local/bin/task-runner-launcher", "javascript", "python"],
151-
# requires_auth=False,
152-
# env_vars={
153-
# "N8N_RUNNERS_LAUNCHER_LOG_LEVEL": "debug",
154-
# "N8N_RUNNERS_TASK_BROKER_URI": "http://n8n-app.flytesnacks-development.svc.cluster.local:5679",
155-
# "N8N_RUNNERS_AUTH_TOKEN": "test-token",
156-
157-
# "BUMP": bump,
158-
# },
159-
# depends_on=[n8n_app, n8n_debugger],
160-
# )
16173

16274
if __name__ == "__main__":
163-
flyte.init_from_config()
164-
# app = flyte.serve(n8n_debugger)
165-
app = flyte.serve(n8n_app)
75+
import random
76+
import string
77+
78+
from flyte._initialize import get_init_config
79+
80+
n8n_version = "2.6.3"
81+
# Create a random 32-character alphanumeric string for the n8n runners auth token. it's okay
82+
# to regenerate this every time the app is deployed, since only the main n8n app and the runner
83+
# sidecar container use this token.
84+
n8n_runners_auth_token = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
85+
86+
image = build_runner_image()
87+
88+
flyte.init_from_config(image_builder="remote")
89+
pod_template = n8n_pod_template(
90+
version=n8n_version,
91+
runner_auth_token=n8n_runners_auth_token,
92+
runner_image_uri=image.uri,
93+
)
94+
95+
subdomain = "n8n-app"
96+
webhook_url = get_webhook_url(subdomain)
97+
98+
app = flyte.serve(
99+
n8n_app.clone_with(
100+
name="n8n-app-with-runners",
101+
pod_template=pod_template,
102+
domain=flyte.app.Domain(subdomain=subdomain),
103+
env_vars=n8n_app.env_vars | {
104+
"WEBHOOK_URL": webhook_url,
105+
"N8N_RUNNERS_AUTH_TOKEN": n8n_runners_auth_token,
106+
},
107+
)
108+
)
166109
print(app.url)

examples/genai/n8n/task_runner.dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM n8nio/runners:2.4.8
1+
FROM n8nio/runners:2.6.3
22
USER root
33
COPY n8n-task-runners.json /etc/n8n-task-runners.json
44
RUN cd /opt/runners/task-runner-javascript && pnpm add moment uuid

examples/genai/vllm/vllm_app.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@
4949
name="qwen3-0-6b-vllm",
5050
model_hf_path="Qwen/Qwen3-0.6B",
5151
model_id="qwen3-0.6b",
52-
resources=flyte.Resources(cpu="4", memory="16Gi", gpu="V100:1", disk="10Gi"),
52+
resources=flyte.Resources(cpu="4", memory="16Gi", gpu="L40s:1", disk="10Gi"),
5353
image=(
5454
flyte.Image.from_debian_base(
5555
name="vllm-app-image",
5656
install_flyte=False,
5757
)
5858
.with_pip_packages("flashinfer-python", "flashinfer-cubin")
5959
.with_pip_packages("flashinfer-jit-cache", index_url="https://flashinfer.ai/whl/cu129")
60+
.with_pip_packages("vllm==0.11.0", "transformers==4.57.6")
6061
.with_pip_packages("flyteplugins-vllm", pre=True)
6162
),
6263
stream_model=True, # Stream model directly from blob store to GPU

src/flyte/app/_app_environment.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ def clone_with(
319319
include = kwargs.pop("include", None)
320320
parameters = kwargs.pop("parameters", None)
321321
cluster_pool = kwargs.pop("cluster_pool", None)
322+
pod_template = kwargs.pop("pod_template", None)
322323

323324
if kwargs:
324325
raise TypeError(f"Unexpected keyword arguments: {list(kwargs.keys())}")
@@ -327,6 +328,8 @@ def clone_with(
327328
kwargs["name"] = name
328329
if image is not None:
329330
kwargs["image"] = image
331+
if pod_template is not None:
332+
kwargs["pod_template"] = pod_template
330333
if resources is not None:
331334
kwargs["resources"] = resources
332335
if env_vars is not None:

0 commit comments

Comments
 (0)