Demo project: Wired Brain Coffee — product e-commerce service using Python/Docker microservices
Table of Contents
- Module 1 — Course Overview
- Module 2 — Getting Started with Python and Docker
- Module 3 — Running Multiple Containers with Docker Compose
- Module 4 — Making Your Application Production-ready
- Module 5 — Debugging Python Applications Running in Containers
- Reference Tables
- Summary of Essential Docker Commands
Module 1 — Course Overview
This course covers developing Python applications in Docker containers, from the basics to production deployment. The main topics covered:
| Topic | Description |
|---|---|
| Dockerizing | Creating a Dockerfile and building a Python image |
| Docker Compose | Orchestrating multiple containers for a single application |
| Production-ready | Logging, external configuration, volumes, secrets, networks |
| Debugging | Remote debugging with PyCharm and Visual Studio Code |
Module 2 — Getting Started with Python and Docker
Basic Architecture
graph TD
DEV[Developer / IDE]
DF[Dockerfile]
IMG[Docker Image]
CTR[Docker Container]
HUB[Docker Hub / Registry]
DEV -->|writes| DF
DF -->|docker build| IMG
IMG -->|docker run| CTR
IMG -->|docker push| HUB
HUB -->|docker pull| IMG
style DF fill:#f0ad4e,color:#000
style IMG fill:#5bc0de,color:#000
style CTR fill:#5cb85c,color:#fff
Setting Up the Environment
The Wired Brain Coffee project uses a microservices architecture. The wired-brain/ root directory contains all services.
Project initialization from the command line:
# Create the directory structure
mkdir wired-brain
cd wired-brain
mkdir product-service
cd product-service
# Create a virtual environment
python -m venv venv
# Activate the virtual environment
# Mac / Linux
source venv/bin/activate
# Windows
venv\Scripts\activate.bat
# Install Flask
pip install flask
# Save dependencies
pip freeze > requirements.txt
Project structure:
wired-brain/
├── product-service/
│ ├── src/
│ │ ├── app.py
│ │ ├── db.py
│ │ └── product.py
│ ├── config/
│ │ ├── db.ini
│ │ └── logging.ini
│ ├── Dockerfile
│ └── requirements.txt
├── nginx/
│ ├── Dockerfile
│ └── nginx.conf
└── docker-compose.yml
Visual Studio Code vs. PyCharm
| Criterion | Visual Studio Code | PyCharm |
|---|---|---|
| License | Open source, free | Commercial (Community/Pro editions) |
| Runtime language | JavaScript / TypeScript (Electron) | Java (JVM) |
| Memory footprint | Low | Higher |
| Python support | Via extension (Python, Pylance) | Native |
| Docker support | Via Docker extension | Native |
| Type | Advanced code editor | Full IDE |
| Remote debugging | debugpy (remote attach) | pydevd-pycharm (connect to IDE) |
Building a Flask Application
Flask is a Python micro web framework: it handles HTTP requests without imposing an ORM, form validation, etc. It follows an optional extensions model.
src/app.py — First iteration with in-memory list:
from flask import Flask, jsonify, request
app = Flask(__name__)
# In-memory data (before database integration)
catalog_items = [
{"id": 1, "name": "Wired Brain Coffee Mug"},
{"id": 2, "name": "Wired Brain Coffee T-Shirt"}
]
@app.route("/products", methods=["GET"])
def get_products():
return jsonify(catalog_items), 200
@app.route("/product/<int:product_id>", methods=["GET"])
def get_product(product_id):
product = next((p for p in catalog_items if p["id"] == product_id), None)
if product is None:
return jsonify({"error": "Product not found"}), 404
return jsonify(product), 200
@app.route("/product", methods=["POST"])
def create_product():
data = request.get_json()
new_id = max(p["id"] for p in catalog_items) + 1
product = {"id": new_id, "name": data["name"]}
catalog_items.append(product)
return jsonify(product), 201
@app.route("/product/<int:product_id>", methods=["PUT"])
def update_product(product_id):
product = next((p for p in catalog_items if p["id"] == product_id), None)
if product is None:
return jsonify({"error": "Product not found"}), 404
data = request.get_json()
product["name"] = data["name"]
return jsonify(product), 200
@app.route("/product/<int:product_id>", methods=["DELETE"])
def delete_product(product_id):
global catalog_items
product = next((p for p in catalog_items if p["id"] == product_id), None)
if product is None:
return jsonify({"error": "Product not found"}), 404
catalog_items = [p for p in catalog_items if p["id"] != product_id]
return jsonify(product), 200
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)
Testing the API with curl:
# GET - list all products
curl http://localhost:5000/products
# GET - retrieve a product by ID
curl -v http://localhost:5000/product/1
# POST - create a product
curl --header "Content-Type: application/json" \
--request POST \
--data '{"name": "New Item"}' \
-v http://localhost:5000/product
# PUT - update a product
curl --header "Content-Type: application/json" \
--request PUT \
--data '{"name": "Updated Item"}' \
-v http://localhost:5000/product/1
# DELETE - remove a product
curl --request DELETE http://localhost:5000/product/1
Dockerizing a Flask Application
A Dockerfile is a text document containing all the commands to assemble an image. The lifecycle is:
- Write a
Dockerfile - Build a
Docker image(docker build) - Start a
Docker container(docker run)
Key concept — layers: Each instruction in the
Dockerfilecreates a layer. Docker reuses cached layers if nothing has changed. Therefore, place least volatile items first (dependencies) and most volatile items last (source code).
Creating a Dockerfile and Starting a Container
product-service/Dockerfile:
# Official Python base image
FROM python:3.9
# Set the working directory inside the container
WORKDIR /code
# Copy dependencies FIRST (stable layer = optimal caching)
COPY requirements.txt .
# Install Python dependencies
RUN pip install -r requirements.txt
# Copy source code LAST (volatile layer)
COPY src/ .
# Start the Flask application
CMD ["python", "./app.py"]
requirements.txt:
Flask
Basic Docker commands:
# Build the image from the Dockerfile
docker build -t wired-brain/product-service:1.0 .
# List local images
docker images
# Start a container in detached mode with port mapping
docker run -d -p 5000:5000 --name product-service wired-brain/product-service:1.0
# View active containers
docker ps
# View container logs
docker logs product-service
# Stop and remove a container
docker stop product-service
docker rm product-service
Module 3 — Running Multiple Containers with Docker Compose
Multi-Container Architecture
graph LR
CLIENT[HTTP Client]
NGINX[Nginx :80\nreverse proxy]
PS[product-service :5000\nFlask + SQLAlchemy]
DB[(MySQL :3306\ndatabase)]
CLIENT -->|HTTP :80| NGINX
NGINX -->|proxy_pass :5000| PS
PS -->|SQL| DB
subgraph "Docker Compose — private network wired-brain"
NGINX
PS
DB
end
style NGINX fill:#009639,color:#fff
style PS fill:#3776ab,color:#fff
style DB fill:#4479a1,color:#fff
Introduction to Docker Compose
Docker Compose is a tool for defining and starting multi-container applications. A single docker-compose.yml file describes all services.
Advantages of Docker Compose:
- Create multiple isolated environments on a single host
- Start / stop the entire application with a single command
- Automatic private network between containers (DNS resolution by service name)
docker-compose buildto build all servicesdocker-compose up -dto start everything in detached modedocker-compose downto stop and remove containers
Configuring Docker Compose for the Product Service
docker-compose.yml — Initial version:
version: "3.8"
services:
productservice:
build: ./product-service
ports:
- "5000:5000"
Docker Compose commands:
# Navigate to wired-brain/
cd wired-brain
# Build all services
docker-compose build
# Start all containers in detached mode
docker-compose up -d
# View active containers
docker ps
# View logs for a service
docker-compose logs productservice
# Stop and remove containers + network
docker-compose down
Adding Nginx as a Reverse Proxy
A reverse proxy receives client requests and redirects them to the appropriate backend. Nginx intercepts requests on port 80 and forwards them to productservice on port 5000.
nginx/nginx.conf:
server {
listen 80;
location / {
proxy_pass http://productservice:5000;
}
}
Note:
productserviceis resolved by Docker Compose’s internal DNS — no IP address needed.
nginx/Dockerfile:
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
docker-compose.yml — With Nginx:
version: "3.8"
services:
web:
build: ./nginx
ports:
- "80:80"
productservice:
build: ./product-service
# No need to expose port 5000 on the host machine
# All traffic goes through Nginx
Introduction to SQLAlchemy (ORM)
SQLAlchemy is a SQL toolkit and ORM (Object-Relational Mapper) for Python. The project uses Flask-SQLAlchemy to simplify integration with Flask.
Why use an ORM?
| Situation | Without ORM | With SQLAlchemy |
|---|---|---|
| Simple relationship (1 table) | Manual SQL acceptable | Simplified |
| Many-to-many relationship | Complex join tables | Handled automatically |
| Database portability | Vendor-specific queries | Abstraction via dialects |
3 steps to use SQLAlchemy:
- Create the
SQLAlchemyobject - Initialize the Flask application with this object
- Create persistence classes (models)
src/db.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Integrating MySQL with SQLAlchemy
src/product.py — SQLAlchemy model:
from db import db
class Product(db.Model):
__tablename__ = "products"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
def json(self):
return {"id": self.id, "name": self.name}
@classmethod
def find_all(cls):
return cls.query.all()
@classmethod
def find_by_id(cls, product_id):
return cls.query.filter_by(id=product_id).first()
def save_to_db(self):
db.session.add(self)
db.session.commit()
def delete_from_db(self):
db.session.delete(self)
db.session.commit()
src/app.py — With SQLAlchemy:
from flask import Flask, jsonify, request
from db import db
from product import Product
app = Flask(__name__)
# MySQL connection URI: mysql://user:password@host/database
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:devpass@db/catalog"
# Initialize SQLAlchemy with the Flask application
db.init_app(app)
@app.before_first_request
def create_tables():
db.create_all()
@app.route("/products", methods=["GET"])
def get_products():
return jsonify([p.json() for p in Product.find_all()]), 200
@app.route("/product/<int:product_id>", methods=["GET"])
def get_product(product_id):
product = Product.find_by_id(product_id)
if product is None:
return jsonify({"error": "Product not found"}), 404
return jsonify(product.json()), 200
@app.route("/product", methods=["POST"])
def create_product():
data = request.get_json()
product = Product(name=data["name"])
product.save_to_db()
return jsonify(product.json()), 201
@app.route("/product/<int:product_id>", methods=["DELETE"])
def delete_product(product_id):
product = Product.find_by_id(product_id)
if product is None:
return jsonify({"error": "Product not found"}), 404
product.delete_from_db()
return jsonify(product.json()), 200
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)
requirements.txt:
Flask
Flask-SQLAlchemy
flask_mysqldb
# SQLAlchemy 1.4+ compatibility workaround
SQLAlchemy<1.4
MySQL initialization script — product-service/init.sql:
CREATE DATABASE IF NOT EXISTS catalog;
USE catalog;
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
docker-compose.yml — With MySQL:
version: "3.8"
services:
web:
build: ./nginx
ports:
- "80:80"
productservice:
build: ./product-service
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: devpass
MYSQL_DATABASE: catalog
volumes:
- ./product-service/init.sql:/docker-entrypoint-initdb.d/init.sql
Testing the Application with Postman
Postman is an API client that allows you to send HTTP requests, inspect responses, and write validation tests.
Postman Collection — Product Service:
| Request | Method | URL | Body |
|---|---|---|---|
| GET /products | GET | http://localhost/products | — |
| GET /product/:id | GET | http://localhost/product/1 | — |
| POST /product | POST | http://localhost/product | {"name": "New Product"} |
| DELETE /product/:id | DELETE | http://localhost/product/1 | — |
Module 4 — Making Your Application Production-ready
Twelve-Factor Methodology
The Twelve-Factor App is a methodology for building robust SaaS applications.
mindmap
root((Twelve-Factor))
Codebase
One repo, multiple deployments
Dependencies
Explicitly declared
Config
Externalized in environment
Backing Services
Treated as attached resources
Build/Release/Run
Strictly separated stages
Processes
Stateless processes
Port Binding
Services exported via port
Concurrency
Scale via process model
Disposability
Fast startup, graceful shutdown
Dev/Prod Parity
Dev and prod as similar as possible
Logs
Treated as event streams
Admin Processes
Isolated one-off tasks
The 4 most relevant factors with Docker:
| Factor | Docker contribution |
|---|---|
| Config | Environment variables, secrets, config files mounted as volumes |
| Dev/Prod Parity | Same image in dev and prod |
| Logs | stdout/stderr collected by Docker |
| Disposability | Containers started / stopped quickly |
Python Logging Module
Python’s logging module is part of the standard library. All Python modules can participate in logging, including third-party libraries.
Log levels:
| Level | Numeric value | Usage |
|---|---|---|
CRITICAL | 50 | Fatal error, application unrecoverable |
ERROR | 40 | Recoverable error |
WARNING | 30 | Warning, unexpected behavior |
INFO | 20 | General information |
DEBUG | 10 | Detailed debugging information |
3 components of the logging module:
- Loggers — Hierarchy (root logger → child loggers)
- Handlers — Destinations (console, file, network)
- Formatters — Message format (timestamp, level, logger, message)
config/logging.ini:
[loggers]
keys=root,app
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=INFO
handlers=consoleHandler
[logger_app]
level=DEBUG
handlers=consoleHandler
qualname=app
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(levelname)s - %(name)s - %(message)s
src/app.py — With logging:
import logging
import logging.config
from flask import Flask, jsonify, request
from db import db
from product import Product
# Load logger configuration from ini file
logging.config.fileConfig("config/logging.ini")
logger = logging.getLogger(__name__)
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:devpass@db/catalog"
db.init_app(app)
@app.route("/products", methods=["GET"])
def get_products():
logger.debug("GET /products called")
try:
return jsonify([p.json() for p in Product.find_all()]), 200
except Exception as e:
logger.exception("Error fetching products")
return jsonify({"error": "Internal Server Error"}), 500
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)
Application Configuration with ConfigParser
The configparser module reads configuration files in INI format.
config/db.ini:
[mysql]
host = db
username = root
password = devpass
database = catalog
src/app.py — Reading the configuration:
import configparser
def get_database_url():
config = configparser.ConfigParser()
config.read("config/db.ini")
mysql = config["mysql"]
return f"mysql://{mysql['username']}:{mysql['password']}@{mysql['host']}/{mysql['database']}"
app.config["SQLALCHEMY_DATABASE_URI"] = get_database_url()
Docker Volumes
graph TD
subgraph "Docker Volume Types"
AV[Anonymous Volume\nDocker generates a random name]
HV[Host Volume\nMounts a local directory into the container]
NV[Named Volume\nDefined name, managed by Docker, persistent]
end
style AV fill:#f0ad4e,color:#000
style HV fill:#5bc0de,color:#000
style NV fill:#5cb85c,color:#fff
| Type | docker-compose.yml syntax | Typical usage |
|---|---|---|
| Anonymous | - /var/lib/mysql | Temporary data |
| Host | - ./src:/code | Dev live reload, config files |
| Named | - db_data:/var/lib/mysql | DB data persistence |
docker-compose.yml — With volumes:
version: "3.8"
services:
productservice:
build: ./product-service
volumes:
# Host volume: mount config from the host machine
- ./product-service/config:/config
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: devpass
volumes:
# Named volume: data persisted between restarts
- db_data:/var/lib/mysql
# Host volume: init script
- ./product-service/init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
db_data:
Docker Secrets
A Docker secret is a blob of sensitive data (passwords, private keys, certificates) managed securely.
| Mode | Encryption | Availability |
|---|---|---|
| File-based (Docker Compose) | No — plaintext file | Local only |
| Encrypted external (Docker Swarm) | Yes — encrypted at rest | Swarm cluster |
db_password.txt:
mysecurepassword
docker-compose.yml — With secrets:
version: "3.8"
services:
productservice:
build: ./product-service
secrets:
- db_password
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txt
Reading the secret in the Python application:
def get_db_password():
try:
with open("/run/secrets/db_password", "r") as f:
return f.read().strip()
except FileNotFoundError:
# Fallback for local development
return "fallback_dev_password"
Docker Compose Networks
By default, all containers in a docker-compose.yml share a single network — a compromised container could access all others. Network segmentation is a security best practice.
graph LR
subgraph "frontend network"
NGINX[Nginx\nweb]
PS[product-service]
end
subgraph "backend network"
PS2[product-service]
DB[(MySQL\ndb)]
end
CLIENT[Client] -->|:80| NGINX
NGINX --> PS
PS -.->|same service| PS2
PS2 --> DB
style NGINX fill:#009639,color:#fff
style PS fill:#3776ab,color:#fff
style PS2 fill:#3776ab,color:#fff
style DB fill:#4479a1,color:#fff
Communication rules:
| Container | Can communicate with |
|---|---|
web (Nginx) | productservice only |
productservice | web AND db |
db (MySQL) | productservice only |
docker-compose.yml — With segmented networks:
version: "3.8"
services:
web:
build: ./nginx
ports:
- "80:80"
networks:
- frontend
productservice:
build: ./product-service
secrets:
- db_password
volumes:
- ./product-service/config:/config
networks:
- frontend
- backend
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password
volumes:
- db_data:/var/lib/mysql
- ./product-service/init.sql:/docker-entrypoint-initdb.d/init.sql
secrets:
- db_password
networks:
- backend
networks:
frontend:
backend:
volumes:
db_data:
secrets:
db_password:
file: ./db_password.txt
Module 5 — Debugging Python Applications Running in Containers
Modifying Python Code in a Container
Without optimization, the development cycle is: modify → stop → rebuild → restart. This can be eliminated by combining:
- Flask in debug mode (
debug=True): automatic reload on every file modification - Host volume: mount the local source code directly into the container
# Add to the productservice service
volumes:
- ./product-service/src:/code # Live reload of source code
- ./product-service/config:/config
Result: modify app.py in the IDE → Flask automatically reloads in the container — without rebuilding.
Debugging Architecture
sequenceDiagram
participant IDE as IDE (PyCharm / VS Code)
participant CTR as Docker Container
participant APP as Flask App
Note over IDE,CTR: PyCharm Mode (push)
IDE->>IDE: Start debug server
CTR->>IDE: pydevd_pycharm.settrace() → incoming connection
IDE-->>CTR: Breakpoints active
Note over IDE,CTR: VS Code Mode (pull)
CTR->>CTR: debugpy.listen(0.0.0.0:5678)
IDE->>CTR: Remote Attach → outgoing connection
IDE-->>CTR: Breakpoints active
Debugging with PyCharm
The PyCharm model is reversed: it is the container that connects to PyCharm (not the other way around).
requirements.txt — Add PyCharm debugpy:
pydevd-pycharm~=213.6461.77
src/app.py — With PyCharm debugger:
import pydevd_pycharm
# host.docker.internal → IP of the host machine from a Docker container
pydevd_pycharm.settrace(
"host.docker.internal",
port=12345,
stdoutToServer=True,
stderrToServer=True
)
Steps in PyCharm:
Run → Edit Configurations → Add → Python Remote Debug- Set the port (e.g.:
12345) - Start the debug server in PyCharm
- Start the containers → the container connects to PyCharm
- Set breakpoints, step through the code
Debugging with Visual Studio Code
The VS Code model is standard: VS Code connects to the container that is listening.
requirements.txt — Add debugpy:
debugpy
src/app.py — With debugpy (VS Code):
import debugpy
# Listen for debugger connections from outside the container
debugpy.listen(("0.0.0.0", 5678))
# Optional: wait for a debugger to connect before continuing
# debugpy.wait_for_client()
Expose the debug port in docker-compose.yml:
productservice:
build: ./product-service
ports:
- "5678:5678" # debugpy port
volumes:
- ./product-service/src:/code
.vscode/launch.json — Remote Attach configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}/product-service/src",
"remoteRoot": "/code"
}
]
}
]
}
Steps in VS Code:
- Start the containers with
docker-compose up -d - Go to
Run and Debug(Ctrl+Shift+D) - Select
Python: Remote Attachand press ▶ - VS Code connects to the container on port 5678
- Set breakpoints in the local source code
Reference Tables
Official Python Images on Docker Hub
| Image | Description | Size (approx.) |
|---|---|---|
python:3.x | Full Debian image | ~900 MB |
python:3.x-slim | Minimal Debian | ~150 MB |
python:3.x-alpine | Alpine Linux (very lightweight) | ~50 MB |
python:3.x-slim-buster | Minimal Debian Buster | ~120 MB |
Python Dockerfile Optimizations
| Technique | Description | Impact |
|---|---|---|
| Layer ordering | Dependencies before source code | Better cache during rebuilds |
.dockerignore | Exclude venv/, __pycache__/, .git/ | Lighter image |
| slim/alpine image | Use python:3.x-slim | ~80% size reduction |
--no-cache-dir | pip install --no-cache-dir | Avoids storing pip cache in image |
| COPY in one pass | COPY src/ . rather than file by file | Fewer layers |
| Multi-stage build | Separate build and runtime | Final image without build tools |
Multi-Stage Build Python
graph LR
subgraph "Stage 1 — Builder"
B1[python:3.9 base]
B2[pip install deps]
B3[Compiled code / wheels]
end
subgraph "Stage 2 — Runner"
R1[python:3.9-slim base]
R2[COPY --from=builder]
R3[Lightweight final image]
end
B3 -->|COPY --from=builder| R2
style B1 fill:#f0ad4e,color:#000
style R1 fill:#5cb85c,color:#fff
Multi-stage Dockerfile example:
# Stage 1: builder — installs dependencies
FROM python:3.9 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# Stage 2: runner — lightweight image without build tools
FROM python:3.9-slim
WORKDIR /code
# Copy only the installed packages
COPY --from=builder /root/.local /root/.local
COPY src/ .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "./app.py"]
Debugging Mode Comparison
| Aspect | PyCharm (pydevd-pycharm) | VS Code (debugpy) |
|---|---|---|
| Connection direction | Container → IDE | IDE → Container |
| Startup | IDE starts debug server first | Container starts debug server first |
| Port | Configurable (e.g.: 12345) | 5678 (convention) |
| Host hostname | host.docker.internal | localhost (with exposed port) |
| Wait for client | On container startup | debugpy.wait_for_client() (optional) |
Summary of Essential Docker Commands
# === Images ===
docker build -t image-name:tag . # Build an image
docker images # List local images
docker pull python:3.9-slim # Download an image from Docker Hub
docker rmi image-name:tag # Remove an image
# === Containers ===
docker run -d -p 5000:5000 --name my-container image-name # Start a container
docker ps # List active containers
docker ps -a # All containers (including stopped)
docker stop my-container # Stop a container
docker rm my-container # Remove a container
docker logs my-container # View logs
docker exec -it my-container bash # Interactive shell in a container
# === Docker Compose ===
docker-compose build # Build all services
docker-compose up -d # Start all containers
docker-compose down # Stop and remove containers + network
docker-compose logs service-name # Logs for a specific service
docker-compose ps # Status of Compose containers
# === Volumes ===
docker volume ls # List volumes
docker volume rm volume-name # Remove a volume
# === Networks ===
docker network ls # List networks
docker network inspect network-name # Inspect a network
Search Terms
developing · python · apps · docker · containerization · containers · kubernetes · application · debugging · compose · architecture · container · dockerfile · flask · pycharm · running · sqlalchemy · studio · visual