简介

在一个集群中,我们可以直接访问 pod.
但是当节点死亡时 (或 pod 消失), Pod 随之死亡,此时控制器会自动建具有不同 IP 的新 Pod.
service 就解决了这个问题。

service 是一种抽象,它定义并指向了一组 Pod (endpoints).

创建时,将为每个服务分配一个唯一的 IP 地址 (cluster IP)。此地址与服务的生命周期相关联,并且一般不会更改。
可以将 Pod 配置为与服务通信,服务将自动负载均衡到其中某个 Pod。

也就是说,服务是沟通集群外界和 pod 群组的桥梁。

相关命令

以 nginx-svc 这个服务为例
简单的 yaml 文件如下

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
externalIPs:
- 172.18.0.3
ports:
- name: http
port: 80
targetPort: 80
selector:
run: my-nginx
type: LoadBalancer

创建
kubectl apply -f nginx-svc.yaml

获取
kubectl get svc my-nginx

描述
kubectl describe svc my-nginx

编辑
kubectl edit scv my-nginx

访问服务

内部访问

在集群内部,访问 service 主要通过 2 种方式:环境变量和 DNS

比如 linux 自带的环境变量,就是在 env 文件里定义好变量名和服务域名 (IP), 写死的.

DNS 是由 coreDNS 负责解析的,每个 service 会自带一个名字 name, 这个 name 由如下规则定义域名
<name>.<namespace>.svc.cluster.local

例如一个叫 collector 的名字的服务,ns 为 juice, 则 dns 为
collector.juice.svc.cluster.local

注意,这个 dns 只能在 pod 里使用

外部访问

如果是从集群外部访问,我们可以通过两种方式:NodePorts 和 LoadBalancer
NodePorts 好配置,Loadbalancer 就是生产环境的内容了,不了解.
还有一个 ingress 也可以用来访问服务,不过这个是另一个对象,相当于服务的再抽象,这里不多说 (反正我暂时用不到).

当节点有 externalIP (也就是所在的机器节点的 IP 地址) 时,我们只需要简单创建服务即可从外部访问
如下为示例的 yaml 文件

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
namespace: juice
name: juice-collector
spec:
selector:
app: juice-collector
ports:
- port: 30002
targetPort: 30002
protocol: TCP
nodePort: 30002
type: NodePort

如上,我们只需要指定 nodeport 或者 load-balancer 即可

此时我们通过 curl https://<EXTERNAL-IP>:<NODE-PORT> -k 即可访问

这个 ExternalIP 是什么呢?

先说结论:
ExternalIP 可以简单理解为公网 IP, 即物理机器对外的 IP 地址。这是和硬件绑定的,k8s 不能创建 ExternalIP.
这个公网是相对的,比如如果是一个学校的局域网 IP, 那这个就是在学校内的 "公网 IP", 而不是校外的公网.

调查 ExternalIP

首先在 k8s 官网可以找到这么一句话

其中 external-ip 是你的服务的外部 IP 地址(LoadBalancer Ingress)

英文版的是这样的

ExternalIP: Typically the IP address of the node that is externally routable (available from outside the cluster).

都说的很含糊

然后搜索引擎,只能找到这种答复

只有公有云上才有ExternalIP
ExternalIP 是公网IP
裸金属众所周知都是<None>

并且,某些 plugin 会判断 InternalIP 和 ExternalIP, 产生不同的结果

那么 k8s 是怎么发现的呢?通过找到这篇文章 , 发现了源码层面的奥义 (这里就不搬运了,源码分析可以自己去原文看)

以下为部分原文

首先,InternalIP是可以被指定的,kubeadm 的init带有一个参数--node-ip让你去指定它。所谓InternalIP实际上就是指Kubernetes集群内部可以被直接访问的Node的IP地址,那么ExternalIP呢?按照定义,它只是在集群外部可路由的,但是Kubernetes并没有规定它到底应该是什么。它把这个字段的设置或者说实现,交给了Cloud Provider,云供应商。

需要特别特别强调的是,不要看到云供应商就以为是公有云,实际上也可以是OpenStack或者vSphere。云供应商需要符合CPI接口规范去开发插件,在Kubernetes的Github组里你可以搜到各种cloud-provider-xxx。

在 OpenStack 的源码里可以找到 ExternalIP 对应的定义

  • 本地环境时,这个 IP 是虚拟机创建的时候指定的参数
  • 云环境时,这个 IP 是云服务提供商指定的,也就是公网 IP

ExternalIP 不是 k8s 自己的,可以简单理解为公网 IP, 在本地环境时是虚拟机硬件层面的东西

服务发现

//todo


参考文章
https://zhuanlan.zhihu.com/p/466681599