【开发笔记】在Python中调用Docker,并运行SDK任务

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的上传出现权限问题

  • 使用paramikoscp工具将本地的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 可能遇到的问题

  1. 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
  • 得到以下结果说明重启完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MomentNi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值