目录
- 概述
- 安装 Ingress
- 使用 Ingress
- 准备工作
- 部署Ingress
- 设置默认后端
- Ingress 中的 nginx 的全局配置
- 限流
- 路径重写
- 基于 Cookie 的会话保持技术
- 配置 SSL
概述
通常情况下,service 和 pod 的 IP 仅可在集群内部访问。
Service 可以也使用 NodePort 暴露集群外访问端口,集群外部的请求需要通过负载均衡转发到 service 在 Node 上暴露的 NodePort 上,然后再由 kube-proxy 通过边缘路由器 (edge router) 将其转发给相关的 Pod 或者丢弃。但是这样性能低、不安全并且端口的范围有限。
Service 缺少七层(OSI 网络模型)的统一访问入口,负载均衡能力很低,不能做限流、验证非法用户、链路追踪等等。
而 Ingress 就是为进入集群的请求提供路由规则的集合,如下图所示:
Ingress 可以给 service 提供集群外部访问的 URL、负载均衡、SSL 终止、HTTP 路由等。为了配置这些 Ingress 规则,集群管理员需要部署一个 Ingress controller,它监听 Ingress 和 service 的变化,并根据规则配置负载均衡并提供访问入口。
可以说,Ingress更像是取代了传统nginx,或者说nginx是Ingress的实现之一。
安装 Ingress
Ingress 正常工作需要集群中运行 Ingress Controller。Ingress Controller 与其他作为 kube-controller-manager 中的在集群创建时自动启动的 controller 成员不同,需要用户选择最适合自己集群的 Ingress Controller,或者自己实现一个。
Ingress Controller 以 Kubernetes Pod 的方式部署,以 daemon 方式运行,保持 watch Apiserver 的 /ingress 接口以更新 Ingress 资源,以满足 Ingress 的请求。
K8提供的Controller有很多,具体可以到官网看。
下面以ingress nginx 为例。它是 k8s 官方出品的,会及时更新一些特性,性能很高,被广泛采用。
- 安装helm
Helm是Kubernetes的包管理器,类似于Python的pip centos的yum,主要用来管理 Charts。后面还会有专门章节介绍。
下载二进制文件
https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz
解压:
tar -zxvf helm-v3.10.2-linux-amd64.tar.gz
我是Mac,直接使用brew安装也可以:
brew install helm
- 添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
查看仓库列表
helm repo list
搜索 ingress-nginx
helm search repo ingress-nginx
- 下载安装包
helm pull ingress-nginx/ingress-nginx
将下载好的安装包解压
tar xf ingress-nginx-xxx.tgz
- 配置参数
解压后,进入解压完成的目录
cd ingress-nginx
修改 values.yaml
镜像地址:修改为国内镜像
registry: [registry.cn-hangzhou.aliyuncs.com](http://registry.cn-hangzhou.aliyuncs.com)
image: google_containers/nginx-ingress-controller
# 注意下面还有一个
registry: [registry.cn-hangzhou.aliyuncs.com](http://registry.cn-hangzhou.aliyuncs.com)
image: google_containers/kube-webhook-certgen
修改tag:
# 也有两个地方修改
tag: v1.3.0
还有如下配置修改:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
# 修改部署配置的
kind: DaemonSet
nodeSelector:
ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
# 将 admissionWebhooks.enabled 修改为 false
admissionWebhooks.enabled: false
# 将 service 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer
service:
type: ClusterIP
-
为 ingress 专门创建一个 namespace
kubectl create ns ingress-nginx
-
为需要部署 ingress 的节点上加标签
kubectl label node k8s-node1 ingress=true
-
安装 ingress-nginx
helm install ingress-nginx ./ingress-nginx -n ingress-nginx
-
检查
kubectl get po -n ingress-nginx
# 结果如下
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-9kp22 1/1 Running 0 116m
使用 Ingress
参考:https://www.yuque.com/fairy-era/yg511q/ed952r#a708d224
准备工作
为了后面的实验比较方便,创建如下图所示的模型:
创建实验所需的 Service 以及 Pod 等:
vi k8s-prepare.yaml
内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 250m
memory: 500Mi
ports:
- containerPort: 80
name: nginx
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: default
labels:
app: tomcat
spec:
selector:
matchLabels:
app: tomcat
replicas: 3
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat:9-jre8
env:
- name: JAVA_OPTS
value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 500m
memory: 500Mi
ports:
- containerPort: 8080
name: tomcat
volumeMounts:
- name: localtime
mountPath: /etc/localtime
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: nginx
type: ClusterIP
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
app: tomcat
type: ClusterIP
ports:
- name: tomcat
protocol: TCP
port: 8080
targetPort: 8080
部署:
kubectl apply -f k8s-prepare.yaml
部署Ingress
Ingress基本配置如下:
- 语法:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules: # 规则
- host: it.nginx.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 it.nginx.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: nginx-svc # 服务名
port:
number: 80 # 服务的端口
pathType说明:
-
- Prefix:基于以
/
分隔的 URL 路径前缀匹配。匹配区分大小写,并且对路径中的元素逐个完成。 路径元素指的是由/
分隔符分隔的路径中的标签列表。 如果每个 p 都是请求路径 p 的元素前缀,则请求与路径 p 匹配。
- Prefix:基于以
-
- Exact:精确匹配 URL 路径,且区分大小写。
-
- ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的 pathType 处理或者与 Prefix 或 Exact 类型作相同处理。
注意:ingress 规则会生效到所有安装了 IngressController 的机器的 nginx 配置。
- 示例:
vi k8s-ingress.yaml
部署:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
rules: # 规则
- host: nginx.xudaxian.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 nginx.xudaxian.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: nginx-svc # 服务名
port:
number: 80 # 服务的端口
- host: tomcat.xudaxian.com # 指定的监听的主机域名,相当于 nginx.conf 的 server { xxx }
http: # 指定路由规则
paths:
- path: /
pathType: Prefix # 匹配规则,Prefix 前缀匹配 tomcat.xudaxian.com/* 都可以匹配到
backend: # 指定路由的后台服务的 service 名称
service:
name: tomcat-svc # 服务名
port:
number: 8080 # 服务的端口
kubectl apply -f k8s-ingress.yaml
示例的示意图:
-
测试示例(后面有更简单的测试方法):
-
第一种方案:
-
- ① 在 win 中的 hosts(
C:\Windows\System32\drivers\etc\hosts
) 文件中添加如下的信息:
- ① 在 win 中的 hosts(
# 用来模拟 DNS ,其中 192.168.65.101 是 ingress 部署的机器,nginx.xudaxian.com 和 tomcat.xudaxian.com 是 ingress 文件中监听的域名
192.168.65.101 nginx.xudaxian.com
192.168.65.101 tomcat.xudaxian.com
-
- ② 在 win 中使用 curl 命令:
为什么这么干?因为我使用了科学上网
,网络出现了问题。
-
第二种方案:
-
- ① 重新建立一个虚拟机(安装有 CentOS7 系统,并且带有桌面),在 hosts (
/etc/hosts
)文件中添加如下的内容:
- ① 重新建立一个虚拟机(安装有 CentOS7 系统,并且带有桌面),在 hosts (
# 用来模拟 DNS ,其中 192.168.65.101 是 ingress 部署的机器,nginx.xudaxian.com 和 tomcat.xudaxian.com 是 ingress 文件中监听的域名
192.168.65.101 nginx.xudaxian.com
192.168.65.101 tomcat.xudaxian.com
-
- ② 通过浏览器访问:
- 证明:ingress 规则会生效到所有安装了 IngressController 的机器的 nginx 配置
cat nginx.conf | grep nginx.xudaxian.com -A 20
设置默认后端
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
defaultBackend: # 指定所有未匹配的默认后端
service:
name: nginx-svc
port:
number: 80
rules:
- host: tomcat.com
http:
paths:
- path: /abc
pathType: Prefix
backend:
service:
name: tomcat-svc
port:
number: 8080
效果:
-
tomcat.com 域名的 非
/abc
开头的请求,都会转到 defaultBackend 。 -
非 tomcat.com 域名下的所有请求,也会转到 defaultBackend 。
Ingress 中的 nginx 的全局配置
官方文档
- 方式一:在安装的时候,添加配置。
apiVersion: v1
data:
allow-snippet-annotations: "true" # Nginx 的全局配置
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.1.2
helm.sh/chart: ingress-nginx-4.0.18
name: ingress-nginx-controller
namespace: ingress-nginx
- 方式二:编辑 cm :
kubectl edit cm ingress-nginx-controller -n ingress-nginx
# 配置项加上
data:
map-hash-bucket-size: "128" # Nginx 的全局配置
ssl-protocols: SSLv2
限流
官方文档
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-ingress
namespace: default
annotations: # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/limit-rps: "1" # 限流
spec:
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
路径重写
官方文档
路径重写,经常用于前后端分离。
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-rewrite
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 路径重写
spec:
ingressClassName: nginx
rules:
- host: baidu.com
http:
paths:
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
基于 Cookie 的会话保持技术
Service 只能基于 ClientIP,但是 ingress 是七层负载均衡,可以基于 Cookie 实现会话保持。
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-ingress
namespace: default
annotations: # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/affinity: "cookie"
spec:
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
配置 SSL
官方地址
- 生成证书语法:
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ${KEY_FILE} -out ${CERT_FILE} -subj "/CN=${HOST:baidu.com}/O=${HOST:baidu.com}"
kubectl create secret tls ${CERT_NAME:baidu-tls} --key ${KEY_FILE:tls.key} --cert ${CERT_FILE:tls.cert}
- 示例:生成证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.cert -subj "/CN=xudaxian.com/O=xudaxian.com"
kubectl create secret tls xudaxian-tls --key tls.key --cert tls.cert
- 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- nginx.xudaxian.com # 通过浏览器访问 https://nginx.xudaxian.com
- tomcat.xudaxian.com # 通过浏览器访问 https://tomcat.xudaxian.com
secretName: xudaxian-tls
rules:
- host: nginx.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- host: tomcat.xudaxian.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-svc
port:
number: 8080
注意:实际开发的时候,需要自己购买证书。