目录

Kubernetes - 服务发布

# Service

负责东西流量(同层级/内部服务网络通信)的通信。

image-20230618225953699

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,从而找到容器。

image-20230620235954118

# 常用类型

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 是四层负载
1
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
1
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
1
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 就先不创建。

实现方式:

  1. 编写 Service 配置文件时,不指定 Selector 属性
  2. 自己创建 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
1
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 请求。

image-20230621010111592

# 代理 k8s 外部服务(域名)

配置文件

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-external-domain
  name: nginx-external-domain
spec:
  type: ExternalName
  externalName: www.youngkbt.cn # 代理的外部域名
1
2
3
4
5
6
7
8
9

# Ingress

Ingress 大家可以理解为也是一种 LB 的抽象,它的实现也是支持 nginx、haproxy 等负载均衡服务的。

如下图,左边是传统的 Nginx 代理,右边是 Ingr ess 代理。

image-20230621204628242

# 安装 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
1
2
3

解压

tar -zxvf helm-v3.2.3-linux-amd64.tar.gz
1

将解压目录下的 helm 程序移动到 usr/local/bin/helm

mv helm /usr/local/bin
1

添加 Helm 仓库

# 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# 查看仓库列表
helm repo list 

# 搜索 ingress-nginx
helm search repo ingress-nginx
1
2
3
4
5
6
7
8

下载包

# 下载安装包
helm pull ingress-nginx/ingress-nginx
1
2

配置参数

# 将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz

# 解压后,进入解压完成的目录
cd ingress-nginx
1
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
1
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 就部署
1
2
3
4

admissionWebhooks.enabled 修改为 false,禁用 https 认证。

将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer。

创建 Namespace

# 为 ingress 专门创建一个 namespace
kubectl create ns ingress-nginx
1
2

安装 ingress

# 为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true

# 安装 ingress-nginx
helm install ingress-nginx -n ingress-nginx .
1
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 的路径前缀匹配
1
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: /
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
26
27
28
29
30
31
32
33
34
35
36
更新时间: 2024/01/17, 05:48:13
最近更新
01
JVM调优
12-10
02
jenkins
12-10
03
Arthas
12-10
更多文章>