Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Containerize Discord bot #13

Open
Open
Assignees

Description

🧠 Context

The Discord bot currently runs only as a local process (make discord β†’ uv run python -m src.apps.discord_bot). To host it always-on later, it needs to run in a container. This ticket containerizes the bot and adds it to docker-compose.yml behind a profile, so it's available for deployment without changing the day-to-day workflow for contributors who only need Postgres/Redis for tests.

There is already a commented-out worker service in docker-compose.yml β€” it shows the exact pattern to follow (build: ., the internal database URL, depends_on). Reference it.

This is infrastructure + docs only β€” no application code changes. src/apps/discord_bot.py is not touched.


πŸ›  Implementation Plan

  1. Dockerfile (new, repo root). Build an image that runs the bot:

    • Use uv's combined base image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim (also published as astral/uv:python3.12-bookworm-slim on Docker Hub). It bundles uv + Python 3.12 on Debian bookworm-slim, so there's no separate base image and no need to copy the uv binary in β€” this is the approach uv's own Docker guide recommends. The tag tracks the current uv for that Python/OS.
    • Install dependencies from the committed lockfile with uv sync --frozen so the image matches CI's resolution. Install dependencies before copying src/ so the dependency layer is cached across code changes.
    • Copy src/ and run the bot module as the container command.
    • Follow uv's official container guide for the layer-caching and project-install details: https://docs.astral.sh/uv/guides/integration/docker/
  2. .dockerignore (new, repo root). Keep the image small and avoid baking in secrets: exclude at least .venv, .git, tests, data, docker, __pycache__, and .env (the token must come in at runtime, never be built into the image).

  3. docker-compose.yml β€” add a bot service behind a profile.

    • build: . (the new Dockerfile), command runs the bot module.
    • profiles: ["bot"] β€” this is the key requirement. With a profile set, a plain docker compose up does not start the bot; only docker compose --profile bot up does. This keeps the default test workflow (Postgres + Redis) unchanged.
    • depends_on: [postgres]. The bot does not use Redis at runtime, so don't depend on it.
    • env_file: .env to supply the token, guild ID, models, etc., plus two environment: overrides for the values that differ inside a container (see networking note below).
  4. README.md β€” add a ## Bot Deployment section. Document: the prerequisites, the build/run commands, and the networking caveats. Keep all new content within this one new section to avoid conflicts with other contributors editing the README concurrently.

  5. (Optional) add a make discord-docker target wrapping docker compose --profile bot up to mirror the existing discord target.

Container networking (host vs internal addresses)

A container does not share the host's localhost, so two settings from .env are wrong inside the container and must be overridden in the bot service's environment::

  • Database β€” inside the compose network, Postgres is reached at postgres:5432 (the service name + internal port), not localhost:5445. The commented worker service already shows this exact URL: postgresql+asyncpg://postgres:postgres@postgres:5432/cs_assistant.
  • Ollama β€” Ollama runs on the host, not in compose, so the container reaches it via host.docker.internal:11434 (OLLAMA_URL=http://host.docker.internal:11434). On Docker Desktop (macOS/Windows) this name resolves automatically; on Linux it does not, so add extra_hosts: ["host.docker.internal:host-gateway"] to the service (harmless on macOS/Windows, so include it unconditionally).

Everything else (DISCORD_BOT_TOKEN, DISCORD_GUILD_ID, OLLAMA_CHAT_MODEL, EMBEDDING_DIM, TOP_K, ...) comes from .env via env_file unchanged.

Prerequisites to document in the Deployment section

  • Postgres running, with migrations and ingestion already run from the host (make migrate + make ingest) β€” the bot container only reads the data; it does not migrate or ingest.
  • Ollama running on the host with both models pulled.
  • .env populated with a valid DISCORD_BOT_TOKEN and DISCORD_GUILD_ID (the bot exits at startup without them).

πŸ“ Notes

  • Ollama stays on the host β€” it is intentionally not containerized (it holds the models and will use a GPU host in production). The container reaches out to it.
  • No app code changes. If you find yourself editing src/apps/discord_bot.py, stop β€” that's out of scope for this ticket.
  • There are no automated tests for this ticket; it's verified by building and running the container (see below). The existing make test still needs Docker for the DB tests.
  • Keep README edits inside the new ## Deployment section.

βœ… Acceptance Criteria

  • A Dockerfile at the repo root builds an image that runs the bot, installing deps via uv sync --frozen.
  • A .dockerignore excludes .venv, .git, tests, data, and .env (at minimum).
  • docker-compose.yml has a bot service behind profiles: ["bot"]. A plain docker compose up -d does not start it (verify with docker compose ps β€” only postgres and redis come up); docker compose --profile bot up does.
  • The bot service reaches Postgres at postgres:5432 and host Ollama at host.docker.internal:11434, with extra_hosts set for Linux.
  • README.md has a ## Deployment section covering prerequisites (migrate + ingest from host, Ollama running, token in .env), the build/run commands, and the database/Ollama networking caveats including the Linux host-gateway note.
  • docker compose --profile bot up builds and starts the bot, it logs discord_ready, and /ask works in the dev server (manual check β€” needs a valid token).
  • make lint passes (the pre-commit check-yaml hook validates docker-compose.yml; trailing-whitespace / end-of-file hooks apply to the Dockerfile and README).

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

Status
In Progress

Milestone

No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /