Docker Bot Deployment: Reproducible Images, Persistent State and Secrets

한국어로 읽기

TECH INSIGHT / EXPLAINED

Docker packages an application and its user-space dependencies into an image. It can reduce deployment differences, but the host kernel, CPU architecture, mounts, configuration and external services still matter.

Three colleagues separate a portable application image from host differences, persistent data and credentials.
AI-generated educational illustration. Three colleagues separate a portable application image from host differences, persistent data and credentials.

Freeze an artifact, not just a tag

A tag such as python:3.12-slim can move to a newer image. For repeatable releases, choose a reviewed base digest, lock application dependencies and record the built image digest and target platform. Rebuilding the same Dockerfile later is not proof of identical bytes. Schedule reviewed updates so pinning does not mean never applying fixes.

This starter assumes a single-file Linux Python application plus requirements.txt. Replace the PYTHON_IMAGE build argument with the tested tag@sha256 digest for a release. Copying dependencies before source can reuse a cached install layer; the actual time saved depends on the build.

ARG PYTHON_IMAGE=python:3.12-slim
FROM ${PYTHON_IMAGE}
ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN useradd --uid 10001 --create-home bot && mkdir /data && chown bot:bot /data
COPY --chown=bot:bot bot.py .
USER bot
CMD ["python", "-u", "bot.py"]

Keep runtime state and credentials outside the image

Exclude sensitive files from the build context even when copying selected sources. Here is a starting .dockerignore; adapt it to every credential and output path in your project.

.git
.env*
secrets/
config*.ini
data/
logs/
__pycache__/
.venv/

Make the application contract visible in Compose

The example starts without automatic restart while deployment behavior is being tested. BOT_MODE, DATA_DIR and the *_FILE names are application conventions: bot.py must implement them, fail on invalid settings and actually disable order submission in paper mode. Docker does not infer those meanings. Create protected local secret files; do not commit them.

services:
  trading-bot:
    build: .
    init: true
    restart: "no"
    environment:
      BOT_MODE: paper
      DATA_DIR: /data
      API_KEY_FILE: /run/secrets/api_key
      API_SECRET_FILE: /run/secrets/api_secret
    secrets:
      - api_key
      - api_secret
    volumes:
      - bot_data:/data
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
secrets:
  api_key:
    file: ./secrets/api_key.txt
  api_secret:
    file: ./secrets/api_secret.txt
volumes:
  bot_data: {}

Understand what survives

The writable layer survives a stop/start of the same container and is lost when that container is removed. A named volume survives replacement unless explicitly removed; it still needs backup and restore tests. Moving only compose.yaml does not migrate database files, secrets or registry access.

Compose mounts the granted secrets as files. This avoids baking credentials into an image, but does not encrypt the source files or protect them from an administrator controlling the host. Verify that the non-root application can read the secret mounts and write its data volume without making them publicly writable.

Test startup, shutdown and recovery

In a Docker-enabled test environment, run docker compose config --quiet, build the image, then verify startup with dummy credentials and a paper adapter. Test persistence after container replacement, graceful SIGTERM handling and restart reconciliation. A health status alone does not make Docker restart a hung process. After recovery is proven, an appropriate restart policy such as unless-stopped can be selected with its documented manual-stop behavior.

Keep time handling explicit in application code; setting TZ without the required timezone data is insufficient. Unbuffered Python output helps timely logs, while rotation bounds disk use. A Linux container cannot simply run a Windows COM dependency. The configuration here was syntax-checked; no container runtime build is claimed.

Sources and further reading

Docker build practices · Docker persistence · Compose secrets · Restart policies · Python timezone data

Content and examples reviewed: 2026-09-29

댓글