目录
- 1 背景
- 2 环境准备
- 3 实现流程
- 3.1 连接远程Docker
- 3.1 创建容器
- 3.2 解压SDK
- 3.3 挂载容器卷
- 3.4 运行任务
- 3.5 判断任务状态
- 3.6 容器的停止与销毁
- 4 可能遇到的问题
1 背景
- 使用Python,在远程Docker中创建一个容器,并在该容器中运行SDK任务
2 环境准备
- Python 3.10.4
- Docker 24.0.5
3 实现流程
3.1 连接远程Docker
- 使用docker.DockerClient进行连接
client = docker.DockerClient(base_url=f"tcp://{DOCKER_IP}:{DOCKER_PORT}", timeout=5)
- 测试是否连接成功
# 输出Docker版本信息
docker_version = json.dumps(client.version(), indent=1)
print(docker_version)
# 输出容器信息
get_container_id_list = client.containers.list()
container_id_list = []
for ids in get_container_id_list:
container_id_list= container_id_list + ids.image.tags
print(container_id_list)
- 若均能正常输出,则说明连接成功
3.1 创建容器
- 使用DockerClient获取远程docker
client = docker.DockerClient(base_url=f"tcp://{DOCKER_IP}:{DOCKER_PORT}", timeout=5)
3.2 解压SDK
注意:此步骤最好在容器run之前执行,否则容器卷目录的所有者可能为root,导致SDK的上传出现权限问题
- 使用
paramiko
和scp
工具将本地的SDK上传至服务器的对应目录
import paramiko
from scp import SCPClient
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(DOCKER_IP, 22, DOCKER_USERNAME, DOCKER_PASSWORD)
with SCPClient(ssh.get_transport()) as scp:
# 将本地的文件拷贝到远程主机中
scp.put(f'{SDK_PATH}/{sdk_id}', DOCKER_SDK_PATH, recursive=True)
3.3 挂载容器卷
- 使用run命令启动容器,在volumes字段中挂在容器卷
container = client.containers.run(name=container_name,
image=image,
ports={f"{inner_port}/tcp": outer_port},
volumes={f"{DOCKER_SDK_PATH}/{sdk_id}": {'bind': f"/app/{sdk_id}", 'mode': "rw"}},
mem_limit='4g',
runtime="nvidia",
device_requests=[docker.types.DeviceRequest(capabilities=[['gpu']])],
working_dir=f"/app/{sdk_id}",
detach=True,
auto_remove=True,
tty=True)
3.4 运行任务
- 调用SDK中的run.sh脚本启动SDK,注意增加执行权限
command = 'bash -c "chmod +x ./run.sh && ./run.sh"'
container.exec_run(command, detach=True)
3.5 判断任务状态
- 若启动的SDK含有server监听端,可使用如下方法进行状态判断
def ready_task(timeout, outer_port, interface):
start = time.time()
while (time.time() - start) < timeout:
try:
requests.post(url=f'http://{DOCKER_IP}:{outer_port}/{interface}')
return True
except requests.exceptions.ConnectionError:
time.sleep(0.1)
else:
return False
- 若server启动成功,则返回
True
,若超时,则返回False
3.6 容器的停止与销毁
- 任务执行完成后,可执行停止或销毁操作
def clean_task(test_id, sdk_id):
client = docker.DockerClient(base_url=f"tcp://{DOCKER_IP}:{DOCKER_PORT}", timeout=5)
try:
client.containers.get(container_name).stop()
client.containers.get(container_name).remove(force=True)
except (NotFound, APIError):
pass
- 由于出现错误只可能是因为容器已经被停止或销毁,因此出现错误直接忽略即可
4 可能遇到的问题
- clinet连接报错:
Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。
- 修改远程服务器内的docker.service内容
- 将黄色框内的第一行修改为第二行,保存退出
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
- 执行下面两行命令,重启docker
systemctl daemon-reload
systemctl restart docker
- 查看docker重启状态
ps -ef | grep docker
- 得到以下结果说明重启完成