k8s服务发布-ingress基础

1.服务发布

1.1传统架构和k8s架构

pAXbT0g.md.png

pAXb5X8.md.png

1.2Label和Selector

一般不推荐更改pod 的标签

pAXb46f.md.png

案例:

pAXbfpt.md.png

查看资源的标签:

1
[root@k8s-master01 pra]# kubectl get node --show-labels

pAXb2tA.md.png

使用-l参数过滤想要的标签:

1
2
3
4
5
6
#查看具有disktype=ssd标签的node节点,使用-l参数
[root@k8s-master01 pra]# kubectl get nodes -l disktype=ssd
NAME STATUS ROLES AGE VERSION
k8s-master03 Ready <none> 26d v1.28.11
k8s-node01 Ready <none> 26d v1.28.11
k8s-node02 Ready <none> 26d v1.28.11

pAXbRfI.md.png

1.2.1定义lable

应用案例:

公司与 xx 银行有一条专属的高速光纤通道,此通道只能与 192.168.7.0 网段进行通信,因此只能将与 xx 银行通信的应用部署到 192.168.7.0 网段所在的节点上,此时可以对节点添加 Label:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#例如k8s-node02是跟银行业务对接的,应用需要部署到k8s-node02节点上
[root@k8s-master01 pra]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready <none> 26d v1.28.11
k8s-master02 Ready <none> 26d v1.28.11
k8s-master03 Ready <none> 26d v1.28.11
k8s-node01 Ready <none> 26d v1.28.11
k8s-node02 Ready <none> 26d v1.28.11

#给k8s-node02 添加region=subnet7标签(该标签表示node02服务器网段是192.168.7.0)
#这将为 k8s-node02 节点添加 region=subnet7 标签。
[root@k8s-master01 pra]# kubectl label nodes k8s-node02 region=subnet7
node/k8s-node02 labeled

#验证node02节点上是否有该标签,-l 跟标签 可以对条件标签进行筛选
[root@k8s-master01 pra]# kubectl get nodes -l region=subnet7
NAME STATUS ROLES AGE VERSION
k8s-node02 Ready <none> 26d v1.28.11



#在deployment或者其他控制器中指定将pod部署到该节点
#spec.template.spec.nodeSelector配置该区域
[root@k8s-master01 pra]# cat nginx-deployment.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 2 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
nodeSelector: #节点选择器
region: subnet7 #匹配具有region=subnet7标签的节点部署pod
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
ports: #端口列表,复数,可以暴露多个端口
- containerPort: 80 #指定容器暴露的端口号
env:
- name: test_env
value: env


#创建deployment
[root@k8s-master01 pra]# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

#验证deployment管理的pod是否部署在k8s-node02节点
[root@k8s-master01 pra]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-69b546f6ff-5wc6b 1/1 Running 0 28s 172.16.58.215 k8s-node02 <none> <none>
nginx-deployment-69b546f6ff-wrq5v 1/1 Running 0 28s 172.16.58.214 k8s-node02 <none> <none>

练习给node节点打标签:

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
37
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready <none> 26d v1.28.11
k8s-master02 Ready <none> 26d v1.28.11
k8s-master03 Ready <none> 26d v1.28.11
k8s-node01 Ready <none> 26d v1.28.11
k8s-node02 Ready <none> 26d v1.28.11

#给node01和node02打上role=node的标签,
[root@k8s-master01 ~]# kubectl label nodes k8s-node01 k8s-node02 role=node


#给master01 和master02打上role=master的标签
[root@k8s-master01 ~]# kubectl label nodes k8s-master01 k8s-master02 role=master

#给master02节点打上gpu=true的标签
[root@k8s-master01 ~]# kubectl label nodes k8s-master02 gpu=true
node/k8s-master02 labeled


