《快速掌握 Kubernetes 网络基础》最先发布在 blog.hdls.me/15376903337…html
由于 Pod 的易变性(重建以后 IP 可能会改变),Service 承担了服务入口的职能,是 k8s 网络部分的核心概念,在 k8s 中,Service 主要担任了四层负载均衡的职责。本文从负载均衡、外网访问、DNS 服务的搭建及 Ingress 七层路由机制等方面,讲解 k8s 的网络相关原理。node
Service 是主要用来实现应用程序对外提供服务的机制。nginx
如上图所示,Service 是对 Pod 的一层抽象,主要经过 TCP/IP 机制及监听 IP 和端口号来对外提供服务。与 Pod 不一样的是,Service 一旦建立,系统会为其分发一个 ClusterIP (也能够本身指定),且在其生命周期内不会发生变化。web
在建立好 RC 后,能够经过命令行 kubectl expose
来快速建立一个对应的 Service 。好比现已有一个名为 hdls 的 rc:数据库
kubectl expose rc hdls
复制代码
这种方式建立出来的 Service,其 ClusterIP 是系统自动为其分配的,而 Service 的端口号是从 Pod 中的 containerPort 复制而来。后端
apiVersion: v1
kind: Service
metadata:
name: hdls
spec:
ports:
- port: 8080 # Service 的虚拟端口
targetPort: 8000 # 指定后端 Pod 的端口号
selector: # Label 选择器
app: hdls
复制代码
定义好 YAML 文件后,经过命令 kubectl create -f <service.yml>
便可建立。Service 的定义须要指定如下几个关键字段:api
k8s 提供了两种负载分发策略:bash
在默认状况下,k8s 采用轮询模式进行路由选择,但咱们也能够经过将 service.spec.SessionAffinity 设置为 “ClusterIP” 来启用 SessionAffinity 模式。网络
Headless Serviceapp
在这种状况下,k8s 经过 Headless Service 的概念来实现,即不给 Service 设置 ClusterIP (无入口 IP),仅经过 Label Selector 将后端的 Pod 列表返回给调用的客户端。
apiVersion: v1
kind: Service
metadata:
name: hdls
spec:
ports:
- port: 8080
targetPort: 8000
clusterIP: None
selector:
app: hdls
复制代码
该 Service 没有虚拟的 ClusterIP ,对其访问能够得到全部具备 app=hdls
的 Pod 列表,客户端须要实现本身的负责均衡策略,再肯定具体访问哪个 Pod。
无 LabelSelector Service
通常来讲,应用系统须要将外部数据库做为后端服务进行链接,或另外一个集群或 namespace 中的服务做为后端服务。这些状况,能够经过创建一个无 Label Selector 的 Service 来实现:
apiVersion: v1
kind: Service
metadata:
name: hdls
spec:
ports:
- port: 8080
targetPort: 8000
复制代码
该 Service 没有标签选择器,即没法选择后端 Pod。这时系统不会自动建立 Endpoint,须要手动建立一个与该 Service 同名的 Endpoint,用于指向实际的后端访问地址。
apiVersion: v1
kind: Endpoints
metadata:
name: hdls # 与 Service 同名
subsets:
- addresss:
- IP: 1.2.3.4 # 用户指定的 IP
ports:
- port: 8000
复制代码
此时,如上面的 YAML 建立出来 Endpoint,访问无 Label Selector 的 Service ,便可将请求路由到用户指定的 Endpoint 上。
多端口的 Service
在 service.spec.ports 中定义多个 port 便可,包括指定 port 的名字和协议。
apiVersion: v1
kind: Service
metadata:
name: hdls
spec:
ports:
- name: dns
port: 8080
protocol: TCP
- name: dns-tcp
port: 8080
protocol: UDP
selector:
app: hdls
复制代码
Pod 和 Service 都是 k8s 集群内部的虚拟概念,因此集群外的客户没法访问。但在某些特殊条件下,咱们须要外网能够访问 Pod 或 Service,这时咱们须要将 Pod 或 Service 的端口号映射到宿主机,这样客户就能够经过物理机访问容器应用。
将容器应用的端口号映射到物理机上。有两种方式,以下。
这种是将容器应用的端口号映射到物理机。设置以下:
apiVersion: v1
kind: Pod
metadata:
name: hdls-pod
spec:
containers:
- name: hdls-container
image: ***
ports:
- containerPort: 8000
hostPort: 8000
复制代码
这种是将该 Pod 中全部容器端口号都直接映射到物理机上。此时须要注意的是,在容器的 ports 定义部分,若不指定 hostPort,默认 hostPort=containerPort,若设置了 hostPort,则 hostPort 必须等于 containerPort。设置以下:
apiVersion: v1
kind: Pod
metadata:
name: hdls-pod
spec:
hostNetwork: true
containers:
- name: hdls-container
image: ***
ports:
- containerPort: 8000
复制代码
也有两种方式。
首先须要设置 nodePort 映射到物理机,同时须要设置 Service 的类型为 NodePort:
apiVersion: v1
kind: Service
metadata:
name: hdls
spec:
type: NodePort # 指定类型为 NodePort
ports:
- port: 8080
targetPort: 8000
nodePort: 8000 # 指定 nodePort
selector:
app: hdls
复制代码
这种用法仅用于在公有云服务提供商的云平台上设置 Service 的场景。须要将 service.status.loadBalancer.ingress.ip 设置为云服务商提供的负载均衡器的 IP。则对该 Service 的访问请求将会经过 LoadBalancer 转发到后端 Pod,且负载均衡的实现方式依赖于云服务商提供的 LoadBalancer 的实现机制。
为了可以实现经过服务名在集群内部进行服务的相互访问,须要建立一个虚拟的 DNS 服务来完成服务名到 ClusterIP 的解析。
k8s 提供的 DNS 服务名为 skydns,由下面四个组件组成:
skyDNS 服务由一个 RC 和一个 Service 组成。在 RC 的配置文件中,须要定义 etcd / kube2sky / skydns / healthz 四个容器,以保证 DNS 服务正常工做。须要注意的是:
--domain
设置为 k8s 集群中 Service 所属域名。容器启动后 kube2sky 会经过 API Server 监控集群中全部 service 的定义,生成相应的记录并保存到 etcd ;-addr=<IP:Port>
表示本机 TCP 和 UDP 的 Port 端口提供服务。在 DNS Service 的配置文件中,skyDNS 的 ClusterIP 须要咱们指定,每一个 Node 的 kubelet 都会使用这个 IP 地址,不会经过系统自动分配;另外,这个 IP 须要在 kube-apiserver 启动参数 --service-cluster-ip-range
内。
在 skydns 容器建立以前,须要先修改每一个 Node 上 kubelet 的启动参数:
/etc/resolv.conf
中增长一条 nameserver 配置和 search 配置,经过 nameserver 访问的实际上就是 skydns 在对应端口上提供的 DNS 解析服务;Service 工做在 TCP/IP 层,而 Ingress 将不一样的 URL 访问请求转发到后端不一样的 Service ,实现 HTTP 层的业务路由机制。而在 k8s 中,须要结合 Ingress 和 Ingress Controller ,才能造成完整的 HTTP 负载均衡。
Ingress Controller 用来实现为全部后端 Service 提供一个统一的入口,须要实现基于不一样 HTTP URL 向后转发的负载分发规则。Ingress Controller 以 Pod 的形式运行,须要实现的逻辑:
/etc/nginx/nginx.conf
;nginx -s reload
,从新加载 nginx.conf 配置文件的内容。k8s 中有一种单独的名为 Ingress 的资源,在其配置文件中能够设置到后端 Service 的转发规则。好比,为 hdls.me 定义一个 ingress.yml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hdls-ingress
spec:
rules:
- host: hdls.me
http:
paths:
- path: /web
backend:
serviceName: hdls
servicePort: 8000
复制代码
最后采用 kubectl create -f ingress.yml
建立 Ingress。能够登陆 nginx-ingress Pod 查看其自动生成的 nginx.conf 配置文件内容。