Docker K8s 09 通过服务访问应用

在定义了 Pod 应用之后, 多个 Pod 组成了一组服务(Service). 借助服务, 可以方便的实现服务发现, 负载均衡, 平滑升级; 让服务之间的依赖与 Pod 应用解构.

Pod 的创建销毁, 扩容缩容, 故障迁移等, 会造成 Pod 服务的 IP 地址并不是可以静态依赖的. Service 用于保证 Pod 应用动态变化对依赖者无感知.

Service 提供服务的无中断升级. 先启动一个新的 Pod 使用升级后的内容, 当新 Pod 可用后, 关闭一个老的 Pod. 依次替换所有老的 Pod 即完成无中断升级.

注意: 前提是新老服务对外提供的 API 等要保持兼容.

Service 的管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v1
# 定义服务
kind: Service
metadata:
name: SERVICE_NAME
spec:
selector:
# 选择器, 符合这些标签的都加入到 Service 中
app: webserver
name: nginx
type: ClusterIP(默认), NodePort, LoadBalancer
clusterIP: # type 为 ClusterIP 的时候, 提供一个集群内部虚拟 IP 用于其他 Pod 调用
ports:
# 负载映射
- name: PORT_NAME
protocol: TCP
port: 80 # 负载均衡端口
targetPort: 80 # 负载均衡映射到的服务端口
nodePort: # type 为 NodePort 的时候, 将此端口映射到主机的外网端口
- name: ...
status:
loadBalancer:
ingress:
ip:
hostname: # type 为 LoadBalancer 的时候, 定义外置负载均衡地址, 并且同时要定义 clusterIP 和 nodePort 字段

定义好后, 执行应用生效, 查看服务.

1
2
kubectl apply -f SERVICES.yaml
kubectl get service -o wide

查看 Service 后面的节点列表(Endpoints), 可以看到服务后面有哪些节点服务. 其中 SERVICE_NAME 为上面第二步获取 Service 列表中的 Service 名.

1
kubectl get endpoints SERVICE_NAME

查看 Service 详细信息, 可以看服务的选择器, 类型, 端口映射关系.

1
kubectl describe service SERVICE_NAME

删除 Service

1
2
kubectl delete -f SERVICES.yaml
kubectl delete service SERVICE_NAME

Service 外部访问功能

type: ClusterIP

使用 kube-proxy 和 ClusterIP 让 Master 转发请求

http://<masterip>:8080/api/v1/proxy/namespaces/<ns>/services/SERVICE_NAME:PORT_NAME/

type: NodePort

使用 nodePort 字段指定向外网映射的端口, 不填随机 30000~32767.

http://<masterip>:nodePort/

type: LoadBalancer

使用 spec.status.loadBalancer 定义外部负载均衡 ip 地址.

CoreDNS 实现外部访问

解决使用 Service 的时候需要预知 ClusterIP 的问题.

安装

可以使用 K8s 的软件包管理工具 Helm, 也可以通过 Yaml 进行安装.

1
wget "https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base"

其中修改下面内容:

1
2
3
__PILLAR__DNS__DOMAIN__  改为 Cluster 机器的 hostname, 例如: cluster.local
__PILLAR__DNS__MEMORY__LIMIT__ 约为 170Mi
__PILLAR__DNS__SERVER__ 修改为 ClusterIP 地址

部署 CoreDNS

1
2
kubectl apply -f coredns.yaml.base
kubectl get pods --namespace=kube-system

客户端接入

修改所有 Node 节点的 kubelet 配置, 增加 DNS 设置: /etc/kubernetes/kubelet

1
KUBELET_ARGS="--cluster-dns=ClusterIP --cluster-domain=cluster.local"

其中 --cluster-dns, --cluster-domain 和上面的配置文件 coredns.yaml 中的内容一致.

客户端测试使用

在一个 pod 中, 调用 nslookup DEPLOYMENT_NAME 查看 DNS 解析. 使用 curl http://DELOYMENT_NAME:PORT/ 访问 restapi 服务.

一般集群内访问其他 Service 可以使用 ClusterIP, NodePort, DNS. 集群内服务向外部服务暴露服务, 使用 LoadBalancer 类型, Ingress 是 Service 向上的一个抽象.

总结

LoadBalancer 推荐在使用云服务的时候使用.

NodePort 提供端口数有限, 在大规模部署下有问题.

ClusterIP 明显不适用与外部调用.

Porter 适用于自己部署的机房用. (文中没有提到, 后续可能会根据了解介绍.)

Donate - Support to make this site better.
捐助 - 支持我让我做得更好.