如何在 Kubernetes 部署中使用本地 Docker 镜像(非 Minikube)

3
我有一个VM,其中安装了使用kubeadm(而非minikube)的kubernetes。该VM充当集群的单个节点,已删除taints以允许其充当主节点和工作节点(如kubernetes文档所示)。
我已将 app:test 映像保存,传输并加载到其中。我可以轻松地使用docker run运行它的容器。
运行 sudo docker images 时,它会显示出来。
当我创建使用此图像并指定 Image-PullPolicy:IfNotPresent Never 的部署/ pod时,仍然会出现 ImagePullBackoff 错误。describe命令向我显示,它尝试从dockerhub拉取该图像…
请注意,当我尝试使用“由于创建另一个pod而拉取的本地映像”时,ImagePullPolicies似乎可以正常工作,没有问题。虽然当我运行sudo docker image --all时,图像并不会出现。 我如何在kubernetes的pod中使用本地映像?是否有一种方法可以不使用私有存储库来实现?

你正在使用哪个Kubernetes版本? - jabbson
我正在使用版本v1.22。 - Olivier
5个回答

3
当我运行sudo docker images --all时,图像没有出现。
根据您的评论,您正在使用K8s v1.22版本,这意味着您的集群很可能使用containerd容器运行时而不是docker(您可以使用kubectl get nodes -o wide检查,并查看最后一列)。
尝试使用crictl images列出您的镜像,并使用crictl pull <image_name>在节点上预加载镜像。

我会尝试。 Docker在底层使用containerd作为运行时,对吗?这就是为什么我在我的节点上使用containerd的原因;这样我就可以依靠Docker获取关于我的映像的信息。我错了吗? - Olivier
2
这是正确的,docker确实使用containerd本身,只是k8s不再使用docker作为中间人了。检查并尝试使用crictl进一步操作。您可以在我的一个k8s节点上查看使用dockercontainerd列出镜像的示例此处 - jabbson
谢谢。运行 crictl images 命令时,我的镜像确实没有弹出。但是,当我尝试拉取它时,我收到了以下错误消息:FATA[0000] 拉取镜像失败:rpc 错误:code = Unknown desc = failed to pull and unpack image "docker.io/library/app:test":failed to resolve reference "docker.io/library/app:test":pull access denied,repository does not exist or may require authorization: server message: insufficient_scope: authorization failed - Olivier
使用 crictl 无法正常工作,但按照这些步骤操作可以正确地工作... 有什么想法为什么 crictl 无法拉取? - Olivier
这似乎是一个私有仓库? - jabbson
如果这篇帖子是任何迹象的话,它实际上是公共的;当没有其他指定时设置的默认值... 这解释了为什么它会要求授权。看起来crictl pull实际上不能直接从本地机器获取镜像... 尽管如此,我还没有找到任何官方确认。 - Olivier

3

如果使用containerd,可以通过crictl和ctr的组合来实现。

简而言之: 这些步骤,也在crictl github文档中有描述:

1- 将镜像放在节点上(在我的情况下是虚拟机),确保它是一个归档文件(.tar)。您可以使用docker savectr image export命令完成此操作。

2- 在与存档镜像相同的目录中使用sudo ctr -n=k8s.io images import myimage.tar将其添加到kubernetes用于跟踪其镜像的名称空间中的containerd中。现在,在运行sudo crictl images时,它应该出现。


如建议所述,我尝试使用crictl列出图像,但我的app:test并未出现。然而,尝试通过crictl导入本地图像似乎也不起作用。我使用了crictl pull app:test,它显示了以下错误消息:
"FATA[0000] pulling image failed: rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/library/app:test": failed to resolve reference "docker.io/library/app:test": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed."
然而,当按照这些步骤时,我的图像最终被识别为kubernetes中的现有本地图像。实际上,它们与crictl github文档中建议的相同。
这是怎么回事?图像如何在kubernetes集群中“注册”?为什么crictl无法导入该图像?我可能会发布另一个问题来询问...

2
由于外部链接往往会失效,因此在此答案中总结“这些步骤”到底是什么会很好。 - Caesar
1
已注意,正在进行编辑。 - Olivier

