我有一个使用felipeogutierrez/tpch-dbgen构建的docker image docker-compose,并使用travis-CI将其推送到docker-hub注册表。

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。虽然我无法在Kubernetes配置文件中执行command: ["ls tpch-dbgen"]命令。
$ 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和main容器中的实际数据上。与所有Unix挂载一样,这将隐藏该目录中以前的数据。没有任何原因导致数据被复制到该卷中。除了Docker named-volume挂载外,其他所有挂载的工作方式相同:如果更改Compose设置以进行主机绑定(bind)挂载,或者使用本地开发系统,则会看到相同的行为。使用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

关于docker - 为什么我不能从Kubernetes中的容器之间的共享PersistentVolumeClaim中读取文件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64008325/

10-12 23:37