一. k8s-ingress 的理论知识
Ingress能把Service(Kubernetes的服务)配置成外网能够访问的URL,流量负载均衡,及SSL,并提供域名访问的虚拟主机等,客户通过访问URL(API资源服务的形式,例如:caas.one/kibana)进入和请求Service,一个Ingress控制器负责处理所有Ingress的请求流量,它通常是一个负载均衡器,它也可以设置在边界路由器上,或者由额外的前端来帮助处理HA方式的流量。如图所示:
1. k8s的访问方式
一般来说k8s对外服务的方式有三种:
LoadBlancer Service
NodePort Service
Ingress
1.1 LoadBlancer Service
LoadBancer Service 是Kubernetes深度结合云平台的一个组件;当使用LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前LoadBlancer Service支持的云平台已经相对完善,比如公有云阿里云,华为云及私有云(Openstack)等等,由于LoadBlancer Service深度结合了云平台,所以只能在一些云平台上使用
1.2 NodePort Service
NodePort Service顾名思义,实质上就是通过在集群的每个Node上暴露一个端口,然后将这个端口映射到某个具体的Service来实现的,虽然每个Node的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,端口冲突问题)实际使用可能并不多。
1.3 ingress
Ingress 是在Kubernetes 1.2后出现的,通过Ingress用户可以实现使用Nginx等开源的反向代理负载均衡实现对外暴露服务,除Ingress之外,traefik
用的也是相同的技术。
2. ingress组件
反向代理负载均衡器
Ingress Controller
Ingress
2.1 反向代理负载均衡
反向代理负载均衡器很简单,说白了就是nginx、apche等;在集群中反向代理负载均衡器可以自由部署,可以使用Replication Controller、Deployment、DaemonSet等等。
2.2 Ingress Controller
Ingress Controller实质上可以理解为是个监视器,Ingress Controller通过不断地跟Kubernetes API打交道,实时的感知后端Service、Pod等变化,比如新增和减少Pod,Service增加与减少等;当得到这些变化信息后,Ingress Controller在结合下文的Ingress生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用。
2.3 Ingress
Ingress简单理解就是个规则定义,比如某个域名对应某个Serivce,即当某个域名的请求进来时转发给某个Service;这个规则将与Ingress Controller结合,然后Ingress Controller将其动态写入到负载均衡器中,从而实现整体的服务发现和负载均衡。Ingress解决的是新的服务加入后,域名和服务的对应问题,基本上是一个ingress的对象,通过yaml进行创建和更新进行加载。
从上图可以很清晰的看到,实际上请求进行被负载均衡器拦截,比如nginx,然后Ingress Controller通过交互得知某个域名对应哪个Service,再通过跟Kubernetes API交互得知Service地址等信息;综合以后生成配置文件实时写入负载均衡器,然后负载均衡器reload该规则便可实现服务发现,即动态映射。
总之,ingress其实就是从 kuberenets 集群外部访问集群的一个入口,将外部的请求转发到集群内不同的 Service 上,说白了就相当于 nginx、haproxy 等负载均衡代理服务器,有人就要问了我们直接使用 nginx 就实现了,但是使用 nginx 有很大缺陷,每次有新服务加入的时候都需要改 Nginx 配置,我们去不可能每次都去更改或者滚动更新前端的 Nginx Pod 。那我们再加上一个服务发现的工具比如 consul 如何?貌似是可以,在之前单独使用 docker 的时候,这种方式已经使用得很普遍了,Ingress 实际上就是这样实现的,只是服务发现的功能自己实现了,不需要使用第三方的服务了,然后再加上一个域名规则定义,路由信息的刷新需要一个靠 Ingress controller 来提供。
现在可以供大家使用的 Ingress controller 有很多,比如 traefik、nginx-controller、Kubernetes Ingress Controller for Kong、HAProxy Ingress controller,当然你也可以自己实现一个 Ingress Controller。现在普遍用得较多的是 traefik 和 nginx-controller,traefik 的性能较 nginx-controller 差,但是配置使用要简单许多。
3. ingress 的几个问题
3.1 Pod漂移问题
Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上,如下图所示:此时的访问方式:http://nodeip:nodeport/
3.2 端口的问题
采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时,我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应Service IP就行了 。如下图所示:
3.3 域名分配及动态更新问题
从上面的方法,采用 Nginx-Pod 似乎已经解决了问题,但是其实这里面有一个很大缺陷:当每次有新服务加入又该如何修改 Nginx 配置呢?我们知道使用Nginx可以通过虚拟主机域名进行区分不同的服务,而每个服务通过upstream进行定义不同的负载均衡池,再加上location进行负载均衡的反向代理,在日常使用中只需要修改nginx.conf即可实现,那在K8S中又该如何实现这种方式的调度呢?假设后端的服务初始服务只有ecshop,后面增加了bbs和member服务,那么又该如何将这2个服务加入到Nginx-Pod进行调度呢?总不能每次手动改或者Rolling Update 前端 Nginx Pod 吧,此时 Ingress 出现了,如果不算上面的Nginx,Ingress 包含两大组件:Ingress Controller 和 Ingress。
Ingress 简单的理解就是原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;那么问题来了:”Nginx 该怎么处理?”Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图
实际上Ingress也是Kubernetes API的标准资源类型之一,它其实就是一组基于DNS名称(host)或URL路径把请求转发到指定的Service资源的规则。用于将集群外部的请求流量转发到集群内部完成的服务发布。我们需要明白,Ingress资源自身不能进行“流量穿透”,仅仅是一组规则的集合,这些集合规则还需要其他功能的辅助,比如监听某接口,然后根据这些规则的匹配进行路由转发,这些能够为Ingress资源监听套接字并将流量转发的组件就是Ingress Controller。
注:Ingress 控制器不同于Deployment 控制器的是,Ingress控制器不直接运行为kube-controller-manager的一部分,它仅仅是Kubernetes集群的一个附件,类似于CoreDNS,需要在集群上单独部署。这部分从不同的维度来理解ingress,使大家能够充分的理解ingress。
4. ingress资源
首先我们先看个简单的资源示例。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
与所有其他 Kubernetes 资源一样,Ingress 需要使用 apiVersion、kind 和 metadata 字段。 Ingress 对象的命名必须是合法的DNS子域名名称。 ingress规约提供了配置负载均衡器或者代理服务器所需的所有信息。 最重要的是,其中包含与所有传入请求匹配的规则列表。 Ingress 资源仅支持用于转发 HTTP 流量的规则。
4.1 ingress规则
每个 HTTP 规则都包含:
可选的 host。在此示例中,未指定 host,因此该规则适用于通过指定 IP 地址的
所有入站 HTTP 通信。 如果提供了 host(例如 foo.bar.com),则 rules 适
用于该 host。
路径列表 paths(例如,/testpath),每个路径都有一个由 serviceName 和
servicePort 定义的关联后端。 在负载均衡器将流量定向到引用的服务之前,主机和
路径都必须匹配传入请求的内容。
backend(后端)是Service文档中所述的服务和端口名称的组合。 与规则的 host
和 path 匹配的对 Ingress 的 HTTP(HTTPS )请求发送到列出的 backend。
通常在 Ingress 控制器中会配置 defaultBackend
(默认后端),服务不符合任何规约中 path
的请求
4.2 DefaultBackend
没有 rules 的 Ingress 将所有流量发送到同一个默认后端。 defaultBackend 通常是ingress控制器的配置选项,而非在 Ingress 资源中指定。如果 hosts 或 paths 都没有与 Ingress 对象中的 HTTP 请求匹配,则流量将路由到默认后端
4.3 资源后端
resource 后端是一个 ObjectRef,指向同一名字空间中的另一个 Kubernetes,将其作为 Ingress 对象。Resource 与 Service 配置是互斥的,在 二者均被设置时会无法通过合法性检查。 Resource 后端的一种常见用法是将所有入站数据导向带有静态资产的对象存储后端。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-resource-backend
spec:
defaultBackend:
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: static-assets
rules:
- http:
paths:
- path: /icons
pathType: ImplementationSpecific
backend:
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: icon-assets
创建了Ingress 之后,我们查看下信息:
kubectl describe ingress ingress-resource-backend
Name: ingress-resource-backend
Namespace: default
Address:
Default backend: APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
Host Path Backends
---- ---- --------
*
/icons APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations: <none>
Events: <none>
4.4 路径类型
Ingress 中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType
的路径无法通过合法性检查。当前支持的三种路径类型:
ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的 pathType 处理或者与 Prefix 或 Exact 类型作相同处理。
Exact:精确匹配 URL 路径,且区分大小写。
Prefix:基于以 / 分隔的 URL 路径前缀匹配。匹配区分大小写,并且对路径中的元素逐个完成。 路径元素指的是由 / 分隔符分隔的路径中的标签列表。 如果每个 p 都是请求路径 p 的元素前缀,则请求与路径 p 匹配。
注意:如果路径的最后一个元素是请求路径中最后一个元素的子字符串,则不会匹配 (例如:/foo/bar 匹配 /foo/bar/baz, 但不匹配 /foo/barbaz)。
4.5 实力
4.6 多重匹配
在某些情况下,Ingress 中的多条路径会匹配同一个请求。 这种情况下最长的匹配路径优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。
主机名可以是精确匹配(例如“foo.bar.com
”)或者使用通配符来匹配 (例如“*.foo.com
”)。 精确匹配要求 HTTP host
头部字段与 host
字段值完全匹配。 通配符匹配则要求 HTTP host
头部字段与通配符规则中的后缀部分相同。
主机 | host头部 | 匹配与否? |
*.foo.com | bar.foo.com | 基于相同的后缀匹配 |
*.foo.com | baz.bar.foo.com | 不匹配,通配符仅覆盖了一个 DNS 标签 |
*.foo.com | foo.com | 不匹配,通配符仅覆盖了一个 DNS 标签 |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
6. ingress类
Ingress 可以由不同的控制器实现,通常使用不同的配置。 每个 Ingress 应当指定一个类,也就是一个对 IngressClass 资源的引用。 IngressClass 资源包含额外的配置,其中包括应当实现该类的控制器名称。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: example.com/ingress-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
IngressClass 资源包含可选的 parameters
字段,可用于为该类引用额外的、 特定于具体实现的配置。
6.1 名字空间域的参数
parameters 字段中scope 和 namespace 字段,可用来引用特定 于名字空间的资源,对 Ingress 类进行配置。 scope 字段默认为 Cluster,表示默认是集群作用域的资源。 将 scope 设置为 Namespace 并设置 namespace 字段就可以引用某特定 名字空间中的参数资源。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: example.com/ingress-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
namespace: external-configuration
scope: Namespace
6.2 默认ingress类
可以将一个特定的 IngressClass 标记为集群默认 Ingress 类。 将 IngressClass 资源的 ingressclass.kubernetes.io/is-default-class 注解设置为 true 将确保新的未指定 ingressClassName 字段的 Ingress 能够分配为这个默认的 IngressClass.
注意: 如果集群中有多个 IngressClass 被标记为默认,准入控制器将阻止创建新的未指定 ingressClassName
的 Ingress 对象。 解决这个问题只需确保集群中最多只能有一个 IngressClass 被标记为默
二. Ingress的部署
在本部分内容主要介绍ingress的部署,这部分看似简单,大概的有那么5-6个yaml文件,大家复制过去,直接执行即可,但是重点是理解yaml文件的内容,上边的内容已经简单的说了下相关配置,这块就不重复了,在下一部分会详细的去讲配置的案例。yaml文件包括,namespace文件,三个configmap文件,两rbac文件。另外除了部署ingress文件外,还有一些测试文件,我用Nginx做的相关测试。大致就这些,先我把相关的内容贴出来,供大家参考。
1. yaml 文件
1.1 namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
#这个没什么可改的,就是创建一个namespace
1.2 default-backend.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-http-backend
labels:
app: default-http-backend
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app: default-http-backend
template:
metadata:
labels:
app: default-http-backend
spec:
terminationGracePeriodSeconds: 60
containers:
- name: default-http-backend
# Any image is permissible as long as:
# 1. It serves a 404 page at /
# 2. It serves 200 on a /healthz endpoint
# 镜像需要我们上传上去,或者使用别的
image: gcr.io/google_containers/defaultbackend:1.5
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
name: default-http-backend
namespace: ingress-nginx
labels:
app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: default-http-backend
# 首先更改image镜像地址,改成自己的就行
#apiVersion: extensions/v1beta1 我这个是老版本的 1.16以上需要改成apps/v1
#这块包含了一个Deployment 与 一个service
#还有一个404的页面的健康检查 livenessProbe: 这个定义
1.3 configmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app: ingress-nginx
# 这几个map文件都没啥可说的
1.4 tcp-services-configmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
1.5 udp-services-configmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
1.6 rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
# ingress-controller需要监听apiserver,获取ingress定义,通过rbac授权;
# rbac不需要我们修改
1.7 with-rbac.yaml
Ingress-Controller以Pod的形式运行,监控apiserver的/ingress接口后端的backend services,如果service发生变化,则Ingress-Controller自动更新转发规则。首先基于监听apiserver,获取全部Ingress定义,然后根据Ingress定义,生成nginx的配置文件/etc/nginx/nginx.conf,最后,执行nginx -s reload,重新加载nginx.conf配置文件的内容。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
replicas: 2
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
hostNetwork: true
## 增加hostNetwork:true
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend ### 此参数是对应上面的default-http-backend 的svc,可以直接调用返回后端的界面
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --annotations-prefix=nginx.ingress.kubernetes.io
#securityContext:
# capabilities:
# drop:
# - ALL
# add:
# - NET_BIND_SERVICE
# www-data -> 33
# runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
# 目前用不到 securityContext先注释掉吧。
# 注意更换image,如果有外网可以不用更换。
# 如果高版本 apiVersion: extensions/v1beta1 注意更改
2. 安装ingress
2.1 创建相关pod及规则等:
kubectl create -f namespace.yaml
kubectl create -f default-backend.yaml
kubectl create -f configmap.yaml
kubectl create -f tcp-services-configmap.yaml
kubectl create -f udp-services-configmap.yaml
kubectl create -f rbac.yaml
kubectl create -f with-rbac.yaml
2.2 验证
检查ingress-Nginx 命名空间的pod
kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default-http-backend-68b9588459-bw86j 1/1 Running 0 29h 172.30.16.3 k8s-master-02 <none> <none>
nginx-ingress-controller-7bd47796f8-87w6m 1/1 Running 0 29h 192.168.243.130 k8s-master-02 <none> <none>
nginx-ingress-controller-7bd47796f8-lgbtw 1/1 Running 0 29h 192.168.243.131 k8s-node-01 <none> <none>
节点本机端口状态
netstat -lntup|grep nginx
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 799538/nginx: maste
tcp 0 0 0.0.0.0:18080 0.0.0.0:* LISTEN 799538/nginx: maste
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 799538/nginx: maste
tcp6 0 0 :::443 :::* LISTEN 799538/nginx: maste
tcp6 0 0 :::18080 :::* LISTEN 799538/nginx: maste
tcp6 0 0 :::10254 :::* LISTEN 799522/nginx-ingres
tcp6 0 0 :::80 :::* LISTEN 799538/nginx: maste
访问ingress-nginx的80任意节点,反回404。ingress-nginx controller与default-http-backend生效
curl 192.168.243.130
default backend - 404
curl 192.168.243.131
default backend - 404
这ingress相关部署完成,但是在实际情况下还需配置后端的server,我们用Nginx为例
3. 安装Nginx进行测试
3.1 部署Nginx,并管理ingress
test.service.yaml
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 31000
type: NodePort
test.deploy.yaml
# API 版本号
apiVersion: apps/v1
# 类型,如:Pod/ReplicationController/Deployment/Service/Ingress
kind: Deployment
metadata:
# Kind 的名称
name: nginx-app
spec:
selector:
matchLabels:
# 容器标签的名字,发布 Service 时,selector 需要和这里对应
app: nginx
# 部署的实例数量
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
# 配置容器,数组类型,说明可以配置多个容器
containers:
# 容器名称
- name: nginx
# 容器镜像
image: nginx:1.17
# 只有镜像不存在时,才会进行镜像拉取
imagePullPolicy: IfNotPresent
ports:
# Pod 端口
- containerPort: 80
nginx.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test-ingress # ingress 名称
namespace: default # 命名空间
spec:
rules:
# 域名
- host: k8s.nginx.com
http:
paths:
- path: /
backend:
# 后端service
serviceName: nginx-service
# service 端口
servicePort: 80
nginx.yaml,关联ingress与service,相当于Nginx的配置文件。然后依次执行这三个文件,我就不写相关命令了。
3.2 验证
查看pod
查看service
查看ingress中的域名
kubectl get ingresses.extensions -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-test-ingress <none> k8s.nginx.com 80 29h
后记:
默认情况下,ingress会把访问重定向为https,这里官网上说明,如果想为某一个模块关闭tls的话,可以在annotations里设置redirect为false:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress
namespace: kube-system
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: prometheus.mine.com
http:
paths:
- backend:
serviceName: prometheus
servicePort: 9090
三. ingress 的基本应用
1. ingress的简单应用
1.1 单个service构成的ingress
这个就比较简单,上部分部署的时候,已经写了。在metadata中定义名称和namespace,在spec中定义规则,host,配置域名,path中配置路径,在backend中配置后端服务和端口。基本上也就这些内容。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test-ingress # ingress 名称
namespace: default # 命名空间
spec:
rules:
# 域名
- host: k8s.nginx.com
http:
paths:
- path: /
backend:
# 后端service
serviceName: nginx-service
# service 端口
servicePort: 80
可以看下状态
kubectl get ingress nginx-test-ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-test-ingress <none> k8s.nginx.com 80 7d23h
如果没有配置域名,可以用相关IP访问,在查看ingress中的HOSTS中显示。
1.2 简单的扇出
扇出(fanout)官网给的说法,说白了就是根据路径去访问不同的地址。一个扇出(fanout)配置根据请求的 HTTP URI 将来自同一 IP 地址的流量路由到多个 Service。 Ingress 允许你将负载均衡器的数量降至最低。
看下具体的配置,这个比较容易理解,我就不做过多解释了:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /bar
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
再看下集体描述:
kubectl describe ingress simple-fanout-example
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
1.3 基于名称的虚拟托管
基于名称的虚拟主机支持将针对多个主机名的 HTTP 流量路由到同一 IP 地址上,简单的说基于扇出相当于Nginx的location,基于名称的虚拟托管相当于server
配置如下 :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: bar.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
是不是当这块有会问,如果配置除了这两个域名之外的泛域名会怎样,在现实中有很多这样的情况,那就看以下的配置:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress-no-third-host
spec:
rules:
- host: first.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: second.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service3
port:
number: 80
在这配置中,如果非以上两个域名,会走最后一个里面。
1.4 HTTPS的配置
通过设定包含 TLS 私钥和证书的Secret 来保护 Ingress。 Ingress 只支持单个 TLS 端口 443,并假定 TLS 连接终止于 Ingress 节点 (与 Service 及其 Pod 之间的流量都以明文传输)。 如果 Ingress 中的 TLS 配置部分指定了不同的主机,那么它们将根据通过 SNI TLS 扩展指定的主机名 (如果 Ingress 控制器支持 SNI)在同一端口上进行复用。 TLS Secret 必须包含名为 tls.crt 和 tls.key 的键名。 这些数据包含用于 TLS 的证书和私钥。
创建私有:
openssl genrsa -out nginx.key 2048
制作自签证书:
openssl req -new -x509 -key nginx.key -out nginx.crt -subj /C=CN/ST=Shanghai/L=Shanghai/O=DevOps/CN=192.168.243.130
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: #base64 编码的 cert
tls.key: #base64 编码的 key
type: kubernetes.io/tls
因为编码的密码太长,我们这里直接使用命令行进行创建吧,操作比较简单
kubectl create secret tls nginx-secret --cert=nginx.crt --key=nginx.key
Ingress 中引用此 Secret 将通知Ingress 控制器使用 TLS 加密从客户端到负载均衡器的通道。 需要确保创建的 TLS Secret 创建自包含 https-example.foo.com(192.168.243.130)
的证书。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- 192.168.243.130
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
注意:我做的IP地址的https,域名的是一样的
1.5 更新ingress
更新ingress必须通过修改yaml文件么?答案是否定的
kubectl edit ingress test
这就可以更新了,但是建议从yaml文件更新,如果用edit做更新,时间久了会忘了都配置了什么,造成一定的失误,这都是经验之谈。