[K8S系列四] K8S核心组件与核心概念(Pod、Deployment、Service)
[K8S系列四] K8S核心组件与核心概念(Pod、Deployment、Service)
K8S集群分为Master节点和Node节点,Master节点负责调度分配任务,Node节点接受Master调度进行工作。
1.1 Master节点组件
1. API Server
集群的统一入口,各组件协调者,以RESTful API方式提供接口服务,所有对象资源的增删查改和监听操作都交给API Server处理后再提交给Etcd存储。
2. Controller Manager
负责维护集群的状态,比如故障检测、自动扩展、滚动更新等。一个资源对应一个控制器,而Controller Manager就是负责管理这些控制器的。
3. Scheduler
负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上。
4.etcd
分布式键值存储系统,用于保存群集状态数据,比如Pod、Service等对象信息。
1.2 Node组件
1. kubelet
kubelet是Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点状态等工作。kubelet将每个Pod转换成一组容器。
2. kube-proxy
责为Service提供cluster内部的服务发现和负载均衡。
2. 核心概念
2.1 Pod
Pod是一个逻辑概念,是一组共享了某些资源的容器。Pod在K8S中是调度的最基本单位,以便容器互相依赖时,可以同时调度。
Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume。每个Pod中都有一个Pause(Infra)容器,Pause容器是Kubernetes基础设施的一部分,Kubernetes管理的所有pod里,pause容器是第一个启动的,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 pause容器关联在一起。
对于 Pod 里的容器 A 和容器 B 来说:
- 它们可以直接使用 localhost 进行通信;
- 它们看到的网络设备跟 Pause容器看到的完全一样;
- 一个 Pod 只有一个 IP 地址,也就是这个 Pod 的 Network Namespace 对应的 IP 地址;
- 当然,其他的所有网络资源,都是一个 Pod 一份,并且被该 Pod 中的所有容器共享;
- Pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。
2.2 Controller
1.ReplicaSet
确保预期的Pod副本数量,很少直接使用,需要被Deployment管理。
2.Deployment
作用于一组Pod的创建和运行,控制pod应用的升级、回滚,当然也能控制pod的数量。
3.Service
在K8S中,一方面Pod有伸缩与重新部署的需求,Pod的IP大多数情况是不固定的,另一方面,同一组Pod之间也有负载均衡的需要。因此,一组Pod被抽象成一个Service统一向外暴露。Service与其后端Pod副本集群之间则是通过Label Selector实现关联。
Service有以下三种类型:
ClusterIP:提供一个集群内部的虚拟IP(clusterIP),以便在集群内部通过clutserIP:port访问;
NodePort:在每个节点上打开一个端口,在集群外部可以通过nodeIP:nodePort访问,在内部依然可以通过clutserIP:port 访问;
LoadBalancer:通过外部的负载均衡器来访问,多用于公有云上。
Service vs Deployment
- Service是从网络角度的抽象概念,类似于Nginx做负载均衡提供的统一网络入口;
- Pod是最终的应用部署实体;
- Deoplyment 负责创建和保持pod运行状态。
3. 示例
3.1 deployment
# whomai-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deployment
labels:
app: whoami
spec:
replicas: 3
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: jwilder/whoami
ports:
- containerPort: 8000
# kubectl get pods -o wide
whoami-deployment-8886867c8-67d4f 1/1 Running 0 45m 10.244.80.206 w2 <none> <none>
whoami-deployment-8886867c8-hgvmb 1/1 Running 0 45m 10.244.80.205 w2 <none> <none>
whoami-deployment-8886867c8-pc67z 1/1 Running 0 45m 10.244.190.88 w1 <none> <none>
# curl 10.244.80.206:8000
I'm whoami-deployment-8886867c8-67d4f
# curl 10.244.80.205:8000
I'm whoami-deployment-8886867c8-hgvmb
# curl 10.244.190.88:8000
I'm whoami-deployment-8886867c8-pc67z
3.2 Service
1. ClusterIP
whoami-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: whoami-clusterip
spec:
type: ClusterIP
selector:
app: whoami
ports:
- protocol: TCP
port: 8080 # 集群的8080端口
targetPort: 8000 # Pod的8000端口
# kubectl apply -f whoami-clusterip.yaml
# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 34d <none>
whoami-clusterip ClusterIP 10.98.191.167 <none> 8080/TCP 8s app=whoami
# curl 10.98.191.167:8080
I'm whoami-deployment-8886867c8-hgvmb
# curl 10.98.191.167:8080
I'm whoami-deployment-8886867c8-67d4f
# curl 10.98.191.167:8080
I'm whoami-deployment-8886867c8-67d4f
# curl 10.98.191.167:8080
I'm whoami-deployment-8886867c8-hgvmb
# curl 10.98.191.167:8080
I'm whoami-deployment-8886867c8-pc67z
# kubectl describe svc whoami-clusterip
Name: whoami-clusterip
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=whoami
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.191.167
IPs: 10.98.191.167
Port: <unset> 8080/TCP
TargetPort: 8000/TCP
Endpoints: 10.244.190.88:8000,10.244.80.205:8000,10.244.80.206:8000
Session Affinity: None
Events: <none>
这种Service在集群外部是无法访问的,因为它是基于每个集群节点上配置的iptables中的虚拟IP地址实现的,并没有真实的网络设备存在。 通过 iptables-save
可以看到如下规则,这条 iptables 规则的含义是:凡是目的地址是 10.98.191.167、目的端口是 8080 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-XYYCMFLZLJQGYLMQ 的 iptables 链进行处理。
而我们前面已经看到,10.98.191.167正是这个 Service 的 VIP。所以这一条规则,就为这个 Service 设置了一个固定的入口地址。并且,由于 10.98.191.167只是一条 iptables 规则上的配置,并没有真正的网络设备,所以你 ping 这个地址,是不会有任何响应的。
KUBE-SVC-XYYCMFLZLJQGYLMQ 它是一组规则的集合,如下所示,这三条链指向的最终目的地,其实就是这个 Service 代理的三个 Pod。所以这一组规则,就是 Service 实现负载均衡的位置。
# iptables-save
-A KUBE-SERVICES -d 10.98.191.167/32 -p tcp -m comment --comment "default/whoami-clusterip cluster IP" -m tcp --dport 8080 -j KUBE-SVC-XYYCMFLZLJQGYLMQ
-A KUBE-SVC-XYYCMFLZLJQGYLMQ -m comment --comment "default/whoami-clusterip" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-SZWRSKR7UEYM347Q
-A KUBE-SVC-XYYCMFLZLJQGYLMQ -m comment --comment "default/whoami-clusterip" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-GXJY2AW3O6IJVNJZ
-A KUBE-SVC-XYYCMFLZLJQGYLMQ -m comment --comment "default/whoami-clusterip" -j KUBE-SEP-3NPGKIHQFRDXBA2I
2. NodePort
whoami-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: whoami-nodeport
spec:
type: NodePort
selector:
app: whoami
ports:
- protocol: TCP
port: 8080. # service 端口
targetPort: 8000 # Pod端口
nodePort: 30000 # 可以指定对外暴露的随机端口。一般30000-32627之间的一个端口就可以
# kubectl apply -f whoami-nodeport.yaml
service/whoami-nodeport created
# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
whoami-nodeport NodePort 10.111.44.34 <none> 8080:30000/TCP 8s app=whoami
通过lsof
可以发现在物理机上开辟30000端口
# lsof -i tcp:30000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
kube-prox 3600 root 12u IPv4 874479 0t0 TCP *:ndmps (LISTEN)
在集群内通过clusterIP:port访问service
# curl 10.111.44.34:8080
I'm whoami-deployment-8886867c8-pc67z
# curl 10.111.44.34:8080
I'm whoami-deployment-8886867c8-67d4f
# curl 10.111.44.34:8080
I'm whoami-deployment-8886867c8-hgvmb
在集群外通过nodeIP:nodePort 访问, nodeIP就是集群物理机的IP,这里是92.168.0.51、92.168.0.61、92.168.0.62。
# curl 192.168.0.62:30000
I'm whoami-deployment-8886867c8-hgvmb
# curl 192.168.0.62:30000
I'm whoami-deployment-8886867c8-67d4f
# curl 192.168.0.62:30000
I'm whoami-deployment-8886867c8-pc67z
# curl 192.168.0.51:30000
I'm whoami-deployment-8886867c8-pc67z
# curl 192.168.0.51:30000
I'm whoami-deployment-8886867c8-67d4f