#查看node的标签
[root@k8s-master01 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master01,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-master02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,gpu=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master02,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-master03 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master03,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node
k8s-node02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node


#查看所有具有role=node标签的节点
#node是资源类型,这里也可以是pod、deployment、sts、dm等
#-l 是 --selector 的缩写,表示根据标签过滤资源。根据role=node标签过滤资源
[root@k8s-master01 ~]# kubectl get nodes -l role=node
NAME STATUS ROLES AGE VERSION
k8s-node01 Ready <none> 27d v1.28.11
k8s-node02 Ready <none> 27d v1.28.11

1.2.2selector选择器

首先使用–show-labels 查看指定资源目前已有的 Label:

1
2
3
4
5
6
7
[root@k8s-master01 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master01,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-master02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,gpu=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master02,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-master03 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master03,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node
k8s-node02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node

选择匹配 role为 master 或者 node 的 节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#如果只想看节点,不带节点的标签可以不加--show-labels
#获取标签 role 的值在 node 或 master 中的节点。
[root@k8s-master01 ~]# kubectl get nodes -l 'role in (node,master)' --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master01,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-master02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,gpu=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master02,kubernetes.io/os=linux,node.kubernetes.io/node=,role=master
k8s-node01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node
k8s-node02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node


#筛选gpu不等于true,role=node或者master的节点
[root@k8s-master01 ~]# kubectl get nodes -l 'gpu!=true ,role in (node,master)'
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready <none> 27d v1.28.11
k8s-node01 Ready <none> 27d v1.28.11
k8s-node02 Ready <none> 27d v1.28.11

#筛选具有某个key的
[root@k8s-master01 ~]# kubectl get nodes -l gpu
NAME STATUS ROLES AGE VERSION
k8s-master02 Ready <none> 27d v1.28.11

标签筛选的方式总结:

  • 等于匹配

    1
    2
    #获取带有 app=nginx 标签的所有 Pods。
    kubectl get pods -l app=nginx
  • 不等于匹配

    1
    2
    #获取不带 app=nginx 标签的所有 Pods。
    kubectl get pods -l app!=nginx
  • 存在匹配

    1
    2
    #获取带有 env 标签的所有 Pods,无论其值是什么。
    kubectl get pods -l 'env'
  • 不存在匹配

    1
    2
    #获取不带 env 标签的所有 Pods。
    kubectl get pods -l '!env'
  • 集合匹配

    • in

      1
      2
      #获取标签 role 的值在 node 或 master 中的节点。
      kubectl get nodes -l 'role in (node,master)'
    • notin

      1
      2
      #获取标签 role 的值不在 node 或 master 中的节点。
      kubectl get nodes -l 'role notin (node,master)'
    • 多条件组合

      1
      2
      #获取同时带有 env=production 和 app=nginx 标签的 Pods。
      kubectl get pods -l 'env=production,app=nginx'

1.2.3修改标签(label)

#将标签region=subnet7改为region=subnet120

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#查看当前node01和node02节点中有region=subnet7标签
[root@k8s-master01 ~]# kubectl get nodes --show-labels -l region
NAME STATUS ROLES AGE VERSION LABELS
k8s-node01 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node
k8s-node02 Ready <none> 27d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=,region=subnet7,role=node


#将node01节点中region=subnet7标签改为region=subnet120,使用--overwrite
#使用--overwrite会覆盖已经存在标签的值,这里表示会覆盖region的值
[root@k8s-master01 ~]# kubectl label nodes k8s-node01 region=subnet120 --overwrite
node/k8s-node01 labeled

#验证k8s-node01节点有region=subnet120标签
[root@k8s-master01 ~]# kubectl get nodes -l region=subnet120
NAME STATUS ROLES AGE VERSION
k8s-node01 Ready <none> 27d v1.28.11

1.2.4删除标签(label)

删除k8s-node01节点 key 名为region 的标签:

1
2
[root@k8s-master01 ~]# kubectl label nodes k8s-node01 region-
node/k8s-node01 unlabeled

批量删除region标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#可以看到只有node02有 region 作为key的标签
[root@k8s-master01 ~]# kubectl get nodes -l region
NAME STATUS ROLES AGE VERSION
k8s-node02 Ready <none> 27d v1.28.11

#删除node节点上具有region标签
#-l region先对具有redion的节点进行筛选,在 region- 对key进行删除。
[root@k8s-master01 ~]# kubectl label nodes -l region region-
node/k8s-node02 unlabeled

#删除后已经没有节点具有region为key的标签
[root@k8s-master01 ~]# kubectl get nodes -l region
No resources found

1.3Service

Service 是一种 Kubernetes 资源对象,它定义了一种访问一组 Pods 的策略。它通过标签选择器将请求路由到相应的 Pods 上,能够在 Kubernetes 集群中稳定地访问一组动态变化的 Pods。

pAXbonS.md.png

1.3.1创建一个service

定义 Service 的 yaml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1  #指定这个资源的api版本
kind: Service #指定资源的类型,这里是Service,区分大小写
metadata: # 定义资源的元数据,name字段是必须的,还以包含namespace、labels、annotations等
name: service-for-nginx-deployment #为service定义一个名称,该名称在命名空间内必须是唯一的
spec: #定义service的具体配置,也就是期望的状态
selector: #选择器,用于选择pod标签的选择器,service会将流量路由到相应标签的pod上
app: nginx #pod的标签,表示选择标签为app=nginx的pod
ports: #定义service暴露的端口,可以有多个
- protocol: TCP #Service 与其后端 Pods 之间通信使用的网络协议。这是由你的应用程序所使用的网络协议决定的
port: 80 #Service 暴露的端口。集群内其他服务通过这个端口访问 Service
targetPort: 80 #后端目标 Pods 上的端口,必须匹配容器在 Pod 中暴露的端口,Service 会将流量转发到这个端口

该示例为 service-for-nginx-deployment:80 即可访问到具有 app=nginx 标签的 Pod 的 80 端口上。

需要注意的是,Service 能够将一个接收端口映射到任意的 targetPort,如果 targetPort 为空,targetPort 将被设置为与 Port 字段相同的值。targetPort 可以设置为一个字符串,引用 backend 的Pod 的一个端口的名称,这样的话即使更改了 Pod 的端口,也不会对 Service 的访问造成影响。

Kubernetes Service 能够支持 TCP、UDP、SCTP 等协议,默认为 TCP 协议。

创建一个deployment管理5个副本的pod:

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
37
38
39
40
[root@k8s-master01 pra]# cat nginx-deployment.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 5 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
ports: #端口列表,复数,可以暴露多个端口
- containerPort: 80 #指定容器暴露的端口号

#创建这个deployment
[root@k8s-master01 pra]# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

#检查创建的deployment和pod
[root@k8s-master01 pra]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 5/5 5 5 15s

#5个副本的pod
[root@k8s-master01 pra]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-66bb646879-4vm88 1/1 Running 0 11s
nginx-deployment-66bb646879-hnwf6 1/1 Running 0 11s
nginx-deployment-66bb646879-m9s9b 1/1 Running 0 11s
nginx-deployment-66bb646879-rpb96 1/1 Running 0 11s
nginx-deployment-66bb646879-vplkh 1/1 Running 0 11s

利用上述service的yaml文件创建service

1
2
[root@k8s-master01 pra]# kubectl create -f service-nginx-deploy.yaml
service/service-for-nginx-deployment created

验证service是否创建:

1
2
3
4
5
#名字是service-for-nginx-deployment的service已经存在
[root@k8s-master01 pra]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
service-for-nginx-deployment ClusterIP 10.96.148.11 <none> 80/TCP 18s

通过service的ip就可以访问后端的pod:

pod需要和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
[root@k8s-master01 pra]# curl 10.96.148.11
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

pod重建或者更新,pod的ip地址是被变动的,但是我们通过service的ip还是可以正常访问pod的:

pAXbh1P.md.png

删除pod:

1
2
3
4
5
6
[root@k8s-master01 pra]# kubectl delete pods -l app=nginx
pod "nginx-deployment-66bb646879-4vm88" deleted
pod "nginx-deployment-66bb646879-hnwf6" deleted
pod "nginx-deployment-66bb646879-m9s9b" deleted
pod "nginx-deployment-66bb646879-rpb96" deleted
pod "nginx-deployment-66bb646879-vplkh" deleted

pod会被重新创建,此时pod的ip地址跟上述pod的ip完全不同,但是使用service还是正常访问pod

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
[root@k8s-master01 pra]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-66bb646879-4dv7z 1/1 Running 0 28s 172.16.58.217 k8s-node02 <none> <none>
nginx-deployment-66bb646879-bg6lm 1/1 Running 0 28s 172.16.32.153 k8s-master01 <none> <none>
nginx-deployment-66bb646879-fc68l 1/1 Running 0 28s 172.16.122.153 k8s-master02 <none> <none>
nginx-deployment-66bb646879-mlt79 1/1 Running 0 28s 172.16.195.22 k8s-master03 <none> <none>
nginx-deployment-66bb646879-rrzt2 1/1 Running 0 28s 172.16.85.248 k8s-node01 <none> <none>


使用service的ip进行访问
[root@k8s-master01 pra]# curl 10.96.148.11
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

跨命名空间访问:service.namespace(service名字.命名空间名字)

1.3.2Service类型

➢ ClusterIP:在集群内部使用,默认值,只能从集群中访问。

使用场景:

  • 微服务之间的通信。
  • 内部 API 或数据库的访问。
  • 不需要暴露给外部的服务。

➢ NodePort:在所有安装了 Kube-Proxy 的节点上打开一个端口,此端口可以代理至后端Pod,可以通过 NodePort 从集群外部访问集群内的服务,格式为 NodeIP:NodePort。

使用场景:

  • 简单的测试环境或开发阶段。
  • 外部临时访问服务。

➢ LoadBalancer:使用云提供商的负载均衡器公开服务,成本较高。

使用场景:

  • 生产环境中需要高可用性和负载均衡的服务。
  • Web 应用或 API 服务的对外访问。

➢ ExternalName:通过返回定义的 CNAME 别名,没有设置任何类型的代理,需要 1.7 或更高版本 kube-dns 支持。

使用场景:

  • 需要在集群内部访问外部数据库或 API 服务。
  • 服务重定向到外部域名。

➢ Headless Service(通过设置 ClusterIP: None):不分配 Cluster IP,直接通过 DNS 名称解析到后端 Pods。适用于需要直接访问 Pod IP 的状态服务

使用场景:

  • 数据库、状态服务等需要直接访问 Pod 的应用。
  • StatefulSet 中的服务发现。

1.3.3NodePort 类型

如果将 Service 的 type 字段设置为 NodePort,则 Kubernetes 将从–service-node-port-range 参数指定的范围(默认为 30000-32767)中自动分配端口,也可以手动指定 NodePort,创建该 Service后,集群每个节点都将暴露一个端口,通过某个宿主机的 IP+端口即可访问到后端的应用。

1
2
3
#默认为 30000-32767根据kube-apiserver.service文件中的范围随机生成
cat /usr/lib/systemd/system/kube-apiserver.service |grep 'service-node-port'
--service-node-port-range=30000-32767 \

定义一个 NodePort 类型的 Service 格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master01 pra]# cat service-nginx-deploy.yaml
apiVersion: v1 #指定这个资源的api版本
kind: Service #指定资源的类型,这里是Service,区分大小写
metadata: # 定义资源的元数据,name字段是必须的,还以包含namespace、labels、annotations等
name: service-for-nginx-deployment #为service定义一个名称,该名称在命名空间内必须是唯一的
spec: #定义service的具体配置,也就是期望的状态
type: NodePort #将service配置为NodePort类型
selector: #选择器,用于选择pod标签的选择器,service会将流量路由到相应标签的pod上
app: nginx #pod的标签,表示选择标签为app=nginx的pod
ports: #定义service暴露的端口,可以有多个
- protocol: TCP #Service 与其后端 Pods 之间通信使用的网络协议。这是由你的应用程序所使用的网络协议决定的
port: 80 #Service 暴露的端口。集群内其他服务通过这个端口访问 Service
targetPort: 80 #后端目标 Pods 上的端口,必须匹配容器在 Pod 中暴露的端口,Service 会将流量转发到这个端口

创建这个service:

1
[root@k8s-master01 pra]# kubectl replace -f service-nginx-deploy.yaml

查看创建的service:名字service-for-nginx-deployment 的service的类型是NodePort,这样就可以通过任意安装Kube-Proxy 节点的ip加32222端口访问到后端的pod

1
2
3
4
5
#可以看到
[root@k8s-master01 pra]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
service-for-nginx-deployment NodePort 10.96.148.11 <none> 80:32222/TCP 4h12m

32222端口也可以手动指定:

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
#手动指定service暴露的端口,通过修改nodePort: 32333手动指定端口,手动指定的端口不能和节点上的端口冲突。
[root@k8s-master01 pra]# kubectl edit service service-for-nginx-deployment
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2024-07-20T10:08:36Z"
name: service-for-nginx-deployment
namespace: default
resourceVersion: "2943581"
uid: 29d10e3c-0f56-494d-a148-669bf7522ed9
spec:
clusterIP: 10.96.148.11
clusterIPs:
- 10.96.148.11
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- nodePort: 32333
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}

