我们来说说 kubernetes 的服务发现。那么首先这个大前提是同主机通信以及跨主机通信都是 ok 的,即同一 kubernetes 集群中各个 pod 都是互通的。这点是由更底层的方案实现,包括 docker0/CNI 网桥、flannel vxlan/host-gw 模式等,在此篇就不展开讲了。
在各 pod 都互通的前提下,我们可以通过访问 podIp 来调用 pod 上的资源,那么离服务发现还有多少距离呢?首先 Pod 的 IP 不是固定的,另一方面我们访问一组 Pod 实例的时候往往会有负载均衡的需求,那么 service 对象就是用来解决此类问题的。
service 首先解决的是集群内通信的需求,首先我们编写一个普通的 deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostnames
spec:
selector:
matchLabels:
app: hostnames
replicas: 3
template:
metadata:
labels:
app: hostnames
spec:
containers:
- name: hostnames
image: mirrorgooglecontainers/serve_hostname
ports:
- containerPort: 9376
protocol: TCP
这个应用干的事儿就是访问它是返回自己的 hostname,并且每个 pod 都带上了 app 为 hostnames 的标签。
那么我们为这些 pod 编写一个普通的 service:
apiVersion: v1
kind: Service
metadata:
name: hostnames
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80
targetPort: 9376
可以看到 service 通过 selector 选择 了带相应的标签 pod,而这些被选中的 pod,成为 endpoints,我们可以试一下:
[root@k8s-master network]# kubectl -n demo get ep hostnames
NAME ENDPOINTS AGE
hostnames 10.244.0.4:9376,10.244.1.38:9376,10.244.2.20:9376 5m34s
当某一个 pod 出现问题,不处于 running 状态或者 readinessProbe 未通过时,endpoints 列表会将其摘除。
以上我们有了 service 和 endpoints,而默认创建 service 的类型是 clusterIp 类型,我们查看一下之前创建的 service:
[root@k8s-master network]# kubectl -n demo get svc hostnames
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.104.31.44 <none> 80/TCP 6m54s
我们看到 cluster-ip 是 10.104.31.44,那么我们此时可以在 kubernetes 集群内通过这个地址访问到 endpoints 列表里的任意 pod:
[root@k8s-master network]# curl 10.104.31.44
hostnames-6d4c8b87-7wt75
[root@k8s-master network]# curl 10.104.31.44
hostnames-6d4c8b87-nkfbl
[root@k8s-master network]# curl 10.104.31.44
访问了三次 clusterIp 地址,返回了三个不同的 hostname,我们意识到 clusterIp 模式的 service 自动对请求做了 round robin 形式的负载均衡。
对于此时 clusterIp 模式 serivice 来说,它有一个 A 记录是 service-name.namespace-name.svc.cluster.local
,指向 clusterIp 地址: