扣丁狼k8s(三)存储与配置
# 配置管理
# ConfigMap
# 创建
例如我们先创建一个配置文件db.properties
username=root
password=123456
2
Redis.properties
port=6379
host=localhost
2
将上面的两个文件放到同一个test/中
root@openstackTest-1:~/yamlPackage/configMap/test# ls
mysql.properties redis.properties
2
kubectl create configmap <configname> --from-file=<dirpath>
基于文件夹进行创建
root@openstackTest-1:~/yamlPackage/configMap# kubectl create cm mytestconfig --from-file=test/
configmap/mytestconfig created
root@openstackTest-1:~/yamlPackage/configMap# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 37h
mytestconfig 2 5s
2
3
4
5
6
查看详细信息
root@openstackTest-1:~/yamlPackage/configMap# kubectl describe cm mytestconfig
Name: mytestconfig
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis.properties:
----
host=127.0.0.1
port=6379
mysql.properties:
----
username=root
password=123456
BinaryData
====
Events: <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
从上面可以看到我们具体设置的信息,通过文件夹的方式,将某个文件夹下面所有的文件的写进了配置
kubectl create cm <cnname> --from-file=key1=filepath --from-file=key2=filepath
基于文件进行创建【key如果不指定,默认使用文件的名字】
我们创建一个配置文件application.yaml
spring:
application:
name: test
server:
port: 8080
2
3
4
5
root@openstackTest-1:~/yamlPackage/configMap# kubectl create cm spring-yaml --from-file=application.yaml=test/spring.yaml
configmap/spring-yaml created
root@openstackTest-1:~/yamlPackage/configMap# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 37h
mytestconfig 2 12m
spring-yaml 1 6s
root@openstackTest-1:~/yamlPackage/configMap# kubectl describe cm spring-yaml
Name: spring-yaml
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
application.yaml:
----
spring:
application:
name: test
server:
port: 8080
BinaryData
====
Events: <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
kubectl create cm <cmname> --from-literal=key1=config1 --from-literal=key2=config2
当参数比较少时,可以用这个方法
root@openstackTest-1:~/k8s1# kubectl create cm keyvalueconfig --from-literal=key1=value1 --from-literal=key2=value2
configmap/keyvalueconfig created
root@openstackTest-1:~/k8s1# kubectl get cm keyvalueconfig
NAME DATA AGE
keyvalueconfig 2 14s
root@openstackTest-1:~/k8s1# kubectl describe cm keyvalueconfig
Name: keyvalueconfig
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
key2:
----
value2
key1:
----
value1
BinaryData
====
Events: <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 使用
首先我们先创建一个我们想要使用的配置
kubectl create cm test-env-config --from-literal=JAVA_OPTS_TEST='-Xms512m -Xmx512m' --from-literal=APP_NAEM=springboot-test
root@openstackTest-1:~/k8s1# kubectl create cm test-env-config --from-literal=JAVA_OPTS_TEST='-Xms512m -Xmx512m' --from-literal=APP_NAEM=springboot-test
configmap/test-env-config created
root@openstackTest-1:~/k8s1# kubectl describe cm test-env-config
Name: test-env-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
APP_NAEM:
----
springboot-test
JAVA_OPTS_TEST:
----
-Xms512m -Xmx512m
BinaryData
====
Events: <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
实现在容器中打印出对应的配置
- 创建我们对应的一个容器
apiVersion: v1
kind: Pod
metadata:
name: test-env-pod
spec:
restartPolicy: Never
containers:
- name: env-test
image: alpine
command: ["/bin/sh","-c","env;sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config
key: JAVA_OPTS_TEST
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们使用命令查看容器的日志:
root@openstackTest-1 ~/y/pod# kubectl logs -f test-env-pod
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=test-env-pod
SHLVL=1
HOME=/root
NGINX_SERVICE_PORT_80_TCP=tcp://10.98.194.204:80
JAVA_VM_OPTS=-Xms512m -Xmx512m
APP=springboot-test
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_SERVICE_SERVICE_HOST=10.98.194.204
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
NGINX_SERVICE_SERVICE_PORT=80
NGINX_SERVICE_PORT=tcp://10.98.194.204:80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
NGINX_SERVICE_PORT_80_TCP_ADDR=10.98.194.204
NGINX_SERVICE_PORT_80_TCP_PORT=80
NGINX_SERVICE_PORT_80_TCP_PROTO=tcp
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
可以看到这个容器确实拿到了我们的对应的数据了。
另一种配置的方式,通过挂载的方式将某个配置文件加载到容器中
apiVersion: v1
kind: Pod
metadata:
name: test-env-pod
spec:
restartPolicy: Never
containers:
- name: env-test
image: alpine
command: ["/bin/sh","-c","env;sleep 3600"]
imagePullPolicy: IfNotPresent
env:
- name: JAVA_VM_OPTS
valueFrom:
configMapKeyRef:
name: test-env-config
key: JAVA_OPTS_TEST
- name: APP
valueFrom:
configMapKeyRef:
name: test-env-config
key: APP_NAME
volumeMounts:
- name: db-config
mountPath: "/usr/local/mysql/conf"
readOnly: true
volumes:
- name: db-config
configMap:
name: test-dir-config
items:
- key: "db.properties"
path: "db.properties"
restartPolicy: Never
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
metadata
: 这是用于定义 Pod 元数据的部分。
name: test-env-pod
: 这里定义了 Pod 的名称。
spec
: 这是用于定义 Pod 规范的部分。
restartPolicy: Never
: 这表示 Pod 的重启策略是 "Never",即不会自动重启。一旦容器退出,它将永远保持在非运行状态。
containers
: 这是一个容器列表,这里定义了一个容器。
name: env-test
: 容器的名称是 "env-test"。image: alpine
: 使用 Alpine Linux 镜像作为容器的基础镜像。command
: 定义容器启动时执行的命令。在这里,容器将打印环境变量 (env
) 的内容,并然后休眠 3600 秒。imagePullPolicy: IfNotPresent
: 这表示如果本地没有这个容器镜像,才从远程仓库拉取,否则使用本地镜像。
env
: 这里定义了容器的环境变量。
name: JAVA_VM_OPTS
: 环境变量的名称是 "JAVA_VM_OPTS"。valueFrom
1: 这表示环境变量的值来自于其他资源。
configMapKeyRef
1: 环境变量的值是从 ConfigMap 中获取的。
name: test-env-config
: 这是 ConfigMap 的名称。key: JAVA_OPTS_TEST
: 这是 ConfigMap 中的键,它的值将赋给 "JAVA_VM_OPTS" 变量。
name: APP
: 另一个环境变量的名称是 "APP"。valueFrom
1: 同样,这个环境变量的值也来自于 ConfigMap。
configMapKeyRef
1: 它引用了同一个 ConfigMap,但使用了不同的键。
name: test-env-config
: 这是相同的 ConfigMap。key: APP_NAME
: 这是不同的键,其值将赋给 "APP" 变量。
volumes
: 这是一个用于定义卷的部分,这里定义了一个卷。
name: db-config
: 卷的名称是 "db-config"。configMap
1: 这表示这个卷是一个 ConfigMap 类型的卷。
name: test-dir-config
: 这是 ConfigMap 的名称,它将被挂载到容器中。items
1: 这里定义了 ConfigMap 中的哪些键值对将被挂载到容器中。
key: "db.properties"
: 这是 ConfigMap 中的键。path: "db.properties"
: 这是挂载到容器中的路径。最后的
restartPolicy: Never
与之前的相同,表示 Pod 的重启策略是 "Never",容器退出后不会自动重启。
# secret
主要是可以配置一些加密的信息,不过这个加密是base64,加密性不高
创建方式和secret差不多
例如:
kubectl create secret generic orig-secret --from-literal=username=admin --from-literal=password=ds@!3-/
上面创建语句没有问题,但是ds@!3-/
这种有特殊字符的数据进行创建,可能会出现一些特殊的问题,导致我们保存的数据不是我们实际想要的数据
更多用在docker私有仓库等。
# subPath
subPath
是 Kubernetes 中用于挂载卷内部文件或目录到容器的特定路径的设置。它通常在 Pod 的volumes
和容器的volumeMounts
中使用。假设你有一个卷(例如 ConfigMap 或者 Secret),其中包含多个文件或目录,而你只想将其中的一部分挂载到容器内的特定路径,你可以使用
subPath
来实现这一点。下面是一个示例:
yamlCopy code apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image volumeMounts: - name: my-volume mountPath: /path/in/container subPath: my-file.txt volumes: - name: my-volume configMap: name: my-configmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17在这个示例中,我们有一个 Pod,其中包含一个容器(
my-container
)和一个卷(my-volume
),卷使用了 ConfigMap(my-configmap
)。我们希望将 ConfigMap 中的my-file.txt
文件挂载到容器中的/path/in/container
路径上。这就是通过在容器的volumeMounts
中使用subPath
来实现的。这将只挂载 ConfigMap 中的my-file.txt
文件到指定路径,而不是整个 ConfigMap。这在某些情况下非常有用,因为你可以选择性地将卷的特定部分挂载到容器中,而不必将整个卷都挂载进来。
意思就是将我们configMap中的的nginx.conf个文件挂在到容器中/etc/nginx/的目录下。但是这里有一个关键点,挂在时,如果容器中对应的目录存在则覆盖,不存在则新建,这样会导致我们所有的nginx的该目录下原本的文件消失,我们是不想要这样的。
这个时候,我们就要使用到subpath这个概念。
- 定义volumes时,需要增加items属性,配置key和path,且path的值不能从/开始
- 在容器内的volumeMounts中增加subpath属性,该值与volumes中的items.path的值相同
# 配置的热更新
我们通常将配置文件作为configmap然后挂载到pod,那么如果更新configmap中汇的配置,会不会更新到pod中呢?
默认方式:会更新,更新周期是更新时间+缓存时间
subpath: 不会更新
变量形式: 如果pod中的一个变量从condigmap或者secret中得到,同样也不会更新的
对于subpath方式,我们可以取消subpath的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后利用软链接的形式,将文件链接到目标位置
更新方式:
- 通过edit命令直接修改configmap
- 通过replace替换
# 不可变的Secret和condigmap
一些线上的配置文件,我们并不想改变,更具有稳定性
对于一些敏感服务的配置文件,在线上有时是不允许修改的,此时在配置configmap时可以设置immutable:true来禁止修改
# 容器中的容器卷技术
空白目录(EmptyDir)卷示例:
主要目的不是为了持久化,而是为了管理一个pod上面有多个容器的情况
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:1.19 volumeMounts: - name: my-volume mountPath: /data volumes: - name: my-volume emptyDir: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14主机路径(HostPath)卷示例:
将节点上的文件或目录挂在到pod上,此时该目录会变成持久化存储目录,即使pod被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:1.19 volumeMounts: - name: my-volume mountPath: /data volumes: - name: my-volume hostPath: path: /path/on/host type: Directory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
需要注意的是,我们创建了一个挂载的容器后,我们首先需要知道这个容器挂在到了哪个node节点,对应的node节点上的主机目录才是对应的挂在目录
如何进入到一个pod中的指定的一个容器:
kubectl exec -it empty-dir-pod -c nginx-emptydir1 -- sh
可以进入到两个容器中,在对应的目录查看文件的共享
没有持久化的能力,pod被删除,对应的数据最终也会被删除
持久卷声明(PersistentVolumeClaim)示例:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:1.19 volumeMounts: - name: my-volume mountPath: /data volumes: - name: my-volume persistentVolumeClaim: claimName: my-pvc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15配置映射(ConfigMap)卷示例:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:1.19 volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: my-config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15密钥和证书卷示例:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:1.19 volumeMounts: - name: tls-volume mountPath: /etc/tls volumes: - name: tls-volume secret: secretName: my-tls-secret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这些示例演示了不同类型的容器卷配置,包括空白目录卷、主机路径卷、持久卷声明、配置映射卷以及密钥和证书卷。你可以根据需要选择适当的卷类型并根据你的应用程序要求进行配置。
# NFS挂载
# 不同的机器之间使用nfs
nfs卷能将NFS(网络文件系统)挂在到你的pod中,不像empty那样会被删除pod的同时也会删除,nfs卷的内容在pod被删除时会被保存,卷只是被卸载。这意味着nfs卷可以被预先填充数据,并且这些数据可以在pod之间共享
因为会存在网络通信,所以不建议存储在频繁读写的情况,例如不适用于mysql。
参考: 安装和原理教程 (opens new window)
下载nfs-server,apt install nfs-server
选定一台机器作为服务器,创建目录/nfs/ro
和/nfs/rw
配置文件/etc/exports
/nfs/rw 10.10.10.0/24(rw,sync,no_subtree_check,no_root_squash)
/nfs/ro 10.10.10.0/24(ro,sync,no_subtree_check,no_root_squash)
2
注意上面的配置,只有对应网段的的机器才可以挂载到这里
重新加载nfs配置exportfs -f
重启服务systemctl reload nfs-server
可以在ro当中写一个文件,便于等会在客户端查看
在客户端安装好nfs-utils
apt install nfs-common
在客户端创建一个用于挂载的目录:mkdir -p /mnt/nfs/rw/
挂载:mount -t nfs 10.10.10.7:/nfs/rw /mnt/nfs/rw
挂载后查看对应的目录发现有可用的文件
# 在容器中使用nfs
同样是通过volume配置的方式进行运用
apiVersion: v1
kind: pod
metadata:
name: nfs-test-pod1
spec:
containers:
- image: nginx
name: test-container
volumeMount:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
nfs:
server: 10.10.10.7
path: /nfs/rw
readOnly: false
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl podip
可以看到返回对应的内容
当我们删除掉这两个pod后,nfs服务器上的资源还是存在的
# PV和PVC
为了解决远程存储的不统一
PV就是对其做一个抽象,屏蔽其底层的细节。
PVC用于描写每个pod服务需要多少的数据资源
# 生命周期
构建
- 静态构建
集群管理员创建若干pv卷,这些卷对象带有真实存储的细节信息,并且对集群用户可见,pv卷存在于k8s api中,可以供用户消费
- 动态构建
绑定
使用
pod与pvc关联
回收策略
- Retain
- delete
- recycle
# PV
配置文件
pv的状态
available 空闲:未被绑定
bound 已被pvc绑定
released:PVC被删除,资源已回收,但是被PV未被重新使用
Failed: 自动回收失败
# PVC
创建后,看pvc就可以看到bound状态
最后我们再来绑定pod