如何在 Kubernetes 中模仿“--volumes-from”
How to mimic '--volumes-from' in Kubernetes
我正在寻找一种模式,允许在 Kubernetes 的同一个 pod 上的两个容器 运行 之间共享卷。
我的用例是:
我在 docker 容器内的 Rails 应用程序 运行 上有一个 Ruby。
docker 图像在 /app/<app-name>/public
目录中包含静态资产,我需要从同一个 pod 中的 nginx 容器 运行 访问这些资产。
在 'vanilla' docker 中,我会使用 --volumes-from
标志来共享此目录:
docker run --name app -v /app/<app-dir>/public <app-image>
docker run --volumes-from app nginx
阅读本文档后:https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md
我试过了(只显示相关条目):
spec:
containers:
- image: <app-image>
name: <app-name>
volumeMounts:
- mountPath: /app/<app-name>/public
name: assets
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/www/html
name: assets
readOnly: true
volumes:
- name: assets
hostPath:
path: /tmp/assets
但是:
- 尽管节点上的
/tmp/assets
存在,但它是空的
/app/<app-name>/public
应用容器里面也是空的
作为解决方法,我将尝试在应用程序容器启动时填充共享目录(只需 cp /app/<app-name>/public/*
到共享目录),但我真的不喜欢这个想法。
问题:如何在Kubernetes中模仿--volumes-from
,或者如果没有直接对应的,我如何将文件从一个容器共享到另一个容器运行 在同一个广告连播中?
apiVersion: v1beta3
Client Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
Server Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
答案是 - 目前 - 你不能。以下是来自 Kubernetes 问题的几个讨论主题:
- https://github.com/GoogleCloudPlatform/kubernetes/issues/6120
- https://github.com/GoogleCloudPlatform/kubernetes/issues/831
但是,我可以建议您使用可能更好的替代设计吗?
- 如果您的资产在容器上线时被锁定,
你可以使用
gitRepo
volume 会在上线时将其复制到 emptyDir
,这意味着您不必在
全部,直接下载到共享目录即可。
- 如果您的资产在集装箱点被锁定
正在构建,最好在那时复制它们,使用
Docker COPY 命令。
- 如果您真的想坚持自己的做法,则必须将内容复制到
emptyDir
卷,该卷专为您寻找的内容而设计(减去不需要复制它)。
NFS[1] 卷也可以解决您的问题,但可能过于复杂。
此外,我建议这两个服务存在于不同的 pods 中,这样您就可以分别扩展每个服务。如果需要,您可以创建服务端点以在它们之间进行通信。
[1] https://github.com/GoogleCloudPlatform/kubernetes/blob/master/examples/nfs/nfs-web-pod.yaml
[update-2016-8] 在最新的 Kubernetes 版本中,您可以使用名为 init-container
的非常好的功能来替换 postStart
部分我在下面的回答,这将确保容器顺序。
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
initContainers:
- name: war
image: resouer/sample:v2
command: ["cp", "/sample.war", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- name: tomcat
image: resouer/mytomcat:7.0
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
注意:initContainer 仍然是 beta 功能 所以这个 yaml 的工作版本实际上是这样的:http://kubernetes.io/docs/user-guide/production-pods/#handling-initialization,请注意 pod.beta.kubernetes.io/init-containers
部分。
---原答案开始---
事实上,你可以。您需要使用容器生命周期处理程序来控制要与其他容器共享的内容 files/dirs。喜欢:
---
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: hostv1
- name: peer
image: busybox
command: ["tail", "-f", "/dev/null"]
volumeMounts:
- name: hostv2
mountPath: /app/sample.war
volumes:
- name: hostv1
hostPath:
path: /tmp
- name: hostv2
hostPath:
path: /tmp/sample.war
请查看我的要点以获取更多详细信息:
https://gist.github.com/resouer/378bcdaef1d9601ed6aa
当然你也可以使用emptyDir。因此,war 容器可以将其 /sample.war 共享给对等容器,而不会弄乱对等方的 /app 目录。
如果我们可以容忍 /app 被覆盖,那就简单多了:
---
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: app-volume
- image: resouer/mytomcat:7.0
name: tomcat
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
未来的进一步更新:
现在有 Docker 个卷的 FlexVol 插件:https://github.com/dims/docker-flexvol
在撰写本文时,FlexVol 仍然是一个 alpha 功能,所以买者自负。
如果您使用的是 Docker v17.0.5 或更高版本,您可以使用多阶段构建在构建期间将文件从一个容器复制到另一个容器。这是 https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae
高级功能的入门读物
我使用它将静态资产从我的后端容器复制到 Nginx 代理的方法是
ARG API_BACKEND_CONTAINER="api:backend"
FROM $API_BACKEND_CONTAINER as source
FROM nginx:mainline-alpine
ARG NGINX_ROOT=/usr/share/nginx/html/
COPY --from=source /var/share/api/static/ ${NGINX_ROOT}
很棒的是,因为 API_BACKEND_CONTAINER
是构建参数,所以我能够传入最新的 API 构建的标签。
Kubernetes 有自己的卷类型,这些是最常用的卷类型:
- 空目录
- 秘密
- gitRepo
- hostPath(类似于 --volumes-from)
- 配置地图
- 持久化存储(云平台提供的存储盘)
您可以在此处找到有关 kubernets 卷的更多信息 -https://kubernetes.io/docs/concepts/storage/volumes/
主机路径卷示例:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
hostpath 会挂载host/node 目录到容器directory.Multiple 一个pod 内的容器可以使用不同或相同的volumes.You 需要在每个容器中提及。
hostPath 卷独立于 pod 生命周期,但它会在 node 和 pod 之间产生紧密耦合,你应该避免使用 hostPath。
我正在寻找一种模式,允许在 Kubernetes 的同一个 pod 上的两个容器 运行 之间共享卷。
我的用例是:
我在 docker 容器内的 Rails 应用程序 运行 上有一个 Ruby。
docker 图像在 /app/<app-name>/public
目录中包含静态资产,我需要从同一个 pod 中的 nginx 容器 运行 访问这些资产。
在 'vanilla' docker 中,我会使用 --volumes-from
标志来共享此目录:
docker run --name app -v /app/<app-dir>/public <app-image>
docker run --volumes-from app nginx
阅读本文档后:https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md 我试过了(只显示相关条目):
spec:
containers:
- image: <app-image>
name: <app-name>
volumeMounts:
- mountPath: /app/<app-name>/public
name: assets
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/www/html
name: assets
readOnly: true
volumes:
- name: assets
hostPath:
path: /tmp/assets
但是:
- 尽管节点上的
/tmp/assets
存在,但它是空的 /app/<app-name>/public
应用容器里面也是空的
作为解决方法,我将尝试在应用程序容器启动时填充共享目录(只需 cp /app/<app-name>/public/*
到共享目录),但我真的不喜欢这个想法。
问题:如何在Kubernetes中模仿--volumes-from
,或者如果没有直接对应的,我如何将文件从一个容器共享到另一个容器运行 在同一个广告连播中?
apiVersion: v1beta3
Client Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
Server Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
答案是 - 目前 - 你不能。以下是来自 Kubernetes 问题的几个讨论主题:
- https://github.com/GoogleCloudPlatform/kubernetes/issues/6120
- https://github.com/GoogleCloudPlatform/kubernetes/issues/831
但是,我可以建议您使用可能更好的替代设计吗?
- 如果您的资产在容器上线时被锁定,
你可以使用
gitRepo
volume 会在上线时将其复制到emptyDir
,这意味着您不必在 全部,直接下载到共享目录即可。 - 如果您的资产在集装箱点被锁定 正在构建,最好在那时复制它们,使用 Docker COPY 命令。
- 如果您真的想坚持自己的做法,则必须将内容复制到
emptyDir
卷,该卷专为您寻找的内容而设计(减去不需要复制它)。
NFS[1] 卷也可以解决您的问题,但可能过于复杂。
此外,我建议这两个服务存在于不同的 pods 中,这样您就可以分别扩展每个服务。如果需要,您可以创建服务端点以在它们之间进行通信。
[1] https://github.com/GoogleCloudPlatform/kubernetes/blob/master/examples/nfs/nfs-web-pod.yaml
[update-2016-8] 在最新的 Kubernetes 版本中,您可以使用名为 init-container
的非常好的功能来替换 postStart
部分我在下面的回答,这将确保容器顺序。
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
initContainers:
- name: war
image: resouer/sample:v2
command: ["cp", "/sample.war", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- name: tomcat
image: resouer/mytomcat:7.0
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
注意:initContainer 仍然是 beta 功能 所以这个 yaml 的工作版本实际上是这样的:http://kubernetes.io/docs/user-guide/production-pods/#handling-initialization,请注意 pod.beta.kubernetes.io/init-containers
部分。
---原答案开始---
事实上,你可以。您需要使用容器生命周期处理程序来控制要与其他容器共享的内容 files/dirs。喜欢:
---
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: hostv1
- name: peer
image: busybox
command: ["tail", "-f", "/dev/null"]
volumeMounts:
- name: hostv2
mountPath: /app/sample.war
volumes:
- name: hostv1
hostPath:
path: /tmp
- name: hostv2
hostPath:
path: /tmp/sample.war
请查看我的要点以获取更多详细信息:
https://gist.github.com/resouer/378bcdaef1d9601ed6aa
当然你也可以使用emptyDir。因此,war 容器可以将其 /sample.war 共享给对等容器,而不会弄乱对等方的 /app 目录。
如果我们可以容忍 /app 被覆盖,那就简单多了:
---
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: app-volume
- image: resouer/mytomcat:7.0
name: tomcat
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
未来的进一步更新:
现在有 Docker 个卷的 FlexVol 插件:https://github.com/dims/docker-flexvol
在撰写本文时,FlexVol 仍然是一个 alpha 功能,所以买者自负。
如果您使用的是 Docker v17.0.5 或更高版本,您可以使用多阶段构建在构建期间将文件从一个容器复制到另一个容器。这是 https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae
高级功能的入门读物我使用它将静态资产从我的后端容器复制到 Nginx 代理的方法是
ARG API_BACKEND_CONTAINER="api:backend"
FROM $API_BACKEND_CONTAINER as source
FROM nginx:mainline-alpine
ARG NGINX_ROOT=/usr/share/nginx/html/
COPY --from=source /var/share/api/static/ ${NGINX_ROOT}
很棒的是,因为 API_BACKEND_CONTAINER
是构建参数,所以我能够传入最新的 API 构建的标签。
Kubernetes 有自己的卷类型,这些是最常用的卷类型:
- 空目录
- 秘密
- gitRepo
- hostPath(类似于 --volumes-from)
- 配置地图
- 持久化存储(云平台提供的存储盘)
您可以在此处找到有关 kubernets 卷的更多信息 -https://kubernetes.io/docs/concepts/storage/volumes/
主机路径卷示例:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
hostpath 会挂载host/node 目录到容器directory.Multiple 一个pod 内的容器可以使用不同或相同的volumes.You 需要在每个容器中提及。 hostPath 卷独立于 pod 生命周期,但它会在 node 和 pod 之间产生紧密耦合,你应该避免使用 hostPath。