背景问题
除了依托容器镜像来定义运行的Container,Pod还需要解决如下问题
1、不可变基础设施(容器)的可变配置
2、敏感信息的存储和使用(如:密码,token等)
3、集群中Pod自我的身份认证
4、容器运行资源的配置管理
5、容器的运行安全管控
6、容器启动前置条件校验
容器
- 可变配置:ConfigMap
- 敏感信息:Secret
- 身份认证:ServiceAccount
- 资源配置:Spec.Containers[].Resources.limits/requests
- 安全管控:Spec.Containers[].SecurityContext
- 前置校验:Spec.InitContainers
ConfigMap介绍
主要管理容器运行所需的配置文件,环境变量,命令行参数等可变配置。用于解耦容器镜像和可变配置,从而保障工作负载(Pod)的可移植性。
ConfigMAp创建
创建命令:kubectl create configmap [NAME] [DATA]
其中DATA:
- 指定文件或者目录
- 指定键值对
示例:
1、指定文件:
kubectl create configmap kube-flannel-cfg --from-file=configure-pod-container/configmap/cni-conf.json -n kube-system
2、指定键值对:
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
ConfigMap使用
ConfigMap主要被Pod使用,一般用于挂载Pod用的配置文件,环境变量,命令行参数等。
具体配置文件:
# 用ConfigMap配置环境变量
apiVersion: v1
kind: Pod
metadata:
name: cm-env-test
spec:
containers:
- name: test-container
image: busybox
command: ["/bin/sh", "-c", "env"]
env:
# 用special-config中special.how定义环境变量
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: specal.how
restartPolicy: Never
# 用ConfigMap配置管控命令行参数
apiVersion: v1
kind: Pod
metadata:
name: cm-test-test
spec:
containers:
- name: test-container
image: busybox
command: ["/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY)"]
env:
# 在命令行参数中使用ConfigMap定义的环境变量
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
restartPolicy: Never
# 用ConfigMap挂载配置文件
apiVersion: v1
kind: Pod
metadata:
name: cm-volume-test
spec:
containers:
- name: test-container
image: busybox
# # ConfigMap中指定的内容以文件形式挂载在容器中的/etc/config目录下
command: ["/bin/sh", "-c", "ls /etc/config/"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
restartPolicy: Never
ConfigMap使用注意点
- ConfigMap文件大小限制:1MB (.ETCD的要求)
- Pod只能引用相同Namespace中的ConfigMap
- Pod引用的ConfigMap不存在时,Pod无法创建成功。即Pod创建前需要先创建好Config Map。
- 使用envFrom从ConfigMap来配置环境变量时,如果CongfigMap中的某些key被认为无效(比如key名称中带有数字),该环境变量将不会注入容器,但是Pod可以正常创建。
- 只有通过k8s api创建的pod才能使用ConfigMap,其他方式创建的pod(如manifest创建的static pod)不能使用ConfigMap
Secret介绍
Secret是在集群中用于存储密码,token等敏感信息用的资源对象。其中的敏感数据采用base-64编码保存,相比存储在明文的ConfigMap中更规范,更安全。
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: kube-system
type: Opaque
data:
username: xxx
password: xxxx
Secret主要有如下类型:
- type=Opaque
- type=kubernetes.io/service-account-token
- type=kubernetes.io/dockerconfigjson
- type=bootstrap.kubernetes.io/token
1、指定文件:
kubectl create secret generic myregistrykey --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
命令:
kubectl create secret generic myregistrykey --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
kubectl get secret
kubectl describe secret/myregistrykey
kubectl get secret/myregistrykey -o yaml
2、指定键值对:
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
命令:
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
kubectl get secret/prod-db-secret -o yaml
Secret使用
Secret主要被Pod使用,一般通过volume挂载到指定容器目录,供容器中业务使用。另外在需要访问私有镜像仓库时,也可以引用Secret来实现。
[root@master pod]# cat secret-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod-3
spec:
containers:
- name: mypod
image: busybox
command: ["/bin/sh", "-c", "sleep 120"]
volumeMounts:
- name: chaitc
mountPath: "/etc/chaitc/"
readOnly: true
volumes:
- name: chaitc
secret:
secretName: myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: mypod-123
namespace: default
spec:
containers:
- name: mypod
image: busybox
command: ["/bin/sh", "-c", "sleep 180"]
volumeMounts:
- name: chaitc
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
serviceAccount: default
serviceAccountName: default
volumes:
- name: chaitc
secret:
defaultMode: 420
secretName: default-token-c9kc7
Secret使用的注意点
1、Secret文件大小限制:1MB
2、Secret虽然采用base-64编码,但是可以简单解码查看原始信息。因此机密信息才用Secret存储仍需要慎重考虑或者Secret访问者进行控制。对Secret加密有较强需求,可以考虑结合Kubernetes + Vault来解决敏感信息的加密和权限管理。
3、Secret最佳实践:因为list/watch的一般处理将获取到的namespace下所有secret,因此不建议采取list/watch方式获取Secret信息。而推荐使用GET来获取需要的Secret,从而减少更多Secret暴露的可能性。
ServiceAccount介绍
ServiceAccount主要用于解决Pod在集群中的身份认证问题。其中认证使用的授权信息,则利用前面讲到Secret(type=kubernetes.io/service-account-token)进行管理。
命令
kubectl get serviceaccount -o yaml
kubectl get secret/default-token-c9kc7 -o yaml
举例: Pod里的应用访问它所属的K8S集群
实现原理:
1、Pod创建时Admission Controller会根据指定的ServiceAccount(默认为default)把对应的Secret挂载到容器的目录下(/var/run/secrets/kubernetes.io/serviceaccount).(*k8s自动实现)
2、当Pod访问集群时,可以默认利用Secret其中的token文件来认证Pod的身份。(ca.crt用于校验服务端)(*参考右边代码)
3、默认token的认证信息为:
- Group: system:serviceaccounts:[namespace-name]
- User: system:serviceaccount:[namespace-name]:[pod-name]
* 同时Pod身份被认证合法后,其权限需要通过RBAC功能来配置。默认具备资源的GET权限。
kubernetes/config.go at 76277917b9b98bfac79d0e25fe8f45dfc5bec145 · kubernetes/kubernetes · GitHub
// InClusterConfig returns a config object which uses the service account
// kubernetes gives to pods. It's intended for clients that expect to be
// running inside a pod running on kubernetes. It will return ErrNotInCluster
// if called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
const (
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, ErrNotInCluster
}
token, err := os.ReadFile(tokenFile)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
if _, err := certutil.NewPool(rootCAFile); err != nil {
klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
TLSClientConfig: tlsClientConfig,
BearerToken: string(token),
BearerTokenFile: tokenFile,
}, nil
}
容器资源配置管理
支持资源类型:
- CPU:单位:millicore (1 Core=1000millicore)
- Memory: 单位:Byte
- ephemeral storage(临时存储):单位:Byte
- 自定义资源:配置时必须为整数
配置方法:
资源配置分为request/limit两种类型
- CPU:
spec.containers[].resources.limits.cpu
spec.containers[].resources.requests.cpu
- Memory:
spec.containers[].resources.limits.memory
spec.containers[].resources.requests.memory
- ephemeral.storage(临时存储):
spec.containers[].resources.limits.ephemeral-storage
spec.containers[].resources.requests.ephemeral-storage
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: wp
image: wordpress
resources:
# 申明需要的资源
requests:
memory: "64Mi"
cpu: "250m"
ephemeral-storage: "2Gi"
# 申明需要资源的边界
limits:
memory: "128Mi"
cpu: "500m"
ephemeral-storage: "4Gi"
Pod服务质量(QoS)配置
依据容器对CPU,Memory资源的request/limit需求,Pod服务质量分类:
- Guaranteed
- Burstable
- BestEffort
Guaranteed定义:
- Pod里的每个容器都必须有内存限制和请求,而且必须是一样的
- Pod里的每个容器都必须有CPU限制和请求,而且必须是一样的
Burstable定义:
- 非Guaranteed
- Pod里至少有一个容器有内存或者CPU请求
BestEffort定义
- 非Guaranteed
- 非Burstable
当节点上Memory资源不足时,将依据BestEffort,Burstable, Buaranteed的优先顺序驱逐Pod
Security Context介绍
Security Context主要用于限制容器的行为,从而保障系统和其他容器的安全。
1、容器级别的Security Context: 仅对指定容器生效
2、Pod级别的Security Context: 对指定Pod中的所有容器生效
3、Pod Security Policies(PSP):对集群内所有Pod生效
权限和访问控制设置项:
1、Discretionary Access Control:根据用户id和组id来控制文件访问权限
2、SElinux: 通过SElinux的策略配置控制用户,进程等对文件等访问控制
3、privileged:容器是否为特权模式
4、Linux Capabilities:给特定进程配置privileged能力
5、AppArmor:控制可执行文件的访问控制权限(读写文件/目录,网络端口读写等)
6、Seccomp:控制进程可以操作的系统调用
7、AllowPrivilegeEscalation:控制一个进程是否能比其父进程获取更多的权限
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
# Pod级别Security Context定义
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
# 容器级别定义
securityContext:
allowPrivilegeEscalation: false
InitContainer介绍
InitContainer和普通Container的区别:
1、InitContainer会先于普通Container启动执行,直到所有InitContainer执行成功后,普通Container才会被启动
2、Pod中多个InitContainer之间是按次序以此启动执行,而Pod中多个普通Container是并行启动
3、InitContainer执行成功后就结束退出了,而普通容器可能会一直执行或者重启(restartPolicy!=Never)
InitContainer用途:
基于InitContainer和普通Container的区别,一般InitContainer用于普通Container启动前的初始化(如配置文件准备)或者普通Container启动的前置条件检查(如网络联通检验)。