2
您的集群被包含在虚拟机中,因此您所称之为本地的内容对于该虚拟机中的集群来说始终是远程的。Kubernetes试图拉取这些镜像的原因是它在虚拟机中找不到它们。
Dockerhub是下载容器的默认位置,但您可以设置Kubernetes从AWS(ECR),Azure(ACR),Github Packages(GCR)和您自己的私有服务器中拉取。您有大约100种解决方法,其中没有一种是简单或者直接可行的。
1- 最简单的方法是将您的镜像推送到Dockerhub并让您的集群从中拉取。
2- 设置本地私有容器注册表,并将您的Kubernetes VM设置为从其中拉取 (查看此文) 3- 在您的Kubernetes集群中设置一个私有容器注册表,并在本地环境中设置脚本以将其推送到该注册表 (查看此文)

你所说的“bottled”具体指什么?我确实将图像放在了VM上...这就是我的困惑之源。而Kubernetes拉取的其他图像即使在VM上看不到也可以被重用。为什么? - Olivier
在封装的意义上,你的虚拟机没有访问你的物理机的权限,反之亦然,除非你使用ssh或者挂载文件夹,但这都属于网络访问。在这种封装的情况下,你的虚拟机无法看到你的物理机的镜像,反之亦然。 - Magus
1
当你说“在VM上显示”时,你是指运行“docker image ls”吗?如果是这样,那可能是因为Kubernetes正在使用不同的容器驱动程序。Docker只是与容器交互的一种方式,它是最著名和真正的硬核容器Linux人士讨厌Docker,因为Docker是一家公司,它有自己的议程。我认为Kubernetes现在使用CRI-O作为默认的容器运行时,请尝试运行crictl images以查看Kubernetes拉取的镜像。 - Magus
好的,那么我必须说:这不是问题所在。正如我在问题中所述,我已经将图像传输到我的虚拟机上并在那里加载了它。运行docker images会在VM上显示它。 是的,这就是我的意思。当我设置kubernetes时,我遵循了使用containerd作为运行时的说明。Docker也使用containerd,因此docker images应该是相关的,对吧? - Olivier
明白了,那么是的,Kubernetes 使用的图像都应该在您的虚拟机上显示出来。有一个愚蠢的问题,您是否使用具有完整标签和图像版本的名称,还是只是图像名称?您能否更新您的问题并提供部署或 Pod 规范?让我们找到这个问题的根源。 - Magus
我遵循crictl提示取得了相当大的进展。直接使用ctr加载可以产生结果。我猜CRI-O的工作方式有些类似,因为它是为kubernetes构建的。 - Olivier

1
在我的情况下,我使用kubeadm设置了k8s集群。 因此,如果您想要使用本地镜像来运行pod,请执行以下操作。
如果您有docker镜像,请使用以下命令创建镜像的tar文件。
docker save <image-name> -o <filename.tar>

如果您有containerd镜像,请使用以下命令创建镜像的tar文件。
ctr image export <output-filename> <image-name>

将独立存档文件传输到其他系统(使用您喜欢的任何方式;我使用了scp),然后使用以下命令将图像加载(或导入)到containerd中:

ctr -n=k8s.io images import <filename-from-previous-step>

请注意,您可能无法使用 ctr image ls 列出导入到 k8s 的此镜像。

0

这是另一个对我有效的解决方案。

最简单的解决方案是安装podman并加载镜像。我正在manjaro上运行,使用CRI-O作为我的CRI和kubeadm作为控制平面。

sudo pacman -Sy podman 

将您的 Docker 镜像保存为 .tar 文件,并使用 sudo podman 加载该镜像。(注意:必须使用 sudo 运行 podman)

sudo podman load -i your-local-image.tar

运行时,它立即显示在 CRI-image 注册表中

sudo crictl images

定义Kubernetes作业的示例:

#local-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: local-job
spec:
  template:
    spec:
      containers:
      - name: local-img-pod
        image: localhost/<Your-image-tag> 
        command: ["./your-app-binary","parameter1"]
        imagePullPolicy: Never
      restartPolicy: Never
  backoffLimit: 4

并开始工作

kubectl apply -f local-job.yaml

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接