Apache Libcloud Docker Compose 部署指南
用 Docker Compose 编排 python:3.10-slim 镜像运行 Apache Libcloud 3.9.1 演示工程(Compute Dummy 驱动 + Storage 本地驱动),覆盖编排文件、启动验证、数据持久化、等价 docker run 与常用运维命令。
Apache Libcloud Docker Compose 部署指南
目标:Apache Libcloud 是 Python 库,不提供官方镜像、也不是常驻服务,因此没有「拉起一个 Libcloud 服务」的 Compose 场景。本文给出一份运行演示工程的 Compose 编排——用
python:3.10-slim基础镜像挂载演示工程目录,启动时安装apache-libcloud==3.9.1及依赖并运行 Compute(Dummy 驱动)+ Storage(本地驱动)完整演练,采集真实回显。已在 Ubuntu 22.04、Docker Compose v5.5.1 环境下实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS,Kernel 6.8.0-138-generic
- Docker Compose:v5.5.1(
docker compose version实测) - 基础镜像:
python:3.10-slim(内含 Python 3.10) - 目标库版本:apache-libcloud 3.9.1 + fasteners 0.20(存储本地驱动依赖)
- 演示工程目录:
/opt/data/ops/libcloud-compose(含compose.yml与app/) - 持久化卷:
libcloud-compose_storage-data(对象存储根目录)、libcloud-compose_pip-cache(pip 缓存)
二、镜像选型说明
| 用途 | 镜像 | 说明 |
|---|---|---|
| 运行演示工程 | python:3.10-slim | 官方 Python 3.10 精简镜像,满足 Libcloud 3.9.1 的 Requires-Python >=3.10,体积小、启动快 |
| 运行演示工程(备选) | python:3.12-slim | 更新解释器版本,Libcloud 兼容;如驱动生态对旧版本有要求可回退 3.10 |
💡 说明:Apache Libcloud 官方不发布任何 Docker 镜像——它是被上层 Python 应用 import 的库。上表镜像仅充当「运行 Libcloud 演示程序」的载体;生产中应把 Libcloud 作为依赖写进业务镜像的
requirements.txt。
三、前置条件
- 服务器已安装 Docker 与 Docker Compose 插件。
- 可访问 PyPI 镜像源(本文用清华镜像
https://pypi.tuna.tsinghua.edu.cn/simple,在启动命令中显式指定)。 - 已创建演示工程目录
/opt/data/ops/libcloud-compose,包含compose.yml与app/main.py、app/requirements.txt(见第四节)。
四、部署步骤(演示工程 Compose)
4.1 创建演示工程文件
工程目录结构:
mkdir -p /opt/data/ops/libcloud-compose/app
依赖清单 /opt/data/ops/libcloud-compose/app/requirements.txt:
apache-libcloud==3.9.1
fasteners==0.20
演示程序 /opt/data/ops/libcloud-compose/app/main.py(Compute 用内置 Dummy 驱动离线演练,Storage 用本地文件驱动,无需真实云账号):
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Libcloud 3.9.1 演示工程:Compute(Dummy 驱动) + Storage(本地驱动) 全流程演练。"""
import os
import shutil
from libcloud.compute.providers import get_driver as get_compute_driver
from libcloud.compute.types import Provider as ComputeProvider
from libcloud.storage.providers import get_driver as get_storage_driver
from libcloud.storage.types import Provider as StorageProvider
import libcloud
STORAGE_ROOT = os.environ.get("LIBCLOUD_STORAGE_ROOT", "/opt/libcloud-demo/storage-data")
def main():
print("=" * 60)
print("libcloud version:", libcloud.__version__)
print("=" * 60)
# ---------- Compute: Dummy 驱动 ----------
cls = get_compute_driver(ComputeProvider.DUMMY)
driver = cls("admin")
images = driver.list_images()
sizes = driver.list_sizes()
print("[compute] images:", [(i.id, i.name) for i in images])
print("[compute] sizes :", [(s.id, s.name, s.ram, s.disk) for s in sizes])
node = driver.create_node(name="demo-node", image=images[0], size=sizes[0])
print("[compute] created:", node.id, node.name, node.state, node.public_ips)
nodes = driver.list_nodes()
print("[compute] list_nodes:", [(n.id, n.name, str(n.state)) for n in nodes])
print("[compute] reboot_node ->", driver.reboot_node(node))
print("[compute] destroy_node ->", driver.destroy_node(node))
print("[compute] remaining:", [(n.id, n.name) for n in driver.list_nodes()])
# ---------- Storage: 本地驱动 ----------
# 清空存储根目录内容而非目录本身(目录可能是挂载点,直接删除会报错)
if os.path.exists(STORAGE_ROOT):
for entry in os.listdir(STORAGE_ROOT):
p = os.path.join(STORAGE_ROOT, entry)
shutil.rmtree(p) if os.path.isdir(p) else os.remove(p)
os.makedirs(STORAGE_ROOT, exist_ok=True)
payload = b"libcloud demo object payload\n"
with open("/tmp/demo-payload.txt", "wb") as f:
f.write(payload)
scls = get_storage_driver(StorageProvider.LOCAL)
sdriver = scls(STORAGE_ROOT)
container = sdriver.create_container(container_name="demo-bucket")
obj = sdriver.upload_object("/tmp/demo-payload.txt", container, object_name="payload.txt")
print("[storage] uploaded:", obj.name, "size:", obj.size)
download_path = "/tmp/demo-payload-downloaded.txt"
sdriver.download_object(obj, download_path, overwrite_existing=True)
with open(download_path, "rb") as f:
data = f.read()
assert data == payload, "downloaded content mismatch"
print("[storage] downloaded content matches, bytes:", len(data))
print("[storage] objects:", [(o.name, o.size) for o in container.list_objects()])
print("[storage] containers:", [c.name for c in sdriver.list_containers()])
print("=" * 60)
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()
4.2 编写 Compose 编排文件
创建 /opt/data/ops/libcloud-compose/compose.yml:
services:
libcloud-demo:
image: python:3.10-slim
container_name: libcloud-demo
working_dir: /app
command: ["sh", "-c", "pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python main.py"]
volumes:
- ./app:/app
- storage-data:/opt/libcloud-demo/storage-data
- pip-cache:/root/.cache/pip
environment:
- LIBCLOUD_STORAGE_ROOT=/opt/libcloud-demo/storage-data
- PIP_CACHE_DIR=/root/.cache/pip
volumes:
storage-data:
pip-cache:
💡 说明:
./app挂载演示源码;storage-data命名卷承接 Storage 本地驱动的对象根目录,实现数据落盘;pip-cache缓存 wheel 包,重复启动免重复下载。
4.3 启动并运行演示工程
cd /opt/data/ops/libcloud-compose
docker compose up
真实回显(关键行):
Volume libcloud-compose_storage-data Creating
Volume libcloud-compose_pip-cache Creating
Network libcloud-compose_default Creating
Volume libcloud-compose_storage-data Created
Volume libcloud-compose_pip-cache Created
Network libcloud-compose_default Created
Attaching to libcloud-demo
Container libcloud-demo Starting
Container libcloud-demo Started
libcloud-demo | Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
libcloud-demo | Collecting apache-libcloud==3.9.1
libcloud-demo | Downloading https://pypi.tuna.tsinghua.edu.cn/packages/ed/fd/6dbe8405dfbd6980513af65901548e3ee894a2879f3be1627830f023e38e/apache_libcloud-3.9.1-py3-none-any.whl (3.8 MB)
libcloud-demo | Collecting fasteners==0.20
libcloud-demo | Downloading https://pypi.tuna.tsinghua.edu.cn/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl (18 kB)
libcloud-demo | Successfully installed apache-libcloud-3.9.1 certifi-2026.7.22 charset_normalizer-3.5.2 fasteners-0.20 idna-3.20 requests-2.34.2 urllib3-2.8.0
libcloud-demo | ============================================================
libcloud-demo | libcloud version: 3.9.1
libcloud-demo | ============================================================
libcloud-demo | [compute] images: [('1', 'Ubuntu 9.10'), ('2', 'Ubuntu 9.04'), ('3', 'Slackware 4')]
libcloud-demo | [compute] sizes : [('1', 'Small', 128, 4), ('2', 'Medium', 512, 16), ('3', 'Big', 4096, 32), ('4', 'XXL Big', 8192, 128)]
libcloud-demo | [compute] created: 3 dummy-3 running ['127.0.0.3']
libcloud-demo | [compute] list_nodes: [('1', 'dummy-1', 'running'), ('2', 'dummy-2', 'running'), ('3', 'dummy-3', 'running')]
libcloud-demo | [compute] reboot_node -> True
libcloud-demo | [compute] destroy_node -> True
libcloud-demo | [compute] remaining: [('1', 'dummy-1'), ('2', 'dummy-2')]
libcloud-demo | [storage] uploaded: payload.txt size: 29
libcloud-demo | [storage] downloaded content matches, bytes: 29
libcloud-demo | [storage] objects: [('payload.txt', 29)]
libcloud-demo | [storage] containers: ['demo-bucket']
libcloud-demo | ============================================================
libcloud-demo | ALL CHECKS PASSED
libcloud-demo exited with code 0
退出码 0 且末行输出 ALL CHECKS PASSED 即演练成功。
4.4 查看运行状态
一次性运行的服务正常退出即成功:
docker compose ps -a
真实回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
libcloud-demo python:3.10-slim "sh -c 'pip install …" libcloud-demo 11 seconds ago Exited (0) Less than a second ago
查看完整运行日志:
docker compose logs libcloud-demo
真实回显(尾部关键行):
libcloud-demo | [storage] uploaded: payload.txt size: 29
libcloud-demo | [storage] downloaded content matches, bytes: 29
libcloud-demo | [storage] objects: [('payload.txt', 29)]
libcloud-demo | [storage] containers: ['demo-bucket']
libcloud-demo | ============================================================
libcloud-demo | ALL CHECKS PASSED
4.5 在编排环境内执行自定义命令
需要单独跑一段验证代码时用 docker compose run(注意必须重新安装依赖,见 FAQ 11.2):
docker compose run --rm libcloud-demo sh -c "pip install -q -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python -c 'import libcloud; print(\"compose run libcloud:\", libcloud.__version__)'"
真实回显(关键行):
compose run libcloud: 3.9.1
五、数据持久化说明
| 卷 | 挂载点 | 用途 | 持久化内容 |
|---|---|---|---|
| storage-data | /opt/libcloud-demo/storage-data | Storage 本地驱动对象根目录 | 演示程序上传的对象文件(按 bucket 建子目录) |
| pip-cache | /root/.cache/pip | pip 下载缓存 | wheel 包缓存,重复启动加速 |
查看卷:
docker volume ls | grep libcloud
真实回显:
local libcloud-compose_pip-cache
local libcloud-compose_storage-data
💡 说明:
docker compose down不会删除命名卷,数据可跨启停保留;docker compose down -v会连同卷一起删除,属于破坏性操作。
六、常用环境变量表
| 环境变量 | 示例值 | 作用 |
|---|---|---|
| LIBCLOUD_STORAGE_ROOT | /opt/libcloud-demo/storage-data | 演示程序 Storage 本地驱动根目录(由 main.py 读取) |
| PIP_CACHE_DIR | /root/.cache/pip | pip 缓存目录,配合 pip-cache 卷加速重复安装 |
| LIBCLOUD_DEBUG | /tmp/libcloud-debug.log | 开启 Libcloud HTTP 请求调试日志并落盘 |
| LIBCLOUD_DEBUG_PRETTY_PRINT_RESPONSE | true | 调试日志以更可读格式输出响应体 |
| LIBCLOUD_RETRY_FAILED_HTTP_REQUESTS | true | 全局启用失败请求重试(对瞬断/限流生效) |
| SSL_CERT_FILE | /path/to/ca-bundle.pem | 覆盖 CA 证书包路径(libcloud.security 读取) |
七、常用配置参数说明(command)
compose.yml 的 command 字段决定该服务一次性执行的动作,按需替换:
command: ["sh", "-c", "pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python main.py"]
pip install -i <镜像源> -r requirements.txt:按清单安装依赖,镜像源显式指定避免默认源慢。python main.py:执行演示程序;替换为python your_script.py即可运行自己的脚本。- 需要交互式探索时改为
["python"]并配合docker compose run --rm libcloud-demo进入 REPL(同样需先安装依赖)。
八、配置文件持久化(挂载)
演示工程的全部文件经 ./app:/app 绑定挂载进运行环境,宿主机直接编辑、运行环境即时生效:
/opt/data/ops/libcloud-compose/app/main.py:演示程序/opt/data/ops/libcloud-compose/app/requirements.txt:依赖清单
如需额外配置(如 CA 证书包),把宿主机文件挂入并配环境变量即可:
volumes:
- ./app:/app
- ./certs/corporate-ca.pem:/etc/ssl/libcloud-ca.pem:ro
environment:
- SSL_CERT_FILE=/etc/ssl/libcloud-ca.pem
九、等价 docker run 运行方式
不用 Compose 时,等价的单条 docker run 命令如下(与 4.3 的编排完全等价,实测退出码 0):
docker run --rm --name libcloud-demo-run \
-v /opt/data/ops/libcloud-compose/app:/app \
-w /app \
-v libcloud-compose_storage-data:/opt/libcloud-demo/storage-data \
-e LIBCLOUD_STORAGE_ROOT=/opt/libcloud-demo/storage-data \
python:3.10-slim \
sh -c "pip install -q -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python main.py"
真实回显(尾部关键行):
[storage] objects: [('payload.txt', 29)]
[storage] containers: ['demo-bucket']
============================================================
ALL CHECKS PASSED
十、常用运维命令
# 启动并前台运行演示工程(完整输出)
docker compose up
# 后台启动
docker compose up -d
# 查看服务状态(含已退出)
docker compose ps -a
# 查看日志
docker compose logs libcloud-demo
docker compose logs -f libcloud-demo
# 临时执行一条自定义命令(用完即删)
docker compose run --rm libcloud-demo sh -c "pip install -q -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python -V"
# 停止并删除运行环境(保留数据卷)
docker compose down
# 停止并删除运行环境与数据卷(破坏性)
docker compose down -v
docker compose down 真实回显(关键行):
Container libcloud-demo Stopping
Container libcloud-demo Stopped
Container libcloud-demo Removing
Container libcloud-demo Removed
Network libcloud-compose_default Removing
Network libcloud-compose_default Removed
十一、常见问题(FAQ)
Q1:运行时报 OSError: [Errno 16] Device or resource busy?
真实报错:
OSError: [Errno 16] Device or resource busy: '/opt/libcloud-demo/storage-data'
定位:程序里对 Storage 根目录执行了 shutil.rmtree(STORAGE_ROOT),而该目录被挂载为数据卷,挂载点本身不能删除。解决:清空目录内容而不是删除目录本身(本文 4.1 的 main.py 已按此方式处理):
for entry in os.listdir(STORAGE_ROOT):
p = os.path.join(STORAGE_ROOT, entry)
shutil.rmtree(p) if os.path.isdir(p) else os.remove(p)
Q2:docker compose run 报 ModuleNotFoundError: No module named 'libcloud'?
真实报错:
ModuleNotFoundError: No module named 'libcloud'
定位:docker compose run libcloud-demo python -c 这类覆盖了默认 command 的调用,新的运行环境里没有执行过 pip install。解决:在 run 的命令里显式补一条安装(见 4.5),或保留默认 command 重新 docker compose up。
Q3:pip 安装慢或超时?
启动命令里的 -i https://pypi.tuna.tsinghua.edu.cn/simple 指定了国内镜像源;同时启用 pip-cache 卷,首次之后的启动走本地缓存。
Q4:如何接入真实云厂商做验证?
把 main.py 中的 Provider.DUMMY 换成目标厂商(如 Provider.EC2、Provider.ALIYUN_ECS),凭据通过 environment 注入驱动构造参数(key/secret),切勿写死进镜像或编排文件。
Q5:如何开启 Libcloud 自身的请求调试日志?
在 environment 增加 LIBCLOUD_DEBUG=/tmp/libcloud-debug.log(目录需可写),即可把每次 HTTP 请求/响应以 curl 命令形式记录下来。
十二、参考链接
- Apache Libcloud 官网:https://libcloud.apache.org
- 官方文档:https://libcloud.readthedocs.io/
- Docker Compose 官方文档:https://docs.docker.com/compose/
- python 官方镜像:https://hub.docker.com/_/python
- PyPI 项目页:https://pypi.org/project/apache-libcloud/