1.3.4使用 Service代理K8s外部服务

使用场景:

➢ 希望在生产环境中使用某个固定的名称而非 IP 地址访问外部的中间件服务;

➢ 希望 Service 指向另一个 Namespace 中或其他集群中的服务;

➢ 正在将工作负载转移到 Kubernetes 集群,但是一部分服务仍运行在 Kubernetes 集群之外的 backend。

使用kubernetes代理外部服务,service的yaml文件就不要指定pod的标签了(spec.selector),创建一个同名的Endpoints就可以被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
26
27
28
29
[root@k8s-master01 pra]# cat service-external-ip.yaml
apiVersion: v1
kind: Service #定义资源的类型
metadata: #定义对象的元数据,例如:名称、标签、注释等
name: service-external-ip #定义资源的名称,要和Endpoints中metadata.name保持一致
labels: #定义资源的标签,键值对的形式
app: external-ip #定义的标签内容
spec: #定义资源对象的期望状态
ports: #定义service服务暴露的端口
- port: 80 #service服务暴露的端口是80,客户端通过此端口访问后端服务
name: http #端口的名称,要和Endpoints中subsets.ports.name一致
protocol: TCP #定义使用的协议,要和Endpoints中subsets.ports.protocol一致
targetPort: 8080 #定义后端服务的端口,必须匹配pod中容器的端口,这里要和Endpoints中subsets.ports.port一致
type: ClusterIP #service的类型,集群内部访问

