From 9c28ec1c7fee6e0edb5a4ec294e139f79551d158 Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Fri, 30 Oct 2026 08:02:44 +0800 Subject: [PATCH 1/7] makefile: mlx-start/stop and provide apple silicon option Signed-off-by: Yuteng Chen --- docker/devbox-bundled/Makefile | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docker/devbox-bundled/Makefile b/docker/devbox-bundled/Makefile index 39ae5cca8c2..44e21488570 100644 --- a/docker/devbox-bundled/Makefile +++ b/docker/devbox-bundled/Makefile @@ -156,6 +156,27 @@ override DEVBOX_CONTEXT := flyte-devbox # 30080 - Flyte Proxy # 30081 - Kourier (Knative apps) # 30300 - Grafana (only serves something after `make monitoring`) +APPLE_SILICON_PORT ?= 30090 +FLYTE_PYTHON ?= uv run --isolated --no-project --with flyte python +APPLE_SILICON_DIR := $(HOME)/.flyte/apple-silicon + +.PHONY: start-mlx-bridge +start-mlx-bridge: + @mkdir -p $(APPLE_SILICON_DIR) + @curl -fs -o /dev/null http://127.0.0.1:$(APPLE_SILICON_PORT)/healthz && exit 0; \ + nohup $(FLYTE_PYTHON) -m flyte._internal.apple_silicon._bridge --port $(APPLE_SILICON_PORT) \ + --state-dir $(APPLE_SILICON_DIR) >$(APPLE_SILICON_DIR)/bridge.log 2>&1 & \ + echo "{\"pid\": $$!, \"port\": $(APPLE_SILICON_PORT)}" > $(APPLE_SILICON_DIR)/bridge.json; \ + for i in $$(seq 60); do curl -fs -o /dev/null http://127.0.0.1:$(APPLE_SILICON_PORT)/healthz && exit 0; sleep 0.5; done; \ + tail -5 $(APPLE_SILICON_DIR)/bridge.log; exit 1 + @echo "Apple Silicon bridge on 127.0.0.1:$(APPLE_SILICON_PORT)" + +.PHONY: stop-mlx-bridge +stop-mlx-bridge: + @pid=$$(sed -n 's/.*"pid": *\([0-9]*\).*/\1/p' $(APPLE_SILICON_DIR)/bridge.json 2>/dev/null); \ + rm -f $(APPLE_SILICON_DIR)/bridge.json; \ + [ -n "$$pid" ] && ps -o command= -p $$pid | grep -q apple_silicon._bridge && kill $$pid || true + .PHONY: start start: FLYTE_DEVBOX_IMAGE := flyte-devbox:latest start: FLYTE_DEV := False @@ -163,11 +184,17 @@ start: [ -n "$(shell docker volume ls --filter name=^flyte-devbox$$ --format {{.Name}})" ] || \ docker volume create flyte-devbox @if [ -z "$(shell docker ps --filter name=^flyte-devbox$$ --format {{.Names}})" ]; then \ + if [ "$(APPLE_SILICON)" = 1 ]; then \ + $(MAKE) --no-print-directory start-mlx-bridge || exit 1; \ + APPLE_SILICON_ENV="--env FLYTE_DEVBOX_APPLE_SILICON_PORT=$(APPLE_SILICON_PORT) \ + --env FLYTE_DEVBOX_APPLE_SILICON_TOKEN_SECRET=$$(cat $(APPLE_SILICON_DIR)/secret)"; \ + fi; \ rm -f $(PWD)/.kube/kubeconfig; \ docker run --detach --rm --privileged --name flyte-devbox \ --add-host "host.docker.internal:host-gateway" \ --env FLYTE_DEV=$(FLYTE_DEV) \ --env K3S_KUBECONFIG_OUTPUT=/.kube/kubeconfig \ + $$APPLE_SILICON_ENV \ --volume $(PWD)/.kube:/.kube \ --volume flyte-devbox:/var/lib/flyte/storage \ --publish "6443":"6443" \ @@ -251,4 +278,5 @@ monitoring-clean: .PHONY: stop stop: + @$(MAKE) --no-print-directory stop-mlx-bridge docker stop --time 5 flyte-devbox From c29007877c75872cd0148a22546b2b57a18f3f02 Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 07:34:55 +0800 Subject: [PATCH 2/7] concrete user hint and make the code easy to read Signed-off-by: Yuteng Chen --- docker/devbox-bundled/Makefile | 49 +++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/docker/devbox-bundled/Makefile b/docker/devbox-bundled/Makefile index 44e21488570..6aaef7a725f 100644 --- a/docker/devbox-bundled/Makefile +++ b/docker/devbox-bundled/Makefile @@ -159,23 +159,53 @@ override DEVBOX_CONTEXT := flyte-devbox APPLE_SILICON_PORT ?= 30090 FLYTE_PYTHON ?= uv run --isolated --no-project --with flyte python APPLE_SILICON_DIR := $(HOME)/.flyte/apple-silicon +APPLE_SILICON_PORT_ENV = --env FLYTE_DEVBOX_APPLE_SILICON_PORT=$(APPLE_SILICON_PORT) +APPLE_SILICON_SECRET_ENV = --env FLYTE_DEVBOX_APPLE_SILICON_TOKEN_SECRET=$$(cat $(APPLE_SILICON_DIR)/secret) + +if_mlx_bridge_healthy = curl -fs -o /dev/null http://127.0.0.1:$(APPLE_SILICON_PORT)/healthz .PHONY: start-mlx-bridge start-mlx-bridge: - @mkdir -p $(APPLE_SILICON_DIR) - @curl -fs -o /dev/null http://127.0.0.1:$(APPLE_SILICON_PORT)/healthz && exit 0; \ + @if [ ! -d $(APPLE_SILICON_DIR) ]; then \ + mkdir -p $(APPLE_SILICON_DIR); \ + echo "$(APPLE_SILICON_DIR) not found, create dir"; \ + fi + @if $(if_mlx_bridge_healthy); then \ + echo "Using existing MLX bridge on 127.0.0.1:$(APPLE_SILICON_PORT)"; \ + exit 0; \ + fi; \ nohup $(FLYTE_PYTHON) -m flyte._internal.apple_silicon._bridge --port $(APPLE_SILICON_PORT) \ --state-dir $(APPLE_SILICON_DIR) >$(APPLE_SILICON_DIR)/bridge.log 2>&1 & \ - echo "{\"pid\": $$!, \"port\": $(APPLE_SILICON_PORT)}" > $(APPLE_SILICON_DIR)/bridge.json; \ - for i in $$(seq 60); do curl -fs -o /dev/null http://127.0.0.1:$(APPLE_SILICON_PORT)/healthz && exit 0; sleep 0.5; done; \ - tail -5 $(APPLE_SILICON_DIR)/bridge.log; exit 1 - @echo "Apple Silicon bridge on 127.0.0.1:$(APPLE_SILICON_PORT)" + pid=$$!; \ + echo "{\"pid\": $$pid, \"port\": $(APPLE_SILICON_PORT)}" > $(APPLE_SILICON_DIR)/bridge.json; \ + for i in $$(seq 60); do \ + if $(if_mlx_bridge_healthy); then \ + break; \ + fi; \ + sleep 0.5; \ + done; \ + if $(if_mlx_bridge_healthy); then \ + echo "MLX bridge is serving on 127.0.0.1:$(APPLE_SILICON_PORT)"; \ + else \ + echo "MLX bridge failed to start, log is at $(APPLE_SILICON_DIR)/bridge.log"; \ + tail -5 $(APPLE_SILICON_DIR)/bridge.log; \ + exit 1; \ + fi .PHONY: stop-mlx-bridge stop-mlx-bridge: @pid=$$(sed -n 's/.*"pid": *\([0-9]*\).*/\1/p' $(APPLE_SILICON_DIR)/bridge.json 2>/dev/null); \ rm -f $(APPLE_SILICON_DIR)/bridge.json; \ - [ -n "$$pid" ] && ps -o command= -p $$pid | grep -q apple_silicon._bridge && kill $$pid || true + if [ -z "$$pid" ]; then \ + echo "MLX bridge pid is empty, skip it"; \ + else \ + if ps -o command= -p $$pid | grep -q apple_silicon._bridge; then \ + kill $$pid; \ + echo "MLX bridge stopped (pid $$pid)"; \ + else \ + echo "MLX bridge (pid $$pid) not found, skip it"; \ + fi; \ + fi .PHONY: start start: FLYTE_DEVBOX_IMAGE := flyte-devbox:latest @@ -186,15 +216,14 @@ start: @if [ -z "$(shell docker ps --filter name=^flyte-devbox$$ --format {{.Names}})" ]; then \ if [ "$(APPLE_SILICON)" = 1 ]; then \ $(MAKE) --no-print-directory start-mlx-bridge || exit 1; \ - APPLE_SILICON_ENV="--env FLYTE_DEVBOX_APPLE_SILICON_PORT=$(APPLE_SILICON_PORT) \ - --env FLYTE_DEVBOX_APPLE_SILICON_TOKEN_SECRET=$$(cat $(APPLE_SILICON_DIR)/secret)"; \ fi; \ rm -f $(PWD)/.kube/kubeconfig; \ docker run --detach --rm --privileged --name flyte-devbox \ --add-host "host.docker.internal:host-gateway" \ --env FLYTE_DEV=$(FLYTE_DEV) \ --env K3S_KUBECONFIG_OUTPUT=/.kube/kubeconfig \ - $$APPLE_SILICON_ENV \ + $(if $(filter 1,$(APPLE_SILICON)),$(APPLE_SILICON_PORT_ENV)) \ + $(if $(filter 1,$(APPLE_SILICON)),$(APPLE_SILICON_SECRET_ENV)) \ --volume $(PWD)/.kube:/.kube \ --volume flyte-devbox:/var/lib/flyte/storage \ --publish "6443":"6443" \ From 548c6885511f1bf1e21dbf73ae230cd4d843a02f Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 07:43:43 +0800 Subject: [PATCH 3/7] APPLE_SILICON use boolean instead of number Signed-off-by: Yuteng Chen --- docker/devbox-bundled/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docker/devbox-bundled/Makefile b/docker/devbox-bundled/Makefile index 6aaef7a725f..2b729a084f2 100644 --- a/docker/devbox-bundled/Makefile +++ b/docker/devbox-bundled/Makefile @@ -209,12 +209,13 @@ stop-mlx-bridge: .PHONY: start start: FLYTE_DEVBOX_IMAGE := flyte-devbox:latest +start: APPLE_SILICON := False start: FLYTE_DEV := False start: [ -n "$(shell docker volume ls --filter name=^flyte-devbox$$ --format {{.Name}})" ] || \ docker volume create flyte-devbox @if [ -z "$(shell docker ps --filter name=^flyte-devbox$$ --format {{.Names}})" ]; then \ - if [ "$(APPLE_SILICON)" = 1 ]; then \ + if [ "$(APPLE_SILICON)" = True ]; then \ $(MAKE) --no-print-directory start-mlx-bridge || exit 1; \ fi; \ rm -f $(PWD)/.kube/kubeconfig; \ @@ -222,8 +223,8 @@ start: --add-host "host.docker.internal:host-gateway" \ --env FLYTE_DEV=$(FLYTE_DEV) \ --env K3S_KUBECONFIG_OUTPUT=/.kube/kubeconfig \ - $(if $(filter 1,$(APPLE_SILICON)),$(APPLE_SILICON_PORT_ENV)) \ - $(if $(filter 1,$(APPLE_SILICON)),$(APPLE_SILICON_SECRET_ENV)) \ + $(if $(filter True,$(APPLE_SILICON)),$(APPLE_SILICON_PORT_ENV)) \ + $(if $(filter True,$(APPLE_SILICON)),$(APPLE_SILICON_SECRET_ENV)) \ --volume $(PWD)/.kube:/.kube \ --volume flyte-devbox:/var/lib/flyte/storage \ --publish "6443":"6443" \ From 59d2a5105b2d8e3eb136b933bc88bef4909a88b3 Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 07:48:21 +0800 Subject: [PATCH 4/7] move the mlx shell script to avoid the devbox port information in wrong position Signed-off-by: Yuteng Chen --- docker/devbox-bundled/Makefile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docker/devbox-bundled/Makefile b/docker/devbox-bundled/Makefile index 2b729a084f2..c037134186b 100644 --- a/docker/devbox-bundled/Makefile +++ b/docker/devbox-bundled/Makefile @@ -145,17 +145,6 @@ build-gpu: build --build-arg BASE_IMAGE=base \ --tag flyte-devbox:gpu-latest . -override DEVBOX_NAME := flyte-devbox -override DEVBOX_CONTEXT := flyte-devbox - -# Port map -# 6443 - k8s API server -# 30000 - Docker Registry -# 30001 - DB -# 30002 - RustFS -# 30080 - Flyte Proxy -# 30081 - Kourier (Knative apps) -# 30300 - Grafana (only serves something after `make monitoring`) APPLE_SILICON_PORT ?= 30090 FLYTE_PYTHON ?= uv run --isolated --no-project --with flyte python APPLE_SILICON_DIR := $(HOME)/.flyte/apple-silicon @@ -207,6 +196,17 @@ stop-mlx-bridge: fi; \ fi +override DEVBOX_NAME := flyte-devbox +override DEVBOX_CONTEXT := flyte-devbox + +# Port map +# 6443 - k8s API server +# 30000 - Docker Registry +# 30001 - DB +# 30002 - RustFS +# 30080 - Flyte Proxy +# 30081 - Kourier (Knative apps) +# 30300 - Grafana (only serves something after `make monitoring`) .PHONY: start start: FLYTE_DEVBOX_IMAGE := flyte-devbox:latest start: APPLE_SILICON := False From d97a8d3d008dac759265bc1ae51707886e812b10 Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 07:52:12 +0800 Subject: [PATCH 5/7] add development information with apple silicon in contribute.dm Signed-off-by: Yuteng Chen --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 618ecba3f40..aa8d583847d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,6 +66,8 @@ make devbox-stop `FLYTE_DEV=True` is required when you intend to run the manager locally — it disables the in-cluster manager so your local process can take over. The value is case-insensitive. `make devbox-run` writes a kubeconfig pointing at the devbox cluster in global kubeconfig, so `kubectl` will target it automatically. +`APPLE_SILICON=True` activates the Apple MLX bridge (requires an M-series Mac). + ### Build and Run the Manager With the devbox running, start the manager locally: From dc393347a17c97814138585301bfc6000b3e9d59 Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 16:29:22 +0800 Subject: [PATCH 6/7] assign the mlx bridge setting for devbox with mlx bridge in make run command Signed-off-by: Yuteng Chen --- go.Makefile | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/go.Makefile b/go.Makefile index 2e12f4be454..88f29908324 100644 --- a/go.Makefile +++ b/go.Makefile @@ -10,6 +10,9 @@ BIN_DIR ?= bin BIN_NAME ?= $(SERVICE_NAME) GOLANGCI_LINT_VERSION ?= v2.14.0 LOCALBIN ?= $(shell pwd)/bin +APPLE_SILICON_PORT ?= 30090 +APPLE_SILICON_DIR := $(HOME)/.flyte/apple-silicon +APPLE_SILICON_CONFIG := $(APPLE_SILICON_DIR)/$(SERVICE_NAME)-config.yaml # ANSI color codes for prettier output COLOR_RESET := \033[0m @@ -118,12 +121,43 @@ bench: ## Run benchmarks .PHONY: run run: build-fast ## Build and run the service @echo "$(COLOR_GREEN)Running $(SERVICE_NAME)...$(COLOR_RESET)" - @./$(BIN_DIR)/$(BIN_NAME) $(RUN_ARGS) + @if [ "$(APPLE_SILICON)" != True ]; then \ + ./$(BIN_DIR)/$(BIN_NAME) $(RUN_ARGS); \ + else \ + $(MAKE) --no-print-directory apple-silicon-config && \ + ./$(BIN_DIR)/$(BIN_NAME) --config $(APPLE_SILICON_CONFIG); \ + fi .PHONY: run-dev run-dev: ## Run service directly with go run (no build) @echo "$(COLOR_GREEN)Running $(SERVICE_NAME) (dev mode)...$(COLOR_RESET)" - @go run $(CMD_PATH) $(RUN_ARGS) + @if [ "$(APPLE_SILICON)" != True ]; then \ + go run $(CMD_PATH) $(RUN_ARGS); \ + else \ + $(MAKE) --no-print-directory apple-silicon-config && \ + go run $(CMD_PATH) --config $(APPLE_SILICON_CONFIG); \ + fi + +.PHONY: apple-silicon-config +apple-silicon-config: ## Generate a config with the MLX bridge settings + @if [ ! -s $(APPLE_SILICON_DIR)/secret ]; then \ + echo "$(APPLE_SILICON_DIR)/secret not found, run 'make devbox-run FLYTE_DEV=True APPLE_SILICON=True' first"; \ + exit 1; \ + fi + @# Pods cannot resolve host.docker.internal, so the bridge endpoint uses the IP the devbox maps it to. + @ip=$$(docker exec flyte-devbox cat /etc/hosts | awk '$$2 == "host.docker.internal" { print $$1; exit }'); \ + if [ -z "$$ip" ]; then \ + echo "host.docker.internal not found in flyte-devbox, is the devbox running?"; \ + exit 1; \ + fi; \ + umask 077; \ + { \ + echo ' apple-silicon-bridge:'; \ + echo " endpoint: \"http://$$ip:$(APPLE_SILICON_PORT)\""; \ + echo " token-secret: \"$$(cat $(APPLE_SILICON_DIR)/secret)\""; \ + echo ' host-platform: "darwin/arm64"'; \ + } | sed '/^ k8s:$$/r /dev/stdin' config.yaml > $(APPLE_SILICON_CONFIG); \ + echo "Apple MLX bridge config set successfully, at $(APPLE_SILICON_CONFIG)" ##@ Cleanup From 42185cc1ce3f90ba3b806aff11efa0aaca82563b Mon Sep 17 00:00:00 2001 From: Yuteng Chen Date: Sat, 31 Oct 2026 18:07:34 +0800 Subject: [PATCH 7/7] use the bridge's known endpoints so apple silicon tasks reach s3 and flyte from the mac Signed-off-by: Yuteng Chen --- go.Makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/go.Makefile b/go.Makefile index 88f29908324..bd6b2c6c856 100644 --- a/go.Makefile +++ b/go.Makefile @@ -144,19 +144,30 @@ apple-silicon-config: ## Generate a config with the MLX bridge settings echo "$(APPLE_SILICON_DIR)/secret not found, run 'make devbox-run FLYTE_DEV=True APPLE_SILICON=True' first"; \ exit 1; \ fi - @# Pods cannot resolve host.docker.internal, so the bridge endpoint uses the IP the devbox maps it to. @ip=$$(docker exec flyte-devbox cat /etc/hosts | awk '$$2 == "host.docker.internal" { print $$1; exit }'); \ if [ -z "$$ip" ]; then \ echo "host.docker.internal not found in flyte-devbox, is the devbox running?"; \ exit 1; \ fi; \ + type=$$(kubectl --context flyte-devbox -n flyte get svc flyte-binary-http -o jsonpath='{.spec.type}' 2>/dev/null); \ + if [ -z "$$type" ]; then \ + kubectl --context flyte-devbox -n flyte create service externalname flyte-binary-http \ + --external-name flyte-devbox-local.flyte.svc.cluster.local --tcp 8090:8090 >/dev/null || exit 1; \ + echo "Created flyte-binary-http in flyte-devbox, pointing at the manager on the host"; \ + elif [ "$$type" != ExternalName ]; then \ + echo "flyte-binary-http is already served inside flyte-devbox, run 'make devbox-run FLYTE_DEV=True APPLE_SILICON=True' first"; \ + exit 1; \ + fi; \ umask 077; \ { \ echo ' apple-silicon-bridge:'; \ echo " endpoint: \"http://$$ip:$(APPLE_SILICON_PORT)\""; \ echo " token-secret: \"$$(cat $(APPLE_SILICON_DIR)/secret)\""; \ echo ' host-platform: "darwin/arm64"'; \ - } | sed '/^ k8s:$$/r /dev/stdin' config.yaml > $(APPLE_SILICON_CONFIG); \ + } | sed -e '/^ k8s:$$/r /dev/stdin' \ + -e 's|rustfs-svc\.flyte\.svc\.cluster\.local:9000|rustfs-svc.flyte:9000|' \ + -e '/_U_EP_OVERRIDE/s|host\.docker\.internal:8090|flyte-binary-http.flyte:8090|' \ + config.yaml > $(APPLE_SILICON_CONFIG); \ echo "Apple MLX bridge config set successfully, at $(APPLE_SILICON_CONFIG)" ##@ Cleanup