Kubernetes - 服务发布
# Service
负责东西流量(同层级/内部服务网络通信)的通信。
Service 工作远程如下:
我们访问一个容器,首先经过 master 的 api-server,然后 api-service 找到容器所在的 Pod 对应的 Service,这个 Service 在创建的时候以及通过选择器 Selector 找到对应的 Pod。Service 找到 Endpoint,Endpoint 找到目标 Pod 的 kube-proxy,然后 kube-proxy 找到容器。
一个 Endpoint 随着一个 Service 创建而创建(前提是 Service 创建的时候添加了选择器 Selector),Serivce 创建后通过选择器 Selector 找到 Pod,然后把 Pod 的 IP、Port 告诉 Endpoint。
如下图,k8s-node1 的一个容器 IP 是 10.244.36.107,Port 是 80;k8s-node2 的一个容器 IP 是 10.244.36.107,Port 是 80,且 app 都是 nginx-deploy,被 Service 的选择器匹配,所以 IP 和 Port 都交给 Endpoint 管理,外界请求的时候,Service 就去找 Endpoint,Endpoint 根据 IP + Prot 找 kube-proxy,从而找到容器。
# 常用类型
Serivce 有如下类型可以选择配置:
ClusterIP:只能在集群内部使用,不配置类型的话默认就是 ClusterIP
ExternalName:返回定义的 CNAME 别名,可以配置为域名
NodePort:会在所有安装了 kube-proxy 的节点都绑定一个端口,此端口可以代理至对应的 Pod,集群外部可以使用任意节点
IP + NodePort
的端口号访问到集群中对应 Pod 中的服务当类型设置为 NodePort 后,可以在 ports 配置中增加 nodePort 配置指定端口,需要在下方的端口范围内,如果不指定会随机指定端口,端口范围:30000 ~ 32767。端口范围配置在
/usr/lib/systemd/system/kube-apiserver.service
文件中LoadBalancer:使用云服务商(阿里云、腾讯云等)提供的负载均衡器服务
# Service 的定义
yaml Demo 文件:
apiVersion: v1
kind: Service # 资源类型为 Service
metadata:
name: nginx-svc # Service 名字
labels:
app: nginx-svc # Service 本身标签
spec:
selector: # 选中当前 Service 匹配哪些 pod,对哪些 pod 的东西流量进行代理
app: nginx # 所有匹配到这些标签的 pod 都可以通过该 Service 进行访问
ports:
- name: http # Service 端口配置的名称
protocol: TCP # 端口绑定的协议,支持 TCP、UDP、SCTP,默认为 TCP
port: 80 # Service 自己的端口,在使用内网 ip 访问时使用
targetPort: 9527 # 目标 pod 的端口
- name: https
port: 443
protocol: TCP
targetPort: 443
type: NodePort # 随机启动一个端口 (3000-32767),陕射到 ports 中的端口,该端口是直接绑定在 node 上的,且集群中的每一个 node 都会绑定这个端,也可以用于将服务暴露给外部访问,但是这种方式实际生产环境不推荐,效率较低,而且 Service 是四层负载
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NodePort 建议只在测试用,因为这个模式实际就是在 node 节点上随机开启一个端口,然后直接给外界通过该 node 的 IP 进行访问,而不是走 master 的 Service 和 Endpoint。
上面的图也有 NodePort 的位置,就在 Node 的上面,然后和 kube-proxy 绑定。类似于 Endpoint 了。
NodePort 默认去随机,如果想指定端口,如下:
apiVersion: v1
kind: Service # 资源类型为 Service
metadata:
name: nginx-svc # Service 名字
labels:
app: nginx-svc # Service 本身标签
spec:
selector: # 选中当前 Service 匹配哪些 pod,对哪些 pod 的东西流量进行代理
app: nginx # 所有匹配到这些标签的 pod 都可以通过该 Service 进行访问
ports:
- name: https
port: 443
nodePort: 32000 # 指定端口
protocol: TCP
targetPort: 443
type: NodePort
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
命令操作:
# 创建 service
kubectl create -f nginx-svc.yaml
# 查看 service 信息,通过 service 的 cluster ip 进行访问
kubectl get svc
# 查看 pod 信息,通过 pod 的 ip 进行访问
kubectl get po -o wide
# 创建其他 pod 通过 service name 进行访问(推荐)
kubectl exec -it busybox -- sh
curl http://nginx-svc
# 默认在当前 namespace 中访问,如果需要跨 namespace 访问 pod,则在 service name 后面加上 .<namespace> 即可
curl http://nginx-svc.default
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 代理 k8s 外部服务(IP)
使用场景:
- 各环境访问名称统一
- 访问 k8s 集群外的其他服务
- 项目迁移
Service 创建的时候不指定选择器 Selector,则不会创建 Endpoint,因为 Endpoint 绑定的 IP、Port 等信息是 Service 告诉的,而 Service 没有选择任意一个 Pod,则 Endpoint 就先不创建。
实现方式:
- 编写 Service 配置文件时,不指定 Selector 属性
- 自己创建 Endpoint
Endpoint 配置:
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: wolfcode-svc-external # 与 Service 一致
name: wolfcode-svc-external # 与 Service 一致
namespace: default # 与 Service 一致
subsets:
- addresses:
- ip: 192.168.199.27 # 访问的目标 IP 地址,原本是 Service 选择后自动填入,但是 Service 没有加选择器,所以手动填
ports: # 与 Service 一致
- name: http # 与 Service 一致
port: 80
protocol: TCP
2
3
4
5
6
7
8
9
10
11
12
13
14
Endpoint 因为手动填写了外部的 IP,所以访问 Service 时,Service 找到 Endpoint,Endpoint 就去访问外部的 IP 地址,而不是容器的 IP。
如果 Service 填写了选择器,那么选择到了 Pod,就把 Pod 的 IP、Port 给自己 Endpoint,这样 Endpoint 就去找 Pod,但是如果手动改了 Endpoint 保存的 IP、Port,则去修改后的 IP、Port 请求。
# 代理 k8s 外部服务(域名)
配置文件
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-external-domain
name: nginx-external-domain
spec:
type: ExternalName
externalName: www.youngkbt.cn # 代理的外部域名
2
3
4
5
6
7
8
9
# Ingress
Ingress 大家可以理解为也是一种 LB 的抽象,它的实现也是支持 nginx、haproxy 等负载均衡服务的。
如下图,左边是传统的 Nginx 代理,右边是 Ingr ess 代理。
# 安装 ingress-nginx
官方文档:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm
。
中文官方文件介绍:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/
。
安装 Helm(包管理器)
后面会介绍 Helm。
下载 Helm:
cd /opt/k8s
wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
2
3
解压
tar -zxvf helm-v3.2.3-linux-amd64.tar.gz
将解压目录下的 helm 程序移动到 usr/local/bin/helm
mv helm /usr/local/bin
添加 Helm 仓库
# 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 查看仓库列表
helm repo list
# 搜索 ingress-nginx
helm search repo ingress-nginx
2
3
4
5
6
7
8
下载包
# 下载安装包
helm pull ingress-nginx/ingress-nginx
2
配置参数
# 将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz
# 解压后,进入解压完成的目录
cd ingress-nginx
2
3
4
5
修改 values.yaml 镜像地址:修改为国内镜像
# 找到
# registry: registry.k8s.io
# image: ingress-nginx/controller
# 改成如下
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/nginx-ingress-controller
tag: v1.5.1
# 把 digest 注释掉
# 找到
# registry: registry.k8s.io
# image: ingress-nginx/kube-webhook-certgen
# 改成如下
registry: registry.cn-hangzhou.aliyuncs.com
image: google_containers/kube-webhook-certgen
tag: v1.5.1
# 找到 hostNetwork 改为 true
hostNetwork: true
# 找到 dnsPolicy 将 ClusterFirst 改为 ClusterFirstWithHostNet
dnsPolicy: ClusterFirstWithHostNet
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
修改部署配置的 kind: Deployment
改成 kind: DaemonSet
,然后修改 nodeSelector
kind: DaemonSet
nodeSelector:
kubernetes.io/os: linux
ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
2
3
4
将 admissionWebhooks.enabled
修改为 false,禁用 https 认证。
将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer。
创建 Namespace
# 为 ingress 专门创建一个 namespace
kubectl create ns ingress-nginx
2
安装 ingress
# 为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true
# 安装 ingress-nginx
helm install ingress-nginx -n ingress-nginx .
2
3
4
5
# 基本使用
创建一个 ingress
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: / # 将匹配的路径重写为 /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.youngkbt.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pathType 支持三种配置:
- ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准
- Exact:精确匹配,URL 需要与 path 完全匹配上,且区分大小写的
- Prefix:以
/
作为分隔符来进行前缀匹配
多域名配置
apiVersion: networking.k8s.io/v1
kind: Ingress # 资源类型为 Ingress
metadata:
name: wolfcode-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules: # ingress 规则配置,可以配置多个
- host: k8s.youngkbt.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /api # 等价于 nginx 中的 location 的路径前缀匹配
- pathType: Exec # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
- host: api.youngkbt.cn # 域名配置,可以使用通配符 *
http:
paths: # 相当于 nginx 的 location 配置,可以配置多个
- pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
backend:
service:
name: nginx-svc # 代理到哪个 service
port:
number: 80 # service 的端口
path: /
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36