一、对象模型总览
k8s可以看做是面向对象的,每类服务可看做是k8s的一个对象。这些对象由用户定义yaml,k8s的api负责创建。所有对象包含spec(规范)+status两类基本信息。
例如:k8s创建pod的api为: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#pod-v1-core
kubectl 也会将yaml转成json发送到master节点。
k8s中常用的对象有pod、deployment、service、statefulSet等,每个对象至少包含3个metadata:namespace、name、uid。
二、k8s中常见的object kind
- pod
- 基本调度单元,特定关系的一组容器集合,最小的部署集合。
- 非持久性实体,调度失败、自愈等情况会被终止,重建,不建议手动创建Pod,而是通过controller创建pod,如deployment。
- Service
- pod 重启之后ip会改变,多个相同服务的pod需要有discovery+loadbalance 。这一点与“微服务”中的概念一致。通过label selector 可轻松实现逻辑分组。
- service 的声明周期内,ip不会改变。可通过nodeport 暴露到外部。
- 有的service不需要ip、有的service 不需要负载均衡。
- Controllers
- Replicaset (rs)副本数,用于loadbalance和冗余。(老版本是ReplicationController- rc,算是功能升级,官方推荐使用rs 代替rc)。现阶段非特殊情况如升级pod的操作,也不推荐单独使用,
- Deployment
使用并管理rs ,算是更高一层的概念,这是现在比较常用的部署app的方式。deployment为pod和rs提供声明式更新(而非命令式)。支持滚动更新(rollingUpdate),支持回滚操作。
statefulSet(k8s 1.9 GA)
我们自己开发的应用一般都是stateless的,像是redis、zk、kafka、mysql这类的中间件通常需要使用statefulSet。通常适用于稳定的持久存储、稳定的网络标识、有序部署有序扩展、有序收缩、有序滚动升级的场景。
pod的存储一般都是volumes外挂到persistent介质。并且伸缩或删除不会删除关联的存储。需要headless service负责pod的网络身份。
<font color=red size=1> "注意:statefulSet 对应的service为headless servie,和普通的service的区别在于,普通的有cluster ip,通过只有service 有dns,通过iptables进行负载。headless service无cluster ip,endpoints是所有pod的dns地址。就意味着statefulset 创建pod的时候为pod生成了dns信息。如3 节点的mysql,会生成mysql-0 ... mysql-2三个pod(pod名称生产规则为pod+递增序号),并且会生成域: $(podname).(headless server name),完整FQDN为: $(podname).(headless server name).namespace.svc.cluster.local"
</font>
看一个完整的statefulSet + headless service 的示例。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.11
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
nodeSelector:
node: kube-node3
volumes:
- name: www
hostPath:
path: /mydir
- DeamonSet
每个node都有一个pod副本运行。常用在后台常驻程序如ceph,日志收集,心跳检查,Prometheus exporter等。 - ConfigMap
向pod 提供非敏感的配置信息,支持键值对,单个属性,配置文件。
使用方式:环境变量,容器命令行参数,数据卷挂载。
定义示例:
apiVersion:V1
kind:ConfigMap
metadata:
name:hello-config
namespace:public-config
data:
title:hello everybody
sex:girl
引用示例:
apiVersion:V1
kind:deployment
metadata:
name:hello-dem
spec:
containers:
- name:goodboy
image:hub/images
command:["/bin/bash","-c","echo ${envTitle} ${envSex}"]
env:
- name:envTitle
valueFrom:
configMapKeyRef:
name:hello-config
key:title
- name:envSex
valueFrom:
configMapKeyRef:
name:hello-config
key:sex
- Secret
对应于ConfigMap,用于敏感信息配置,如token,密码,秘钥等。 - Endpoints
service 和 pod 之间的关系会创建endpoint对象,默认与service 同名。kube-proxy将会监听service 和 endpoint的变化,从而更新iptables的规则。 - PodDisruptionBudget(pdb,主动驱逐保护)
- 没有pdb。当进行节点维护时,如果某个服务的多个pod在该节点上,则节点的停机可能会造成服务中断或者服务降级。举个例子,某服务有5个pod,最低3个pod能保证服务质量,否则会造成响应慢等影响,此时该服务的4个pod在node01上,如果对node01进行停机维护,此时只有1个pod能正常对外服务,在node01的4个pod迁移过程中,就会影响该服务正常响应;
- pdb能保证应用在节点维护时不低于一定数量的pod运行,从而保持服务质量;
- 等等其他的如 ingress
三、 k8s中有常见的metadata
- name && UID (uid是在k8s的整个声明周期中均唯一,不会产生相同的uid,可对等为mysql的auto increment key)
来看一个api访问对象的路径:/api/{version}/namespaces/{namespace}/{object-kind}/{name} ,k8s通过层层限定来寻找唯一标识的name。 - namespace
对一组资源和对象的抽象集合,从逻辑上划分k8s实现分层管理,并实现一定层度上的资源和权限隔离。
内置三个namespace:default,kube-system(存放api-server、dns插件等),kube-public(供所有用户包含未经过身份验证的用户使用,实现资源集群内共享)
Node和persistentVolume(简称PV,通过PVC和pod绑定)不属于任何namespace。 - label
标识性的数据,有严格的命名规范,k8s可通过标签组合管理对象,达到松耦合。在spec中通过selectors进行匹配。 - annotation(理解为java注释吧)
非标识性的元数据附加到对象上。通常会有时间戳,版本号,用户信息等辅助信息。
四、k8s spec中常见的参数
- selectors(标签和标签选择器)
对应label对应的key-value 进行对象的选择
K8S的ip模型
k8s的ip:
- node Ip :node节点的ip,为物理ip.
- pod Ip:pod的ip,即docker 容器的ip,为虚拟ip。
- cluster Ip:service 的ip,为虚拟ip。提供一个集群内部的虚拟IP以供Pod访问。
六、k8s的volume
k8s的volume和docker有所不同,v是独立于容器的,与pod声明周期相同,即pod删除空间也被删除。有多重类型
- emptydir
空目录,pod中的容器会共享此目录
如下所示,busybox的文件写入,在nginx容器中能够读出来。
[root@master ~]# cat test.yaml
apiVersion: v1
kind: Service
metadata:
name: serivce-mynginx
namespace: default
spec:
type: NodePort
selector:
app: mynginx
ports:
- name: nginx
port: 80
targetPort: 80
nodePort: 30080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: mynginx
template:
metadata:
labels:
app: mynginx
spec:
containers:
- name: mynginx
image: lizhaoqwe/nginx:v1
volumeMounts:
- mountPath: /usr/share/nginx/html/
name: share
ports:
- name: nginx
containerPort: 80
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "sleep 4444"
volumeMounts:
- mountPath: /data/
name: share
volumes:
- name: share
emptyDir: {}