K8S-INGRESS原理,部署及应用

       

一. 题记


       各位,总算回来!博客断更快一年了吧,这一年过的真不容易,和疫情一样。公司降薪换工作,到了新公司和我八字不合,差点给我整出来抑郁症,又开始换工作,刚稳定了两周,又出车祸了,被一个老大爷骑着三轮车怼成了骨折。自己遭罪又贴钱,倒了血霉了。这本命年真是不好过呀。还好到年底了,这一年就要结束了。小太爷又回来了!回来就好,回来就继续写博客吧,就这命了!我记得k8s原理我写到了pod原理这块,先放放,刚做了ingress,先学这个吧,这个有点意思。
       我打算用三个部分来写ingress,理论知识,部署及应用。理论篇幅比较长,可能需要一定的网络及运维基础,各位看官如果基础不好,咋办?等着吧,回头我有时间了写点网络基础及运维基础的文章。估计且得等呢,我保证退休之前肯定写完。第二部分将写部署相关,这个比较简单,也就是几个yaml文件,我会把原始文件贴出来,如果有哪不明白的可在留言区讨论。另外有需要镜像文件可给我留言,我传给大家,可能我的版本有点低。最后一部分将写点应用相关的,包括https,访问路径过滤,基于名称解析虚拟机,常用的就这几块吧,如果还有其他用的地方,可以给我留言,大家一起研究。好了,闲话少说,书归正传,开整!这说的就不少了,开整。

二.  k8s-ingress 的理论知识


       Ingress能把Service(Kubernetes的服务)配置成外网能够访问的URL,流量负载均衡,及SSL,并提供域名访问的虚拟主机等,客户通过访问URL(API资源服务的形式,例如:caas.one/kibana)进入和请求Service,一个Ingress控制器负责处理所有Ingress的请求流量,它通常是一个负载均衡器,它也可以设置在边界路由器上,或者由额外的前端来帮助处理HA方式的流量。如图所示:

K8S-INGRESS原理,部署及应用_第1张图片

1. k8s的访问方式 

        一般来说k8s对外服务的方式有三种

  1. LoadBlancer Service
  2. NodePort Service 
  3. 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组件

  1. 反向代理负载均衡器
  2. Ingress Controller
  3. 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进行创建和更新进行加载。

K8S-INGRESS原理,部署及应用_第2张图片

         从上图可以很清晰的看到,实际上请求进行被负载均衡器拦截,比如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/

K8S-INGRESS原理,部署及应用_第3张图片

3.2 端口的管理问题

        采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时,我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应Service IP就行了 。如下图所示:

K8S-INGRESS原理,部署及应用_第4张图片

 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。

K8S-INGRESS原理,部署及应用_第5张图片

        Ingress 简单的理解就是原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;那么问题来了:”Nginx 该怎么处理?”Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图

K8S-INGRESS原理,部署及应用_第6张图片

         实际上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 需要使用 apiVersionkind 和 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:  
Events:       

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 示例

类型 路径 请求路径 匹配与否?
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 类型

 4.6 多重匹配

        在某些情况下,Ingress 中的多条路径会匹配同一个请求。 这种情况下最长的匹配路径优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。

5. 主机名通配符

        主机名可以是精确匹配(例如“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: 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: 这个定义

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 "-"
      # 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不需要我们修改

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: 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 注意更改

        需要的两个镜像可能现在不太好下载了,大家需要的话可以联系我,应该阿里云的可以下载吧,貌似可以。

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              
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为例。

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

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的配置文件。然后依次执行这三个文件,我就不写相关命令了。

3.2 验证

查看pod

K8S-INGRESS原理,部署及应用_第7张图片

 查看service

 查看ingress中的域名

 kubectl get ingresses.extensions -o wide    
NAME                 CLASS    HOSTS           ADDRESS   PORTS   AGE
nginx-test-ingress      k8s.nginx.com             80      29h

改下hosts文件浏览器上看下,奇迹发生了。

K8S-INGRESS原理,部署及应用_第8张图片

         这样就发布出来了一个服务,下一部分将针对Nginx.yaml中的配置做具体的说明。

四. 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     k8s.nginx.com             80      7d23h

        如果没有配置域名,可以用相关IP访问,在查看ingress中的HOSTS中显示。

1.2 简单的扇出

        扇出(fanout)官网给的说法,说白了就是根据路径去访问不同的地址。一个扇出(fanout)配置根据请求的 HTTP URI 将来自同一 IP 地址的流量路由到多个 Service。 Ingress 允许你将负载均衡器的数量降至最低。

K8S-INGRESS原理,部署及应用_第9张图片

 

        看下具体的配置,这个比较容易理解,我就不做过多解释了:

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。

K8S-INGRESS原理,部署及应用_第10张图片

         配置如下 :

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 的证书和私钥。

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

1.5 更新ingress 

        更新ingress必须通过修改yaml文件么?答案是否定的

        

kubectl edit ingress test 

        这就可以更新了,但是建议从yaml文件更新,如果用edit做更新,时间久了会忘了都配置了什么,造成一定的失误,这都是经验之谈。

你可能感兴趣的:(k8s实践,kubernetes,容器,微服务)