--- #一个yaml文件写两种资源类型需要用---分割
apiVersion: v1
kind: Endpoints #资源类型Endpoints
metadata: #定义资源对象的元数据
name: service-external-ip #定义资源的名称,要与service中metadata.name保持一致
labels: #标签
app: external-ip #定义资源的标签
subsets: #定义端点的子集,包括 IP 地址和端口信息。确保子集配置正确且对应实际的外部服务。
- addresses: #包含一个或多个 IP 地址。确保 IP 地址是外部服务的实际地址
- ip: 123.249.7.183 #外部服务的 IP 地址。
ports: #定义服务暴露的端口。配置要与外部服务的实际端口一致。
- name: http #端口的名称,要与service中spec.ports.name保持一致
port: 8080 #外部服务的端口。要与service中spec.ports.targetPort的端口保持一致
protocol: TCP #定义使用的协议。要与service中spec.ports.protocol的协议保持一致

总结:

  1. Service 的 port 可以与 Endpoints 的 port 不同,port 是集群内的 Pod 访问 Service 的端口。
  2. Service 的 targetPort 必须与 Endpoints 的 port 相同,确保请求能够正确转发到实际的外部服务端口。

通过上述配置,集群内的 Pod 可以通过访问 service-external-ip:80 来连接到外部服务 123.249.7.183:8080

