k8s 中的卷 pod/Container ... 失去某人死于容器映像

Volumes in k8s pod/Container ... loosing some dirs from the Conatiner Image

我有一个用于 postgresql 的自定义容器镜像,并尝试运行将其作为有状态的 kubernetes 应用程序

图像知道 2 个卷安装到

  1. /opt/db/data/postgres/data(我的postgres安装的$PGDATA目录)
  2. /opt/db/backup

备份卷包含在 Dockerfile 中定义的更深层次的文件夹结构

Docker 文件

(节选)

...
...
# Environment variables required for this build (do NOT change)
# -------------------------------------------------------------
...
ENV PGDATA=/opt/db/data/postgres/data
ENV PGBASE=/opt/db/postgres
...
ENV PGBACK=/opt/db/backup/postgres/backups
ENV PGARCH=/opt/db/backup/postgres/archives


# Set up user and directories
# ---------------------------
RUN mkdir -p $PGBASE $PGBIN $PGDATA $PGBACK $PGARCH && \
    useradd -d /home/postgres -m -s /bin/bash --no-log-init --uid 1001 --user-group postgres && \
    chown -R postgres:postgres $PGBASE $PGDATA $PGBACK $PGARCH && \
    chmod a+xr $PGBASE

# set up user env
# ---------------
USER postgres
...
...
# bindings
# --------
VOLUME ["$PGDATA", "$DBBASE/backup"]
...
...
# Define default command to start Database.
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["postgres", "-D", "/opt/db/data/postgres/data"]

当我 运行 将其作为 kubernetes 中的容器或单个 pod 时,没有任何 volumeMounts 一切都很好,文件夹结构看起来应该如此

find /opt/db/backup -ls
2246982      4 drwxr-xr-x   3 root     root         4096 Feb 18 09:00 /opt/db/backup
2246985      4 drwxr-xr-x   4 root     root         4096 Feb 18 09:00 /opt/db/backup/postgres
2246987      4 drwxr-xr-x   2 postgres postgres     4096 Feb 11 14:59 /opt/db/backup/postgres/backups
2246986      4 drwxr-xr-x   2 postgres postgres     4096 Feb 11 14:59 /opt/db/backup/postgres/archives

