k8s 中的卷 pod/Container ... 失去某人死于容器映像
Volumes in k8s pod/Container ... loosing some dirs from the Conatiner Image
我有一个用于 postgresql 的自定义容器镜像,并尝试运行将其作为有状态的 kubernetes 应用程序
图像知道 2 个卷安装到
/opt/db/data/postgres/data
(我的postgres安装的$PGDATA
目录)
/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" ]
...
我有一个用于 postgresql 的自定义容器镜像,并尝试运行将其作为有状态的 kubernetes 应用程序
图像知道 2 个卷安装到
/opt/db/data/postgres/data
(我的postgres安装的$PGDATA
目录)/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" ]
...