【k8s】Ingress 集群进出流量总管(十一)
提示:这里对文章进行总结:例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
文章目录
Ingress 解决了什么问题
上一篇笔记中讲解了 Service
的功能和运行机制。Service
本质上是一个由 kube-proxy
控制的四层负载均衡,在 TCP/IP 协议栈上转发流量。然而四层负载均衡能做的很有限,现在绝大多应用运行在应用层(五层/ OSI 七层)的 HTTP/HTTPS 协议之上,有更多的高级路由条件,而这些在传输层是不可见的。
Service
比较适合代理集群内部的服务。如果想要把服务暴露到集群外部,就只能使用 NodePort
或者 LoadBalancer
这两种方式,而它们都缺乏足够的灵活性,难以管控。
Kubernetes 为了解决这个问题,引入了一个新的 API 对象做七层负载均衡
。除了七层负载均衡
,这个对象还承担了更多的职责——作为流量的总入口,管理进出集群的数据(南北向流量),让外部用户能够安全便捷地访问集群内部的服务。这个 API 对象被命名为 Ingress
,意思就是集群内外边界上的入口。
图示是一个将所有流量都发送到同一 Service 的简单 Ingress 示例 图片来源
提示:以下是本篇文章正文内容,下面案例可供参考
一、Ingress Controller
Service
本身是没有服务能力的,它只是一些 iptables
规则,真正配置、应用这些规则的实际上是节点里的kube-proxy
组件。如果没有 kube-proxy
,Service
定义得再完善也没有用。
同样的,Ingress
也只是一些 HTTP 路由规则的集合,相当于一份静态的描述文件,真正要把这些规则在集群里实施运行,还需要有另外一个东西,这就是 Ingress Controller
,它的作用就相当于 Service
的 kube-proxy
,能够读取、应用 Ingress
规则,处理、调度流量。
为了让 Ingress
资源工作,集群必须有一个正在运行的 Ingress
控制器。Ingress
控制器不是随集群自动启动的,用户可以选择最适合集群的 Ingress
控制器实现。Kubernetes 目前支持和维护 AWS、 GCE 和 Nginx Ingress 控制器。还有很多控制器可供选择。
从 Ingress Controller
的描述上我们也可以看到,HTTP 层面的流量管理、安全控制等功能其实就是经典的反向代理,而 Nginx
则是其中稳定性最好、性能最高的产品,所以它也理所当然成为了 Kubernetes 里应用得最广泛的 Ingress Controller
。不过,因为 Nginx
是开源的,谁都可以基于源码做二次开发,所以它又有很多的变种。这里我们选取 Nginx 对 Ingress Controller
的开发实现 NGINX Ingress Controller。
图示展示了 Ingress Controller 在集群中的位置
二、指定 Ingress Class 使用多个 Ingress Controller
IngressClass Docs
起初,Kubernetes 集群内只有一个 Ingress Controller,这样的用法会带来一些问题:
- 由于某些原因,项目组需要引入不同的 Ingress Controller,但 Kubernetes 不允许这样做
- Ingress 规则太多,都交给一个 Ingress Controller 处理会让它不堪重负
- 多个 Ingress 对象没有很好的逻辑分组方式,管理和维护成本很高
- 集群里有不同的租户,他们对 Ingress 的需求差异很大甚至有冲突,无法部署在同一个 Ingress Controller 上
Kubernetes 就又提出了一个 Ingress Class
的概念,让它插在 Ingress
和Ingress Controller
中间,作为流量规则和控制器的协调人,解除了 Ingress
和 Ingress Controller
的强绑定关系。
Kubernetes 用户可以转向管理Ingress Class
,用它来定义不同的业务逻辑分组,简化 Ingress
规则的复杂度。比如说,我们可以用 Class A 处理博客流量、Class B 处理短视频流量、Class C 处理购物流量。这些Ingress
和 Ingress Controller
彼此独立,不会发生冲突。
三、使用 YAML 描述 Ingress / Ingress Class
首先用命令 kubectl api-resources 查看它们的基本信息:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
ingressclasses networking.k8s.io/v1 false IngressClass
ingresses ing networking.k8s.io/v1 true Ingress
Ingress Controller
是一个处理流量的应用程序,稍后可以使用 Deployment 和 DaemonSet 来部署
1.Ingress
Ingress
可以使用 kubectl create
来创建样板文件,它需要用两个附加参数:
--class
- 指定 Ingress 从属的 Ingress Class 对象--rule
- 指定路由规则,基本形式是URI=Service
,也就是说是访问HTTP 路径
就转发到对应的Service
对象,再由 Service 对象转发给后端的 Pod
$ export out="--dry-run=client -o yaml"
$ kubectl create ing ngx-ing --rule="ngx.test/=ngx-svc:80" --class=ngx-ink $out
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ngx-ing
spec:
ingressClassName: ngx-ink
rules:
- host: ngx.test
http:
paths:
- backend:
service:
name: ngx-svc
port:
number: 80
path: /
pathType: Exact
这份 YAML 文档中有两个关键字段 ingressClassName
和 rules
,rules
的格式稍显复杂:它将路由规则拆散为 host
和http path
,在 path
里又指定了路径的匹配方式,可以是精确匹配 Exact
或者是前缀匹配 Prefix
,再用 backend
来指定转发的目标 Service
对象。
2.Ingress Class
Ingress Class
本身并没有什么实际的功能,只是起到联系Ingress
和Ingress Controller
的作用,所以它的定义非常简单,在 spec 里只有一个必需的字段controller
,表示要使用哪个Ingress Controller
,具体的名字就要看实现文档了。
比如,要使用 Nginx 开发的Ingress Controller
,那么就要用名字nginx.org/ingress-controller
:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: ngx-ink
spec:
controller: nginx.org/ingress-controller
四、使用 Ingress / Ingress Class
使用 kubectl apply 创建 Ingress
和 Ingress Class
这两个对象:
$ kubectl apply -f ngx-ing-class.yaml
ingressclass.networking.k8s.io/ngx-ink created
$ kubectl apply -f ngx-ing.yaml
ingress.networking.k8s.io/ngx-ing created
然后我们查看 Ingress 和 Ingress Class 的状态:
$ kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
ngx-ing ngx-ink ngx.test 80 67s
$ kubectl get ingressclass -o wide
NAME CONTROLLER PARAMETERS AGE
ngx-ink nginx.org/ingress-controller <none> 84s
可以使用 kubectl describe
查看详细的信息:
$ kubectl describe ing ngx-ing
Name: ngx-ing
Labels: <none>
Namespace: default
Address:
Ingress Class: ngx-ink
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
ngx.test
/ ngx-svc:80 (10.10.1.38:80,10.10.1.40:80,10.10.1.41:80)
Annotations: <none>
Events: <none>
可以看到 Ingress
对象的路由规则Host/Path
就是在 YAML 里设置的域名 ngx.test/
。
五、使用 Ingress Controller
准备好了 Ingress
和 Ingress Class
,接下来就需要部署真正处理路由规则的Ingress Controller
。
Nginx Ingress Controller以 Pod 的形式运行在 Kubernetes 里,同时支持 Deployment 和 DaemonSet 两种部署方式。我们现在根据 Nginx Ingress Controller Installation Docs 部署 Nginx Ingress Controller。
在使用 kubectl 的主机上首先克隆仓库并进入部署文件夹:
$ git clone https://github.com/nginxinc/kubernetes-ingress.git --branch v2.4.1
$ cd kubernetes-ingress/deployments
Nginx Ingress Controller 的安装略微麻烦一些,有很多个 YAML 需要执行,但如果只是做简单的试验,就只需要用到 4 个 YAML:
$ kubectl apply -f common/ns-and-sa.yaml
namespace/nginx-ingress created
serviceaccount/nginx-ingress created
$ kubectl apply -f rbac/rbac.yaml
clusterrole.rbac.authorization.k8s.io/nginx-ingress created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress created
$ kubectl apply -f common/nginx-config.yaml
configmap/nginx-config created
$ kubectl apply -f common/default-server-secret.yaml
secret/default-server-secret created
前两条命令为Ingress Controller
创建了一个独立的名字空间nginx-ingress
,还有相应的账号和权限,这是为了访问apiserver
获取Service
、Endpoint
信息用的;后两条则是创建了一个 ConfigMap 和 Secret,用来配置 HTTP/HTTPS 服务。
接下来我们还需要部署一些 Custom Resources,没有它们我们部署的 Ingress Controller 就无法运行:
默认情况下,需要为虚拟服务器、虚拟服务器路由、传输服务器和策略创建自定义资源的定义。否则,Ingress Controller Pod 将不会变为 Ready 状态。如果要禁用该要求,请将 -enable-custom-resources 命令行参数配置为 Readyfalse 并跳过此部分。
$ kubectl apply -f common/crds/k8s.nginx.org_policies.yaml
customresourcedefinition.apiextensions.k8s.io/policies.k8s.nginx.org created
$ kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml
customresourcedefinition.apiextensions.k8s.io/transportservers.k8s.nginx.org created
$ kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml
customresourcedefinition.apiextensions.k8s.io/virtualserverroutes.k8s.nginx.org created
$ kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml
customresourcedefinition.apiextensions.k8s.io/virtualservers.k8s.nginx.org created
部署 Ingress Controller 不需要我们自己从头编写 Deployment,Nginx 已经为我们提供了示例 YAML (位置是:kubernetes-ingress/deployments/deployment/nginx-ingress.yaml
),现在我们对其进行一些小小的改动:
metadata
里的name
要改成自己的名字,比如ngx-ing-dep
spec.selector
和template.metadata.labels
也要修改成自己的名字,比如还是用ngx-ing-dep
containers.image
可以改用apline
版本,加快下载速度,比如nginx/nginx-ingress:2.2-alpine
- 最下面的
args
要加上-ingress-class=ngx-ink
,也就是前面创建的Ingress Class
的名字,这是让Ingress Controller
管理Ingress
的关键
apiVersion: apps/v1
kind: Deployment
metadata:
name: ngx-ing-dep
namespace: nginx-ingress
spec:
replicas: 1
selector:
matchLabels:
app: ngx-ing-dep
template:
metadata:
labels:
app: ngx-ing-dep
spec:
serviceAccountName: nginx-ingress
automountServiceAccountToken: true
containers:
- image: nginx/nginx-ingress:2.2-alpine
imagePullPolicy: IfNotPresent
name: nginx-ingress
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: readiness-port
containerPort: 8081
- name: prometheus
containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
resources:
requests:
cpu: "100m"
memory: "128Mi"
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
runAsNonRoot: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
- -ingress-class=ngx-ink
有了 Ingress Controller
,这些 API 对象的关联就更复杂了。然后我们创建对象:
$ kubectl apply -f ngx-ing-dep.yaml
deployment.apps/ngx-ing-dep created
注意 Ingress Controller
位于名字空间 nginx-ingress
,所以查看状态需要用 -n
参数显式指定,否则我们只能看到 default
名字空间里的 Pod
:
$ kubectl get deploy -n nginx-ingress
NAME READY UP-TO-DATE AVAILABLE AGE
ngx-ing-dep 1/1 1 1 10m
$ kubectl get pod -n nginx-ingress
NAME READY STATUS RESTARTS AGE
ngx-ing-dep-7c48c74865-vzmnf 1/1 Running 0 11m
现在 Ingress Controller
就算是运行起来了。还有最后一道工序,因为 Ingress Controller
本身也是一个 Pod,想要向外提供服务还是要依赖于 Service
对象。所以至少还要再为它定义一个 Service
,使用 NodePort
或者 LoadBalancer
暴露端口,才能真正把集群的内外流量打通。
这里还有个取巧的办法,使用 kubectl port-forward
直接把本地的端口映射到 Kubernetes 集群的某个 Pod 里,在测试验证的时候非常方便。
$ kubectl port-forward -n nginx-ingress ngx-ing-dep-7c48c74865-vzmnf 8080:80 &
可以修改/etc/hosts
来手工添加域名解析,也可以使用 --resolve
参数,指定域名的解析规则,比如在这里把 ngx.test
强制解析到127.0.0.1
,也就是被kubectl port-forward
转发的本地地址。
和 Service 一样,Ingress 把请求转发到了集群内部的 Pod,但 Ingress 的路由规则不再是 IP 地址,而是 HTTP 协议里的域名、URI
等要素。
再补充一点,目前的Kubernetes
流量管理功能主要集中在 Ingress Controller
上,已经远不止于管理入口流量
了,它还能管理出口流量
,也就是 egress
,甚至还可以管理集群内部服务之间的东西向流量
。此外,Ingress Controller
通常还有很多的其他功能,比如 TLS 终止、网络应用防火墙、限流限速、流量拆分、身份认证、访问控制
等等,完全可以认为它是一个全功能
的反向代理或者网关
.
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
更多推荐
所有评论(0)