4、服务发布
四、服务发布
1. Pod生命周期带来的问题
Pod 的生命是有限的,死亡过后不会复活了。每个 Pod 都有自己的 IP 地址,但是如果 Pod 重建了的话那么他的 IP 很有可能也就变化了。
这就会带来一个问题:比如我们有一些后端的 Pod 集合为集群中的其他应用提供 API 服务,如果我们在前端应用中把所有的这些后端的 Pod 的地址都写死,然后以某种方式去访问其中一个 Pod 的服务,这样看上去是可以工作的,对吧?但是如果这个 Pod 挂掉了,然后重新启动起来了,是不是 IP 地址非常有可能就变了,这个时候前端就极大可能访问不到后端的服务了。
2. k8s为什么要发布服务
当我们通过 Replication Controller(简称 RC)、ReplicaSet 、Deployment、StatefulSet 、DaemonSet创建完 Pod 后,每个 Pod 都会被分配到一个 IP 地址,而 Pod 的 IP 地址总是不稳定和难依赖的。假设后端的一组 Pod 为前端的 Pod 提供服务,此时如果后端的这组 Pod 异常重建,Pod 的 IP 地址也随之改变,导致它们之间服务无法正常通信。
为了解决上面问题,k8s 引入 Service 这样的概念。这样我们只需访问 Service 即可,不用关注 Pod 是否异常重建导致服务无法通信的问题。
3. 什么是Service
在没有使用 Kubernetes 之前,比如我们在部署一个 WEB 服务的时候,前端一般部署一个 Nginx 作为服务的入口,然后 Nginx 后面肯定就是挂载的这个服务的大量后端服务,很早以前我们可能是去手动更改 Nginx 配置中的 upstream 选项,来动态改变提供服务的数量,到后面出现了一些服务发现的工具,比如 Consul、ZooKeeper 还有我们熟悉的 etcd 等工具,有了这些工具过后我们就可以只需要把我们的服务注册到这些服务发现中心去就可以,然后让这些工具动态的去更新 Nginx 的配置就可以了,我们完全不用去手工的操作了,是不是非常方便。
同样的,要解决我们上面遇到的问题是不是实现一个服务发现的工具也可以解决?没错的,当我们 Pod 被销毁或者新建过后,我们可以把这个 Pod 的地址注册到这个服务发现中心去就可以,但是这样的话我们的前端应用就不能直接去连接后台的 Pod 集合了,应该连接到一个能够做服务发现的中间件上面,对吧?
为解决这个问题 Kubernetes 就为我们提供了这样的一个对象 Service。Service 是一种抽象的对象,它定义了一组 Pod 的逻辑集合和一个用于访问它们的策略,其实这个概念和微服务非常类似。一个 Serivce 下面包含的 Pod 集合是由 Label Selector 来决定的。
Service 主要用于 Pod 之间的通信,对于 Pod 的 IP 地址而言,Service 是提前定义好并且是不变的资源类型,在生产环境中最佳的实践方式就是每个应用互相调用时使用 Service 的名字进行连接,而非 IP 地址。
4. Service的类型
Kubernetes Service Type(服务类型)主要包括以下几种:
- ClusterIP:在集群内部使用,默认值,只能从集群中访问。
- NodePort:在所有安装了 Kube-Proxy 的节点上打开一个端口,此端口可以代理至后端Pod,可以通过 NodePort 从集群外部访问集群内的服务,格式为 NodeIP:NodePort。
- LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
- ExternalName:通过返回定义的 CNAME 别名,没有设置任何类型的代理,需要 1.7 或更高版本 kube-dns 支持。
5. 使用Service
5.1 定义Service
和创建其他类型的资源一样,定义一个YAML文件,即可通过kubectl客户端创建一个Service。假定有一组 Pod 服务,它们对外暴露了 80 端口,同时都被打上了 app=zzb 这样的标签,那么我们就可以像下面这样来定义一个 Service 对象:
[root@k8s-master01 service]# cat /yaml/service/zzb-80.yaml
apiVersion: v1
kind: Service
metadata:
name: zzb-80
spec:
selector:
app: zzb
ports:
- protocol: TCP
port: 32000
targetPort: 80
name: http
Tips:targetPort如果为空,targetPort将被设置为与Port字段相同的值。
5.2 创建Service
根据上述yaml文件配置创建一个名为 zzb-80 的 Service 对象,它会将请求代理到 TCP 端口为 80 并且具有标签 app=zzb 的 Pod 上。这个 Service 会被分配一个IP地址,通常称为 ClusterIP,它会被服务的代理使用。在集群内部可以通过该 ClusterIP(不建议使用ClusterIP进行访问)或 Service 名加上 port(port名称)进行访问,该示例zzb-80:32000(port名称)即可访问具有app=zzb标签的Pod的80端口。
Tips:该 Service 还会持续的监听 selector 下面的 Pod,会把这些 Pod 信息更新到一个名为 zzb-80 的Endpoints 对象上去。
创建Deployment
根据下面的yaml文件进行创建Deployment
[root@k8s-master01 service]# cat /yaml/service/nginx-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: app-nginx
spec:
replicas: 3
selector: #selector:定义Deployment如何找到要管理的Pod,与template的label (标签)对应
matchLabels:
app: zzb
template:
metadata:
labels:
app: zzb #使用label(标签)标记Pod
spec:
containers:
- name: app-nginx
image: nginx:1.14.2 #运行此Pod使用的镜像
ports:
- containerPort: 80 #容器用于发送和接收流量的端口
重新查看 Service,该 Service 持续的监听定义的 selector,也就 zzb标签下面的 Pod,会把这些 Pod 信息更新到 Endpoints 上去。
5.3 集群内IP访问方式
例如是多 deployment(在同一命名空间下)之间需要互相的访问,此时创建一个测试的deployment
kubectl create deploy cluster-test --image=registry.cn-beijing.aliyuncs.com/dotbalo/debug-tools -- sleep 3600
进入该测试 deployment 下的Pod,进行访问 zzb-80 这个Service(此时Service Endpoints中的Pod,index.html已修改,方便看实验效果)。此时能看到访问Service IP + 端口号能够正常负载访问!
Tips:Cluster IP方式通过kube-proxy组件实现负载均衡和服务代理的功能。
5.4 集群内域名访问方式
采用域名 + 端口访问
也可以通过这种DNS方式进行访问,但是解析的还是Cluster IP。
5.5 Headless Service
如果是Headless Service(无头服务),我们访问“zzb-80.default.svc.cluster.local”
这条 DNS 记录,就可以访问到 default 这个命名空间下面名为 zzb-80 的 Service 所代理的某一个 Pod。(通常末尾svc.cluster.local没修改就不变)
下面更改普通Service为Headless Service,删除原来的,重新创建下面这个。
[root@k8s-master01 service]# cat zzb-80.yaml
apiVersion: v1
kind: Service
metadata:
name: zzb-80
spec:
selector:
app: zzb
clusterIP: None
ports:
- protocol: TCP
port: 32000
targetPort: 80
name: http
进入该测试 deployment 下的 Pod,测试访问 Headless Service,没有 Cluster IP,直接访问zzb-80.default.svc.cluster.local
就能访问 Service 所代理的某一个 Pod。(DNS轮询方式实现流量分发)
访问Service名称也可以。
5.6 多端口Service
对于某些服务,需要公开多个端口。 Kubernetes 允许在 Service 对象上配置多个端口定义。 为服务使用多个端口时,必须提供所有端口名称,以使它们无歧义。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- name: port1
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30001
- name: port2
protocol: TCP
port: 8081
targetPort: 8081
nodePort: 30002
type: NodePort
6. 使用NodePort对外发布服务
通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 NodeIp:NodePort
,可以从集群的外部访问一个 NodePort 服务。
Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。
Tips:Service 的 spec.ports.nodePort 字段如果不指定的话会自动生成一个端口。
修改Service的yaml文件如下:
[root@k8s-master01 service]# cat zzb-80.yaml
apiVersion: v1
kind: Service
metadata:
name: zzb-80
spec:
selector:
app: zzb
type: NodePort
ports:
- protocol: TCP
port: 32000
targetPort: 80
name: http
nodePort: 30076
创建Service,Service的端口是32000,暴露在Node节点上的端口是30076。
宿主机进行访问,访问方式NodeIP:NodePort
,只要是各节点上的IP都可以.
7. 使用Service代理k8s外部服务
我们有时需要通过Service代理集群外部服务时,可以创建一个没有Selector字段的Service,之后再手动创建Endpoint添加外部服务即可,以下情况均可使用无选择器的Service,例如:
- 希望在生产环境中使用某个固定的名称而非IP地址访问外部的中间件服务。
- 希望Service指向另一个Namespace或其他集群中的服务。
- 正在将工作负载转移到Kubernetes集群,但是一部分服务仍运行在Kubernetes集群之外的backend。
定义一个无Selector的yaml文件,下面的Service没有Selector字段,那就不会去筛选带标签的Pod,自然Endpoints也是None。(如果创建带有Selector字段和标签的,会自动创建一个和Service name同名的Endpoints)
[root@k8s-master01 service]# vim nginx-svc-external.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
sessionAffinity: None
type: ClusterIP
如果刚才的配置后面加上这个Endpoints的yaml内容,创建出来则会是带上subsets字段定义的IP。(此时删除刚才的Service,重新执行下面yaml内容的文件)
[root@k8s-master01 service]# vim nginx-svc-external.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
spec:
ports:
- name: http
port: 80 #暴露给集群内的端口,可改
protocol: TCP
targetPort: 80 #要与Endpoints的port一致,包括协议。
sessionAffinity: None
type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
subsets:
- addresses:
- ip: 121.14.77.221
ports:
- name: http
port: 80
protocol: TCP
Tips:同名的Service和Endpoints会自动建立连接!
进入一个Pod,来测试是否能访问到该Service所代理的外部服务,没问题!
8. ExternalName方式
ExternalName 是 Service 的特例,它没有 selector
,也没有定义任何的端口和 Endpoint。对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
定义一个 ExternalName 的yaml文件
[root@k8s-master01 service]# vim externalname-service.yaml
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
type: ExternalName
externalName: www.baidu.com
当查找主机 external-service.default.svc.cluster.local
时,集群 DNS 服务返回 CNAME
记录, 其值为 www.baidu.com
。 访问 external-service
的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。
进入一个Pod当中,使用wget访问external-service服务(给百度拒绝了是正常的)。
9. Ingress对外暴露集群服务
9.1 传统架构和K8s架构访问
在没有使用Kubernetes的传统架构中,部署一个应用并使用域名进行发布的流程如下:
- 部署应用至宿主机,启动应用并暴露一个端口号。
- 通过Nginx或其他代理工具配置域名,并代理至后端应用。
- 在域名厂商进行域名解析,设置DNS记录至Nginx或其他代理工具(Nginx的前面可能还有其他代理服务器,在此不进行说明)的服务器上,之后就能通过域名访问我们的应用。
在使用Kubernetes时,部署一个应用并使用域名进行发布的流程如下:
- 部署应用至Kubernetes集群,容器内定义了程序启动的方式。
- 配置ClusterIP类型的Service,通过Selector链接到容器内的应用。
- 配置Ingress链接到该应用的Service,之后将域名解析到Ingress(Ingress前面可能还有其他代理服务器)对应的宿主机上即可。
9.2 为什么使用Ingress
可以使用 NodePort 和 LoadBlancer类型的 Service 可以把应用暴露给外部用户使用,除此之外,Kubernetes 还为我们提供了一个非常重要的资源对象可以用来暴露服务给外部用户,那就是Ingress。对于小规模的应用我们使用 NodePort 或许能够满足我们的需求,但是当你的应用越来越多的时候,你就会发现对于 NodePort 的管理就非常麻烦了,这个时候使用 Ingress 就非常方便了,可以避免管理大量的端口。
9.3 了解Ingress
Ingress就是实现用域名的方式访问应用。Ingress实现的方式有很多,比如Nginx、HAProxy、Treafik等,就Nginx而言,和上述提到的传统服务架构用Nginx类似。Ingress控制器在每个符合条件的宿主机上部署一个Pod,这个Pod里面运行的就是Nginx进程,里面的实现逻辑和宿主机部署Nginx的方式并无太大区别。
Ingress 其实就是从 Kuberenets 集群外部访问集群的一个入口,将外部的请求转发到集群内不同的 Service 上,其实就相当于 nginx、haproxy 等负载均衡代理服务器,可能你会觉得我们直接使用 nginx 就实现了,但是只使用 nginx 这种方式有很大缺陷。
每次有新服务加入的时候怎么改 Nginx 配置?不可能让我们去手动更改或者滚动更新前端的 Nginx Pod 吧?那我们再加上一个服务发现的工具比如 consul 如何?貌似是可以,对吧?Ingress 实际上就是这样实现的,只是服务发现的功能自己实现了,不需要使用第三方的服务了,然后再加上一个域名规则定义,路由信息的刷新依靠 Ingress Controller 来提供。
Ingress Controller 可以理解为一个监听器,通过不断地监听 kube-apiserver,实时的感知后端 Service、Pod 的变化,当得到这些信息变化后,Ingress Controller 再结合 Ingress 的配置,更新反向代理负载均衡器,达到服务发现的作用。
9.4 Ingress Controller安装
官方安装文档:https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters ,如果使用官网的yaml,记得自己先同步gcr(容器)镜像,然后再替换镜像地址。
下面进行安装Ingress Controller,先定义一个yaml。
[root@k8s-master01 Ingress]# cat /yaml/Ingress/deploy-ingress.yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-nginx-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
spec:
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.cn-beijing.aliyuncs.com/dotbalo/ingress-nginx-controller:v1.7.1
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v20230312
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v20230312
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.7.1
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
安装ingress服务并查询Pod状态,出现以下情况即可。
kubectl create -f deploy-ingress.yaml
安装后会将 NGINX Ingress Controller 安装在一个统一的 ingress-nginx 的 namespace 下面!
9.5 使用域名发布K8s内部服务
在完成Ingress Controller安装后,进行创建一个测试nginx的Pod。
kubectl create deploy nginx --image=nginx:1.14.2
暴露Service的80端口
#命令格式:kubectl expose deploy deployment名称 --port 要暴露的端口
kubectl expose deploy nginx --port 80
定义一个Ingress的yaml文件
[root@k8s-master01 Ingress]# vim web-ingress.yaml
apiVersion: networking.k8s.io/v1 #版本大于1.22,必须选择v1,小于1.22是v1beta1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: nginx #ingressClassName:指定ingress controller的名字,一个集群中可以有多个controller,如果是ingress-nginx,controller名字为nginx。(可通过这个命令查看kubectl get ingressclass)
rules: #一个Ingress可以配置多个rule。
- host: nginx.zzb.com #一般都会配置对应的域名。
http:
paths: #域名的location配置,同一个host可以配置多个path。比如有一个路径格式为xxx.com/abc,可以配置path为/abc,每个路径都有一个对应的backend,对应到应用的Service和Port。
- backend: #描述Service和Port的组合,对Ingress匹配主机和路径的HTTP与HTTPS请求将被发送到对应的后端。
service:
name: nginx #代理的Service名字
port:
number: 80 #代理的Service端口配置
#name:web #名字型的端口号配置,比如web,表示Port的名字。
path: /
pathType: ImplementationSpecific #pathType:路径的匹配方式,目前有ImplementationSpecific、Exact和Prefix方式。
关于pathType
ImplementationSpecific:这种类型的路由匹配根据Ingress Controller来实现,可以当作一个单独的类型。
Exact:精确匹配,比如配置的path为/bar,那么/bar/将不能被路由。
Prefix:前缀匹配,基于以“/”分隔的URL路径。比如path为/abc,可以匹配到/abc/bbb等,比较常用的配置。
创建并查看Ingress和Ingress暴露的端口
浏览器访问域名,宿主机需要做host解析(节点上的Node IP,或者VIP)。
注:本篇学习笔记内容参考杜宽的《云原生Kubernetes全栈架构师》,视频、资料文档等,大家可以多多支持!还有YinJayChen语雀、k8s训练营、“我为什么这么菜”知乎博主等资料文档,感谢无私奉献!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了