Service 的 port 是客户端访问 Service 的入口端口。

Service 的 targetPort 必须与 Endpoints 的 port 一致,以便正确转发请求到后端实际服务。

Endpoint IP 地址不能是 loopback(127.0.0.0/8)、link-local(169.254.0.0/16)或者 linklocal 多播地址(224.0.0.0/24)。

访问没有 Selector 的 Service 与有 Selector 的 Service 的原理相同,通过 Service 名称即可访问,请求将被路由到用户定义的 Endpoint。

验证k8s代理外部服务是否成功:

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
37
[root@k8s-master01 pra]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
service-external-ip ClusterIP 10.96.20.32 <none> 80/TCP 37m
service-for-nginx-deployment NodePort 10.96.148.11 <none> 80:32333/TCP 19h

[root@k8s-master01 pra]# wget 10.96.20.32
--2024-07-21 13:50:20-- http://10.96.20.32/
Connecting to 10.96.20.32:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 [text/html]
Saving to: ‘index.html’

100%[==========================================================>] 612 --.-K/s in 0s

2024-07-21 13:50:20 (167 MB/s) - ‘index.html’ saved [612/612]


#ep是Endpoints的缩写
[root@k8s-master01 pra]# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.0.200:6443,192.168.0.201:6443,192.168.0.202:6443 28d
service-external-ip 123.249.7.183:80 38m
service-for-nginx-deployment 172.16.122.154:80,172.16.195.22:80,172.16.32.154:80 + 2 more... 19h

