A container runs a process in an isolated environment based on an image. An image packages the application and its runtime dependencies. Building an image and running a container are separate operations. A container’s writable layer should not be the only copy of important application data.
Expose only necessary ports and keep runtime secrets out of the image. A service listening inside a container is not automatically reachable from the host. Understand the mapping between internal and external ports and the network names used between services.
Use a persistent volume or external store for data that must survive replacement. A reproducible container still needs configuration checks, health behavior, and a rollback plan.
Exercise: write a container design for your Python API, identifying source files, dependency installation, startup command, port, and persistent data. If a container runtime is available, build and run it locally.
Check: replacing the application container does not silently erase the intended durable data, and no credential is baked into the image.
Guided workshop: reproduce an application environment
The Python importer is your first deployable artifact. Before adding AI, prove that another machine can run the same version. A Git commit identifies source; an environment description identifies dependencies; a container image packages a runnable filesystem. None of these automatically backs up application data.
Create a learning repository with the importer and its tests. Run these commands from that new repository, not inside a work repository you do not intend to change:
git init
git add import_documents.py test_import_documents.py
git commit -m "Add tested document importer"
git switch -c add-import-report
python3 -m unittest discover -v
git diff
If Git asks for identity, configure it for this repository using your own name and email. Do not copy someone else's identity. Make a small report-format change, review the diff, and commit it. Explain how a reviewer can compare it with the parent commit and run the same tests.
For a local container exercise, use this Dockerfile alongside your application. Save an actual CLI entry point as main.py; it should accept the input path and database path described in the Python exit project.
FROM python:3.12-slim
WORKDIR /app
COPY main.py /app/main.py
RUN useradd --uid 10001 --create-home learner
USER learner
ENTRYPOINT ["python", "/app/main.py"]
Build with docker build -t academy-importer:lesson .. Mount a fixture directory read-only and a separate writable output directory when running. On Linux, set the output directory's ownership for the container user rather than making it world-writable. Pin the tested base image by digest for a reproducible release; this illustrative tag can change.
Failure rehearsal: run once without the input mount and once with an unwritable output location. The application should exit unsuccessfully with a useful diagnostic. Delete and recreate the container, then check whether a database stored on the output mount survives. Data stored only in the container's writable layer does not provide the persistence contract your service needs.
Worked reasoning: localhost inside a container refers to that container. A database on another container needs reachable networking and a service hostname. Environment variables configure the process, but putting a secret in a Dockerfile or build command can expose it in image history or logs. Inject runtime secrets through the deployment environment.
Checkpoint: submit the commit ID, build command, runtime command, test output, and a diagram distinguishing image, container, process, network, and persistent volume. Explain who owns backup and restore; a volume alone is not a backup.