docker - 为什么我无法从 Kubernetes 容器之间的共享 PersistentVolumeClaim 中读取文件?
问题描述
我有一个felipeogutierrez/tpch-dbgen
使用构建的dockerdocker-compose
映像,并使用.travis-CI
version: "3.7"
services:
other-images: ....
tpch-dbgen:
build: ../docker/tpch-dbgen
image: felipeogutierrez/tpch-dbgen
volumes:
- tpch-dbgen-data:/opt/tpch-dbgen/data/
- datarate:/tmp/
stdin_open: true
这是Dockerfile
构建此图像的方法:
FROM gcc AS builder
RUN mkdir -p /opt
COPY ./generate-tpch-dbgen.sh /opt/generate-tpch-dbgen.sh
WORKDIR /opt
RUN chmod +x generate-tpch-dbgen.sh && ./generate-tpch-dbgen.sh
最后,这个脚本创建了一个目录/opt/tpch-dbgen/data/
,其中包含一些我想从我在 Kubernetes 上运行的另一个 docker 镜像中读取的文件。然后,我创建了一个 Flink 映像,可以在 Kubernetes 中运行。该镜像启动了 3 个 Flink 任务管理器和一个从镜像中读取文件的流应用程序tpch-dbgen-data
。我认为正确的方法是创建一个PersistentVolumeClaim
这样我就可以在 Kubernetes 中将目录/opt/tpch-dbgen/data/
从镜像共享felipeogutierrez/tpch-dbgen
到我的 flink 镜像。所以,首先我有这个文件来创建PersistentVolumeClaim
:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tpch-dbgen-data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Mi
然后,我正在创建一个initContainers
启动图像felipeogutierrez/tpch-dbgen
,然后启动我的图像felipeogutierrez/explore-flink:1.11.1-scala_2.12
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flink-taskmanager
spec:
replicas: 3
selector:
matchLabels:
app: flink
component: taskmanager
template:
metadata:
labels:
app: flink
component: taskmanager
spec:
initContainers:
- name: tpch-dbgen
image: felipeogutierrez/tpch-dbgen
#imagePullPolicy: Always
env:
command: ["ls"]
# command: ['sh', '-c', 'for i in 1 2 3; do echo "job-1 `date`" && sleep 5s; done;', 'ls']
volumeMounts:
- name: tpch-dbgen-data
mountPath: /opt/tpch-dbgen/data
containers:
- name: taskmanager
image: felipeogutierrez/explore-flink:1.11.1-scala_2.12
#imagePullPolicy: Always
env:
args: ["taskmanager"]
ports:
- containerPort: 6122
name: rpc
- containerPort: 6125
name: query-state
livenessProbe:
tcpSocket:
port: 6122
initialDelaySeconds: 30
periodSeconds: 60
volumeMounts:
- name: flink-config-volume
mountPath: /opt/flink/conf/
- name: tpch-dbgen-data
mountPath: /opt/tpch-dbgen/data
securityContext:
runAsUser: 9999 # refers to user _flink_ from official flink image, change if necessary
volumes:
- name: flink-config-volume
configMap:
name: flink-config
items:
- key: flink-conf.yaml
path: flink-conf.yaml
- key: log4j-console.properties
path: log4j-console.properties
- name: tpch-dbgen-data
persistentVolumeClaim:
claimName: tpch-dbgen-data-pvc
Flink 流应用程序正在启动,但它无法读取/opt/tpch-dbgen/data
图像目录中的文件felipeogutierrez/tpch-dbgen
。我收到错误:java.io.FileNotFoundException: /opt/tpch-dbgen/data/orders.tbl (No such file or directory)
。这很奇怪,因为当我尝试进入容器时,felipeogutierrez/tpch-dbgen
我可以列出文件。所以我想我的 Kubernetes 配置有问题。有谁知道指出我在 Kubernetes 配置文件中缺少什么?
$ docker run -i -t felipeogutierrez/tpch-dbgen /bin/bash
root@10c0944a95f8:/opt# pwd
/opt
root@10c0944a95f8:/opt# ls tpch-dbgen/data/
customer.tbl dbgen dists.dss lineitem.tbl nation.tbl orders.tbl part.tbl partsupp.tbl region.tbl supplier.tbl
此外,当我列出容器的日志时,tpch-dbgen
我可以看到tpch-dbgen
我想要读取的目录。虽然我无法command: ["ls tpch-dbgen"]
在 Kubernetes 配置文件中执行命令。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
flink-jobmanager-n9nws 1/1 Running 2 17m
flink-taskmanager-777cb5bf77-ncdl4 1/1 Running 0 4m54s
flink-taskmanager-777cb5bf77-npmrx 1/1 Running 0 4m54s
flink-taskmanager-777cb5bf77-zc2nw 1/1 Running 0 4m54s
$ kubectl logs flink-taskmanager-777cb5bf77-ncdl4 tpch-dbgen
generate-tpch-dbgen.sh
tpch-dbgen
解决方案
Docker 有一个不寻常的功能,在某些特定情况下,它会从映像中填充新创建的卷。您不应依赖此功能,因为它完全忽略了底层映像中的更新,并且不适用于 Kubernetes。
在您的 Kubernetes 设置中,您创建一个新的空 PersistentVolumeClaim,然后将其挂载到 init 和主容器中的实际数据上。与所有 Unix 挂载一样,这会隐藏该目录中先前的数据。没有什么会导致数据被复制到该卷中。这与其他所有类型的挂载方式相同,除了 Docker 命名卷挂载:如果您将 Compose 设置更改为进行主机绑定挂载,或者使用本地开发系统进行操作,您将看到相同的行为使用 USB 驱动器作为“卷”。
您需要使您的 init 容器(或其他东西)显式地将数据复制到目录中。例如:
initContainers:
- name: tpch-dbgen
image: felipeogutierrez/tpch-dbgen
command:
- /bin/cp
- -a
- /opt/tpch-dbgen/data
- /data
volumeMounts:
- name: tpch-dbgen-data
mountPath: /data # NOT the same path as in the image
如果主进程修改了这些文件,您可以使命令更智能,或者将脚本写入您的映像中,仅在单个文件不存在时复制它们。
让您的映像在启动时而不是在映像构建时生成数据文件可能更有意义。这可能看起来像:
FROM gcc
COPY ./generate-tpch-dbgen.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/generate-tpch-dbgen.sh
CMD ["generate-tpch-dbgen.sh"]
然后在您的 init 容器中,您可以运行默认命令(生成脚本),并将工作目录设置为卷目录
initContainers:
- name: tpch-dbgen
image: felipeogutierrez/tpch-dbgen
volumeMounts:
- name: tpch-dbgen-data
mountPath: /opt/tpch-dbgen/data # or anywhere really
workingDir: /opt/tpch-dbgen/data # matching mountPath
推荐阅读
- angular - 我可以在角 4 上使用什么版本的角材料?
- php - BadMethodCallException:方法 App\Http\Controllers\Auth\AdminLoginController::showLoginForm 不存在
- powershell - 使用 '"' 的字符串连接
- php - 如何从控制器中分离请求以使代码更清晰
- python - 如何在 python 中分隔字段和路径 gps 坐标?
- javascript - javascript正则表达式从特定字符串的第n行查找字符串
- c# - 从文本框中读取 sql 字符串并在 datagridview 中显示
- php - 在laravel中将数组转换为对象
- python - 名称错误:使用函数时未定义名称“x”
- hadoop - 如果在 impala statestore 关闭时执行 DDL,为什么 Impala 查询会失败?