fix(installer): harden install.sh for Podman macOS (#2068)

# What does this PR do?
Several fixes to ensure the script runs properly on macOS & Podman: 
- Automates Podman VM startup on macOS
- Fixes host-gateway handling 
- Adds explicit ARM64 platform overrides (this also fixes the platform
warning on Docker)
- Switches health checks to in-container exec calls to avoid Podman
timeouts
- Minor formatting nits

# (Closes #2064 )

## Test Plan
- Manual testing on macOS and Podman
This commit is contained in:
Alexey Rybak 2025-05-05 00:31:58 -07:00 committed by GitHub
parent d27a0f276c
commit 15a1648be6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -16,61 +16,120 @@ WAIT_TIMEOUT=300
log(){ printf "\e[1;32m%s\e[0m\n" "$*"; } log(){ printf "\e[1;32m%s\e[0m\n" "$*"; }
die(){ printf "\e[1;31m❌ %s\e[0m\n" "$*" >&2; exit 1; } die(){ printf "\e[1;31m❌ %s\e[0m\n" "$*" >&2; exit 1; }
wait_for_service() {
local url="$1"
local pattern="$2"
local timeout="$3"
local name="$4"
local start ts
log "⏳ Waiting for ${name}"
start=$(date +%s)
while true; do
if curl --retry 5 --retry-delay 1 --retry-max-time "$timeout" --retry-all-errors --silent --fail "$url" 2>/dev/null | grep -q "$pattern"; then
break
fi
ts=$(date +%s)
if (( ts - start >= timeout )); then
return 1
fi
printf '.'
sleep 1
done
return 0
}
if command -v docker &> /dev/null; then if command -v docker &> /dev/null; then
ENGINE="docker" ENGINE="docker"
HOST_DNS="host.docker.internal"
elif command -v podman &> /dev/null; then elif command -v podman &> /dev/null; then
ENGINE="podman" ENGINE="podman"
HOST_DNS="host.containers.internal"
else else
die "Docker or Podman is required. Install Docker: https://docs.docker.com/get-docker/ or Podman: https://podman.io/getting-started/installation" die "Docker or Podman is required. Install Docker: https://docs.docker.com/get-docker/ or Podman: https://podman.io/getting-started/installation"
fi fi
# Explicitly set the platform for the host architecture
HOST_ARCH="$(uname -m)"
if [ "$HOST_ARCH" = "arm64" ]; then
if [ "$ENGINE" = "docker" ]; then
PLATFORM_OPTS=( --platform linux/amd64 )
else
PLATFORM_OPTS=( --os linux --arch amd64 )
fi
else
PLATFORM_OPTS=()
fi
# macOS + Podman: ensure VM is running before we try to launch containers
# If you need GPU passthrough under Podman on macOS, init the VM with libkrun:
# CONTAINERS_MACHINE_PROVIDER=libkrun podman machine init
if [ "$ENGINE" = "podman" ] && [ "$(uname -s)" = "Darwin" ]; then
if ! podman info &>/dev/null; then
log "⌛️ Initializing Podman VM…"
podman machine init &>/dev/null || true
podman machine start &>/dev/null || true
log "⌛️ Waiting for Podman API…"
until podman info &>/dev/null; do
sleep 1
done
log "✅ Podman VM is up"
fi
fi
# Clean up any leftovers from earlier runs # Clean up any leftovers from earlier runs
for name in ollama-server llama-stack; do for name in ollama-server llama-stack; do
ids=$($ENGINE ps -aq --filter "name=^${name}$") ids=$($ENGINE ps -aq --filter "name=^${name}$")
if [ -n "$ids" ]; then if [ -n "$ids" ]; then
log "⚠️ Found existing container(s) for '${name}', removing..." log "⚠️ Found existing container(s) for '${name}', removing"
$ENGINE rm -f "$ids" $ENGINE rm -f "$ids" > /dev/null 2>&1
fi fi
done done
###############################################################################
# 0. Create a shared network
###############################################################################
if ! $ENGINE network inspect llama-net >/dev/null 2>&1; then
log "🌐 Creating network…"
$ENGINE network create llama-net >/dev/null 2>&1
fi
############################################################################### ###############################################################################
# 1. Ollama # 1. Ollama
############################################################################### ###############################################################################
log "🦙 Starting Ollama…" log "🦙 Starting Ollama…"
$ENGINE run -d --name ollama-server \ $ENGINE run -d "${PLATFORM_OPTS[@]}" --name ollama-server \
-p "${OLLAMA_PORT}:11434" \ --network llama-net \
-p "${OLLAMA_PORT}:${OLLAMA_PORT}" \
ollama/ollama > /dev/null 2>&1 ollama/ollama > /dev/null 2>&1
log "⏳ Waiting for Ollama daemon…" if ! wait_for_service "http://localhost:${OLLAMA_PORT}/" "Ollama" "$WAIT_TIMEOUT" "Ollama daemon"; then
if ! timeout "$WAIT_TIMEOUT" bash -c \
"until curl -fsS http://localhost:${OLLAMA_PORT}/ 2>/dev/null | grep -q 'Ollama'; do sleep 1; done"; then
log "❌ Ollama daemon did not become ready in ${WAIT_TIMEOUT}s; dumping container logs:" log "❌ Ollama daemon did not become ready in ${WAIT_TIMEOUT}s; dumping container logs:"
$ENGINE logs ollama-server --tail=200 $ENGINE logs --tail 200 ollama-server
die "Ollama startup failed" die "Ollama startup failed"
fi fi
log "📦 Ensuring model is pulled: ${MODEL_ALIAS}..." log "📦 Ensuring model is pulled: ${MODEL_ALIAS}"
$ENGINE exec ollama-server ollama pull "${MODEL_ALIAS}" > /dev/null 2>&1 if ! $ENGINE exec ollama-server ollama pull "${MODEL_ALIAS}" > /dev/null 2>&1; then
log "❌ Failed to pull model ${MODEL_ALIAS}; dumping container logs:"
$ENGINE logs --tail 200 ollama-server
die "Model pull failed"
fi
############################################################################### ###############################################################################
# 2. LlamaStack # 2. LlamaStack
############################################################################### ###############################################################################
log "🦙📦 Starting LlamaStack…" cmd=( run -d "${PLATFORM_OPTS[@]}" --name llama-stack \
$ENGINE run -d --name llama-stack \ --network llama-net \
-p "${PORT}:${PORT}" \ -p "${PORT}:${PORT}" \
--add-host="${HOST_DNS}:host-gateway" \ "${SERVER_IMAGE}" --port "${PORT}" \
"${SERVER_IMAGE}" \ --env INFERENCE_MODEL="${MODEL_ALIAS}" \
--port "${PORT}" \ --env OLLAMA_URL="http://ollama-server:${OLLAMA_PORT}" )
--env INFERENCE_MODEL="${MODEL_ALIAS}" \
--env OLLAMA_URL="http://${HOST_DNS}:${OLLAMA_PORT}" > /dev/null 2>&1
log "⏳ Waiting for Llama-Stack API…" log "🦙 Starting LlamaStack…"
if ! timeout "$WAIT_TIMEOUT" bash -c \ $ENGINE "${cmd[@]}" > /dev/null 2>&1
"until curl -fsS http://localhost:${PORT}/v1/health 2>/dev/null | grep -q 'OK'; do sleep 1; done"; then
if ! wait_for_service "http://127.0.0.1:${PORT}/v1/health" "OK" "$WAIT_TIMEOUT" "Llama-Stack API"; then
log "❌ Llama-Stack did not become ready in ${WAIT_TIMEOUT}s; dumping container logs:" log "❌ Llama-Stack did not become ready in ${WAIT_TIMEOUT}s; dumping container logs:"
$ENGINE logs llama-stack --tail=200 $ENGINE logs --tail 200 llama-stack
die "Llama-Stack startup failed" die "Llama-Stack startup failed"
fi fi