#可以看到直接访问123.249.7.183:80和访问wget 10.96.20.32的效果是一样的,表示代理外部服务成功
[root@k8s-master01 pra]# wget 123.249.7.183:80
--2024-07-21 13:51:02-- http://123.249.7.183/
Connecting to 123.249.7.183:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 [text/html]
Saving to: ‘index.html’

100%[============================================================>] 612 --.-K/s in 0s

2024-07-21 13:51:02 (179 MB/s) - ‘index.html’ saved [612/612]

1.3.5 ExternalName Service

ExternalName Service 是 Service 的特例,它没有 Selector,也没有定义任何端口和 Endpoint,它通过返回该外部服务的别名来提供服务。

比如可以定义一个 Service,后端设置为一个外部域名,这样通过 Service 的名称即可访问到该域名。使用 nslookup 解析以下文件定义的 Service,集群的 DNS 服务将返回一个值为my.database.example.com 的 CNAME 记录:

1
2
3
4
5
6
7
8
[root@k8s-master01 pra]# cat externalname-service.yaml
apiVersion: v1
kind: Service #定义资源的类型,这里是service
metadata: #定义资源的元数据
name: external-name #定义这个资源的名称
spec: #定义资源的期望状态
type: ExternalName #资源的类型是externalname
externalName: www.jiugen.net #指定代理的后端外部域名,集群内部pod可以通过这个service的名称访问到www.jiugen.net的内容

验证pod通过上述创建的srvice名称访问www.jiugen.net

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
#创建service
[root@k8s-master01 pra]# kubectl create -f externalname-service.yaml

#查看创建的svc
[root@k8s-master01 pra]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
external-name ExternalName <none> www.jiugen.net <none> 7m3s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28d
service-external-ip ClusterIP 10.96.20.32 <none> 80/TCP 102m
service-for-nginx-deployment NodePort 10.96.148.11 <none> 80:32333/TCP 20h
[root@k8s-master01 pra]#

#进入pod中,访问名称是external-name 的service,验证是否代理到了 www.jiugen.net
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-66bb646879-4kjwj -- sh
/ # ping external-name #可以看到这里和ping www.jiugen.net返回的ip相同,代理成功
PING external-name (121.36.48.57): 56 data bytes
64 bytes from 121.36.48.57: seq=0 ttl=44 time=8.858 ms
64 bytes from 121.36.48.57: seq=1 ttl=44 time=9.396 ms
64 bytes from 121.36.48.57: seq=2 ttl=44 time=9.854 ms
^C
--- external-name ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 8.858/9.369/9.854 ms
/ # ping www.jiugen.net #可以看到这里和ping external-name返回的ip相同,代理成功
PING www.jiugen.net (121.36.48.57): 56 data bytes
64 bytes from 121.36.48.57: seq=0 ttl=44 time=9.215 ms
64 bytes from 121.36.48.57: seq=1 ttl=44 time=9.739 ms
64 bytes from 121.36.48.57: seq=2 ttl=44 time=28.221 ms
^C
--- www.jiugen.net ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 9.215/15.725/28.221 ms

