从Docker到Kubernetes——Kubernetes设计解读之ReplicationController、Service
文章目录Kubernetes的设计解读replication controller 设计解读replication controller 使用示例service的设计解读service的使用示例Kubernetes的设计解读replication controller 设计解读k8s第二个重要的概念就是replication controller,它决定了一个pod有多少同时运行的副本,并保...
Kubernetes的设计解读
replication controller 设计解读
k8s第二个重要的概念就是replication controller,它决定了一个pod有多少同时运行的副本,并保证这些副本的期望状态与当前状态一致。
replication controller在设计上依然体现出了“旁路控制”的思想,在k8s中并没有像Cloud Foundry那样设置一个专门的健康检查组件,而是为每个pod“外挂”了一个控制器进程,从而避免健康检查组件成为性能的瓶颈;即使这个控制器进程失效,容器仍然可以正常运行。
根据上一章的实践,我们大概知道了pod有这么几个状态:
- Pending:pod已经被创建,但是pod中有一个或多个容器未启动,可能是因为下载镜像的网络传输慢或者pod的调度时间,或者pod没有找到绑定的工作节点等等。
- Running:pod被绑定到工作节点上且pod中的所有容器均被创建。最重要的是pod中至少有一个容器处于运行、启动或者重启状态。
- Succeeded:专指pod所有容器均成功正常退出,且不会发生重启。
- Failed:pod内所有容器均退出且至少有一个容器退出发生错误。
- Unknown:因为未知原因无法获取pod状态。
pod的状态转移与pod的重启策略息息相关,由于其复杂性在此不表。只需记住,replication controller 会识别pod某状态而实现重启策略。
replication controller的描述文件
与pod对象类似,k8s也可以使用一份JSON格式的资源配置文件来定义一个replication controller对象。主要由3方面组成:
- 一个用于创建pod的pod template
- 一个期望副本数(replicas)
- 一个用于选择被控制pod集合的label selector
apiVersion: v1
kind: ReplicationController //ReplicationController类型
metadata:
name: nginx //pod名字
spec:
replicas: 2 //2个副本
selector:
app: nginx //通过这个标签找到生成的pod
template: //定义pod模板,在这里不需要定义pod名字,就算定义创建的时候也不会采用这个名字而是.metadata.generateName+5位随机数。
metadata:
labels: //定义标签
app: nginx //key:v 这里必须和selector中定义的KV一样
spec:
containers: //rc 的容器重启策略必须是Always(总是重启),这样才能保证容器的副本数正确
- image: nginx
name: nginx
ports:
- containerPort: 80
replication controller 对pod数量和健康状况的监控是通过副本选择器(replica selector或者label selector的一种)来实现的。replica selector 定义了replication controller和它控制的pod之间的松耦合关系。这与pod和Docker容器之间强耦合的关系相反。因为可以修改pod的labels将一个pod从replication controller的控制中集中移除。
replication controller的典型场景:
- 重调度:不管是想运行多少个pod副本,replication controller都能保证指定数目的pod正常运行。一旦当前的宿主机节点异常崩溃或者pod停止运行,k8s就会进行相应的重调度。
- 弹性伸缩:顾名思义,修改relicas来达到pod数目的弹性伸缩。
- 滚动更新(灰度发布):replication controller 被设计成为通过逐个替换pod的方式来进行副本的增删操作。实现起来很简单:创建新的replication controller ,并按时间逐步将新的replication controller副本数+1,旧的replication controller副本数-1即可。
replication controller 使用示例
{
"apiVersion":"v1",
"kind":"ReplicationController",
"metadata":{
"name":"redis-controller",
"labels":{
"name":"redis"
}
},
"spec":{
"replicas":1,
"selector":{
"name":"redis"
},
"template":{
"metadata":{
"labels":{
"name":"redis"
}
},
"spec":{
"containers":[{
"name":"redis",
"image":"redis:latest",
"ports":[{
"containerPort":6379,
"hostPort":6380
}]
}]
}
}
}
}
使用资源配置文件配合kubectl create命令创建一个replication controller对象:
[root@master ~]# kubectl create -f redis-controller.json
replicationcontroller/redis-controller created
使用kubectl get查询replication controller的基本信息并查看这个controller自动创建的pod。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
podtest 1/1 Running 0 11m
redis-controller-vsmwz 1/1 Running 0 2m7s
[root@master ~]# kubectl get replicationController -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
redis-controller 1 1 1 2m24s redis redis:latest name=redis
这时,我们要验证replication controller是不是真的有效。使用删除pod命令:
[root@master ~]# kubectl delete pod redis-controller-vsmwz
pod "redis-controller-vsmwz" deleted
[root@master ~]# kubectl delete pod podtest
pod "podtest" deleted
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
redis-controller-2pzsh 1/1 Running 0 21s
我们发现,删除了之后,又创建了一个新的pod。
删除副本控制器的命令:
[root@master ~]# kubectl delete replicationController redis-controller
replicationcontroller "redis-controller" deleted
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
redis-controller-2pzsh 0/1 Terminating 0 99s
[root@master ~]# kubectl get replicationController
No resources found in default namespace.
service的设计解读
其实service这个名字很容易引起误解,我认为应该定义成为proxy或者router更为贴切。
service主要由一个IP地址和一个label selector组成。在创建之初,每个service便被分配了一个独一无二的IP地址,该IP地址与service的生命周期相同并且不可以更改(pod的IP会随pod的生命周期的产生及消亡)。
定义一个service:
和pod一样,service也是一个k8s REST对象,客户端可以通过APIServer发送一个POST请求来创建一个新的service实例。假设有一个pod集,该pod集中所有pod均被贴上labels:{“app”:“MyAPP”},且所有容器均对外暴露TCP9376端口,那么一个service的JSON文件可以这么写:
{
"kind":"Service",
"apiVersion":"v1",
"metadata":{
"name":"my-service",
"labels":{
"enviroment":"testing"
}
},
"spec":{
"selector":{
"app":"MyAPP"
},
"ports":[{
"protocol":"TCP",
"port":80,
"targetPort":9376
}]
}
}
该service能将外部流量转发到所有label匹配{“app”:“MyAPP”}的pod的TCP9376端口上,每个service会由系统分配一个虚拟IP地址作为service的入口IP地址(cluster IP),然后监听上述文件中的指定端口(上述的是80端口)。
而当名为"my-service"的service对象被创建后,系统就会随之创建一个同样名为my-service的Endpoints对象,该对象即保存了所有匹配label selector后端pod的IP地址和端口。
使用kubectl get services
即可获取到service的IP地址信息。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
使用service来代理遗留系统:
与replication controller不同,service的selector其实是可选项。**这样做的目的是能用service来代理一些非pod或者得不到的label资源。**比如:
- 访问k8s集群外部的一个数据库。
- 访问其他namespace或者其他集群的service。
- 任何其他类型的外部遗留系统。
所以定义一个没有selector属性的service对象,如下:
{
"kind":"Service",
"apiVersion":"v1",
"metadata":{
"name":"my-service"
},
"spec":{
"ports":[{
"protocol":"TCP",
"port":80,
"targetPort":1111
}]
}
}
由于该service没有selector,所以系统不会自动创建一个EndPoints对象,此时可以通过自定义一个EndPoints对象,将上述service对象映射到一个或者多个后端:
{
"kind":"Service",
"apiVersion":"v1",
"metadata":{
"name":"my-service"
},
"subsets":[{
"address":[{
"IP":"1.2.3.4"
}],
"ports":[{
"port":1111
}]
}]
}
service的使用示例
首先定义两个pod,都分别运行nginx容器。第一个80:8088,第二个80:8089(即容器内的80端口映射到宿主机的8088和8089)。
第一个:
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{
"name":"nignx-a",
"labels":{
"name":"service-nginx"
}
},
"spec":{
"containers":[{
"name":"nginx",
"image":"nginx:latest",
"ports":[{
"containerPort":80,
"hostPort":8088
}]
}]
}
}
第二个:
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{
"name":"nignx-b",
"labels":{
"name":"service-nginx"
}
},
"spec":{
"containers":[{
"name":"nginx",
"image":"nginx:latest",
"ports":[{
"containerPort":80,
"hostPort":8089
}]
}]
}
}
创建以上两个pod:
[root@master ~]# vi nginx-a.json
[root@master ~]# kubectl create -f nginx-a.json
pod/nignx-a created
[root@master ~]# vi nginx-b.json
[root@master ~]# kubectl create -f nginx-b.json
pod/nignx-b created
配置文件中,我们同时把pod的labels设置成为了name=service-nginx。比如用下面的查询语句查询label。
[root@master ~]# kubectl get pod -l name=service-nginx
NAME READY STATUS RESTARTS AGE
nignx-a 1/1 Running 0 2m34s
nignx-b 1/1 Running 0 2m10s
接下来定义一个service:
{
"kind":"Service",
"apiVersion":"v1",
"metadata":{
"name":"nginx-service-clusterip",
"labels":{
"name":"nginx-service-clusterip"
}
},
"spec":{
"selector":{
"name":"service-nginx"
},
"ports":[{
"port":80
}]
}
}
selector字段表明的是service选择的labels是{“name”:“service-nginx”}。
创建service并查看:
[root@master ~]# kubectl create -f NginxService.json
service/nginxservice created
[root@master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
nginx-service-clusterip ClusterIP 10.98.112.219 <none> 80/TCP 56s
我们可以看到 service nginxservice创建且分配到的入口是10.103.124.74,该Ip与8000端口组成该service的入口地址(cluster IP)。
可以再来查看映射关系:
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nignx-a 1/1 Running 0 133m 10.244.0.14 master <none> <none>
nignx-b 1/1 Running 0 133m 10.244.0.15 master <none> <none>
sshd-test-service 1/1 Running 0 11m 10.244.0.18 master <none> <none>
[root@master ~]# kubectl describe service nginx-service-clusterip
Name: nginx-service-clusterip
Namespace: default
Labels: name=nginxservice-clusterip
Annotations: <none>
Selector: name=service-nginx
Type: ClusterIP
IP: 10.98.112.219
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.0.14:80,10.244.0.15:80
Session Affinity: None
Events: <none>
可以看到EndPoints分别对应了两个pod的IP+端口。
Service 通过 Cluster 内部的 IP 对外提供服务,只有 Cluster 内的节点和 Pod 可访问,这是默认的 Service 类型,前面实验中的 Service 都是 ClusterIP。
再定义一个sshd客户端pod。首先先搜索images:docker search sshd
。
这里我们决定下载bmoorman/sshd这个镜像。
所以写sshd-pod.json如下:
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{
"name":"sshd-test-service",
"labels":{
"user":"service-nginx",
"name":"client-sshd"
}
},
"spec":{
"containers":[{
"name":"client-container",
"image":"bmoorman/sshd:latest",
"ports":[{
"containerPort":22,
"hostPort":1314
}]
}]
}
}
创建完成后进入pod:
[root@master ~]# kubectl create -f sshd-pod.json
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nignx-a 1/1 Running 0 103m
nignx-b 1/1 Running 0 103m
sshd-test-service 1/1 Running 0 49s
[root@master ~]# kubectl exec -it sshd-test-service /bin/bash
root@sshd-test-service:/# curl 10.98.112.219:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
.....
也可以使用NodePort和LoadBalance的方式访问。在此不表。
[root@master ~]# cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service-nodeport
spec:
selector:
app: service-nginx
ports:
- name: http
port: 8000
protocol: TCP
targetPort: 80
- name: https
port: 8443
protocol: TCP
targetPort: 443
type: NodePort
更多推荐
所有评论(0)