各位,总算回来!博客断更快一年了吧,这一年过的真不容易,和疫情一样。公司降薪换工作,到了新公司和我八字不合,差点给我整出来抑郁症,又开始换工作,刚稳定了两周,又出车祸了,被一个老大爷骑着三轮车怼成了骨折。自己遭罪又贴钱,倒了血霉了。这本命年真是不好过呀。还好到年底了,这一年就要结束了。小太爷又回来了!回来就好,回来就继续写博客吧,就这命了!我记得k8s原理我写到了pod原理这块,先放放,刚做了ingress,先学这个吧,这个有点意思。
我打算用三个部分来写ingress,理论知识,部署及应用。理论篇幅比较长,可能需要一定的网络及运维基础,各位看官如果基础不好,咋办?等着吧,回头我有时间了写点网络基础及运维基础的文章。估计且得等呢,我保证退休之前肯定写完。第二部分将写部署相关,这个比较简单,也就是几个yaml文件,我会把原始文件贴出来,如果有哪不明白的可在留言区讨论。另外有需要镜像文件可给我留言,我传给大家,可能我的版本有点低。最后一部分将写点应用相关的,包括https,访问路径过滤,基于名称解析虚拟机,常用的就这几块吧,如果还有其他用的地方,可以给我留言,大家一起研究。好了,闲话少说,书归正传,开整!这说的就不少了,开整。
Ingress能把Service(Kubernetes的服务)配置成外网能够访问的URL,流量负载均衡,及SSL,并提供域名访问的虚拟主机等,客户通过访问URL(API资源服务的形式,例如:caas.one/kibana)进入和请求Service,一个Ingress控制器负责处理所有Ingress的请求流量,它通常是一个负载均衡器,它也可以设置在边界路由器上,或者由额外的前端来帮助处理HA方式的流量。如图所示:
一般来说k8s对外服务的方式有三种:
- LoadBlancer Service
- NodePort Service
- Ingress
LoadBancer Service 是Kubernetes深度结合云平台的一个组件;当使用LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前LoadBlancer Service支持的云平台已经相对完善,比如公有云阿里云,华为云及私有云(Openstack)等等,由于LoadBlancer Service深度结合了云平台,所以只能在一些云平台上使用.
NodePort Service顾名思义,实质上就是通过在集群的每个Node上暴露一个端口,然后将这个端口映射到某个具体的Service来实现的,虽然每个Node的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,端口冲突问题)实际使用可能并不多。
Ingress 是在Kubernetes 1.2后出现的,通过Ingress用户可以实现使用Nginx等开源的反向代理负载均衡实现对外暴露服务,除Ingress之外,traefik
用的也是相同的技术。
- 反向代理负载均衡器
- Ingress Controller
- Ingress
反向代理负载均衡器很简单,说白了就是nginx、apche等;在集群中反向代理负载均衡器可以自由部署,可以使用Replication Controller、Deployment、DaemonSet等等。
Ingress Controller实质上可以理解为是个监视器,Ingress Controller通过不断地跟Kubernetes API打交道,实时的感知后端Service、Pod等变化,比如新增和减少Pod,Service增加与减少等;当得到这些变化信息后,Ingress Controller在结合下文的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 差,但是配置使用要简单许多。
Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上,如下图所示:此时的访问方式:http://nodeip:nodeport/
采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时,我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应Service IP就行了 。如下图所示:
从上面的方法,采用 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。
首先我们先看个简单的资源示例。
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 流量的规则。
每个 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
的请求。
没有 rules
的 Ingress 将所有流量发送到同一个默认后端。 defaultBackend
通常是ingress控制器的配置选项,而非在 Ingress 资源中指定。如果 hosts
或 paths
都没有与 Ingress 对象中的 HTTP 请求匹配,则流量将路由到默认后端
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:
Events:
Ingress 中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType
的路径无法通过合法性检查。当前支持的三种路径类型:
ImplementationSpecific
:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的pathType
处理或者与Prefix
或Exact
类型作相同处理。
Exact
:精确匹配 URL 路径,且区分大小写。
Prefix
:基于以/
分隔的 URL 路径前缀匹配。匹配区分大小写,并且对路径中的元素逐个完成。 路径元素指的是由/
分隔符分隔的路径中的标签列表。 如果每个 p 都是请求路径 p 的元素前缀,则请求与路径 p 匹配。注意:如果路径的最后一个元素是请求路径中最后一个元素的子字符串,则不会匹配 (例如:
/foo/bar
匹配/foo/bar/baz
, 但不匹配/foo/barbaz
)。
类型 | 路径 | 请求路径 | 匹配与否? |
---|---|---|---|
Prefix | / |
(所有路径) | 是 |
Exact | /foo |
/foo |
是 |
Exact | /foo |
/bar |
否 |
Exact | /foo |
/foo/ |
否 |
Exact | /foo/ |
/foo |
否 |
Prefix | /foo |
/foo , /foo/ |
是 |
Prefix | /foo/ |
/foo , /foo/ |
是 |
Prefix | /aaa/bb |
/aaa/bbb |
否 |
Prefix | /aaa/bbb |
/aaa/bbb |
是 |
Prefix | /aaa/bbb/ |
/aaa/bbb |
是,忽略尾部斜线 |
Prefix | /aaa/bbb |
/aaa/bbb/ |
是,匹配尾部斜线 |
Prefix | /aaa/bbb |
/aaa/bbb/ccc |
是,匹配子路径 |
Prefix | /aaa/bbb |
/aaa/bbbxyz |
否,字符串前缀不匹配 |
Prefix | / , /aaa |
/aaa/ccc |
是,匹配 /aaa 前缀 |
Prefix | / , /aaa , /aaa/bbb |
/aaa/bbb |
是,匹配 /aaa/bbb 前缀 |
Prefix | / , /aaa , /aaa/bbb |
/ccc |
是,匹配 / 前缀 |
Prefix | /aaa |
/ccc |
否,使用默认后端 |
混合 | /foo (Prefix), /foo (Exact) |
/foo |
是,优选 Exact 类型 |
在某些情况下,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
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
字段,可用于为该类引用额外的、 特定于具体实现的配置。
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
可以将一个特定的 IngressClass 标记为集群默认 Ingress 类。 将 IngressClass 资源的 ingressclass.kubernetes.io/is-default-class
注解设置为 true
将确保新的未指定 ingressClassName
字段的 Ingress 能够分配为这个默认的 IngressClass.
注意: 如果集群中有多个 IngressClass 被标记为默认,准入控制器将阻止创建新的未指定
ingressClassName
的 Ingress 对象。 解决这个问题只需确保集群中最多只能有一个 IngressClass 被标记为默
在本部分内容主要介绍ingress的部署,这部分看似简单,大概的有那么5-6个yaml文件,大家复制过去,直接执行即可,但是重点是理解yaml文件的内容,上边的内容已经简单的说了下相关配置,这块就不重复了,在下一部分会详细的去讲配置的案例。yaml文件包括,namespace文件,三个configmap文件,两rbac文件。另外除了部署ingress文件外,还有一些测试文件,我用Nginx做的相关测试。大致就这些,先我把相关的内容贴出来,供大家参考。
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
#这个没什么可改的,就是创建一个namespace
apiVersion: extensions/v1beta1
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.4
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: 这个定义
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app: ingress-nginx
# 这几个map文件都没啥可说的
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
---
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 "-"
# Here: "-"
# 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不需要我们修改
Ingress-Controller以Pod的形式运行,监控apiserver的/ingress接口后端的backend services,如果service发生变化,则Ingress-Controller自动更新转发规则。首先基于监听apiserver,获取全部Ingress定义,然后根据Ingress定义,生成nginx的配置文件/etc/nginx/nginx.conf,最后,执行nginx -s reload,重新加载nginx.conf配置文件的内容。
apiVersion: extensions/v1beta1
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: registry.cn-beijing.aliyuncs.com/k8s_apps/nginx-ingress-controller:0.14.0
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --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 注意更改
需要的两个镜像可能现在不太好下载了,大家需要的话可以联系我,应该阿里云的可以下载吧,貌似可以。
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
检查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
nginx-ingress-controller-7bd47796f8-87w6m 1/1 Running 0 29h 192.168.1.102 k8s-master-02
nginx-ingress-controller-7bd47796f8-lgbtw 1/1 Running 0 29h 192.168.1.104 k8s-node-01
节点本机端口状态
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.1.102
default backend - 404
curl 192.168.1.104
default backend - 404
这ingress相关部署完成,但是在实际情况下还需配置后端的server,我们用Nginx为例。
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
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- 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的配置文件。然后依次执行这三个文件,我就不写相关命令了。
查看pod
查看service
查看ingress中的域名
kubectl get ingresses.extensions -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-test-ingress k8s.nginx.com 80 29h
改下hosts文件浏览器上看下,奇迹发生了。
这样就发布出来了一个服务,下一部分将针对Nginx.yaml中的配置做具体的说明。
这个就比较简单,上部分部署的时候,已经写了。在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-ingressk8s.nginx.com 80 7d23h
如果没有配置域名,可以用相关IP访问,在查看ingress中的HOSTS中显示。
扇出(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
基于名称的虚拟主机支持将针对多个主机名的 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
在这配置中,如果非以上两个域名,会走最后一个里面。
通过设定包含 TLS 私钥和证书的Secret 来保护 Ingress。 Ingress 只支持单个 TLS 端口 443,并假定 TLS 连接终止于 Ingress 节点 (与 Service 及其 Pod 之间的流量都以明文传输)。 如果 Ingress 中的 TLS 配置部分指定了不同的主机,那么它们将根据通过 SNI TLS 扩展指定的主机名 (如果 Ingress 控制器支持 SNI)在同一端口上进行复用。 TLS Secret 必须包含名为 tls.crt
和 tls.key
的键名。 这些数据包含用于 TLS 的证书和私钥。
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: #base64 编码的 cert
tls.key: #base64 编码的 key
type: kubernetes.io/tls
Ingress 中引用此 Secret 将通知Ingress 控制器使用 TLS 加密从客户端到负载均衡器的通道。 需要确保创建的 TLS Secret 创建自包含 https-example.foo.com
的证书。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
更新ingress必须通过修改yaml文件么?答案是否定的
kubectl edit ingress test
这就可以更新了,但是建议从yaml文件更新,如果用edit做更新,时间久了会忘了都配置了什么,造成一定的失误,这都是经验之谈。