1.3.6多端口的service

在 Kubernetes 中,Service 对象可以配置为支持多个端口。

假设你有一个应用 Pod,它既提供 HTTP 服务也提供 HTTPS 服务,你可以通过单个 Service 来管理这两种服务的网络访问。下面是一个配置示例,其中一个 Pod 运行在 80 和 443 端口上,分别对应 HTTP 和 HTTPS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Service
metadata:
name: multi-port-service
labels:
app: multi-service-app
spec:
selector:
app: multi-service-app
ports:
- name: http #端口名字
protocol: TCP #定义协议,要与 Pod 上的应用一致
port: 80 #将service的80端口转发到后端targetPort的8080端口上
targetPort: 8080 #这里指的是pod中容器的端口
- name: https #端口的名字
protocol: TCP #定义协议,要与 Pod 上的应用一致
port: 443 #将service的443端口转发到后端targetPort的8443端口上
targetPort: 8443 #这里指的是pod中容器的端口
type: ClusterIP #指定service的类型,ClusterIP集群内部访问

1.4Ingress

pAj8ia6.md.png

pAj8APO.md.png
Ingress 资源:

  • 这是一个 Kubernetes 中定义的 API 对象。
  • 它包含了路由规则,指定了从外部进入集群的请求应该被路由到哪个服务上。
  • 例如,它定义了如果访问 example.com,请求应该被路由到名为 my-service 的服务上。

Ingress Controller:

  • 这是一个运行在 Kubernetes 集群中的组件。
  • 它监视集群中的 Ingress 资源,读取其中定义的路由规则。
  • 然后,它根据这些规则配置底层的负载均衡器或反向代理(如 Nginx、Traefik)。
  • Ingress Controller 是实际执行流量控制的组件,它确保外部请求按照 Ingress 资源中定义的规则被正确路由。

pAj8EGD.md.png

1.4.1Ingress Contorller安装

官方安装文档:https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters

将学习资料中的deploy-ingress.yaml 上传服务器,并创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#创建资源
[root@k8s-master01 pra]# kubectl create -f deploy-nginx.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created

1.4.2使用域名发布k8s服务

创建一个web服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#使用deployment部署5个副本的pod,pod中的容器镜像使用nginx
[root@k8s-master01 pra]# vim nginx-deployment.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 5 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
ports: #端口列表,复数,可以暴露多个端口
- containerPort: 80 #指定容器暴露的端口号

创建service代理上述的pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master01 pra]# cat service-nginx-deploy.yaml
apiVersion: v1 #指定这个资源的api版本
kind: Service #指定资源的类型,这里是Service,区分大小写
metadata: # 定义资源的元数据,name字段是必须的,还以包含namespace、labels、annotations等
name: service-for-nginx-deployment #为service定义一个名称,该名称在命名空间内必须是唯一的
spec: #定义service的具体配置,也就是期望的状态
type: ClusterIP
selector: #选择器,用于选择pod标签的选择器,service会将流量路由到相应标签的pod上
app: nginx #pod的标签,表示选择标签为app=nginx的pod
ports: #定义service暴露的端口,可以有多个
- protocol: TCP #Service 与其后端 Pods 之间通信使用的网络协议。这是由你的应用程序所使用的网络协议决定的
port: 80 #Service 暴露的端口。集群内其他服务通过这个端口访问 Service
targetPort: 80 #后端目标 Pods 上的端口,必须匹配容器在 Pod 中暴露的端口,Service 会将流量转发到这个端口

创建上述deployment和service

1
2
[root@k8s-master01 pra]# kubectl create -f nginx-deployment.yaml
[root@k8s-master01 pra]# kubectl create -f service-nginx-deploy.yaml

