带你玩转kubernetes-k8s(第30篇:k8s-深入掌握Service:定义详解)
Headless Service在某些应用场景中,开发人员希望自己控制负载均衡的策略,不使用Service提供的默认负载均衡的功能,或者应用程序希望知道属于同组服务的其他实例。k8s提供了Headless Service来实现这种功能,即不为Service设置ClusterIP(入口IP地址),仅通过Label Selector将后端的Pod列表返回给调用的客户端。apiVers...
Headless Service
在某些应用场景中,开发人员希望自己控制负载均衡的策略,不使用Service提供的默认负载均衡的功能,或者应用程序希望知道属于同组服务的其他实例。k8s提供了Headless Service来实现这种功能,即不为Service设置ClusterIP(入口IP地址),仅通过Label Selector将后端的Pod列表返回给调用的客户端。
apiVersion: v1
kind: Service
metadata:
name: nginx
lables:
app: nginx
spec:
ports:
- port: 80
clusterIP: None
selector:
app: nginx
这样,Service就不再具有一个特定的ClusterIP地址,对其进行访问将获得包含Label “app=nginx” 的全部Pod列表,然后客户端程序自行决定如何处理这个Pod列表。例如,StatefulSet就是使用Headless Service为客户端返回多个服地址的。
对于“去中心化”类的应用集群,Headless Service 将非常有用。下面以搭建Cassandra集群为例,看看如何通过对Headless Servie的巧妙使用,自动实现应用集群的创建。
Apache Cassandra是一套开源分布式NoSQL数据库系统,主要特点为它不是单个数据库,而是由一组数据库节点共同构成的一个分布式的集群数据库。由于Cassandra使用的是“去中心化”模式,所以在集群里的一个节点启动之后,需要一个途径获知集群中新节点的加入。Cassandra使用了Seed(种子)来完成集群中节点之间的相互查找和通信。
通过对Headless Service的使用,实现了Cassandra各节点之间的相互查找和集群的自动搭建。主要步骤包含:自定义SeedProvider;通过Headless Service自动查找后端Pod;自动添加新Cassandra节点。
通过Service动态查找Pod
在KubernetesSeedProovider类中,通过查询环境变量CASSANDRA_SERVICE的值来获得服务的名称。这样就要求Service在Pod之前创建。如果我们已经创建好DNS服务,那么也可以直接使用服务的名称为无须使用环境变量。
回顾一下Service的概念。Service通常作为一个负载均衡器,提供k8s集群中其他应用(Pod)对属于该Service的一组Pod进行访问。由于Pod的创建和销毁都会实现更新Service的Endpoint数据,所以可以动态地对Service的后端Pod进行查询。Cassandra的去中心化设计使得Cassandra集群中的一个Cassandra实例只需要要查询到其他节点,即可以自动组成一个集群,正好可以使用Service的这个特性查询到新增节点。
需要先创建一个单节点的pod。
cassandra-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: cassandra
name: cassandra
spec:
containers:
- args:
- /run.sh
resources:
limits:
cpu: "0.5"
image: docker.io/shenshouer/cassandra:v5
imagePullPolicy: IfNotPresent
name: cassandra
ports:
- name: cql
containerPort: 9042
- name: thrift
containerPort: 9160
volumeMounts:
- name: data
mountPath: /cassandra_data
env:
- name: MAX_HEAP_SIZE
value: 512M
- name: HEAP_NEWSIZE
value: 100M
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumes:
- name: data
在k8s系统中,首先需要为Cassandra集群定一个Service:
cassandra-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
name: cassandra
name: cassandra
spec:
ports:
- port: 9042
selector:
name: cassandra
cassandra-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
labels:
name: cassandra
name: cassandra
spec:
replicas: 1
selector:
name: cassandra
template:
metadata:
labels:
name: cassandra
spec:
containers:
- command:
- /run.sh
resources:
limits:
cpu: 0.5
env:
- name: MAX_HEAP_SIZE
value: 512M
- name: HEAP_NEWSIZE
value: 100M
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: docker.io/shenshouer/cassandra:v5
name: cassandra
ports:
- containerPort: 9042
name: cql
- containerPort: 9160
name: thrift
volumeMounts:
- mountPath: /cassandra_data
name: data
volumes:
- name: data
emptyDir: {}
y依次执行
kubectl create -f cassandra-pod.yaml
kubectl create -f cassandra-service.yaml
kubectl create -f cassandra-rc.yaml
现在,一个Cassandra Pod运行起来了,但还没有组成Cassandra集群。
Cassandra集群中新节点的自动添加
现在,我们使用k8s提供的Scale(扩容和缩容)机制对Cassandra进行扩容
使用cassandra提供的nodetool工具对任一cassandra实例(pod)进行访问来验证cassandra集群的状态。下面的命令将访问名为cassandra的Pod:
kubectl exec -it cassandra -- nodetool status
可以看看到对应节点的状态。
本例描述了一种通过API查询Service来完成动态Pod发现的应用场景。对于类似于Cassandra的去中心化集群类应用,都可以使用Headless Service查询后端Endpoint这种巧妙的方法来实现对应用集群(属于同一Service)中新加入节点的查找。
从集群外部访问Pod或Service
由于Pod和Service都是k8s集群范围内的虚拟概念,所以集群外的客户端系统无法通过Pod的IP地址或者Service的虚拟IP地址和虚拟端口号访问它们。为了让外部客户可以访问这些服务,可以将Pod或Service的端口号映射到宿主机,以使客户端应用能够通过物理机访问容器应用。
将容器应用的端口号映射到物理机
(1)通过设置容器级别的hostPort,将容器应用的端口号映射到物理机上:
apiVersion: v1
kind: Pod
metadata:
name: webapp
labels:
app: webapp
spec:
containers:
- name: webapp
image: tomcat
ports:
- containerPort: 8080
hostPort: 8081
(2) 通过设置Pod级别的hostNetwork=true,该Pod中所有容器的端口号都将被直接映射到物理机上。在设置hostNetwork=true时需要注意,在容器ports定义部分如果不指定hostPort,则默认hostPort等于containerPort,如果指定了hostPort,则hostPort必须等于containerPort的值:
apiVersion: v1
kind: Pod
metadata:
name: webapp1
labels:
app: webapp1
spec:
hostNetwork: true
containers:
- name: webapp
image : tomcat
ports:
- containerPort: 18080
同样,对该Service的访问也将被负载分发到后端的多个Pod上。
(2) 通过设置LoadBlancer映射到云服务商提供的LoadBalancer地址。这种用法仅用于在公有云服务提供商的云平台上设置Service的场景。
在下面的例子中,status.loadBalancer.ingress.ip设置的146.148.47.155为云服务商提供的负载均衡器的IP地址。对该Service的访问请求将会通过LoadBalancer转发到后端Pod上,负载分发的实现方式则依赖于云服务商提供的LoadBalancer的实现机制:
kind: Service
apiVersion: v1
metadata:
name: my-server
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
nodePort: 30061
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
小结:
今天的内容到此结束,近几天的内容相对来说比较简单。
希望大家可以认真看哦~
多多关注,谢谢。
更多推荐
所有评论(0)