本篇是关于k8s的Pod,主要包括Pod和容器的使用、Pod的控制和调度管理、应用配置管理等内容。node
Pod是k8s的核心概念一直,就名字同样,是k8s中一个逻辑概念。Pod是docekr容器的集合,每一个Pod中至少有一个Pause容器和业务容器。和docker容器关注单个可用的资源不一样,Pod更多在应用层的角度,将多个docker容器组合来实现做为一个应用,它是k8s中最小的资源单位。linux
结合docker自己容器的特性,Pod中全部容器都是共享资源,如磁盘、网络、CPU、内存等,同时,一个Pod共用一个网络。nginx
如下的yaml格式的Pod定义文件:redis
apiVersion: v1 kind: Pod metadata: name: string namespace: string labels: - name: string annotations: - name: string spec: containers: - name: string image: string imagePullPolicy: [Always | Never | IfNotPresent] command: [string] args: [string] workingDir: string volumeMounts: string - name: string mountPath: string readOnly: boolean ports: - name: string containerPort: int hostPort: int protocol: string env: - name: string value: string resources: limits: cpu: string memory: string requests: cpu: string memory: string livenessProbe: exec: command: [string] httpGet: path: string port: number scheme: string httpHeaders: - name: string value: string tcpSocket: port: number initialDelaySeconds: 0 timeoutSeconds: 0 periodSeconds: 0 successThreshold: 0 failureThreshold: 0 securityContext: privileged: false restartPolicy: [Always | Never | OnFailure] nodeSelector: object imagePullSecrets: - name: string hostNetwork: false volumes: - name: string emptyDir: {} hostPath: path: string secret: secretName: string items: - key: string value: string configMap: name: string items: - key: string - path: string
Pod定义文件模板中各属性的说明以下:
算法
注:k8s的Pod启动命令不能是后台执行的,否则k8s会不断建立新的Pod而陷入无限循环中。若是docker镜像的命令没法改造为前台执行,可使用开源工具Supervisor。或是 && tail -f xx 这样的组合命令。docker
静态Pod是由Kubelet进行管理的的仅存在于特定Node上的Pod。它们不能经过API Server进行管理,也没法和ReplicationController、Deployment或者DaemonSet进行关联,kubelet也不乏对它们进行健康检查。静态Pod老是由kubelet建立,也由kubelet来销毁。同时也只运行在该kubelet所在的Node上。json
建立静态Pod由两种方式:配置文件和HTTP。api
1.配置文件方式bash
静态文件存放的位置在kubelet的配置文件中定义,由参数staticPodPath指定,若是k8s集群由kubeadm搭建,那默认存储在目录/etc/kubernetes/manifests
下。咱们定义配置文件static-nginx.yaml
:网络
apiVersion: v1 kind: Pod metadata: name: static-nginx labels: name: static-nginx spec: containers: - name: static-nginx image: nginx ports: - name: nginx containerPort: 80
不须要使用命令建立,等他一会,kubelet会自动建立Pod
[root@k8s-master ~]# kubectl get pods static-nginx-k8s-master 1/1 Running 0 12m
注:若是一段时间仍是没有生成Pod,能够查看日志文件 /var/log/messages
删除Pod不是使用命令kubelet delete ...
,而是直接删除/etc/kubernetes/manifests/static-nginx.yaml
,kubelet自动会删除Pod。
2.HTTP方式
kubelet会定时根据参数--manifest-url
来下载镜像并生成静态Pod。
注:比较巧妙地方的是kubeadm安装地管理节点 kube-apiserver、kube-sheduler、kube-controller-manager 组件都是静态的Pod。
以前说过,同一个Pod中的容器能共享Volume,那怎么将Volume共享给Pod呢。
关键在于配置文件中的spec.containers[].volumeMounts
和spec.volumes[]
参数,例如Pod中容器之间共享一个emptyDir的目录,名为logs,配置文件就能够这样:
apiVersion: v1 kind: Pod metadata: name: volume-pod spec: containers: - name: nginx image: nginx volumeMounts: - name: logs mountPath: /usr/local/nginx/logs - name: busybox image: busybox volumeMounts: - name: logs mountPath: /logs volumes: - name: logs emptyDir: {}
这样一来,容器nginx和busybox就共享一个目录,且各自挂载的路径也不一样。重点是用volumes
定义要共享的volume,再在containers上使用volumeMounts
参数来使用。
k8s 在 1.2版本时提供了一种统一的集群配置管理方案,就是ConfigMap,利用不一样配置和不一样容器分离开的方式,让复杂容器管理简单化。
ConfigMap供容器使用的典型用法以下:
1.yaml文件方式
# cm.appvars.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-appvars data: apploglevel: info appdatadir: /var/data
指定命令建立:
kubectl create -f cm-appvars.yaml
查看命令就用:
kubectl get configMap -o json
或者key:value也可使用配置文件的别名和文件的内容。
data: key-serverxml: | <?xml ?> ...... ...... <?xml ... ?> key-properties: "key=... .... "
注意格式问题。
2.kubelet命令行建立 直接经过kubectl create configmap
也能够建立ConfigMap,可使用参数--from-file
或--from-literal
指定内容。
经过--from-file
参数从文件中建立,能够指定key的名称,能够在一个命令中建立包含多个key的ConfigMap,语法为:
kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
经过--from-file
参数从目录中进行建立,该目录的每一个配置文件名都被设置为key,文件的内容被设置为value,语法为:
kubectl create configmap NAME --from-file=config-files-dir
经过--file-literal
从文本中进行建立、直接将指定的key#=value#建立为ConfigMap的内容,语法为:
kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
ConfigMap的使用也有几种方式。
1.环境变量
apiVersion: v1 kind: Pod metadata: name: cm-test-pod spec: containers: - name: cm-test image: buysbox env: - name: APPLOGLEVEL # 定义环境变量名称 valueFrom: # key "apploglevel" 对应的值 configMapKeyRef: name: cm-appvars # 环境变量的值取自 cm-appvars 中 key: apploglevel # key 为 "apploglevel" - name: APPDATADIR valueFrom: configMapKeyRef: name: cm-appvars key: appdatadir restartPolicy: Never
要点是环境变量中使用valueFrom
参数指定configMapKeyRef
2.volumeMount的方式
... spec: containers: - name: cm-test-app image: busybox volumeMounts: - name: serverxml # 引用volume名 mountPath: /configfiles # 挂载到容器内的目录 volumes: - name: serverxml configMap: name: cm-appconfigfiles # 使用 ConfigMap "cm-appconfigfiles" items: - key: key-serverxml # key=key-serverxml path: server.xml # value将server.xml文件名进行挂载
若是在引用 ConfigMap 时不指定 items,则使用 volumeMount 方式在容器内的目录中为每一个 item 生成一个文件名为 key 的文件。
使用 ConfigMap 的限制条件以下:
Pod的状态
状态值 | 描述 |
---|---|
Peding | API Server 已经建立该Pod,但Pod内还有一个或多个容器的镜像没有建立,包括正在下载镜像的过程 |
Running | Pod内全部容器均已建立,且至少有一个容器处于运行状态、正在启动状态或正在重启状态 |
Succeeded | Pod内全部容器均成功执行退出,且不会再重启 |
Failed | Pod内全部容器均已退出,但至少有一个容器退出为失败状态 |
Unknown | 因为某种缘由没法获取该Pod的状态,可能因为容器通讯不顺畅致使 |
Pod的RestartPolicy重启策略:
每种控制器对Pod的重启策略不一样:
Pod的健康状态检查能够经过两类探针来检查:LivenessProbe 和 ReadinessProbe。
kubelet按期执行LivenessProbe探针来诊断容器的健康情况。LivenessProbe有三种实现方式。
ExecAction:在容器内部执行一个命令,若是该命令的返回码为0,则代表容器健康。
... spec: containers: - name: liveness ... livenessProbe: exec: command: - cat - /tmp/health initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒 timeoutSeconds: 1 # 返回超时时间,单位为秒。若是超时kubelet会重启容器
TCPSocketAction:经过容器的IP地址和端口号执行TCP检查,若是可以创建TCP链接。则代表容器健康。
... spec: containers: - name: liveness ... livenessProbe: tcpSocket: port: 80 initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒 timeoutSeconds: 1 # 返回超时时间,单位为秒
HTTPGetAction:经过容器的IP地址、端口号及路径调用HTTP Get方法,若是响应的状态码大于等于200且小于等于400,则认为容器状态健康。
... spec: containers: - name: liveness ... livenessProbe: httpGet: path: /_status/healthz port: 80 initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒 timeoutSeconds: 1 # 返回超时时间,单位为秒
在k8s中,Pod在大部分场景在都只是容器的载体而已,一般须要经过RC、Deployment、DaemonSet、Job等对象来完成Pod的调度与自动控制功能。
RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终保持用户指定的副本数量。
Pod的调度策略除了有系统内置的Node调度算法,还能够在Pod的定义中使用NodeSelector或者NodeAffinity来指定知足条件的Node进行调度。
1.NodeSelector:定向调度
k8s上的服务Scheduler服务负责实现Pod的调度,整个调度经过执行一系列复杂的算法,最终为每一个Pod计算出一个最佳的目标节点,这一过程是自动完成的。NodeSelector 调度就是经过给Node打上Label,使用Pod的NodeSelector属性来匹配的。
首先经过kubectl label命令给目标Node打上一些标签:
kubectl label node <node-name> <label-key>=<label-value>
而后,在Pod的定义中加上nodeSelector的设置
... template: ... spec: ... nodeSelector: label-key: label-value
注:若是有多个节点都定义了相同的label,scheduler就会根据调度算法从这组Node进行Pod调度,可是若是Pod上定义了nodeSelector参数,可是Node上没法找到对应的Node,则Pod没法被调度成功。
2.NodeAffinity:亲和性调度
NodeAffinity意为亲和性的策略调度,是一种更加灵活的调度策略。增长了In、NotIn、Exists、DoesNotExists、Gt、Lt等操做符来选择Node。同时还添加一些信息来设置亲和性调度策略:
NodeAffinity 对应地还有 PodAffinity 和 PodAntiAffinity。
下面来个实例,指定Pod运行到kubernetes.io/e2e-az-name值为e2e-az1 或e2e-az2的节点上面
apiVersion: v1 kind: Pod metadata: name: with-node-affinity annotations: scheduler.alpha.kubernetes.io/affinity: > { "nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { "nodeSelectorTerms": [ { "matchExpressions": [ { "key": "kubernetes.io/e2e-az-name", "operator": "In", "values": ["e2e-az1", "e2e-az2"] } ] } ] } } } another-annotation-key: another-annotation-value spec: containers: - name: with-node-affinity image: gcr.io/google_containers/pause:2.0
DaemonSet是k8s1.2版本新增地一种资源对象,用于在集群中每一个Node上仅运行一份Pod的副本实例。它具备如下的应用实例:
DaemonSet 的 Pod 调度策略与 RC 相似,除了使用系统内置的算法在每台Node上进行调度,也能够在Pod的定义中使用NodeSelector或NodeAffinity来指定知足条件的Node范围进行调度。
k8s在1.2版本之后,开始支持批处理类型的应用,咱们能够经过k8s Job资源对象来定义并启动一个批处理任务。批处理任务一般并行或串行启动多个计算进程去处理一批工做项(work item)。
apiVersion: batch/v1 kind: Job metadata: name: myjob spec: template: metadata: name: myjob spec: containers: - name: hello image: busybox command: ["echo", "hello world"] restartPolicy: Never
查看批处理任务:
[root@k8s-master ~]# kubectl get jobs NAME COMPLETIONS DURATION AGE myjob 1/1 21s 4m44s
同时也能够指定批处理的并行个数和重复次数
... spec: completions: 6 # 重复次数 parallelism: 3 # 并行个数 ...
同时k8s还支持定时任务,相似linux的Crontab。利用 CronJob 资源对象表示:
apiVersion: batch/v2alpha1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox command: ["echo","hello k8s job!"] restartPolicy: Never
可是建立CronJob会报错:
[root@k8s-master ~]# kubectl apply -f job/cronJob.yaml error: unable to recognize "job/cronJob.yaml": no matches for kind "CronJob" in version "batch/v2alpha1"
修改kube-apiserver配置文件,/etc/kubernetes/manifests/kube-apiserver.yaml
... spec: containers: - command: - kube-apiserver - --advertise-address=192.168.10.20 - --runtime-config=batch/v2alpha1=true # 添加版本 ...
重启kubelet
systemctl restart kubelet
从新建立CronJob
kubectl apply -f job/cronJob.yaml
k8s RC的Scale机制能让咱们在运行中修改Pod的数量。经过命令:
[root@k8s-master ~]# kubectl get rc NAME DESIRED CURRENT READY AGE redis-master 1 1 1 4d11h redis-slave 2 2 2 4d11h [root@k8s-master ~]# kubectl scale rc redis-slave --replicas=3 replicationcontroller/redis-slave scaled
关键在于指定参数--replicas
的值,若是该值大于当前rc对应的Pod的值,就添加Pod;反之,则杀死。
除了使用命令kubectl scale以外,k8s还支持 HPA(Horizontal Pod Autoscaler)用于实现基于CPU使用率进行自动Pod扩容缩容的功能。HPA针对RC或Department对象,且Pod必须定义resource.request.cpu。HPA控制器基于Master的kube-controller-manager
服务启动参数--horizontal-pod-autoscaler-sync-period
定义的探测周期(默认值为15s),周期性地监测目标Pod地资源性能指标,并与HPA资源对象中地扩缩容条件进行对比,在知足条件时对Pod副本数量进行调整。
须要自动调整的RC或Deployment配置以下:
apiVersion: v1 kind: Service metadata: name: svc-hpa namespace: default spec: selector: app: myapp type: NodePort ##注意这里是NodePort,下面压力测试要用到。 ports: - name: http port: 80 nodePort: 31111 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: default spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: name: myapp-demo namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 resources: requests: cpu: 50m memory: 50Mi limits: cpu: 50m memory: 50Mi
HPA配置以下:
apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa-v2 namespace: default spec: minReplicas: 1 ##至少1个副本 maxReplicas: 8 ##最多8个副本 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp metrics: - type: Resource resource: name: cpu targetAverageUtilization: 50 ##注意此时是根据使用率,也能够根据使用量:targetAverageValue - type: Resource resource: name: memory targetAverageUtilization: 50 ##注意此时是根据使用率,也能够根据使用量:targetAverageValue
其中关键的参数:
k8s支持对如下资源的升级和回滚:
以Deployment为例:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
使用升级命令:
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
或者使用kubectl edit
命令修改nginx版本为1.9.1。
一旦镜像名(或Pod的定义)发生修改,则将触发系统完成Deployment全部运行Pod的滚动升级操做,使用命令查看:
kubectl rollout status deployment/nginx-deployment
首先可使用命令来查看可回滚的版本:
kubectl rollout history deployment/nginx-deployment
而后使用命令进行回滚:
kubectl rollout undo deployment/nginx-deployment
或者使用指定回滚版本:
kubectl rollout undo deployment/nginx-deployment --to-revision=3
若是Deployment的恢复比较复杂或者在回滚过程当中临时须要修改,就能够先暂停回滚,当修改完成后再恢复。
暂停回滚使用命令
kubectl rollout pause deployment/nginx-deployment
暂停回滚后咱们能够对deployment进行任意次的修改,如更新容器的资源限制:
kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
修改完成后再恢复回滚:
kubectl rollout resume deployment/nginx-deployment