Compare commits
8 Commits
38943392c2
...
docker
| Author | SHA1 | Date | |
|---|---|---|---|
| 42f8df2589 | |||
|
|
90f5451ff8 | ||
|
|
2e229ceadd | ||
|
|
32615bf615 | ||
|
|
7de5efab3f | ||
|
|
6fbd717868 | ||
|
|
6be588aa58 | ||
|
|
01a3efd424 |
274
Docs/Libs/Docker/01-Setup.md
Normal file
274
Docs/Libs/Docker/01-Setup.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# Docker SDK for Python – Setup and First Steps
|
||||
|
||||
This document introduces the **Docker SDK for Python (`docker` library)** and explains how to connect to the Docker Engine, inspect its status, and authenticate with a registry. The goal is not just to show code, but to clearly explain **what each part does, why it exists, and when you would use it**.
|
||||
|
||||
This guide assumes you already understand basic Docker concepts (images, containers, daemon) and are approaching this from a DevOps perspective.
|
||||
|
||||
---
|
||||
|
||||
## 1. Installing the Docker SDK for Python
|
||||
|
||||
Before Python can communicate with Docker, we need to install the official SDK.
|
||||
|
||||
```bash
|
||||
pip install docker
|
||||
```
|
||||
|
||||
### What this does
|
||||
|
||||
* Installs the **docker** Python package (often called *docker-py*).
|
||||
* This package acts as a **client wrapper** around Docker’s REST API.
|
||||
* All interactions ultimately talk to the Docker daemon (`dockerd`) over a socket or TCP connection.
|
||||
|
||||
Important note:
|
||||
|
||||
* Installing the library alone is not enough.
|
||||
* Docker **must already be installed and running** on the system.
|
||||
|
||||
---
|
||||
|
||||
## 2. Connecting to Docker Using Environment Configuration
|
||||
|
||||
The simplest and most common way to create a Docker client is by using environment-based configuration.
|
||||
|
||||
```python
|
||||
import docker
|
||||
|
||||
client = docker.from_env()
|
||||
version = client.version()
|
||||
ping_docker = client.ping()
|
||||
|
||||
print(version, ping_docker)
|
||||
```
|
||||
|
||||
### Step-by-step explanation
|
||||
|
||||
#### `import docker`
|
||||
|
||||
* Imports the Docker SDK.
|
||||
* This module exposes high-level objects for interacting with Docker resources.
|
||||
|
||||
#### `docker.from_env()`
|
||||
|
||||
* Automatically creates a `DockerClient` instance.
|
||||
* Reads Docker connection details from environment variables such as:
|
||||
|
||||
* `DOCKER_HOST`
|
||||
* `DOCKER_TLS_VERIFY`
|
||||
* `DOCKER_CERT_PATH`
|
||||
* On Linux, this usually resolves to:
|
||||
|
||||
* `unix:///var/run/docker.sock`
|
||||
|
||||
This is why `from_env()` is preferred:
|
||||
|
||||
* Works across Linux, macOS, Windows, and CI systems
|
||||
* Requires no hardcoded connection strings
|
||||
|
||||
#### `client.version()`
|
||||
|
||||
* Calls the Docker Engine `/version` API endpoint.
|
||||
* Returns detailed metadata such as:
|
||||
|
||||
* Docker Engine version
|
||||
* API version
|
||||
* Go version
|
||||
* OS and architecture
|
||||
|
||||
This is commonly used for:
|
||||
|
||||
* Debugging
|
||||
* Compatibility checks
|
||||
* Logging runtime environment details
|
||||
|
||||
#### `client.ping()`
|
||||
|
||||
* Sends a lightweight request to the Docker daemon.
|
||||
* Returns `True` if Docker is reachable and responsive.
|
||||
|
||||
This is a **health check**, often used in:
|
||||
|
||||
* Startup validation
|
||||
* Monitoring scripts
|
||||
* CI/CD pipelines
|
||||
|
||||
---
|
||||
|
||||
## 3. What Does “from_env” Actually Mean?
|
||||
|
||||
Using `from_env()` tells the SDK:
|
||||
|
||||
> “Figure out how to connect to Docker using the same configuration the Docker CLI uses.”
|
||||
|
||||
Behind the scenes, it:
|
||||
|
||||
* Detects whether Docker is local or remote
|
||||
* Determines socket vs TCP
|
||||
* Applies TLS settings if required
|
||||
|
||||
### When should you use it?
|
||||
|
||||
* Local development
|
||||
* Kubernetes nodes
|
||||
* CI runners
|
||||
* Most production automation
|
||||
|
||||
### When not to use it?
|
||||
|
||||
* When you need explicit control over connection parameters
|
||||
* When connecting to a **remote Docker daemon** with custom networking
|
||||
|
||||
---
|
||||
|
||||
## 4. Creating a Docker Client Explicitly
|
||||
|
||||
Instead of relying on environment detection, you can create a client manually.
|
||||
|
||||
```python
|
||||
import docker
|
||||
|
||||
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||
version = client.version()
|
||||
ping_docker = client.ping()
|
||||
|
||||
print(version, ping_docker)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
#### `docker.DockerClient(...)`
|
||||
|
||||
* Directly instantiates a Docker client object.
|
||||
* Requires you to specify how to reach the Docker daemon.
|
||||
|
||||
#### `base_url='unix://var/run/docker.sock'`
|
||||
|
||||
* Points to the Unix socket used by Docker on Linux systems.
|
||||
* This socket is owned by root and the `docker` group.
|
||||
|
||||
Important implications:
|
||||
|
||||
* Your Python process must have permission to access the socket
|
||||
* Usually means running as root or a user in the `docker` group
|
||||
|
||||
### When this approach is useful
|
||||
|
||||
* Controlled environments
|
||||
* Educational examples
|
||||
* Explicit infrastructure scripts
|
||||
|
||||
### Why it is less common
|
||||
|
||||
* Not portable across OSes
|
||||
* Hardcodes infrastructure assumptions
|
||||
|
||||
---
|
||||
|
||||
## 5. Inspecting Docker and Authenticating
|
||||
|
||||
Once connected, the client can retrieve detailed system information and authenticate with registries.
|
||||
|
||||
```python
|
||||
import docker
|
||||
|
||||
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||
version = client.version()
|
||||
ping_docker = client.ping()
|
||||
information = client.info()
|
||||
|
||||
client.login(
|
||||
username='user',
|
||||
password='password',
|
||||
registry='registry_link'
|
||||
)
|
||||
|
||||
print(information, ping_docker)
|
||||
```
|
||||
|
||||
### `client.info()`
|
||||
|
||||
* Calls the Docker `/info` endpoint.
|
||||
* Returns a comprehensive snapshot of the Docker host, including:
|
||||
|
||||
* Number of containers (running/stopped)
|
||||
* Number of images
|
||||
* Storage driver
|
||||
* Cgroup and kernel features
|
||||
* Security options (AppArmor, seccomp)
|
||||
|
||||
This is extremely valuable for:
|
||||
|
||||
* Capacity planning
|
||||
* Debugging runtime issues
|
||||
* Auditing host configuration
|
||||
|
||||
### `client.login(...)`
|
||||
|
||||
* Authenticates Docker with a container registry.
|
||||
* Stores credentials in Docker’s credential store.
|
||||
|
||||
Parameters:
|
||||
|
||||
* `username`: registry account username
|
||||
* `password`: registry password or access token
|
||||
* `registry`: registry URL (e.g. Docker Hub or private registry)
|
||||
|
||||
Common use cases:
|
||||
|
||||
* Pulling private images
|
||||
* Pushing images in CI/CD pipelines
|
||||
* Automating registry interactions
|
||||
|
||||
Security note:
|
||||
|
||||
* Avoid hardcoding credentials in source code
|
||||
* Prefer environment variables or secret managers
|
||||
|
||||
---
|
||||
|
||||
## 6. High-Level vs Low-Level API (Important Concept)
|
||||
|
||||
What you are using here is the **high-level Docker client**.
|
||||
|
||||
Characteristics:
|
||||
|
||||
* Pythonic object model
|
||||
* Resource-oriented (containers, images, networks)
|
||||
* Easier to read and maintain
|
||||
|
||||
The SDK also exposes a **low-level API**:
|
||||
|
||||
* Direct access to Docker REST endpoints
|
||||
* More control, less abstraction
|
||||
|
||||
As a DevOps engineer, you will typically:
|
||||
|
||||
* Use high-level API for automation
|
||||
* Drop to low-level API for advanced edge cases
|
||||
|
||||
---
|
||||
|
||||
## 7. Summary
|
||||
|
||||
In this setup phase, you learned how to:
|
||||
|
||||
* Install the Docker SDK for Python
|
||||
* Connect to Docker using environment-based configuration
|
||||
* Explicitly define Docker connection settings
|
||||
* Verify Docker availability
|
||||
* Retrieve system-level Docker information
|
||||
* Authenticate with container registries
|
||||
|
||||
This foundation is critical before moving on to:
|
||||
|
||||
* Managing containers
|
||||
* Building images
|
||||
* Working with volumes and networks
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
Official Docker SDK for Python documentation:
|
||||
|
||||
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|
||||
360
Docs/Libs/Docker/02-Images.md
Normal file
360
Docs/Libs/Docker/02-Images.md
Normal file
@@ -0,0 +1,360 @@
|
||||
# Docker SDK for Python – Working with Images
|
||||
|
||||
This document explains how to **manage Docker images** using the Docker SDK for Python. Instead of treating the SDK as a set of function calls, we’ll approach images the same way Docker itself does: as immutable artifacts that are pulled, built, tagged, pushed, inspected, and eventually cleaned up.
|
||||
|
||||
All examples assume:
|
||||
|
||||
* Docker is installed and running
|
||||
* The Python process has access to the Docker socket
|
||||
|
||||
---
|
||||
|
||||
## 1. Creating the Docker Client
|
||||
|
||||
```python
|
||||
import docker
|
||||
|
||||
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||
ping_docker = client.ping()
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* `DockerClient` establishes a connection to the Docker daemon.
|
||||
* `ping()` verifies that Docker is reachable before doing any real work.
|
||||
|
||||
This is a common pattern in automation:
|
||||
|
||||
* Fail fast if Docker is unavailable
|
||||
* Avoid partial execution later in the script
|
||||
|
||||
---
|
||||
|
||||
## 2. Pulling Images from a Registry
|
||||
|
||||
```python
|
||||
def pull_image(name_image, tag_image):
|
||||
image = client.images.pull(name_image, tag=tag_image)
|
||||
print(image)
|
||||
```
|
||||
|
||||
### What this does
|
||||
|
||||
* Downloads an image from a registry (Docker Hub or private registry).
|
||||
* If the image already exists locally, Docker may reuse layers.
|
||||
|
||||
Parameters:
|
||||
|
||||
* `name_image`: repository name (e.g. `alpine`, `nginx`, `myrepo/app`)
|
||||
* `tag_image`: specific version or variant (e.g. `3.20`, `latest`)
|
||||
|
||||
Returned value:
|
||||
|
||||
* An `Image` object representing the pulled image
|
||||
|
||||
Why this matters:
|
||||
|
||||
* Pulling explicitly avoids relying on implicit image downloads
|
||||
* Makes automation predictable and repeatable
|
||||
|
||||
---
|
||||
|
||||
## 3. Building Images from a Dockerfile
|
||||
|
||||
### Basic build
|
||||
|
||||
```python
|
||||
def build_image():
|
||||
image, logs = client.images.build(
|
||||
path=".",
|
||||
tag="myapp:1.0"
|
||||
)
|
||||
|
||||
for log in logs:
|
||||
if "stream" in log:
|
||||
print(log["stream"].strip())
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* `path="."` tells Docker to use the current directory as the build context.
|
||||
* Docker automatically looks for a file named `Dockerfile`.
|
||||
* `tag="myapp:1.0"` assigns a name and version to the resulting image.
|
||||
|
||||
The build process returns:
|
||||
|
||||
* `image`: the final built image object
|
||||
* `logs`: a stream of build output messages
|
||||
|
||||
Printing build logs is important because:
|
||||
|
||||
* Docker build failures are only visible in logs
|
||||
* CI pipelines rely on this output for debugging
|
||||
|
||||
---
|
||||
|
||||
## 4. Advanced Build with Custom Dockerfile and Build Arguments
|
||||
|
||||
```python
|
||||
def build_image_2():
|
||||
image, logs = client.images.build(
|
||||
path=".",
|
||||
dockerfile="Dockerfile.prod",
|
||||
tag="myapp:prod",
|
||||
buildargs={
|
||||
"APP_ENV": "production",
|
||||
"VERSION": "1.0.0"
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
This version adds more control:
|
||||
|
||||
* `dockerfile="Dockerfile.prod"`
|
||||
|
||||
* Allows multiple Dockerfiles per project
|
||||
* Common for dev vs prod builds
|
||||
|
||||
* `buildargs`
|
||||
|
||||
* Passed to `ARG` instructions inside the Dockerfile
|
||||
* Enables parameterized builds without editing the Dockerfile
|
||||
|
||||
Typical DevOps use cases:
|
||||
|
||||
* Environment-specific builds
|
||||
* Injecting version numbers
|
||||
* Feature flags during build time
|
||||
|
||||
---
|
||||
|
||||
## 5. Tagging Images
|
||||
|
||||
```python
|
||||
def tag_image():
|
||||
image = client.images.get("myapp:1.0")
|
||||
image.tag("myrepo/myapp", tag="latest")
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* Docker images are immutable, but tags are not.
|
||||
* This creates an additional reference to the same image ID.
|
||||
|
||||
Why tagging is important:
|
||||
|
||||
* One image can have multiple tags
|
||||
* Tags represent lifecycle stages (`1.0`, `prod`, `latest`)
|
||||
|
||||
This is how promotion pipelines work:
|
||||
|
||||
* Build once
|
||||
* Tag many times
|
||||
* Push selectively
|
||||
|
||||
---
|
||||
|
||||
## 6. Removing Images
|
||||
|
||||
```python
|
||||
def remove_image():
|
||||
client.images.remove("myapp:1.0", force=True)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* Removes the image reference from the local Docker host.
|
||||
* `force=True` removes the image even if it is in use by stopped containers.
|
||||
|
||||
Use with care:
|
||||
|
||||
* Running containers still prevent deletion
|
||||
* Forced removal is destructive
|
||||
|
||||
---
|
||||
|
||||
## 7. Pushing Images to a Registry
|
||||
|
||||
```python
|
||||
def push_image():
|
||||
client.images.push(
|
||||
repository="myrepo/myapp",
|
||||
tag="latest"
|
||||
)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* Uploads the image layers to a registry.
|
||||
* Requires prior authentication (`client.login`).
|
||||
|
||||
Important notes:
|
||||
|
||||
* Only new or changed layers are pushed
|
||||
* Tags determine what remote users pull
|
||||
|
||||
This step is usually automated in:
|
||||
|
||||
* CI/CD pipelines
|
||||
* Release workflows
|
||||
|
||||
---
|
||||
|
||||
## 8. Cleaning Up Unused Images
|
||||
|
||||
```python
|
||||
def prune_images():
|
||||
result = client.images.prune()
|
||||
print(result)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* Removes dangling images (untagged and unused).
|
||||
* Helps reclaim disk space on build servers.
|
||||
|
||||
The result includes:
|
||||
|
||||
* Number of images removed
|
||||
* Amount of disk space freed
|
||||
|
||||
This is essential for:
|
||||
|
||||
* CI runners
|
||||
* Long-lived build machines
|
||||
|
||||
---
|
||||
|
||||
## 9. Inspecting Image Metadata
|
||||
|
||||
```python
|
||||
def inspect_image():
|
||||
alpine_image = client.images.get("alpine:3.20")
|
||||
|
||||
print(alpine_image.attrs)
|
||||
print(alpine_image.attrs["Id"])
|
||||
print(alpine_image.attrs["Size"])
|
||||
print(alpine_image.attrs["Config"]["Env"])
|
||||
print(alpine_image.attrs["Config"]["Cmd"])
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* `attrs` exposes the raw Docker image inspection data.
|
||||
* This is equivalent to `docker image inspect`.
|
||||
|
||||
Useful fields:
|
||||
|
||||
* `Id`: content-addressable image hash
|
||||
* `Size`: image size in bytes
|
||||
* `Config.Env`: environment variables baked into the image
|
||||
* `Config.Cmd`: default command
|
||||
|
||||
This information is often used for:
|
||||
|
||||
* Debugging unexpected behavior
|
||||
* Auditing images
|
||||
* Validating build output
|
||||
|
||||
---
|
||||
|
||||
## 10. Listing Local Images
|
||||
|
||||
```python
|
||||
def image_list():
|
||||
images = client.images.list()
|
||||
for item in images:
|
||||
print(item.id, item.tags)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
* Lists all images stored locally.
|
||||
* Each image may have multiple tags or none.
|
||||
|
||||
This mirrors:
|
||||
|
||||
* `docker images`
|
||||
|
||||
---
|
||||
|
||||
## 11. Ensuring an Image Exists
|
||||
|
||||
```python
|
||||
def ensure_image(name):
|
||||
try:
|
||||
client.images.get(name)
|
||||
print(f"{name} exists")
|
||||
except docker.errors.ImageNotFound:
|
||||
print(f"Pulling {name}")
|
||||
client.images.pull(name)
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
This is a very common DevOps pattern:
|
||||
|
||||
* Check if the image exists locally
|
||||
* Pull it only if necessary
|
||||
|
||||
Benefits:
|
||||
|
||||
* Avoids unnecessary network calls
|
||||
* Makes scripts idempotent
|
||||
|
||||
---
|
||||
|
||||
## 12. Important Exceptions to Know
|
||||
|
||||
When working with images, you must handle failures explicitly.
|
||||
|
||||
### `docker.errors.ImageNotFound`
|
||||
|
||||
* Raised when an image does not exist locally
|
||||
* Common when calling `get()`
|
||||
|
||||
### `docker.errors.BuildError`
|
||||
|
||||
* Raised when an image build fails
|
||||
* Usually due to Dockerfile errors or missing files
|
||||
|
||||
### `docker.errors.APIError`
|
||||
|
||||
* Raised for general Docker API failures
|
||||
* Includes permission issues, daemon errors, and network problems
|
||||
|
||||
Catching these exceptions is critical for:
|
||||
|
||||
* Reliable automation
|
||||
* Meaningful error reporting
|
||||
* CI/CD stability
|
||||
|
||||
---
|
||||
|
||||
## 13. Summary
|
||||
|
||||
In this section, you learned how to:
|
||||
|
||||
* Pull images from registries
|
||||
* Build images using Dockerfiles
|
||||
* Use build arguments and multiple Dockerfiles
|
||||
* Tag and push images
|
||||
* Inspect and list images
|
||||
* Clean up unused images
|
||||
* Handle common Docker image errors
|
||||
|
||||
This image workflow is the backbone of:
|
||||
|
||||
* CI pipelines
|
||||
* Release automation
|
||||
* Platform engineering systems
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
Official Docker SDK for Python documentation:
|
||||
|
||||
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|
||||
284
Docs/Libs/Docker/03-Containers.md
Normal file
284
Docs/Libs/Docker/03-Containers.md
Normal file
@@ -0,0 +1,284 @@
|
||||
# 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/)
|
||||
68
Docs/Libs/Docker/05-Networks.md
Normal file
68
Docs/Libs/Docker/05-Networks.md
Normal file
@@ -0,0 +1,68 @@
|
||||
```python
|
||||
import docker
|
||||
import time
|
||||
|
||||
docker_client = docker.DockerClient(base_url="unix://var/run/docker.sock")
|
||||
docker_client.ping()
|
||||
|
||||
print("All Networks:\n")
|
||||
|
||||
all_networks = docker_client.networks.list()
|
||||
|
||||
for network in all_networks:
|
||||
print(network.name, network.id)
|
||||
|
||||
print("\nNetworks Named host and bridge:\n")
|
||||
|
||||
system_networks = docker_client.networks.list(names=["host", "bridge"])
|
||||
|
||||
for network in system_networks:
|
||||
print(network.name, network.id)
|
||||
|
||||
print("\nNetwork With Custom ID:\n")
|
||||
|
||||
custom_id_networks = docker_client.networks.list(
|
||||
ids=["29c9e588bb8e0db6445f2a2278a1c2f42e39dc163c0a404f744dc4139fe47d21"]
|
||||
)
|
||||
|
||||
for network in custom_id_networks:
|
||||
print(network.name, network.id)
|
||||
|
||||
print("\nNetwork With Custom ID (Including Attributes):\n")
|
||||
|
||||
custom_id_networks = docker_client.networks.list(
|
||||
ids=["29c9e588bb8e0db6445f2a2278a1c2f42e39dc163c0a404f744dc4139fe47d21"]
|
||||
)
|
||||
|
||||
for network in custom_id_networks:
|
||||
print(network.name, network.id, network.attrs)
|
||||
|
||||
print("\nNetwork With Custom Filter:\n")
|
||||
|
||||
filtered_networks = docker_client.networks.list(
|
||||
names=["gitea_default"],
|
||||
filters={"driver": "bridge"}
|
||||
)
|
||||
|
||||
for network in filtered_networks:
|
||||
if network.attrs["Driver"]:
|
||||
print(network.name, network.id)
|
||||
|
||||
print("\nNetwork With Custom Filter (Greedy):\n")
|
||||
|
||||
filtered_networks = docker_client.networks.list(
|
||||
names=["gitea_default"],
|
||||
filters={"driver": "bridge"},
|
||||
greedy=True
|
||||
)
|
||||
|
||||
for network in filtered_networks:
|
||||
if network.attrs["Driver"]:
|
||||
print(network.name, network.id, network.attrs)
|
||||
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
|
||||
```
|
||||
0
Docs/Libs/Docker/06-Volumes.md
Normal file
0
Docs/Libs/Docker/06-Volumes.md
Normal file
0
Docs/Libs/Docker/07-Monitoring.md
Normal file
0
Docs/Libs/Docker/07-Monitoring.md
Normal file
0
Docs/Libs/Docker/08-Error-Handeling.md
Normal file
0
Docs/Libs/Docker/08-Error-Handeling.md
Normal file
0
Docs/Libs/Docker/09-Compose.md
Normal file
0
Docs/Libs/Docker/09-Compose.md
Normal file
167
Docs/Libs/FastAPI/14-File-Post.md
Normal file
167
Docs/Libs/FastAPI/14-File-Post.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# FastAPI – POST Requests with File Uploads
|
||||
|
||||
This document demonstrates how to handle **file uploads** in FastAPI.
|
||||
File uploads are essential for APIs that need to receive **images, documents, or binary data** from clients.
|
||||
|
||||
---
|
||||
|
||||
## Example Application
|
||||
|
||||
Create or update `main.py` with the following content:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, File, UploadFile, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
users_db = [
|
||||
{"id": "1", "name": "radin", "password": "123"}
|
||||
]
|
||||
|
||||
|
||||
@app.post("/file")
|
||||
def upload_file_bytes(file: bytes = File(...)):
|
||||
"""
|
||||
Receive file as raw bytes.
|
||||
Returns the size of the uploaded file.
|
||||
"""
|
||||
return {"file_size": len(file)}
|
||||
|
||||
|
||||
@app.post("/uploadfile")
|
||||
def upload_file_uploadfile(file: UploadFile):
|
||||
"""
|
||||
Receive file as UploadFile.
|
||||
Returns filename, content type, and size.
|
||||
"""
|
||||
content = file.read()
|
||||
return {
|
||||
"filename": file.filename,
|
||||
"content_type": file.content_type,
|
||||
"file_size": len(content)
|
||||
}
|
||||
|
||||
|
||||
@app.post("/uploadmultifile")
|
||||
def upload_multiple_files(files: List[UploadFile]):
|
||||
"""
|
||||
Receive multiple files as UploadFile list.
|
||||
Returns filenames and content types.
|
||||
"""
|
||||
return [
|
||||
{"filename": file.filename, "content_type": file.content_type}
|
||||
for file in files
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Upload Methods
|
||||
|
||||
### 1. `File` as Bytes
|
||||
|
||||
* Accepts the uploaded file as raw bytes
|
||||
* Suitable for small files or direct in-memory processing
|
||||
* Fast but lacks metadata (filename, content type)
|
||||
|
||||
**Example Request (curl):**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/file" \
|
||||
-F "file=@example.txt"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"file_size": 128
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. `UploadFile`
|
||||
|
||||
* Accepts file as `UploadFile` object
|
||||
* Provides metadata: `filename` and `content_type`
|
||||
* Supports `.read()`, `.write()`, and `.seek()` operations
|
||||
* More efficient for large files (uses spooled temporary files)
|
||||
|
||||
**Example Request (curl):**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/uploadfile" \
|
||||
-F "file=@example.txt"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"filename": "example.txt",
|
||||
"content_type": "text/plain",
|
||||
"file_size": 128
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Multiple File Uploads
|
||||
|
||||
* Accepts a list of `UploadFile`
|
||||
* Allows uploading multiple files in one request
|
||||
* Useful for batch uploads or form submissions
|
||||
|
||||
**Example Request (curl):**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/uploadmultifile" \
|
||||
-F "files=@file1.txt" \
|
||||
-F "files=@file2.txt"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
[
|
||||
{"filename": "file1.txt", "content_type": "text/plain"},
|
||||
{"filename": "file2.txt", "content_type": "text/plain"}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Content-Type
|
||||
|
||||
For file uploads, the request must include:
|
||||
|
||||
```
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
* Each file is sent as a separate part in the multipart request
|
||||
|
||||
---
|
||||
|
||||
## Running the Application
|
||||
|
||||
Start the service using `uvicorn`:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
* Use `UploadFile` for large or multiple files
|
||||
* Validate file type and size on the server
|
||||
* Avoid loading very large files fully into memory
|
||||
* Use HTTPS for secure file transfer
|
||||
* Store files in dedicated storage (S3, local disk, or DB)
|
||||
* Return clear metadata (filename, size, content type) to clients
|
||||
* Support multiple files when needed for batch operations
|
||||
121
Docs/Libs/FastAPI/15-Life-Span.md
Normal file
121
Docs/Libs/FastAPI/15-Life-Span.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# FastAPI – Application Lifespan (Startup & Shutdown Events)
|
||||
|
||||
FastAPI allows you to run code when your application **starts up** or **shuts down**.
|
||||
This is useful for initializing resources, database connections, caches, or background tasks.
|
||||
|
||||
---
|
||||
|
||||
## Deprecated Method: `@app.on_event`
|
||||
|
||||
Older FastAPI versions use the `@app.on_event` decorator for lifecycle events:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
def on_startup():
|
||||
print("App is loading")
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
def on_shutdown():
|
||||
print("App is shutting down")
|
||||
```
|
||||
|
||||
### Characteristics
|
||||
|
||||
* `startup` runs once when the app starts
|
||||
* `shutdown` runs once when the app is stopped
|
||||
* Works for synchronous and asynchronous functions
|
||||
* Still supported but **deprecated** in favor of the `lifespan` parameter
|
||||
|
||||
---
|
||||
|
||||
## Recommended Modern Approach: `lifespan` with `asynccontextmanager`
|
||||
|
||||
FastAPI now recommends using the `lifespan` parameter in the `FastAPI` constructor.
|
||||
This uses Python's `asynccontextmanager` to define a **single lifecycle context**.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Code to run before the app starts
|
||||
print("App is loading")
|
||||
yield # Application runs after this point
|
||||
# Code to run after the app stops
|
||||
print("App is shutting down")
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Code **before `yield`** executes on startup
|
||||
2. Code **after `yield`** executes on shutdown
|
||||
3. Supports async operations, e.g., connecting to a database
|
||||
|
||||
---
|
||||
|
||||
## Example: Using Lifespan for Database Initialization
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
app.state.db = await connect_to_db()
|
||||
print("Database connected")
|
||||
yield
|
||||
await app.state.db.close()
|
||||
print("Database disconnected")
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
```
|
||||
|
||||
* `app.state` is used to store shared resources
|
||||
* Clean startup and shutdown handling
|
||||
* Ensures proper resource cleanup
|
||||
|
||||
---
|
||||
|
||||
## Benefits of the Lifespan Approach
|
||||
|
||||
* Centralized lifecycle management
|
||||
* Cleaner async support
|
||||
* Avoids multiple scattered `@app.on_event` decorators
|
||||
* Better for testing and production-ready apps
|
||||
|
||||
---
|
||||
|
||||
## Running the Application
|
||||
|
||||
Start the service with `uvicorn`:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload
|
||||
```
|
||||
|
||||
* On startup, `App is loading` prints to the console
|
||||
* On shutdown (Ctrl+C), `App is shutting down` prints to the console
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
* Always use `lifespan` for new applications
|
||||
* Use `app.state` to store shared resources
|
||||
* Close database connections, caches, or background services in shutdown
|
||||
* Keep startup logic lightweight to avoid blocking the server
|
||||
* Avoid printing in production; use logging instead
|
||||
|
||||
---
|
||||
|
||||
This approach provides a **modern, production-ready pattern** for managing application startup and shutdown events in FastAPI.
|
||||
|
||||
Reference in New Issue
Block a user