配置ingress的yaml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@k8s-master01 pra]# vim web-ingress.yaml
apiVersion: networking.k8s.io/v1 # k8s >= 1.22 必须 v1
kind: Ingress #定义了资源的类型为Ingress,ingress资源用于管理集群外部对内部服务的访问
metadata: #定义资源的元数据
name: nginx-ingress #定义了ingress的名称是nginx-ingress
spec: #定义ingress的期望状态
ingressClassName: nginx #指定使用Ingress 控制器类
rules: #定义了如何将请求路由到服务的规则
- host: nginx.test.com #允许基于域名的虚拟主机,也就是用域名访问该服务
http: #定义http路由规则
paths: #定义了基于路径的路由规则
- backend: #指定后端服务的详情
service: #后端service服务的名称
name: service-for-nginx-deployment #这里是名字叫service-for-nginx-deployment的service
port: #服务暴露的端口
number: 80 #这个端口是名字叫service-for-nginx-deployment的service暴露的端口
path: / #匹配所有规则
pathType: ImplementationSpecific #路径匹配的类型,允许 Ingress 控制器使用自己的路径匹配算法
  • pathType:路径的匹配方式,目前有 ImplementationSpecific、Exact 和 Prefix 方式

    • Exact:精确匹配,比如配置的 path 为/bar,那么/bar/将不能被路由;

    • Prefix:前缀匹配,基于以 / 分隔的 URL 路径。比如 path 为/abc,可以匹配到/abc/bbb 等,比较常用的配置;

    • ImplementationSpecific:这种类型的路由匹配根据 Ingress Controller 来实现,可以当做一个单独的类型,也可以当做 Prefix 和 Exact。ImplementationSpecific是 1.18 版本引入 Prefix 和 Exact 的默认配置;

创建ingress:

1
2
3
4
5
[root@k8s-master01 pra]# kubectl create -f web-ingress.yaml
ingress.networking.k8s.io/nginx-ingress created
[root@k8s-master01 pra]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress nginx nginx.test.com 80 8s

注意:ingress中配置的hosts域名nginx.test.com要解析到ingress controller的IP上。

首先,需要理解 Ingress Controller 在 Kubernetes 集群中的部署方式:

  • Ingress Controller 通常部署在它自己的命名空间中,最常见的名称是 ingress-nginx
  • 它作为一个服务运行,通常是 LoadBalancer 类型的服务(在云环境中)或 NodePort 类型(在非云环境中)。
1
2
3
[root@k8s-master01 pra]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.152.84 <none> 80:31422/TCP,443:30715/TCP 5h17m

因为ingress-nginx-controller 的service的类型是NodePort,所以使用宿主机ip+31422端口就可以访问到ingress代理服务。

这里使用域名解析,利用hosts文件模拟,任意节点ip 解析到nginx.test.com 然后在浏览器上加上31422端口就可以访问

pAj89q1.png

pAj8PVx.md.png

pAj8FIK.md.png

1.4.3Ingress特例:不配置域名发布服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@k8s-master01 pra]# cat no-host-web-ingress.yaml
apiVersion: networking.k8s.io/v1 # k8s >= 1.22 必须 v1
kind: Ingress #定义了资源的类型为Ingress,ingress资源用于管理集群外部对内部服务的访问
metadata: #定义资源的元数据
name: no-host-nginx-ingress #定义了ingress的名称是nginx-ingress
spec: #定义ingress的期望状态
ingressClassName: nginx #指定使用Ingress 控制器类
rules: #定义了如何将请求路由到服务的规则
#- host: nginx.test.com #允许基于域名的虚拟主机,也就是用域名访问该服务,不配置域名发布服务去掉该参数
- http: #定义http路由规则
paths: #定义了基于路径的路由规则
- backend: #指定后端服务的详情
service: #后端service服务的名称
name: service-for-nginx-deployment #这里是名字叫service-for-nginx-deployment的service
port: #服务暴露的端口
number: 80 #这个端口是名字叫service-for-nginx-deployment的service暴露的端口
path: /no-hosts #去掉匹配所有规则,不配置域名发布服务这里配置no-hosts参数
pathType: ImplementationSpecific #路径匹配的类型,允许 Ingress 控制器使用自己的路径匹配算法

创建这个ingress:

1
[root@k8s-master01 pra]# kubectl create -f no-host-web-ingress.yaml

1.4.4Ingress v1和v1beta1的区别

待补充