K8s,Kubernetes 的缩写,起源于希腊语意为舵手、领航员。是一种容器编排工具,于14.7被Docker收购,同类产品有docker swarm:
master节点:k8s集群的管理节点,提供集群资源数据访问入口,负责运行Api Server进程、Scheduler服务进程、Controller Manager服务进程、etcd存储服务,负责关联工作节点 Node。
node节点:k8s集群中运行Pod的服务节点,是k8s集群最小操作单元,用于承载被分配Pod的运行(Pod宿主机); 关联Master管理节点,拥有名称、IP、系统资源信息; 负责运行:docker eninge服务、守护进程kunelet、负载均衡器kube-proxy;
每个Node节点都运行一组关键进程: Docker Engine:负责本机容器的创建和管理工作; kubelet:负责对 Pod对应的容器的创建、启停等任务;(Node节点可以在运行时动态增加到K8s集群中) kube-proxy:实现K8s Service的通信与负载均衡机制的重要组件;
K8s【推荐的、默认的】Node管理方式:kubelet会向master注册自己,kubelet进程会定时向Master汇报自身情报(如操作系统、Docker版本、CPU和内存,以及有哪些Pod在运行等等),这样Master可以获知每个Node节点的资源使用情况,并实现高效均衡的资源调度策略。
Pod:是k8s最小的调度单位,包含一/多个container,内部共享一个namespace。
K8s 中内建了很多 Controller 控制器,这些相当于一个状态机,用来控制 Pod 的具体状态和行为。
ReplicationController 和 ReplicaSet Deployment(RC、RS)
Deployment
DaemonSet
StateFulSet
Job/CronJob
Horizontal Pod Autoscaling
ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟 ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector;
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: nginx:1.7.9
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
Deployment,是常见的K8s对象类型,提供了对 Pod 和 ReplicaSet 的声明式定义 (declarative) 方法和管理方式,每个Deployment对应集群的一次部署,常用来创建 ReplicaSet 和 Pod,解决了 ReplicaSet 更新的诸多问题,用来替代以前的ReplicationController来方便的管理应用。(部署一个新的微服务往往不会直接在集群中使用 ReplicaSet,因为ReplicaSet功能不够强大,不支持一些常见的更新、扩容、缩容运维操作,引入 Deployment 就是为了支持这些复杂操作。)
在 K8s 集群中创建 Deployment 对象时,会创建 Deployment 资源、ReplicaSet、三个Pod对象,组成以下的拓扑结构:
拓扑结构中的子节点都是稳定的,任意节点删除都会被 K8s 控制器重启。
每个 Deployment 都会和它的依赖组成以下的拓扑结构,在这个拓扑结构中的子节点都是『稳定』的,任意节点的删除都会被 Kubernetes 的控制器重启。
DeploymentController:负责管理 K8s 集群中的所有 Deployment 对象,实现 Deployment 对象的各种操作:同步、扩容、重新创建、滚动更新、回滚、暂定恢复、删除。
Deployment:典型的应用场景包括: ·定义 Deployment 来创建 Pod 和 ReplicaSet; ·滚动升级和回滚应用 ·扩容和缩容; ·暂停和继续 Deployment;
1.部署一个简单的 Nginx 应用
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record
## --record 参数可以记录命令,我们可以很方便的查看每次revision的变化
2.扩容
kubectl scale deployment nginx-deployment --replicas 10
3.为 Deployment 设置自动扩展
## (若集群支持 horizontal pod autoscaling)
kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
4.更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
5.回滚
kubectl rollout undo deployment/nginx-deployment
Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的入口。
借助 Service,应用可以方便的实现服务发现与负载均衡,并实现应用的零宕机升级。
Service 通过标签来选取服务后端,一般配合 Replication Controller 或者 Deployment 来保证后端容器的正常运行。这些匹配标签的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上。
Service 有四种类型:
另外,也可以将已有的服务以 Service 的形式加入到 Kubernetes 集群中来,只需要在创建 Service 的时候不指定 Label selector,而是在 Service 创建好后手动为其添加 endpoint。
K8s 中的 Pod 是有生命周期的对象,随时都有可能由于集群的状态变化而被销毁和创建,此时要面临的问题:当一些 Pod 需要为其它 Pod 提供服务时,如何提供同一功能服务的一组 Pod 建立一个抽象并追踪这组服务中节点的健康状态。 这个抽象在 K8s 集群中就是 Service,每个K8s的 Service 都是一组Pod的逻辑集合和访问方式的抽象,可以把 Service 加上的一组 Pod 称为一个微服务。
K8s Service 定义了这样一个抽象:一个Pod的逻辑分组,一种够可以访问它们的策略 - - 通常称为微服务。 这一组Pod能够被Service访问到,通常是通过Label Selector。
K8s 中 Service 实现原理: 1.如何处理服务的创建;2.如何转发来自节点内部和外部的流量;
在 K8s 中创建一个新的 Service 对象需要两大模块同时协作:控制器 与 kube-proxy。 控制器,需要在每次客户端创建新的 Service 对象时生成其他用于暴露一组 Pod 的 K8s 对象,即 Endpoint 对象; kube-proxy,运行在 K8s 集群中的每一个节点上,会根据 Service 和 Endpoint 的变动改变节点上 iptables 或 ipvs 中保存的规则。
ServiceController 在 Service 对象变动时发生了什么事情:
拥有三种代理模式:userspace、iptables和ipvs。
现在默认使用iptables,在1.8版本之后增加了ipvs功能。
client先请求serviceip,经由iptables转发到kube-proxy上之后再转发到pod上去。这种方式效率比较低。
client请求serviceip后会直接转发到pod上。这种模式性能会高很多。kube-proxy就会负责将pod地址生成在node节点iptables规则中。
这种方式是通过内核模块ipvs实现转发,这种效率更高。
创建一个service.yaml
文件:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
在selector字段中指定了为哪一个标签的app进行负载均衡。ports字段指定了暴露的端口,每一个- name指定一组端口,targetPort为目标容器的端口。
创建service
kubectl create -f service.yaml
查看service
然后通过命令
kubectl get svc
查看创建的service
通过命令kubectl get endpoints my-service
查看创建的service当后端代理的pod的ip
并没有给它分配pod所以代理的ip为空。
首先查看了一下当前有哪些pod:
现在想让刚创建的service代理nginx-pod
修改service.yaml
文件中app:MyApp
为app:nginx
,这样就可以匹配到标签为app=nginx的pod了。
然后重新生效这个service:
kubectl replace -f service.yaml --force
pod已经连接上了。
首先查看下service的clusterip:
然后在节点上可以通过这个ip和端口的方式访问pod上的应用:
服务发现支持Service环境变量和DNS两种模式
当一个pod运行到node,kubelet会为每个容器添加一组环境变量,Pod容器中程序就可以使用这些环境变量发现Service。
环境变量名格式如下:
{SVCNAME}_SERVICE_HOST
{SVCNAME}_SERVICE_PORT
其中服务名和端口名转为大写,连字符转换为下划线。查看方法是进入pod中输入
env
查看环境变量,在程序中调用这个变量就可以访问这个组件。
限制:
1)Pod和Service的创建顺序是有要求的,Service必须在Pod创建之前被创建,否则环境变量不会设置到Pod中。
2)Pod只能获取同Namespace中的Service环境变量。
DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。这样Pod中就可以通过DNS域名获取Service的访问地址。
kube-dns用于记录集群svc的域名解析相关记录,dnsmasq主要用于dns缓存。
yaml文件中为kube-dns指定了一个固定的ip,所以需要注意修改node节点kubelet配置的kube-dns是否为这个ip(我之前配置的不是,所以要修改)
服务类型
ClusterIP:
分配一个内部集群IP地址,只能在集群内部访问(同Namespace内的Pod),默认ServiceType。
NodePort:
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务,可以在集群外部访问。
访问地址:
LoadBalancer:
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。
除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。