285 lines
5.8 KiB
Markdown
285 lines
5.8 KiB
Markdown
# Docker SDK for Python – Working with Containers
|
||
|
||
This document explains how to **manage Docker containers** using the Docker SDK for Python. Containers are the runtime unit of Docker, so this section focuses on lifecycle management: listing, creating, running, starting, stopping, restarting, pausing, and inspecting logs.
|
||
|
||
The goal is to understand **how container state changes**, how the Python SDK maps to Docker CLI behavior, and how these operations are typically used in real DevOps automation.
|
||
|
||
---
|
||
|
||
## 1. Creating the Docker Client
|
||
|
||
```python
|
||
import docker
|
||
import time
|
||
|
||
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||
ping_docker = client.ping()
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* Establishes a connection to the Docker daemon via the Unix socket.
|
||
* `ping()` is used as a sanity check before executing container operations.
|
||
|
||
In production-grade scripts, this check prevents:
|
||
|
||
* Silent failures
|
||
* Partial execution when Docker is down
|
||
|
||
---
|
||
|
||
## 2. Listing Running Containers
|
||
|
||
```python
|
||
def get_containers_list():
|
||
containers = client.containers.list()
|
||
|
||
for c in containers:
|
||
print(c.id, c.name, c.status)
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* `containers.list()` returns **only running containers** by default.
|
||
* Each returned object represents a live container instance.
|
||
|
||
Common attributes:
|
||
|
||
* `id`: unique container identifier
|
||
* `name`: human-readable container name
|
||
* `status`: runtime state (running)
|
||
|
||
This is equivalent to:
|
||
|
||
* `docker ps`
|
||
|
||
---
|
||
|
||
## 3. Listing All Containers (Including Stopped)
|
||
|
||
```python
|
||
def get_all_containers_list():
|
||
containers = client.containers.list(all=True)
|
||
|
||
for c in containers:
|
||
print(c.id, c.name, c.status)
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* `all=True` includes stopped, exited, and created containers.
|
||
* Useful for cleanup, auditing, and lifecycle reconciliation.
|
||
|
||
Equivalent CLI command:
|
||
|
||
* `docker ps -a`
|
||
|
||
---
|
||
|
||
## 4. Creating a Container (Without Starting It)
|
||
|
||
```python
|
||
def create_container():
|
||
container = client.containers.create(
|
||
image="nginx:latest",
|
||
name="my_nginx",
|
||
ports={"80/tcp": 8080},
|
||
detach=True
|
||
)
|
||
```
|
||
|
||
### Explanation
|
||
|
||
This creates a container in the **created** state.
|
||
|
||
Key parameters:
|
||
|
||
* `image`: base image for the container
|
||
* `name`: explicit container name
|
||
* `ports`: port mapping (container → host)
|
||
* `detach=True`: container runs in background when started
|
||
|
||
Important distinction:
|
||
|
||
* `create()` does **not** start the container
|
||
* This mirrors `docker create`
|
||
|
||
Use cases:
|
||
|
||
* Deferred startup
|
||
* Multi-step initialization
|
||
|
||
---
|
||
|
||
## 5. Running a Container (Create + Start)
|
||
|
||
```python
|
||
def run_container():
|
||
container = client.containers.run(
|
||
"nginx:latest",
|
||
name="nginx_run",
|
||
ports={"80/tcp": 8081},
|
||
detach=True
|
||
)
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* `run()` is a convenience method.
|
||
* Internally performs `create()` followed by `start()`.
|
||
|
||
Equivalent CLI command:
|
||
|
||
* `docker run -d -p 8081:80 nginx:latest`
|
||
|
||
This is the most common approach for:
|
||
|
||
* Short-lived workloads
|
||
* Simple services
|
||
|
||
---
|
||
|
||
## 6. Managing Container Lifecycle
|
||
|
||
```python
|
||
def start_container():
|
||
container = client.containers.get("my_nginx")
|
||
|
||
container.start()
|
||
time.sleep(1000)
|
||
|
||
container.restart()
|
||
time.sleep(1000)
|
||
|
||
container.pause()
|
||
container.unpause()
|
||
time.sleep(1000)
|
||
|
||
container.stop(timeout=10)
|
||
```
|
||
|
||
### Explanation
|
||
|
||
This function demonstrates multiple lifecycle transitions.
|
||
|
||
#### `containers.get(name)`
|
||
|
||
* Retrieves an existing container by name or ID.
|
||
* Raises an exception if the container does not exist.
|
||
|
||
#### `start()`
|
||
|
||
* Transitions container from `created` or `stopped` → `running`.
|
||
|
||
#### `restart()`
|
||
|
||
* Stops and immediately starts the container.
|
||
* Often used after configuration changes.
|
||
|
||
#### `pause()` / `unpause()`
|
||
|
||
* Freezes container processes using cgroups.
|
||
* Network and filesystem state remain intact.
|
||
|
||
#### `stop(timeout=10)`
|
||
|
||
* Sends SIGTERM, then SIGKILL after timeout.
|
||
* Allows graceful shutdown.
|
||
|
||
The `sleep()` calls simulate:
|
||
|
||
* Long-running services
|
||
* Observing container behavior between states
|
||
|
||
---
|
||
|
||
## 7. Reading Container Logs
|
||
|
||
```python
|
||
def log_container():
|
||
container = client.containers.get("my_nginx")
|
||
logs = container.logs(tail=20)
|
||
print(logs.decode())
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* Retrieves logs from the container’s stdout/stderr.
|
||
* `tail=20` limits output to the last 20 lines.
|
||
|
||
Important details:
|
||
|
||
* Logs are returned as bytes
|
||
* Decoding is required for readable output
|
||
|
||
Equivalent CLI command:
|
||
|
||
* `docker logs --tail 20 my_nginx`
|
||
|
||
This is critical for:
|
||
|
||
* Debugging runtime issues
|
||
* Health checks
|
||
* Observability tooling
|
||
|
||
---
|
||
|
||
## 8. Conditional Execution Based on Docker Availability
|
||
|
||
```python
|
||
if ping_docker:
|
||
get_containers_list()
|
||
```
|
||
|
||
### Explanation
|
||
|
||
* Ensures container operations only run if Docker is reachable.
|
||
* Prevents unhandled API errors.
|
||
|
||
This pattern is common in:
|
||
|
||
* Entry-point scripts
|
||
* Health probes
|
||
* Automation jobs
|
||
|
||
---
|
||
|
||
## 9. Container States (Conceptual Model)
|
||
|
||
Understanding container states is essential:
|
||
|
||
* `created`: container exists but is not running
|
||
* `running`: container processes are active
|
||
* `paused`: execution is suspended
|
||
* `exited`: container stopped normally
|
||
* `dead`: container failed unexpectedly
|
||
|
||
Every method in this document transitions the container between these states.
|
||
|
||
---
|
||
|
||
## 10. Summary
|
||
|
||
In this section, you learned how to:
|
||
|
||
* List running and stopped containers
|
||
* Create containers separately from starting them
|
||
* Run containers in a single step
|
||
* Control container lifecycle states
|
||
* Read container logs
|
||
* Safely execute operations based on Docker availability
|
||
|
||
This container-level control is the foundation for:
|
||
|
||
* Service orchestration
|
||
* CI/CD job execution
|
||
* Debugging and recovery automation
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
Official Docker SDK for Python documentation:
|
||
|
||
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|