4.2.1 配置Pod的liveness和readiness探针
Kubelet使用liveness probe(存活探针)来确定何时重启容器。
Kubelet使用readiness probe(就绪探针)来确定容器是否已经就绪可以接受流量。
只有当Pod中的容器都处于就绪状态时Kubelet才会认定该Pod处于就绪状态。
该信号的作用是控制哪些Pod应该作为service的后端。如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除。
定义liveness命令
长时间运行的应用程序最终会转换到broken状态,除非重启,否则无法恢复。Kubernetes提供了liveness probe来检测和补救这种情况。
基于gcr.io/google_containers/busybox镜像创建运行一个容器的Pod。
Pod配置文件exec-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
image: gcr.io/google_containers/busybox
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
periodSeconds:规定kubelet要每隔5秒执行一次liveness probe。
initialDelaySeconds:告诉kubelet在第一次执行probe之前要等待5秒钟。
探针检测命令是在容器中执行cat /tmp/healthy命令。
如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。
如果返回非0值,kubelet就会杀掉这个容器并重启它。
定义一个liveness HTTP请求
可以使用HTTP GET请求作为liveness probe。
基于gcr.io/google_containes/liveness镜像运行一个容器的Pod:
配置文件名称:http-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
args:
- /server
image: gcr.io/google_containers/liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initalDelaySeconds: 3
periodSeconds: 3
livenessProbe:指定Kubelet需要每隔3秒执行一次liveness probe。
initalDelaySeconds:指定kubelet在该执行第一次探测之前需要等待3秒钟。
该探针将向容器中的Server的8080端口发送一个HTTP GET请求。
如果Server的/healthz路径的handler返回一个成功的返回码,kubelet就会认定该容器是活着的并且很健康。
如果返回失败的返回码,kubelet将杀掉该容器并重启。
任何大于200小于400的返回码都会认定是成功的返回码。其他返回码被认定为失败的返回码。
定义TCP liveness探针
第三种liveness probe使用TCP Socket。使用此配置,kubelet将尝试在指定端口上打开容器的套接字。
如果可以建立连接,容器被认为是健康的。如果不能则认为是失败的。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: gcr.io/google_containers/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
此示例同时使用了livenessProbe和readinessProbe。
容器启动后5秒钟,kubelet将发送第一个readiness probe。这将尝试连接到端口8080上的goproxy容器。
如果探测成功,则该Pod将被标记为就绪。kubelet每隔10秒钟执行一次检查。
容器还配置了livenessProbe。
容器启动15秒后,kubelet将运行第一个liveness probe。并尝试连接到goproxy容器的8080端口上。
如果livenessProbe探测失败,容器将重新启动。
使用命名的端口
使用命名的ContainerPort作为HTTP或TCP liveness检查:
ports:
- name: liveness-port
containersPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
定义Readiness Probe探针
有时,应用程序暂时无法对外部流量提供服务。
例如:应用程序可能需要在启动期间加载大量数据或配置文件,在这种情况下,不想杀死应用程序,也不想发送请求。Kubernetes中可以采用readinessProbe。
Pod中的容器可以报告自己还没有准备,不能处理Kubernetes服务发送过来的流量。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
Readiness和liveness Probe可以并行用于同一容器。
配置Probe
Probe详细的配置如下:
- initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒
- periodSeconds:执行探测的频率。默认是10秒,最小1秒
- timeoutSeconds:探测超时时间。默认1秒,最小1秒。
- successThreshold:探测失败后,最少连接探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1.
- failureThreshold:探测成功后,最少连接探测失败多少次被认定为失败。默认为3。最小值是1
HTTP probe中可以给httpGet设置其他配置项:
- host:连接的主机名,默认连接到Pod的IP。你可能想在http header中设置“Host”而不是使用IP。
- schema:连接使用的schema,默认HTTP。
- path:访问的HTTP server的path。
- httpHeaders:自定义请求的header。HTTP运行重复的header。
- port:访问的容器的端口名字或者端口号。端口号介于1和65535之间。
对于HTTP探测器,kubelet向指定的路径和端口发送HTTP请求以执行检查。
Kubelet将probe发送到容器的IP地址。除非地址被httpGet中的可选host字段覆盖。
4.2.2 配置Pod的Service Account
Service Account为Pod中的进程提供身份信息。
当您访问集群时,apiserver会将您认证为一个特定的User Account(通常是admin)。
使用默认的Service Account访问API Server
当创建Pod时,如果没有指定一个Service Account,系统会自动在与该Pod相同的namespace下为其指派一个default service account。
如果您获取刚创建的pod的原始json或者yaml信息,您将看到spec.serviceAccountName字段已经被设置为automatically。
可以在Pod中使用自动挂载的service account凭证来访问API。
Service Account是否能够取得访问API的许可取决于您使用的授权插件和策略。
可选择取消为Service Account自动挂载API凭证,只需要在Service Account中设置automountServiceAccountToken: false:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
只取消单个Pod的API凭证自动挂载:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
如果在Pod和Service Account中同时设置了automountServiceAccountToken,Pod设置中的优先级更高。
使用Service Account作为用户权限管理配置kubeconfig
创建服务账号**
kubectl create serviceaccount sample-sc
创建角色
创建一个只可以查看集群deployments、services、pods相关的角色。采用如下配置:
apiVersion: rbac.authorization.k8s.io/v1
#这里也可以用Role
kind: ClusterRole
metadata:
name: mofang-viewer-role
labels:
from: mofang
rules:
- apiGroups:
- ""
resources:
- pods
- pods/status
- pods/log
- services
- services/status
- endpoints
- endpoints/status
- deployments
verbs:
- get
- list
- watch
创建角色绑定
apiVersion: rbac.authorization.k8s.io/v1
#这里也可以使用RoleBinding
kind: ClusterRoleBinding
metadata:
name: sample-role-binding
labels:
from: mofang
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mofang-viewer-role
subjects:
- kind: ServiceAccount
name: sample-sc
namespace: default
配置kubeconfig
可以动态更改ClusterRole的授权来及时控制某个账号的权限。配置如下:
apiVersion: v1
clusters:
- cluster:
##这个是集群的TLS证书,与授权无关。
certificate-authorization-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvekNDQW1pZ0F3SUJBZ0lEQnN0WU1BMEdDU3FHU0liM0RRRUJDd1VBTUdJeEN6QUpCZ05WQkFZVEFrTk8KTVJFd0R3WURWUVFJREFoYWFHVkthV0Z1WnpFUk1BOEdBMVVFQnd3SVNHRnVaMXBvYjNVeEVEQU9CZ05WQkFvTQpCMEZzYVdKaFltRXhEREFLQmdOVkJBc01BMEZEVXpFTk1Bc0dBMVVFQXd3RWNtOXZkREFlRncweE9EQTFNamt3Ck16UXdNREJhRncwek9EQTFNalF3TXpRMU5UbGFNR294S2pBb0JnTlZCQW9USVdNMlpUbGpObUpqWVRjellqRTAKWTJNMFlXRTNPVE13WWpNNE5ERXhORFpqWVRFUU1BNEdBMVVFQ3hNSFpHVm1ZWFZzZERFcU1DZ0dBMVVFQXhNaApZelpsT1dNMlltTmhOek5pTVRSall6UmhZVGM1TXpCaU16ZzBNVEUwTm1OaE1JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUURMY0VaYnJwK0FrS1o0dThOSVUzbmNoVThiQTEyeEpHSkkzOXF1N3hoUWxHeUcKZmpBMWp1dXhxUzJoTi9ManAzbVc2R0hpbTN3aUl3Y3VZS1Q3dEY5b1R6OCtPOEFDNkdiemRYTEgvVFBNa0JnZgo5U1hoR2h3WGd2SUxvdjNudmVLUzNESXFTdSt5L04rWG4zOE45bndIcXpLSnZYTVE5a0lpQm5NeDBWeXNIUUlECkFRQUJvNEc2TUlHM01BNEdBMVVkRHdFQi93UUVBd0lDckRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUI4R0ExVWQKSXdRWU1CYUFGSVZhLzkwanpTVnZXRUZ2bm0xRk9adFlmWFgvTUR3R0NDc0dBUVVGQndFQkJEQXdMakFzQmdncgpCZ0VGQlFjd0FZWWdhSFIwY0RvdkwyTmxjblJ6TG1GamN5NWhiR2w1ZFc0dVkyOXRMMjlqYzNBd05RWURWUjBmCkJDNHdMREFxb0NpZ0pvWWthSFIwY0RvdkwyTmxjblJ6TG1GamN5NWhiR2w1ZFc0dVkyOXRMM0p2YjNRdVkzSnMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNEdCQUpYVGlYSW9DVVg4MUVJTmJ1VFNrL09qdEl4MzRyRXR5UG5PK0FTagpqSzNpNHd3UFEwS3kwOGZOU25TZnhDUTJ4RjU1MjE1U29TMzFTd0x6WUlUSnVYWkE3bFdPb1FTVFkvaUFMdVBCCi9rM0JsOE5QY2Z6OEY1eVk3L25jU3pYNHBNeDE4cjBjb09MTWJmWlRRcm1IcGZDTndtZGNCZUIrQm5EUkxQSkYKaDNJRAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg
server: https://47.95.24.167:6443
name: beta
contexts:
- context:
cluster: beta
user: beta-viewer
name: beta-viewer
current-context: beta-viewer
kind: Config
preferences: {}
users:
- name: beta-viewer
user:
##这个使我们在创建serviceaccount生成相关secret之后的data.token的base64编码字段,它本质是一个jwt token
token: eyJhbGciOiJSUzI1NiIsInR5dffg6IkpXVCJ9
使用多个Service Account
每个namespace中都有一个默认的叫做default的service account资源。
在Pod创建之初service account就必须已经存在,否则创建将被拒绝。
4.2.3 Secret配置
Secret用来保存敏感信息。例如密码、OAuth令牌和ssh key。
Secret概览
Secret是一种包含少量敏感信息例如密码、token或key的对象。这样的信息可能被放在Pod Spec中或者镜像中;
要使用Secret,Pod需要引用secret。
Pod可以用两种方式使用secret:作为Volume中的文件被挂载到Pod中的一个或者多个容器里,或者当kubelet为Pod拉取镜像时使用。
内置secret
Service Account使用API凭证自动创建和附加secret
**
Kubernetes自动创建包含访问API凭据的secret,并自动修改您的Pod以使用此类型的secret。
创建您自己的Secret
使用kubectl创建Secret
有些Pod需要访问数据库。这些Pod需要使用的用户名和密码在本机的./username.txt和./password.txt文件里。
$ echo -n "admin" > ./username.txt
$ echo -n "1f2d1e2e67df" > ./password.txt
kubectl create secret命令将这些文件打包到一个Secret中并在API Server中创建了一个对象。
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
手动创建Secret
可以以json或yaml格式在文件中创建一个Secret对象,然后创建该对象。
每一项必须是base64编码:
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
写一个Secret对象:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
解码Secret
使用kubectl get secret命令获取Secret。
解码密码字段:
$ echo "MWYyZDFlMmU2N2Rm"| base64 --decode
使用Secret
Secret可以作为数据卷被挂载,或作为环境变量暴露出来以供Pod中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在Pod内。
在Pod中使用Secret文件
在Pod中的Volume里使用Secret:
- 创建一个secret或者使用已有的secret。多个Pod可以引用同一个secret。
- 修改您的Pod的定义在spec.volumes[]下增加一个volume。可以给这个volume随意命名,它的spec.volumes[].secret.secretName必须等于secret对象的名字。
- 将spec.containers[].volumeMounts[]加到需要用到该secret的容器中。指定spec.containers[].volumeMounts[].readOnly=true和spec.containers[].volumeMounts[].mountPath为您想要该secret出现的尚未使用的目录。
- 修改您的镜像并且/或者命令行让程序从该目录下寻找文件。Secret的data映射中的每一个键都成为了mountPath下的一个文件名。
在一个Pod中使用volume挂载secret的例子:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
想要用的每个secret都需要在spec.volumes中指明。
如果pod中有多个容器,每个容器都需要自己的volumeMounts配置块,但是每个secret只需要一个spec.volumes。
向特性路径映射secret密钥
可以控制Secret key映射在volumes中的路径。可以使用spec.volumes[].secret.items字段修改每个key的目标路径:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
- username secret 存储在/etc/foo/my-group/my-username文件中而不是/etc/foo/username中。
- password secret没有被映射
如果使用了spec.volumes[].secret.items,只有在items中指定的key被映射。
要使用的Secret中所有的key,所有这些都必须列在items字段中。
所有列出的密钥必须存在于相应的Secret中。否则,不会创建卷。
Secret文件权限
可以指定Secret将拥有的权限模式位文件。如果不指定,默认为0644。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
defaultMode: 256
然后,Secret将被挂载到/etc/foo目录,所有通过该secret volume挂载创建的文件的权限都是0400。
Secret作为环境变量
将Secret作为pod中的环境变量使用:
- 创建一个Secret或者使用一个已存在的Secret。多个Pod可以引用同一个Secret。
- 在每个容器中修改你想要使用secret key的Pod定义,为要使用的每个Secret key添加一个环境变量。消费Secret key的环境变量填充Secret的名称,并键入env[x].valueFrom.secretKeyRef。
- 修改镜像并/或者命令行,以便程序在指定的环境变量中查找值。
apiVersion: v1 kind: Pod metadata: name: secret-env-pod spec: containers: - name: mycontainer image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password restartPolicy: Never
详细
限制
Secret API对象驻留在命名空间中。它们只能由同一命名空间中的pod引用。
每个Secret的大小限制为1MB。这是为了防止创建非常大的Secret会耗尽apiserver和kubelet的内存。
Kubelet仅支持从API Server获取的Pod使用Secret。包括使用kubectl创建的任何Pod,或间接通过replication controller创建的Pod。它不包括通过kubelet —manifest-url标志,其 —config标志或其REST API创建的Pod。
必须先创建Secret,除非将它们标记为可选项,否则必须在将其作为环境变量在Pod中使用之前创建Secret。对不存在的Secret的引用将阻止其启动。
通过secretKeyRef对不存在于命名的key中的key进行引用将阻止其启动。
使用案例
使用案例:包含ssh密钥的pod
创建一个包含ssh key的secret:
$ kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
我们创建一个使用ssh密钥引用secret的Pod,并在一个卷中使用它:
kind: Pod
apiVersion: v1
metadata:
name: secret-test-pod
labels:
name: secret-test
spec:
volumes:
- name: secret-volume
secret:
secretName: ssh-key-secret
containers:
- name: ssh-test-container
image: mySshImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
当容器中的命令运行时,密钥的片段将可在以下目录:
/etc/secret-volume/ssh-publickey
/etc/secret-volume/ssh-privatekey
然后容器可以自由使用密钥数据建立一个ssh连接。
使用案例:包含prod/test凭据的Pod
创建Secret:
$ kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
$ kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
创建Pod:
apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
这2个容器将在其文件系统上显示如下文件,其中包含每个容器环境的值:
/etc/secret-volume/username
/etc/secret-volume/password
使用案例:Secret卷中以点号开头的文件
为了将数据隐藏起来,让该键以一个点开始。例如:当如下Secret被挂载到卷中:
kind: Secret
apiVersion: v1
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
kind: Pod
apiVersion: v1
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: gcr.io/google_containers/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
Secret-volume将包含一个单独的文件,叫做.secret-file,dotfile-test-container的/etc/secret-volume/.secret-file路径下将有该文件。
以点号开头的文件在ls -l的输出中被隐藏起来了;列出目录内容时,必须使用ls -la才能查看它们。
4.2.4 管理namespace中的资源配额
开启资源配额限制功能
目前有两种资源分配管理相关的控制策略插件ResourceQuota和LimitRange。
两种控制策略的作用范围都是对于某一namespace。
ResourceQuota用来限制namespace中所有的Pod占用的总的资源request和limit;
LimitRange用来设置namespace中Pod的默认的资源request和limit值;
资源配额分为三种类型:
- 计算资源配额
- 存储资源配额
- 对象数量配额
示例
为spark-cluster这个namespace设置ResourceQuota和LimitRange。
配置计算资源配额
配置文件:spark-compute-resource.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: spark-cluster
spec:
hard:
pods: "20"
requests.cpu: "20"
requests.memory: 100Gi
limits.cpu: "40"
limits.memory: 200Gi
查看该配置:
kubectl -n spark-cluster describe resourcequota compute-resources
配置对象数量限制
配置文件:spark-object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: spark-cluster
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
配置CPU和内存LimitRange
配置文件:spark-limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 50Gi
cpu: 5
defaultRequest:
memory: 1Gi
cpu: 1
type: Container
- default即limit值
- defaultRequest即request值