kubernetes服务发布进阶
基本概念
service 的作用体现在两个方面,对集群内部,它不断跟踪 pod 的变化,更新 endpoint(端点)中对应 pod 的对象,提供了 ip 不断变化的 pod 的服务发现机制;对集群外部,他类似负载均衡器,可以在集群内外部对 pod 进行访问。
在 Kubernetes 中,Pod 的 IP地址和 service 的 ClusterIP 仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,Kubernetes 目前提供了以下几种方案:
NodePort:将 service 暴露在节点网络上,NodePort 背后就是 Kube-Proxy,Kube-Proxy 是沟通service 网络、Pod 网络和节点网络的桥梁,测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort 的端口管理就是个灾难。因为每个端口只能是一种服务,端口范围只能是 30000-32767。
LoadBalancer:通过设置 LoadBalancer 映射到云服务商提供的 LoadBalancer 地址。这种用法仅用于在公有云服务提供商的云平台上设置 Service 的场景。受限于云平台,且通常在云平台部署LoadBalancer 还需要额外的费用。在 service 提交后,Kubernetes 就会调用 cloudProvider 在公有云上为你创建一个负载均衡服务,并且把被代理的 Pod 的 IP 地址配置给负载均衡服务做后端。
externalIPs:service 允许为其分配外部 IP,如果外部 IP 路由到集群中一个或多个 Node 上,Service 会被暴露给这些 externalIPs。通过外部 IP 进入到集群的流量,将会被路由到 Service 的Endpoint 。
Ingress:只需一个或者少量的公网 IP 和 LB,即可同时将多个 HTTP 服务暴露到外网,实现七层反向代理。可以简单理解为 service 的 service,它其实就是一组基于域名和 URL 路径,把用户的请求转发到一个或多个 service 的规则。
目前比较流行的Ingresscontroller有ingress-nginx(由 Kubemetes 官方维护nginx-ingress(由 Nginx 官方维护,注意和 Ingress-nginx的区别)、Traefik、Istio 等。
Ingress 组成
(1)ingress:
ingress 是一个 API 对象,通过 yam1 文件来配置,ingress 对象的作用是定义请求如何转发到service 的规则,可以理解为配置模板。
ingress 通过 http 或 https 暴露集群内部 service,给 service 提供外部 URL、负载均衡、SSL/TLS能力以及基于域名的反向代理。ingress要依靠 ingress-controller 来具体实现以上功能。
(2)ingress-controller:
ingress-controller 是具体实现反向代理及负载均衡的程序,对 ingress 定义的规则进行解析,根据配置的规则来实现请求转发。
ingress-controller 并不是 k8s 自带的组件,实际上 ingress-controller 只是一个统称,用户可以选择不同的 ingress-controller 实现,目前,由 k8s 维护的 ingress-controller 只有 google云的 GCE与 ingress-nginx 两个,其他还有很多第三方维护的 ingress-controller,具体可以参考官方文档。但是不管哪一种 ingress-controller,实现的机制都大同小异,只是在具体配置上有差异。
一般来说,ingress-controller 的形式都是一个 pod,里面跑着 daemon 程序和反向代理程序。daemon 负责不断监控集群的变化,根据 ingress 对象生成配置并应用新配置到反向代理,比如ingress-nginx 就是动态生成 nginx 配置,动态更新 upstream,并在需要的时候 reload 程序应用新配置。
ingress-controller 才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到 ingress-controller,而ingress 对象是用来告诉 ingress-controller 该如何转发请求,比如哪些域名、哪些 URL 要转发到哪些 service 等等。
Ingress工作流程
用户访问一个业务的流程如下:
(1)用户在浏览器中输入域名
(2)域名解析至业务的入口 IP(一般为外部负载均衡器,比如阿里的 SLB 或者 DMZ 的网关)
(3)外部负载均衡器反向代理至 kubernetes 的入口(一般为 Ingress,或者通过 NodePort 暴露的服务等)。
(4)Ingress 根据自身的配置找到对应的 Service,再代理到对应的 Service 上。
(5)最后到达 service 对应的某一个 Pod 上。
可见,在一般情况下,Ingress 主要是一个用户 kubernetes 集群业务的入口。是业务能够正常提供服务的核心,所以在生产环境中,推荐使用单独的服务器作为Ingress controller。controller 可以使用 Traefik、Istio、Nginx、HaProxy 等作为 Ingress controller。因为相对于其他 IngressController,管理人员更熟悉 Nginx 或者 HaProxy 等服务,所以本章主要讲解 Ingress Nginx 的安装与常用配置,这也是 kubernetes 官方提供的 Ingress controller。
Ingress工作流程
(1)ingress-controller 通过和 kubernetes APIServer 交互,动态的去感知集群中 ingress 规则变化,
(2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个 service,生成一段 nginx 配置,
(3)再写到nginx-ingress-controller 的pod 里,这个 ingress-controller 的pod 里运行着一个Nginx 服务,控制器会把生成的 nginx配置写入 /etc/nginx.conf 文件中,
(4)然后reload 一下使配置生效。以此达到域名区分配置和动态更新的作用。
安装Ingress Nginx Controller
下载并安装helm(已有helm环境可忽略)
wget https://get.helm.sh/helm-v3.9.4-linux-amd64.tar.gz
tar zxvf helm-v3.9.4-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/
下载并修改Ingress Controller参数
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo undate
helm pull ingress-nginx/ingress-nginx --version 4.7.1
tar zxvf ingress-nginx-4.7.1.tgz
vim ingress-nginx/va;ues.yaml
(1)将Controller的registry仓库地址修改为国内的
controller:
name: controller
image:
chroot: false
registry: registry.cn-hangzhou.aliyuncs.com
image: tanzu/controller
tag: "v1.6.4"
#digest: sha256...
#digestChroot: sha256...
(2)修改opentelemetry镜像地址
opentelemetry
enabled: false
image: registry.cn-hangzhou.aliyuncs.com/tanzu/opentelemetry:v20230107
containerSecurityContext:
allowPrivilegeEscalation: false
(3)将admissionWebhook的镜像修改为国内的
patchWebhookJob:
securitycontext:
allowPrivilegeEscalation:false
resources:)
patch:
enabled: true
image:
registry: registry.cn-hangzhou.aliyuncs.com
image: tanzu/kube-webhook-certgen
tag: v20220916-gd32f8c343
#digest: sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
pullPolicy: IfNotPresent
(4)修改hostNetwork 的值为 true
设置为 true 时,该 Pod 将与其所在节点共享网络命名空间。
(5)dnsPolicy 设置为 ClusterFirstWithHostNet
kubernetes可以在pod级别通过dnspolicy字段设置DNS策略,目前支持的DNs策略如下:
DNS策略 | 说明 |
---|---|
Default | 继承 pod 所在宿主机的域名解析设置 |
ClusterFirst | 将优先使用 kubernetes 环境的 dns 服务(如 coreDNS 提供的域名解析服务)将无法解析的域名转发到系统配置的上游 DNS 服务器 |
ClusterFirstwithHostNet | 适用与以 hostNetwork 模式运行的 pod |
None | 忽略集群的 DNS 配置,需要手工通过 dnsconfig 自定义 DNS 配置。这个选项在 1.9 版本中None:开始引入,到 1.10 版本时升级为 Beta,到 1.14 版本时达到稳定版本 |
(6)nodeSelector添加ingress:“true’
nodeSelector:
ingress: true
kubetnetes.io/os: linux
(7)修改kind类型为DaemonSet
kind: DaemonSet
部署ingress
(1)给需要部署Ingress Controller的节点打标签
ku label node k8s-node1 ingress=true
(2)创建namespace(命名空间)
ku create ns ingress-nginx
(3)安装ingress-nginx
cd ingress-nginx
#安装
helm install ingress-nginx -n ingress-nginx
#如果需要卸载(不建议)
helm uninstall ingress-nginx -n ingress-nginx
#查看安装信息
Ingress Nginx使用入门
创建一个用于学习的namespace
ku create ns study-ingress
创建一个nginx作为web服务
ku create deployment nginx --image=nginx:1.7.9 -n study-ingress
创建一个该web容器的Service
ku expose deployment nginx --port 80 -n study-ingress
创建ingress指向上一步中的Service
vim web-ingress.yaml
路径类型
有3种支持的 path 类型:
ImplementationSpecific:对于这种 path 类型,匹配取决于 Ingressclass。可以将其视为一个单独的 pathType 或者将其认为和 Prefix 或者 xact 路径类型一样。
Exact:精确匹配 URL路径,并且区分大小写
Prefix:根据 URL 中的,被/分割的前缀进行匹配。匹配区分大小写并日按照元素对路径进行匹配path 元素指的是路径中由/分隔符分隔的标签列表。即只要用户请求的路径以指定的路径开始即可。
注意:如果路径的最后一个元素是请求路径中最后一个元素的子字符串,那么这个是不匹配的。举例:/foo/bar 匹配/foo/bar/baz,但是不匹配/foo/barbaz
创建该ingress
ku create -f web-ingress.yaml
注意不要删除该ingress,否则会后的ssl无法访问
客户端访问
创建的 Ingress 绑定的域名为 nginx.test.com,由于本书的 IngressController 是以hostNetwork 模式部署的,因此将域名解析至 Ingresscontroller 所在的节点即可。如果Ingresscontroller 上层还有一层网关,解析至网关 IP 即可。接下来通过域名 nginx.test.com 即可访问 web 服务器。
Ingress Nginx实现域名重定向Redirect
当一个服务需要更换域名时,并不能对其直接更改,需要一个过渡的过程。在这个过程中,需要将旧域名的访问跳转到新域名,此时可以使用 Redirect 功能。待旧域名无访问时,再停止旧域名。
在 Nginx作为代理服务器时,Redirect可用于域名的重定向,比如访问old.com被重定向到new.com.Ingress 可以更简单地实现 Redirect 功能。接下来用 nginx.redirect.com 作为旧域名,baidu.com作为新域名进行演示。
编辑Ingress文件
vim redirect.yaml
创建Ingress
ku create -f redirect.yaml
测试
在客户端的 hosts 文件添加域名 nginx.redirect.com,IP 地址为 k8s-node01 节点的 IP 地址。使用域名 nginx.redirect.com 访问网站,打开的是 baidu.com,说明跳转成功。
Ingress Nginx实现前后端分离rewrite
现在大部分应用都是前后端分离的架构,也就是前端用某个域名的根路径进行访问,后端接口采用/api 进行访问,用来区分前端和后端。或者同时具有很多个后端,需要使用/api-a到A服务,/api-b到B服务,但是由于A和B服务可能并没有/api-a和/api-b的路径,因此需要将/api-x重写为“/”,才可以正常到A或者B服务,否则将会出现 404 的报错。此时可以通过 Rewrite 功能达到这种效果。
创建一个应用模拟后端服务
ku create deployment backend-api --image=nginx:1.7.9 -n study-ingress
创建Service暴露应用
ku expose deployment backend-api --port 80 -n study-ingress
查看该Service的地址,并通过/api-a访问测试
ku get svc -n study-ingress
访问
http://nginx.test.com/api-a
编辑ingress,实现rewirte
vim rewirte.yaml
备注:
annotations: ##用来定义 ingress 控制器的行为,具体行为如下nginx.ingress.kubernetes.io/rewrite-target: /$2
##用于重写 URL,使得传入的请求在转发给后端服务之前,其路径部分会被修改。本案例中当用户访问nginx.test.com/api-a/xxxx的时候,都被重定向为nginx.test.com/api-anginx.test.com/api-a指向了 service 名称为 backend-api 的后端 pod
path: /api-a(/|$)(.):这个路径使用正则表达式来匹配请求。这里有两个捕获组:
第一个捕获组(/|$)匹配 /或者以 api-a结尾。
第二个捕获组(.)匹配任意字符串,表示/api-a之后的路径部分,此处表示任意路径名称。
$2 指的是匹配第二个捕获组。
创建该ingress
ku create -f rewirte.yaml
访问测试
http://nginx.test.com/api-a
Ingress Nginx实现SSl配置
生成证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj"/CN=nginx.test.com"
openssl req:这是 0penssl 的请求(request)子命令,用于创建一个新的 x.509 证书请求或者直接创建一个自签名证书。
-x509:这个选项告诉 openssL 创建一个自签名证书,而不是一个证书签名请求(CSR)
-nodes:此选项表示在生成密钥时不应加密密钥。这样生成的私钥将不会要求密码来解密,方便自动处理,但也意味着安全性较低,不适合生产环境。
-days 365:指定自签名证书的有效期为365天。这表示证书将在一年后过期。
-newkey rsa:2048:这个选项指示 0penssL 生成一个新的 RSA 密钥对,其中密钥长度为 2048 位。这是一个常见的安全密钥长度。
-keyout tls.key:指定生成的私钥文件名。在这个例子中,私钥将被保存为 tls.key 文件。
-out tls.crt:指定输出的证书文件名。生成的自签名证书将被保存为 tls.crt 文件。
-subj"/CN=nginx.test.com":这是证书的主题(subject)字段。
创建证书的secret
ku create secret tls ca-secret --cert=tls.crt --key=tls.key -n study-ingress
编辑ingress
vim ingress-ssl.yaml
创建此ingress
ku create -f ingress-ssl.yaml
访问测试
https://nginx.test.com
Ingress Nginx实现基本认证
有些网站可能需要通过密码来访问,对于这类网站可以使用nfinx的basic-bash设置密码访问,具体方法如下
安装httpd-tools
dnf -y install htttpd-tools
使用htpasswd创建用户
htpasswd -c auth zhangsan
基于之前创建的密码文件创建secret
ku create secret generic basic-auth --from-file=auth -n study-ingress
编辑ingress,包含密码认证
部署此ingress
ku create -f ingress-with-auth.yaml
访问测试
在客户端添加auth.test.com的解析