Docker SDK Automation¶
Overview¶
Drive the Docker Engine API from Python to list images/containers, sketch cleanup safely with --apply, and understand networks, volumes, and registry automation boundaries.
The Docker SDK for Python talks to the same API as the Docker CLI. Use it for inventory and controlled cleanup — not for surprise prune in production without dry-run.
Complete Git Automation first. Diagrams use Excalidraw only.
This is a core tutorial in Module 17 · Docker Automation of the REBASH Academy Python for Cloud & DevOps Engineers series — written for Cloud, DevOps, Platform, and SRE engineers.
Prerequisites¶
Required¶
- Linux Automation habits (timeouts, exit codes)
- Docker Engine available or use the offline fixture path below
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Connect with
docker.from_env() - List containers and images
- Explain networks and volumes at an ops level
- Design prune/cleanup with dry-run
- Note registry auth as a separate concern
Architecture¶
This topic’s control points and relationships are shown below.
Theory¶
What it is¶
The Docker SDK for Python (docker package) talks to the Docker Engine API the same way the docker CLI does — usually over the Unix socket unix:///var/run/docker.sock, or via DOCKER_HOST for remote daemons. You get objects for containers, images, networks, and volumes: list, inspect, build, run, stop, and prune, without shelling out and scraping text.
Why it matters¶
DevOps automation invents containers for tests, cleans stale images on builders, and audits what is running on a host. Subprocess wrappers break when CLI output changes; the SDK returns structured attributes (status, tags, labels). In Continuous Integration / Continuous Delivery (CI/CD), Python jobs can assert “only expected containers exist” or pull pinned digests before a deploy smoke test — with the same safety flags you use for kubectl-style tools.
How it works¶
docker.from_env() builds a client from environment and default socket paths. client.ping() confirms the daemon is reachable. Listing containers with all=True includes stopped ones; images expose tags and IDs. Networks and volumes are separate namespaces — list first, delete only unused resources. Registry operations (login, pull, push) need credentials from the environment or credential helpers; never embed tokens in code. Production promotion should pin by digest (image@sha256:…), not only by floating tags like latest.
import docker
client = docker.from_env()
client.ping()
for c in client.containers.list(all=True):
print(c.short_id, c.status, c.image.tags)
Key concepts and comparisons¶
| Resource | SDK entry | Typical automation |
|---|---|---|
| Containers | client.containers | Inventory, stop/remove with --apply |
| Images | client.images | List, pull, prune dangling |
| Networks / volumes | client.networks / volumes | Cleanup unused lab resources |
| Swarm / Compose | Separate APIs / tools | Prefer Compose CLI for stacks |
| Action | Tutorial default |
|---|---|
| List / inspect / ping | Allowed |
| Stop / remove / prune | Require --apply |
| Force remove | Extra confirmation in real tools |
Common pitfalls¶
- Assuming the script’s user can access the Docker socket (group/
sudoissues). - Pruning aggressively on shared builders and deleting in-use layers.
- Logging registry passwords or auth configs.
- Treating tag
latestas immutable. - Mutating production hosts without dry-run and an allow-list of names.
Hands-on Lab¶
Focus: practise the core workflow for Docker SDK Automation
mkdir -p ~/rebash-python/module-17
cd ~/rebash-python/module-17
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install 'docker==7.1.0'
Step 1 – Fixture inventory (offline)¶
cd ~/rebash-python/module-17
source .venv/bin/activate
mkdir -p fixtures
cat > fixtures/containers.json << 'EOF'
[
{"id": "abc123", "status": "exited", "image": "nginx:1.27"},
{"id": "def456", "status": "running", "image": "redis:7"}
]
EOF
cat > docker_inventory.py << 'EOF'
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def from_fixture(path: Path) -> list[dict]:
return json.loads(path.read_text(encoding="utf-8"))
def from_docker() -> list[dict]:
import docker
client = docker.from_env()
client.ping()
rows = []
for c in client.containers.list(all=True):
tags = c.image.tags or [""]
rows.append({"id": c.short_id, "status": c.status, "image": tags[0]})
return rows
def main() -> int:
p = argparse.ArgumentParser(description="Docker container inventory")
p.add_argument("--fixture", type=Path)
p.add_argument("--apply-prune-exited", action="store_true", help="dangerous lab flag")
args = p.parse_args()
try:
rows = from_fixture(args.fixture) if args.fixture else from_docker()
except Exception as exc: # noqa: BLE001
print(f"error: {exc}", file=sys.stderr)
print("hint: use --fixture fixtures/containers.json", file=sys.stderr)
return 1
print(json.dumps(rows, indent=2))
exited = [r for r in rows if r["status"] == "exited"]
print(f"exited_count={len(exited)}", file=sys.stderr)
if args.apply_prune_exited:
print("error: prune not implemented in tutorial — use dedicated cleanup lab", file=sys.stderr)
return 2
return 0
if __name__ == "__main__":
raise SystemExit(main())
EOF
python docker_inventory.py --fixture fixtures/containers.json
Step 2 – Live ping (optional)¶
python - <<'PY'
try:
import docker
print("ping", docker.from_env().ping())
except Exception as exc:
print("docker unavailable:", exc)
PY
Step 3 – Cleanup policy notes¶
Write cleanup-policy.md: age threshold, exclude labels (keep=true), dry-run JSON plan, then --apply.
Validation¶
- Lab commands run under
~/rebash-python/module-17/ - You can explain each Theory section in your own words
- You used modern tooling where it applies to this topic
- You can describe one production failure mode for this topic
Code Walkthrough¶
Production practice for Docker SDK Automation always combines:
- Inspect before you change (status, plan, logs, dry-run)
- Prefer reversible, documented changes (Git, IaC, drop-ins, version pins)
- Capture evidence (command output, pipeline logs) for handovers
- Prefer current tools and APIs over legacy shortcuts
- Least privilege — escalate credentials only when required
Keep runbooks short enough to follow under pressure. Automate checks; keep humans for judgement.
Security Considerations¶
- Treat credentials and tokens for python as privileged — never commit them
- Prefer short-lived auth (OIDC, roles, SSO) over long-lived keys
- Validate blast radius before apply/deploy/delete operations
- Restrict who can approve production changes
- Collect audit logs; limit who can read sensitive traces
Common Mistakes¶
Assuming the script’s user can access the Docker socket (group/sudo issues).
Validate assumptions against the Theory section and official docs before changing production.
Pruning aggressively on shared builders and deleting in-use layers.
Lab shortcuts (open security groups, admin roles, skip approvals) must not ship unchanged.
Changing production without a rollback path
Always know how to revert (previous artefact, prior release, state rollback, DNS failback).
Best Practices¶
- Encode Docker SDK Automation changes as code and review them in pull requests
- Pin versions (images, modules, actions, provider plugins)
- Separate environments with clear promotion gates
- Alert on symptoms with runbooks attached
- Destroy lab resources; tag everything with owner and expiry where possible
Troubleshooting¶
| Symptom | Likely cause | What to do |
|---|---|---|
| Permission denied on socket | User not in docker group | Rootless or group membership |
| API version errors | Old engine/SDK mismatch | Align versions |
| Accidental wipe | Prune without filter | Labels + dry-run |
Summary¶
- SDK mirrors CLI capabilities over the Engine API
- Inventory first; prune only with explicit apply
- Lab: Docker Cleanup Tool
Interview Questions¶
- How does Docker SDK Automation show up when operating Cloud or production platforms?
- What would you check first if this area misbehaves in production?
- Which modern tools or APIs replace older equivalents here?
- What security control should accompany this capability?
- How would you automate verification of this topic in CI?
Sample answer — question 2
Start with blast radius and recent changes, gather evidence (logs, status, plan/diff), then fix forward with a known rollback path — not guesswork.