fix(pipeline): Pre-create ollama-internal network when LiteLLM enabled#617
Merged
Conversation
LiteLLM's docker-compose declares `ollama-internal` as an external
network so it can reach the Ollama stack's container by service name
when both stacks run side-by-side. Without a network of that name
already existing, `docker compose up` aborts with
network ollama-internal declared as external, but could not be
found
BEFORE the container is even created — the operator gets a Bad
Gateway on https://litellm.<domain>/ because nothing is listening
on the proxied port. The hard dependency on Ollama being enabled
defeats LiteLLM's core value proposition (OpenAI-compatible proxy
for ANY provider — operator-supplied OPENAI_API_KEY / ANTHROPIC_API_KEY
should be sufficient).
Fix: add an idempotent pre-compose block to compose_runner that
inspects-then-creates `ollama-internal` whenever LiteLLM is enabled,
mirroring the existing dify_storage_prep / metabase_storage_prep
flag pattern. When Ollama is ALSO enabled, its own compose joins
the same network by name (already pinned via `name: ollama-internal`
on both sides) — no behaviour change for the joint-enabled case.
Tests pin: (a) block presence is gated on the flag, (b) the
inspect-||-create shape is idempotent under set -euo pipefail,
(c) run_compose_up defaults the flag to `"litellm" in enabled`,
(d) explicit override beats inference.
Contributor
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes the LiteLLM stack resilient when Ollama is not enabled by ensuring the external Docker network ollama-internal exists before docker compose up runs, preventing LiteLLM startup from aborting due to a missing external network.
Changes:
- Add an optional
litellm_network_preppre-compose step incompose_runnertoinspect || createtheollama-internalDocker network. - Default
litellm_network_prepto enabled when"litellm"is in the enabled-services list (with an explicit override escape hatch). - Add unit tests covering script rendering, default inference behavior, and explicit override semantics; update the LiteLLM compose comment to reflect the new pipeline behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/nexus_deploy/compose_runner.py |
Introduces litellm_network_prep and injects an idempotent `docker network inspect … |
tests/unit/test_compose_runner.py |
Adds regression tests validating that the network-prep block is rendered only when intended and that default/override behavior is correct. |
stacks/litellm/docker-compose.yml |
Updates comments to document that the deployment pipeline pre-creates the external ollama-internal network so LiteLLM can start without Ollama. |
- docs/stacks/litellm.md: replace the "Ollama MUST be enabled" paragraph with the actual post-fix behaviour — the deploy pipeline pre-creates ollama-internal idempotently, so LiteLLM starts cleanly whether or not Ollama is also enabled. Remove the two-step "edits required for no-Ollama" instructions since the compose change is no longer needed. - tests/unit/test_compose_runner.py::test_render_litellm_network_prep_is_idempotent: tighten the assertion from a loose `\"||\" in script` (which could pass if any unrelated || appeared in the rendered bash) to a full inspect→||→create chain match. Whitespace and the bash line-continuation backslash are normalised so the test isn't brittle to renderer-side line-wrap tweaks.
…c ownership
Previously the Ollama stack declared `ollama-internal` as a
compose-managed network (`driver: bridge`, `name: ollama-internal`)
while LiteLLM declared it `external: true`. The pipeline's pre-create
block was gated on LiteLLM-being-enabled, which left two ambiguous
cases:
* Joint LiteLLM + Ollama: pre-create runs, network exists with the
`managed-by=nexus-stack` label. Ollama's compose-up then tries to
treat it as a project-managed network. Modern Compose v2 tolerates
this with a warning, but the behaviour is version-dependent and
the joint case was never tested by the previous fix — the merged
PR (#617) only verified the LiteLLM-only path on production.
* Ollama-only future: would have been fine before, but breaks if
Ollama's compose later moves to `external: true` for any reason.
Switch Ollama's compose to also declare `ollama-internal` as
`external: true` + `name: ollama-internal`. Network ownership now lives
entirely in the pre-create block, neither compose project tries to
create it, and Compose's tolerance for pre-existing networks no longer
matters. Rename the gate parameter `litellm_network_prep` →
`ollama_internal_network_prep` since it's no longer LiteLLM-specific,
and broaden the default inference to fire when either stack is enabled.
Added two new tests:
* `test_run_compose_up_network_prep_default_when_ollama_in_enabled`
locks the ollama-only firing path (regression guard for the
inference change).
* `test_run_compose_up_network_prep_renders_once_in_joint_case`
confirms the joint case renders exactly one pre-create block, not
a duplicate per matching service.
Addresses Copilot review comment 3308563617 on PR #617.
stefanko-ch
pushed a commit
that referenced
this pull request
May 28, 2026
🤖 I have created a release *beep* *boop* --- ## [0.68.0](v0.67.0...v0.68.0) (2026-05-28) ### 🚀 Features * **stacks:** Add Evidence — SQL+markdown BI for analytics engineers ([#616](#616)) ([ac9ef64](ac9ef64)) ### 🐛 Bug Fixes * **hedgedoc:** Seeded admin account + R2 snapshot/restore persistence ([#619](#619)) ([a04d529](a04d529)) * **pipeline:** Pre-create ollama-internal network when LiteLLM enabled ([#617](#617)) ([3ea36be](3ea36be)) * **stacks:** Raise Metabase JVM heap to prevent OOM ([#620](#620)) ([70bb786](70bb786)) * **stacks:** Remove hardcoded credential fallbacks (audit C1-C3) ([#623](#623)) ([3002629](3002629)) * **stacks:** Resolve host-port 8888 collision (adminer ⇔ seaweedfs) ([#624](#624)) ([6831d2c](6831d2c)) * **tofu:** Validate cloudflare_account_id, cloudflare_zone_id, domain shapes ([#622](#622)) ([47f25c6](47f25c6)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LiteLLM's compose declares
ollama-internalas an external Docker network so it can reach the Ollama stack's container by name when both stacks are enabled. If Ollama is NOT enabled, the network doesn't exist anddocker compose upfor LiteLLM aborts BEFORE the container is created:The operator sees a Bad Gateway on
https://litellm.<domain>because nothing is listening on the proxied port. This was the live state on production — confirmed by SSH'ing in and seeingcompose psempty + the error on manualdocker compose up.This is a hard dependency that defeats LiteLLM's core value proposition: it's meant to be an OpenAI-compatible proxy for any provider (OpenAI, Anthropic, Mistral, ...), so operator-supplied API keys should be sufficient — Ollama is just one of N possible backends.
Fix
Two parts, in two commits.
Part 1 — pre-create the network (initial commit)
Add an idempotent pre-compose block to
compose_runner.render_remote_script:Part 2 — symmetric ownership (1923edf, after Copilot review)
Originally the Ollama stack still declared
ollama-internalas a compose-managed network (driver: bridge,name: ollama-internal) while LiteLLM declared itexternal: true. Joint LiteLLM+Ollama deployments then relied on Compose v2's tolerance for pre-existing networks — version-dependent behaviour that the merged fix never actually exercised on production.Switch Ollama's compose to also declare
ollama-internalasexternal: true+name: ollama-internal. Network ownership now lives entirely in the pre-create block — neither compose project tries to create it, and Compose's tolerance for pre-existing networks no longer matters.Pre-create flag is renamed and broadened accordingly: parameter
litellm_network_prep→ollama_internal_network_prep, default inference"litellm" in enabled→"litellm" in enabled OR "ollama" in enabled. Same pattern as the existingdify_storage_prep/metabase_storage_prepflags.Behaviour matrix after the fix
config.yamlhttp://ollama:11434resolves with no race on creationUpdated docs
Replaced the "Requires the ollama stack to be enabled" warning in
stacks/litellm/docker-compose.ymlwith the actual behaviour (pipeline pre-creates the network).Test plan
test_render_ollama_internal_network_prep_only_when_flagged— block present iff flag settest_render_ollama_internal_network_prep_is_idempotent—inspect → || → createshort-circuit shape lockedtest_run_compose_up_network_prep_default_when_litellm_in_enabled— LiteLLM-only default inferencetest_run_compose_up_network_prep_default_when_ollama_in_enabled— Ollama-only default inference (new in Part 2)test_run_compose_up_network_prep_renders_once_in_joint_case— joint case renders exactly one pre-create block, not duplicated per matching service (new in Part 2)test_run_compose_up_network_prep_omitted_when_neither_in_enabledtest_run_compose_up_network_prep_explicit_override_beats_enabled_inferencetest_compose_runner.pytests passpre-commit runclean (ruff format, ruff check, mypy strict)Live verification: manually applied the network-create on production server while debugging — LiteLLM now runs (
https://litellm.nexus-stack.chreturns 200 instead of 502). Next deploy via this code will be self-healing.Out of scope
ollama-internal); over-engineering this would be premature abstraction.config.yamlto omit the Ollama model entry when Ollama is disabled. Operator can edit the template; the existing comment in the template already explains the "Option B" wiring for real-provider keys.