CTFd-Whale 无镜像容器拉取问题修复

CTFd-Whale 无镜像容器拉取问题修复

IShirai_KurokoI

众所周知,CTFd-Whale会按照题目中设置的镜像名称去创建题目容器,然而在前端返回创建成功后,可能等了很长时间都没有创建成功,去后台一查,诶您猜怎么着,服务器没镜像!

按理说他是应该自动拉取镜像的,所以找下问题所在吧。

image-20230630160142268

也就是说,whale插件是创建了一个服务,由这个服务的task来创建容器docker。

那么Whale是如何判断创建是否成功的呢?

image-20230630160555959

创建失败的条件是添加容器时报错/注册路由时失败。

那么问题就来了,既然镜像没拉下来,为什么不报错呢?

很遗憾,第一张图片中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
client.services.create(
image=container.challenge.docker_image,
name=f'{container.user_id}-{container.uuid}',
env={'FLAG': container.flag}, dns_config=docker.types.DNSConfig(nameservers=dns),
networks=[get_config("whale:docker_auto_connect_network", "ctfd_frp_containers")],
resources=docker.types.Resources(
mem_limit=DockerUtils.convert_readable_text(
container.challenge.memory_limit),
cpu_limit=int(container.challenge.cpu_limit * 1e9)
),
labels={
'whale_id': f'{container.user_id}-{container.uuid}'
}, # for container deletion
constraints=['node.labels.name==' + node],
endpoint_spec=docker.types.EndpointSpec(mode='dnsrr', ports={})
)

会自动拉取镜像,但是并不会在拉取失败时报错,这也就导致CTFd在服务创建完成时认为容器创建成功,于是去注册路由,给前端返回一个根本不能用的链接。。。。

解决这个问题的方法也很简单,我们在执行这个操作之前添加几行代码:

1
2
3
4
5
try:
image = client.images.get(container.challenge.docker_image)
except Exception as e:
print(e)
client.api.pull(container.challenge.docker_image)

首先根据题目的镜像名称,查询是否存在这个镜像,如果存在则跳过这段代码直接去创建镜像。

如果镜像不存在,函数会抛出异常 docker.errors.ImageNotFound代码进入异常处理,执行拉取镜像操作,如果这时拉取仍然失败,pull函数会抛出docker.errors.APIError,然后异常会抛出给上层创建容器的函数,提示创建失败,移除docker记录。此时service尚未创建,移除record也不会产生幽灵容器(幽灵容器的处理见我另一篇文章)。

这样这个问题就解决啦。

PS:我们Scr1w战队二次开发的CTFd整合版地址:https://github.com/dlut-sss/CTFD-Public

  • 标题: CTFd-Whale 无镜像容器拉取问题修复
  • 作者: IShirai_KurokoI
  • 创建于 : 2023-06-28 00:00:00
  • 更新于 : 2023-12-24 16:33:59
  • 链接: https://ishiraikurokoi.top/2023-06-28-CTFd-Whale-Pull-Fix/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
CTFd-Whale 无镜像容器拉取问题修复