安装 Docker SDK for Python
我们都知道,SDK 从某个角度来说就是对 API 的封装,以方便开发者使用,Docker SDK 官方支持的语言总共有两种:
Go
Python
其余语言则是社区开发的非官方版本,而这里我们选用的是 Python,直接从 PyPI 安装即可:
pip install docker
初始化 Docker client
使用 Python SQL driver 类的包我们都需要先创建一个“连接”,比如:
import pymysql
connection = pymysql.connect(
host='localhost',
user='user',
password='passwd',
database='db')
同理,要操作 Docker Engine 也需要先创建一个“客户端连接”,毕竟 Docker 是典型的 client/server 架构,我们平常使用的 Docker CLI 就是一个 Docker client,而 server 端则是 Docker Engine,又称为 Docker daemon。
import docker
client = docker.from_env()
绝大部分的 Docker 操作,都是从这个 client 开始。初始化 client 连接非常简单,只需要from_env()一行解决,不过这里有一个需要注意的点,那就是 Docker daemon 所在的连接地址——DOCKER_HOST环境变量。
事实上,from_env()会自动使用相关环境变量,来获取 Docker daemon 的连接地址。如果没有设置,那么默认会连接到本机上的地址,通常是unix://var/run/docker.sock。
和 Docker CLI 相同,from_env()会使用这三个环境变量:
DOCKER_HOST
DOCKER_TLS_VERIFY
DOCKER_CERT_PATH
通常我们只需要关注第一个——DOCKER_HOST——即可。
DOCKER_HOST 环境变量
平常我们在本机安装 Docker,实际上是同时安装了 Docker CLI 和 Docker Engine,启动 Docker Engine 在本机启动一个进程,即为 Docker daemon。
注意:一般提到 Docker host,通常指的是 Docker network 中的 host network,和这里的DOCKER_HOST环境变量所代表的意义并不相同。
因为 Docker client 和 Docker Engine 都安装在同一台主机上,此时DOCKER_HOST地址通常是像unix://var/run/docker.sock或tcp://127.0.0.1:2375这类的本机路径,使用from_env()可以轻松创建 client 连接。
当然,Docker Engine 必须先启动。
Remote Docker daemon
但如果想要连接的 Docker daemon 是位于远程主机,通过from_env()创建连接时,就要先设置DOCKER_HOST这个环境变量,以取代 SDK 提供的连接默认值。换句话说,在连接 localhost 时,这个变量可以不设置,而在连接远程主机时,就必须要有。
最简单的方式如下:
import os
import docker
os.environ["DOCKER_HOST"] = 'tcp://22.22.22.22:2375'
client = docker.from_env()
但最好还是直接在.env之类的环境设置文件把环境变量值设置好,并在 app 中获取。在代码中明示任何帐号、密码、内部主机地址都不妥,应尽量避免。
如果远程主机要求使用 SSL 连接,则连接地址要设置在DOCKER_TLS_VERIFY。
from_env()是 Docker SDK 提供创建连接的捷径,如果想使用更完整的参数,则要直接调用DockerClient类型来创建连接对象(实例),如下:
import docker
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
这部分请直接参考官方文档,大部分情况使用from_env()应该已经足够。
Docker socket 权限问题
即使是通过本机上的 socket 连接本机的 Docker daemon,程序也可能遇到连接问题,通常是程序 app 的执行权限不符合主机上 Docker socket 的要求,会出现类似下面的错误讯息:
Error while fetching server API version: ('Connection aborted.', PermissionError(13, 'Permission denied'))
此时可能要修改var/run/docker.sock文件或 app 本身的权限,而这样做是否安全,需具体考量,这里只是点出这个潜在问题。
容器操作
Docker 最常见使用的就是容器操作,我们来大概了解一下。
创建并启动容器:containers.run
先看个例子:
client.containers.run('alpine', command='echo hello world', ports={'2222/tcp': 3333})
方式是使用 SDK 中containers模块的run方法(method),再看一下官方文档中run的使用说明:
run(image, command=None, **kwargs)
Run a container. By default, it will wait for the container to finish and return its logs, similar to docker run.
简单来说,执行run的结果,即是依据给定的参数,来创建相对应的Container对象,和你使用 CLI 执行docker container run指令很类似。
从官方文档中可知run方法具有两个位置参数:image与command。image调用时一定不可省略,而command有参数默认值None,调用时可以省略,位置参数的特色是可以直接按顺序赋值调用,不需使用参数名称,如下:
client.containers.run('alpine', 'echo hello world')
从这上述两个例子可以轻易看出,这里的参数就相当于我们使用 CLI 时的 flag(也是参数啦)!很容易理解与转换,换句话说,本段开头的第一个例子可以理解为下面的 CLI 指令:
docker container run -p 2222:3333 alpine echo hello world
containers模块的角色相当于 CLI 中的docker container,了解怎么创建与启动容器后,剩下就是容器的获取与操作问题了。
创建时即获取容器对象:detach=True
程序成功执行containers.run方法后,容器就会创建及启用,但若想要直接获取该容器对象以进行后续操作,则需要在调用run方法时加上detach=True参数,类似于 CLI 中的-d:
>>> client.containers.run('alpine', detach=True)
<Container '45e6d2de7c54'>
虽然都是 detach 的意思,但 CLI 使用-d通常是为了不要让容器的 process 占用前景,而这里是程序执行,没有前景占用问题,detach=True的主要意义在于获取容器。
获取容器并存为变量:
container = client.containers.run('alpine', detach=True)
获取容器对象通常是想要进一步存取该容器的相关信息,比如容器 id、logs 等:
container_id = container.id
logs = container.logs
容器对象的所有属性及方法,请参考官方文档。
获取已存在的容器对象:containers.get
上面讲的是创建的时候顺便获取容器对象,而如果要获取“已存在”的容器,不论容器是否执行中,都可以通过容器 id 或容器名称获取——使用get方法:
container = client.containers.get('<容器id>')
container = client.containers.get('<容器名称>')
这里的容器 id 和使用 CLI 一样,可以只取前面几位即可,比如只取'45e6',只要没有重复的容器 id 就能成功获取,反之则会出 error。不过这毕竟是程序执行,谨慎起见,建议还是不要取太少位,但可以不必是全部。
常用容器操作示例
获取特定容器对象后,才能对它进行操作,这里就只演示一下几个常用的操作即可。
删除容器
container.remove()
container.remove(force=True)
相当于docker container rm、docker container rm -f。
启动容器
container.start()
相当于docker container start。
停止容器
container.stop()
相当于docker container stop。
小结
可以看出,只要熟悉 CLI 操作指令,使用 SDK 也会很容易上手。可以想见,平常我们通过 CLI 操作 Docker,其实也是内部 SDK 帮你把指令转换为代码再与 Docker daemon 进行交互。
上一条:Docker Hub访问恢复?
下一条:Docker中可以跑MySQL吗