用于记录下k8s集群中pv(Persistent)、sc(Storeage Class)、pvc(PersistenVolumeClaim)的相关概念。
PersistentVolume(PV 存储卷)是集群中的一块存储空间,由集群管理员管理、或者由 Storage Class(存储类)自动管理。PV(存储卷)和 node(节点)一样,是集群中的资源(kubernetes 集群由存储资源和计算资源组成)。PersistentVolumeClaim(存储卷声明)是一种类型的 Volume(数据卷),PersistentVolumeClaim(存储卷声明)引用的 PersistentVolume(存储卷)有自己的生命周期,该生命周期独立于任何使用它的容器组。PersistentVolume(存储卷)描述了如何提供存储的细节信息(NFS、cephfs等存储的具体参数)。
PersistentVolumeClaim(PVC 存储卷声明)代表用户使用存储的请求。Pod 容器组消耗 node 计算资源,PVC 存储卷声明消耗 PersistentVolume 存储资源。Pod 容器组可以请求特定数量的计算资源(CPU / 内存);PersistentVolumeClaim 可以请求特定大小/特定访问模式(只能被单节点读写/可被多节点只读/可被多节点读写)的存储资源。
根据应用程序的特点不同,其所需要的存储资源也存在不同的要求,例如读写性能等。集群管理员必须能够提供关于 PersistentVolume(存储卷)的更多选择,无需用户关心存储卷背后的实现细节。为了解决这个问题,K8s 引入了 StorageClass(存储类)的概念。
PV和PVC的关系
PV是集群中的存储资源,通常由集群管理人员创建和管理;
SC用于对PV进行分类,如果正确配置,SC可以根据PVC的请求动态创建PV;
PVC是使用该资源的请求,通常由应用程序提出的请求,并指定对应的SC和需要的存储空间大小;
PVC可以作为数据卷的一种,被挂载到容器中使用。
PVC的管理过程
PV和PVC的管理过程如下:
存储资源的回收策略
当用户不在需要其数据卷时,可以删除掉其 PVC,此时其对应的 PV 将被集群回收并再利用。K8s 集群根据 PV 中的 reclaim policy(回收策略)决定在其被回收时做对应的处理。当前支持的回收策略有:Retained(保留)、Recycled(重复利用)、Deleted(删除)
Retain
保留策略需要集群管理员手工回收该资源。当绑定的 PVC 被删除后,PV 仍然存在,并被认为是”已释放“。但是此时该存储卷仍然不能被其他 PVC 绑定,因为前一个绑定的 PVC 对应容器组的数据还在其中。
可以通过如下步骤回收该 PV:
删除该 PersistentVolume。PV删除后,其数据仍然存在于对应的外部存储介质中(nfs、cefpfs、glusterfs 等)
手工删除对应存储介质上的数据
手工删除对应的存储介质,也可以创建一个新的PV并再次使用该存储介质。
Recycle
再利用策略将在 PV 回收时,执行一个基本的清除操作(rm -rf /thevolume/*),并使其可以再次被新的 PVC 绑定。
也可以自定义一个 recycler pod template,用于执行清除操作。参考: 官方文档。
Delete
删除策略将从 k8e 集群移除 PV 以及其关联的外部存储介质(云环境中的 AWA EBS、GCE PD、Azure Disk 或 Cinder volume
core-dns的配置文件
coredns部署脚本
#!/bin/bash
# Deploys CoreDNS to a cluster currently running Kube-DNS.
show_help () {
cat << USAGE
usage: $0 [ -r REVERSE-CIDR ] [ -i DNS-IP ] [ -d CLUSTER-DOMAIN ] [ -t YAML-TEMPLATE ]
-r : Define a reverse zone for the given CIDR. You may specify this option more
than once to add multiple reverse zones. If no reverse CIDRs are defined,
then the default is to handle all reverse zones (i.e. in-addr.arpa and ip6.arpa)
-i : Specify the cluster DNS IP address. If not specified, the IP address of
the existing "kube-dns" service is used, if present.
-s : Skips the translation of kube-dns configmap to the corresponding CoreDNS Corefile configuration.
USAGE
exit 0
}
# Simple Defaults
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
CLUSTER_DOMAIN=cluster.local
YAML_TEMPLATE="$DIR/coredns.yaml.sed"
STUBDOMAINS=""
UPSTREAM=\\/etc\\/resolv\.conf
# Translates the kube-dns ConfigMap to equivalent CoreDNS Configuration.
function translate-kube-dns-configmap {
kube-dns-upstreamnameserver-to-coredns
kube-dns-stubdomains-to-coredns
}
function kube-dns-upstreamnameserver-to-coredns {
up=$(kubectl -n kube-system get configmap kube-dns -ojsonpath='{.data.upstreamNameservers}' 2> /dev/null | tr -d '[",]')
if [[ ! -z ${up} ]]; then
UPSTREAM=${up}
fi
}
function kube-dns-stubdomains-to-coredns {
STUBDOMAIN_TEMPLATE='
SD_DOMAIN:53 {
errors
cache 30
loop
forward . SD_DESTINATION {
max_concurrent 1000
}
}'
function dequote {
str=${1#\"} # delete leading quote
str=${str%\"} # delete trailing quote
echo ${str}
}
function parse_stub_domains() {
sd=$1
# get keys - each key is a domain
sd_keys=$(echo -n $sd | jq keys[])
# For each domain ...
for dom in $sd_keys; do
dst=$(echo -n $sd | jq '.['$dom'][0]') # get the destination
dom=$(dequote $dom)
dst=$(dequote $dst)
sd_stanza=${STUBDOMAIN_TEMPLATE/SD_DOMAIN/$dom} # replace SD_DOMAIN
sd_stanza=${sd_stanza/SD_DESTINATION/$dst} # replace SD_DESTINATION
echo "$sd_stanza"
done
}
sd=$(kubectl -n kube-system get configmap kube-dns -ojsonpath='{.data.stubDomains}' 2> /dev/null)
STUBDOMAINS=$(parse_stub_domains "$sd")
}
# Get Opts
while getopts "hsr:i:d:t:k:" opt; do
case "$opt" in
h) show_help
;;
s) SKIP=1
;;
r) REVERSE_CIDRS="$REVERSE_CIDRS $OPTARG"
;;
i) CLUSTER_DNS_IP=$OPTARG
;;
d) CLUSTER_DOMAIN=$OPTARG
;;
t) YAML_TEMPLATE=$OPTARG
;;
esac
done
# Conditional Defaults
if [[ -z $REVERSE_CIDRS ]]; then
REVERSE_CIDRS="in-addr.arpa ip6.arpa"
fi
if [[ -z $CLUSTER_DNS_IP ]]; then
# Default IP to kube-dns IP
CLUSTER_DNS_IP=$(kubectl get service --namespace kube-system kube-dns -o jsonpath="{.spec.clusterIP}")
if [ $? -ne 0 ]; then
>&2 echo "Error! The IP address for DNS service couldn't be determined automatically. Please specify the DNS-IP with the '-i' option."
exit 2
fi
fi
if [[ "${SKIP}" -ne 1 ]] ; then
translate-kube-dns-configmap
fi
orig=$'\n'
replace=$'\\\n'
sed -e "s/CLUSTER_DNS_IP/$CLUSTER_DNS_IP/g" \
-e "s/CLUSTER_DOMAIN/$CLUSTER_DOMAIN/g" \
-e "s?REVERSE_CIDRS?$REVERSE_CIDRS?g" \
-e "s@STUBDOMAINS@${STUBDOMAINS//$orig/$replace}@g" \
-e "s/UPSTREAMNAMESERVER/$UPSTREAM/g" \
"${YAML_TEMPLATE}"
corednsyaml清单
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes CLUSTER_DOMAIN REVERSE_CIDRS {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . UPSTREAMNAMESERVER {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}STUBDOMAINS
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/name: "CoreDNS"
app.kubernetes.io/name: coredns
spec:
# replicas: not specified here:
# 1. Default is 1.
# 2. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
template:
metadata:
labels:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
spec:
priorityClassName: system-cluster-critical
serviceAccountName: coredns
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
kubernetes.io/os: linux
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values: ["kube-dns"]
topologyKey: kubernetes.io/hostname
containers:
- name: coredns
image: coredns/coredns:1.9.4
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
dnsPolicy: Default
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
---
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "CoreDNS"
app.kubernetes.io/name: coredns
spec:
selector:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
clusterIP: CLUSTER_DNS_IP
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCP
在Kubernetes中,使用以下默认Corefile配置安装了CoreDNS:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
log
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
Corefile配置包括以下CoreDNS 插件:
errors: 将错误记录到stdout。
log: 记录解析记录的日志。
health:据报告CoreDNS的健康http://localhost:8080/health。使用这种扩展语法,lameduck将使进程运行不正常,然后等待5秒钟,然后关闭进程。
ready:当所有能够发出信号准备就绪的插件都这样做时,端口8181上的HTTP端点将返回200 OK。
kubernetes:CoreDNS将基于Kubernetes的服务和Pod的IP答复DNS查询。可以在CoreDNS网站上找到有关该插件的更多详细信息。ttl允许您为响应设置自定义TTL。默认值为5秒。允许的最小TTL为0秒,最大为3600秒。将TTL设置为0将防止记录被缓存。提供该pods insecure选项是为了与kube-dns向后兼容。您可以使用该pods verified选项,仅当在相同名称空间中存在具有匹配IP的容器时,该选项才返回A记录。pods disabled如果您不使用pod记录,则可以使用该选项。
prometheus:CoreDNS的Metrics可在http://localhost:9153/metrics在普罗米修斯中展示(也称为OpenMetrics)。
forward:不在Kubernetes集群域内的任何查询都将转发到预定义的解析器(/etc/resolv.conf)。若要转发至其他dns服务器,而不是/etc/resolv.conf,可以写为: forward . dns_ip。
cache:这将启用前端缓存。
loop:检测简单的转发循环,如果发现循环,则暂停CoreDNS进程。
reload:允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟,以使更改生效。
loadbalance:这是一个轮询DNS负载平衡器,用于随机分配答案中A,AAAA和MX记录的顺序。
如何更改configmap
$ kubectl get configmap -n kube-system # 查看当前名称空间
NAME DATA AGE
calico-config 4 24d
coredns 1 24d
extension-apiserver-authentication 6 24d
kube-proxy 2 24d
kubeadm-config 2 24d
kubelet-config-1.18 1 24d
安全上下文 Security Context
一组用于决定容器是如何创建和运行的约束条件,它们代表创建和运行容器时使用的运行时参数;
比如:容器运行时的用户、用户的权限等
Pod上的SC有两个级别 分别为Pod级别、容器级别
常用字段 Pod级别的安全上下文
apiVersion: v1
kind: Pod
metadata: {...}
spec:
securityContext: #Pod级别的安全上下文,对内部所有容器均有效
runAsUser <integer> #以指定的用户身份运行容器进程,默认由镜像中的USER指定
runAsGroup <integer> #以指定的用户组运行容器进程,默认使用的组随容器运行时
supplementalGroups <[]integer> #为容器中1号进程的用户添加的附加组;
fsGroup <integer> #为容器中的1号进程附加的一个专用组,其功能类似于sgid
runAsNonRoot <boolean> #是否以非root身份运行
seLinuxOptions <0bject> #SELinux的相关配置
windowsOptions<Object> #Windows容器专用的设置
sysctls <[]Object> #应用到当前Pod上的名称空间级别的sysctl参数设置列表
Pod内可安全内核参数只有4个:
kernel.shm_rmid_forced
net.ipv4.ip_local_port_range
net.ipv4.tcp_syncookies
net.ipv4.ping_group_range (从 Kubernetes 1.18 开始)
其它参数需要重启K8S 在/etc/defaulte/kubelte(如果没有则新建)中添加
net.ipv4.ip_unprivileged_port_start
--allowed-unsafe-sysctls=net.core.somaxconn
......
常用字段 容器级别的安全上下文
containers:
- name: ...
image: .
securityContext: #容器级别的安全上下文,仅生效于当前容器
runAsUser <integer> #以指定的用户身份运行容器进程
runAsGroup <integer> #以指定的用户组运行容器进程
runAsNonRoot <boolean> #是否以非root身份运行
allowPrivilegeEscalation <boolean> #是否允许特权升级
capabilities <Object> #于当前容器上添加(add)或删除(drop)的内核能力
add<[]string> #添加由列表定义的各内核能力
drop <[]string> #移除由列表定义的各内核能力
CAP_CHOWN:改变UID和GID;
CAP_MKNOD:mknod() 创建设备文件;
CAP_NET_ADMIN:网络管理权限;
CAP_SYSADMIN:大部分的管理权限;
CAP_SYS_TIME:同步时间
CAP_SYS MODULE:装载卸载内核模块
CAP_NET_BIND_SERVER:允许绑定1024以内特权端口
也可以管理员 getcap, setcap直接设置权限(了解)
privileged <boolean> #是否运行为特权容器 可直接使用宿主机内核 谨慎使用
procMount <string> #设置容器的procMount类型,默认为DefaultProcMount;
readOnlyRootFilesystem boolean> #是否将根文件系统设置为只读模式
seLinux0ptions <Object> #SELinux的相关配置
windowsoptions <Object> #windows容器专用的设置
网友评论