hostPath
hostPath 概述
- Host 级持久卷,数据不会随着容器的删除而删除,而是持久存放在宿主机
应用场景:
- 采集宿主机的日志、
参考文档:
hostPath 注意事项
-
HostPath 卷可能会暴露特权系统凭据(例如 Kubelet)或特权 API(例如容器运行时套接字),可用于容器逃逸或攻击集群的其他部分。
-
具有相同配置(例如基于同一 PodTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。
-
下层主机上创建的文件或目录只能由 root 用户写入。你需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入
hostPath卷。 -
为了安全考虑,当必须使用 HostPath 卷时,它的范围应仅限于所需的文件或目录,并以只读方式挂载 即 readOnly: true
-
只读方式挂载其实是为了避免在容器中误操作导致宿主机的内容一同被删除
-
只读方式挂载 如果宿主机不存在 volumes 定义的目录则会自动创建 但无法往其中写入数据
-
但是有的时候以只读方式挂载有时会导致容器无法启动,所以可以选择将需要读写的目录进行读写挂载(比如日志目录),其它不需要读写操作的目录进行只读挂载
-
范例:nginx全部目录以只读方式挂载报错如下,这时就可以单独将日志目录进行读写挂载
-
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (30: Read-only file system) 2022/07/25 01:51:16 [emerg] 1#1: open() "/var/log/nginx/error.log" failed (30: Read-only file system)
-
-
hostPath Explain
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- name: test-hostpath
image: nginx-1.18-ubuntu:1.0
volumeMounts:
- name: hostpath # 引用pod级别存储卷的名称
mountPath: /var/log/nginx # 容器上的路径,不存在则会自动创建
volumes:
- name: hostpath # 定义pod级别存储卷的名称
hostPath: # 定义存储卷类型为hostPath
path: /data/logs/nginx # 宿主上的位置,不存在则会自动创建,也可以加下面的type进行判断
#type: Directory # 默认在关联hostPath存储卷之前不进行任何检查(不检查文件或目录是否存在,以及文件类型为何)。type
deployments.spec.template.spec.volumes.hostPath.type
- File:事先必须存在的文件路径;
- Directory:事先必须存在的目录路径;
- DirectoryOrCreate:指定的路径不存时自动将其创建为0755权限的空目录,属主属组均为kubelet;
- FileOrCreate:指定的路径不存时自动将其创建为0644权限的空文件,属主和属组同为kubelet;
- Socket:事先必须存在的Socket文件路径;
- CharDevice:事先必须存在的字符设备文件路径;
- BlockDevice:事先必须存在的块设备文件路径;
—
hostPath Example - 1
yaml
- 此示例中将宿主机的日志等目录挂载到容器中,该容器可以实现采集指定挂载点的日志数据发送到redis
apiVersion: v1
kind: Pod
metadata:
name: volumes-hostpath-demo
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.7-alpine
env:
- name: REDIS_HOST
value: redis.ilinux.io:6379
- name: LOG_LEVEL
value: info
volumeMounts:
- name: varlog
mountPath: /var/log
- name: socket
mountPath: /var/run/docker.sock
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true # 设为只读,防止此关键目录中的数据被误删除
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: socket
hostPath:
path: /var/run/docker.sock验证
# kubectl describe pod volumes-hostpath-demo
Name: volumes-hostpath-demo
Namespace: default
Priority: 0
Node: k8s-node-1/10.0.0.101
...
Containers:
...
Mounts:
/var/lib/docker/containers from varlibdockercontainers (ro)
/var/log from varlog (rw)
/var/run/docker.sock from socket (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hv26d (ro)
...
Volumes:
varlog:
Type: HostPath (bare host directory volume)
Path: /var/log
HostPathType:
varlibdockercontainers:
Type: HostPath (bare host directory volume)
Path: /var/lib/docker/containers
HostPathType:
socket:
Type: HostPath (bare host directory volume)
Path: /var/run/docker.sock
HostPathType:
...
---------------------------
# 宿主机
root@k8s-node-1:~# ls /var/log/ -l
total 6412
-rw-r--r-- 1 root root 0 Oct 1 20:59 alternatives.log
-rw-r--r-- 1 root root 8768 Sep 25 08:41 alternatives.log.1
-rw-r--r-- 1 root root 2260 Mar 24 2022 alternatives.log.2.gz
-rw-r----- 1 root adm 0 Oct 18 10:04 apport.log
-rw-r----- 1 root adm 115 Oct 17 17:59 apport.log.1
drwxr-xr-x 2 root root 4096 Dec 23 12:43 apt
...
# 容器中
root@k8s-master-1:~# kubectl exec volumes-hostpath-demo -- ls -l /var/log
total 6412
-rw-r--r-- 1 root root 0 Oct 1 12:59 alternatives.log
-rw-r--r-- 1 root root 8768 Sep 25 00:41 alternatives.log.1
-rw-r--r-- 1 root root 2260 Mar 24 2022 alternatives.log.2.gz
-rw-r----- 1 root adm 0 Oct 18 02:04 apport.log
-rw-r----- 1 root adm 115 Oct 17 09:59 apport.log.1
drwxr-xr-x 2 root root 4096 Dec 23 04:43 apt
...宿主机中创建文件
root@k8s-node-1:~# echo 'Create in Host' > /var/log/hostfile.txt
root@k8s-node-1:~# cat /var/log/hostfile.txt
Create in Host
root@k8s-master-1:~# kubectl exec volumes-hostpath-demo -- cat /var/log/hostfile.txt
Create in Host
# Pod删除后文件会在宿主机持久保存
# kubectl delete -f volumes-hostpath-demo.yaml
pod "volumes-hostpath-demo" deleted
root@k8s-node-1:~# cat /var/log/hostfile.txt
Create in Host容器中创建文件
root@k8s-master-1:~# kubectl exec -it volumes-hostpath-demo -- sh
/ # echo 'Create in Container' > /var/log/containerfile.txt
/ # cat /var/log/containerfile.txt
Create in Container
root@k8s-node-1:~# cat /var/log/containerfile.txt
Create in Container
# Pod删除后文件会在宿主机持久保存
# kubectl delete -f volumes-hostpath-demo.yaml
pod "volumes-hostpath-demo" deleted
root@k8s-node-1:~# cat /var/log/containerfile.txt
Create in ContainerhostPath Example - 2
yaml
- test-hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- name: test-hostpath
image: nginx-1.18-ubuntu:1.0
volumeMounts:
- name: hostpath # 引用pod级别存储卷的名称
mountPath: /var/log/nginx # 容器上的路径,不存在则会自动创建
volumes:
- name: hostpath # 定义pod级别存储卷的名称
hostPath: # 定义存储卷类型为hostPath
path: /data/logs/nginx # 宿主上的位置,不存在则会自动创建,也可以加下面的type进行判断
#type: Directory # Directory、 File、DirectoryOrCreate...,默认在关联hostPath存储卷之前不进行任何检查。Test
#创建
# kubectl apply -f test-pod.yaml
pod/test-pod created
#进入容器中并创建测试文件
# kubectl exec -it test-pod -- bash
root@test-pod:/# echo 'hello k8s!' > /cache/test.txt
root@test-pod:/# ls -l /cache/
total 4
-rw-r--r-- 1 root root 11 Jun 29 06:16 test.txt
root@test-pod:/# cat /cache/test.txt
hello k8s!
#查看pod被创建到哪个节点
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
...
test-pod 1/1 Running 0 6m25s 10.10.1.26 k8s-work-1 <none> <none>
#来到被创建到的节点查找文件
root@k8s-work-1:~# tree /data
/data
└── logs
└── nginx
├── access.log
└── error.log
#删除容器
# kubectl delete -f test-pod.yaml
pod "test-pod" deleted
#卷会保留
root@k8s-work-1:~# tree /data
/data
└── logs
└── nginx
├── access.log
└── error.log当多个镜像使用相同的 hostPath
- 结论:数据会以增量形式添加,而非覆盖
# cat test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: nginx
name: test-container
volumeMounts:
- mountPath: /var/log/nginx #容器上的路径
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data/logs/nginx #宿主上目录位置
# cat test-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pod2
spec:
containers:
- image: nginx
name: test-container2
volumeMounts:
- mountPath: /var/log/nginx #容器上的路径
name: test-volume #调用
volumes:
- name: test-volume #定义
hostPath:
path: /data/logs/nginx #宿主上目录位置
root@k8s-master:~# kubectl exec -it test-pod bash
root@test-pod:/# echo 111 >> /var/log/nginx/access.log
root@k8s-master:~# kubectl exec -it test-pod2 bash
root@test-pod2:/# echo 222 >> /var/log/nginx/access.log
root@k8s-work-1:~# tail -f /data/logs/nginx/access.log
111
222如果宿主机事先有目录并且有文件
- 总结:有原有目录的话数据不会丢 容器内的文件会以增量的方式存放在宿主机,容器中可以看到宿主机挂载目录的全部内容 并且可以进行删除等操作
# test-hostPath.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test-hostpath
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test-hostpath
namespace: test-hostpath
spec:
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
restartPolicy: Always
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: log
mountPath: /var/log/nginx
volumes:
- name: log
hostPath:
path: /data/logs/nginx
# 宿主机目录
# ll /data/logs/nginx/
...
-rw-r--r-- 1 root root 630 Jul 25 09:49 fstab
-rw-r--r-- 1 root root 2099 Jul 25 09:49 passwd
# 再次查看宿主机目录
# kubectl apply -f test-hostPath.yaml
namespace/test-hostpath created
daemonset.apps/test-hostpath created
# ll /data/logs/nginx/
...
-rw-r--r-- 1 root root 0 Jul 25 09:53 access.log
-rw-r--r-- 1 root root 505 Jul 25 09:53 error.log
-rw-r--r-- 1 root root 630 Jul 25 09:49 fstab
-rw-r--r-- 1 root root 2099 Jul 25 09:49 passwd
# 容器中会看到宿主机中的内容
# kubectl exec -it -n test-hostpath test-hostpath-bl5vj -- bash
root@test-hostpath-bl5vj:/# ls -l /var/log/nginx/
total 12
-rw-r--r-- 1 root root 0 Jul 25 02:00 access.log
-rw-r--r-- 1 root root 505 Jul 25 02:00 error.log
-rw-r--r-- 1 root root 630 Jul 25 02:01 fstab
-rw-r--r-- 1 root root 2099 Jul 25 02:00 passwdhostpath 采集宿主机日志
- 以只读方式挂载
- 注意:此方式没有解决针对不同宿主机日志分类存放的问题,如何解决?
# test-hostPath.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test-hostpath
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test-hostpath
namespace: test-hostpath
spec:
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
restartPolicy: Always
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: log
mountPath: /tmp
readOnly: true
volumes:
- name: log
hostPath:
path: /var/log
# kubectl apply -f test-hostPath.yaml
namespace/test-hostpath created
daemonset.apps/test-hostpath created
# kubectl get pod -n test-hostpath
NAME READY STATUS RESTARTS AGE
test-hostpath-cjwb2 1/1 Running 0 3s
test-hostpath-hlzxk 1/1 Running 0 3s
# kubectl exec -it -n test-hostpath test-hostpath-cjwb2 -- bash
root@test-hostpath-cjwb2:/# ls /tmp/
alternatives.log cloud-init.log haproxy.log haproxy.log.3.gz kern.log.3.gz
...
# 只能查看 不能删除
root@test-hostpath-cjwb2:/# rm -f /tmp/syslog
rm: cannot remove '/tmp/syslog': Read-only file system同一 Pod 中多个容器挂载相同的 hostPath
- 挂载前,各容器数据存放位置
# cat demoapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demoapp
spec:
replicas: 1
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
- name: demoapp
image: registry.cn-hangzhou.aliyuncs.com/xiangzheng_repo/demoapp:v1.0
command:
- tail
- -f
- /dev/null
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/xiangzheng_repo/nginx:1.23
# nginx 容器数据
# ls /usr/share/nginx/html/
50x.html index.html
# demoapp 容器数据
# ls /usr/local/bin/demo.py
/usr/local/bin/demo.py- 如果宿主机事先未创建挂载目录,则该目录会被自动创建,并将该目录挂载至对应的容器中。因此 nginx 与 demoapp 容器之前的数据将看不到(看到的是宿主机 /share-data 目录的内容)。
- 总结:宿主机的目录挂载到容器中
# 注意!该目录应在 Pod 被调度的节点查询!
root@local-k8s-worker-1:~# ls /share-data
ls: cannot access '/share-data': No such file or directory
# cat demoapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demoapp
spec:
replicas: 1
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
- name: demoapp
image: registry.cn-hangzhou.aliyuncs.com/xiangzheng_repo/demoapp:v1.0
command:
- tail
- -f
- /dev/null
volumeMounts:
- name: test-hostpath
mountPath: /usr/local/bin/
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/xiangzheng_repo/nginx:1.23
volumeMounts:
- name: test-hostpath
mountPath: /usr/share/nginx/html/
volumes:
- name: test-hostpath
hostPath:
path: /share-data
# Pod 创建后,该目录在被调度的节点上出现
root@local-k8s-worker-1:~# ls /share-data -d
/share-data