然而,一旦我 运行 这是基于下面的 Statefulset(将卷安装到 pod @ /opt/db/data/postgres/data & /opt/db/backup(其中包括比安装更深的文件夹结构点,如上所述)这不是按预期进行的

find /opt/db/backup –ls
2      4 drwxr-xr-x   3 postgres postgres     4096 Feb 17 16:40 /opt/db/backup
11     16 drwx------   2 postgres postgres    16384 Feb 17 16:40 /opt/db/backup/lost+found

/opt/db/backup/postgres/backups&/opt/db/backup/postgres/archives,Image中的继承都没有了。

任何人都可以告诉我从哪里开始寻找这个问题的解决方案吗?

状态集

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: postgres-stateful
  name: postgres-stateful
  labels:
    app.kubernetes.io/name: postgres
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: postgres
    app: postgres
spec:
  serviceName: "postgres"
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: postgres
      app.kubernetes.io/component: database
      app.kubernetes.io/part-of: postgres
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
        app.kubernetes.io/name: postgres
        app.kubernetes.io/component: database
        app.kubernetes.io/part-of: postgres
    spec:
      serviceAccountName: default
      initContainers:           # Give `postgres` user (id 1001) permissions to mounted volumes
      - name: take-volume-mounts-ownership
        image: dev-local.dev.dlz.net/postgresql:14.2-deb11
        securityContext:
          readOnlyRootFilesystem: true
        env:
          - name: "PGDATA"
            value: "/opt/db/data/postgres/data"
        command: [ "/bin/sh" ]
        args: ["-c", "chown -R 1001:1001 /opt/db/data/postgres /opt/db/backup /tmp" ]
        volumeMounts:
        - name: pv-data
          mountPath: /opt/db/data/postgres
        - name: pv-backup
          mountPath: /opt/db/backup     # /opt/db/backup/postgres
        - name: emptydir-tmp
          mountPath: /tmp
      containers:
      - name: postgres
        image: dev-local.dev.dlz.net/postgresql:14.2-deb11
        imagePullPolicy: Always
        readinessProbe:
          exec:
            command: ["pg_isready", "-q"]
          periodSeconds: 10
          initialDelaySeconds: 7
          timeoutSeconds: 2
        livenessProbe:
          exec:
            command: ["psql", "-q", "-c", "SELECT 1 WHERE 1=0"]
          periodSeconds: 15
          initialDelaySeconds: 20
          timeoutSeconds: 2
        env:
          - name: "PGDATA"
            value: "/opt/db/data/postgres/data"
        envFrom:
        - configMapRef:
            name: postgres-configuration
        ports:
        - containerPort: 5432
          name: postgresdb
        resources:
          requests:
            memory: "256Mi"
            cpu: "50m"
          limits:
            memory: "1Gi"
            cpu: "1"
        securityContext:
          privileged: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1001
          allowPrivilegeEscalation: false
        volumeMounts:
        - name: pv-data
          mountPath: /opt/db/data/postgres/data   # /var/lib/postgresql/data
        - name: pv-backup
          mountPath: /opt/db/backup     # /opt/db/backup/postgres
        - name: emptydir-tmp
          mountPath: /tmp
      volumes:
      - name: pv-data
        persistentVolumeClaim:
          claimName: pgdata-ina-pvc
      - name: pv-backup
        persistentVolumeClaim:
          claimName: pgbackup-ina-pvc
      - name: emptydir-tmp
        emptyDir: {}

您遇到的是 Docker 和 Kubernetes 之间的许多不同行为之一。在这种情况下,这就是 Docker vs Kubernetes 在特定路径上挂载卷时如何处理图像的原始内容。

对于Docker,the original contents will be copied to the volume if it is a new volume。因此,您在 Docker 容器中看到的四个子文件夹是图像中的 pre-existing(由 RUN mkdir Docker 文件行创建)。

然而,至于 Kubernetes,你只能靠自己了。 Kubernetes 只是将空 PVC 挂载到遮盖原始图像内容的父路径,然后让您留在那儿。这就是为什么对于您的具体情况,您缺少这些文件夹。

一种常见的方法是使用initContainer,将PVC挂载到另一个路径上,并在实际容器启动之前先执行复制,并将具有复制内容的PVC挂载到预期路径上。

这是预期的行为。毕竟,目标是持久化数据。

想象一下它会按照您想要的方式工作。容器在启动时填充卷,您将获得文件夹结构。现在,1 小时后,容器将备份添加到此文件夹结构。如果容器重新启动,您预计会发生什么?新容器在其初始文件系统中没有备份。它应该覆盖卷并清除备份,还是应该保留备份?答案是卷才是真相的来源,而不是容器的文件系统。

也就是说,docker 这实际上是可能的。参见 https://docs.docker.com/storage/volumes/#populate-a-volume-using-a-container。这需要通过 运行 指令创建卷。

在 Kubernetes 中,如果不存在,您需要使用入口点或初始化容器来创建所需的文件夹结构。

当您将持久卷挂载到同一路径时,您在 Dockerfile 中创建的目录将被覆盖。您可以 re-construct 您的“take-volume-mounts-ownership”容器中的目录结构:

...
initContainers:
- name: take-volume-mounts-ownership
  ...
  env:
  - name: PGDATA
    value: /opt/db/data/postgres/data
  - name: PGBASE
    value: /opt/db/postgres
  - name: PGBACK
    value: /opt/db/backup/postgres/backups
  - name: PGARCH
    value: /opt/db/backup/postgres/archives
  ...
  args: ["-c", "mkdir -p $PGBASE $PGBIN $PGDATA $PGBACK $PGARCH && chown -R 1001:1001 /opt/db/data/postgres /opt/db/backup /tmp" ]
  ...