k8s系列---ingress资源和ingress-controller

 https://www.cnblogs.com/zhangeamon/p/7007076.html

http://blog.itpub.net/28916011/viewspace-2214747/

以下内容总结自上面两个连接。实验环节自己已全部实现,偷懒就全复制过来了

一、Ingress 介绍

Kubernetes 暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress;

LoadBlancer Service 是 kubernetes 深度结合云平台的一个组件;当使用 LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前 LoadBlancer Service 支持的云平台已经相对完善,比如国外的 GCE、DigitalOcean,国内的 阿里云,私有云 Openstack 等等,由于 LoadBlancer Service 深度结合了云平台,所以只能在一些云平台上来使用

NodePort Service 顾名思义,实质上就是通过在集群的每个 node 上暴露一个端口,然后将这个端口映射到某个具体的 service 来实现的,虽然每个 node 的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,还有端口冲突问题)实际使用可能并不多

Ingress 这个东西是 1.2 后才出现的,通过 Ingress 用户可以实现使用 nginx 等开源的反向代理负载均衡器实现对外暴露服务,以下详细说一下 Ingress,毕竟 traefik 用的就是 Ingress

1.1、Ingress 是个什么玩意

可能从大致印象上 Ingress 就是能利用 Nginx、Haproxy 啥的负载均衡器暴露集群内服务的工具;那么问题来了,集群内服务想要暴露出去面临着几个问题:

1.2、Pod 漂移问题

众所周知 Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,总之一句话,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Service IP 上

1.3、端口管理问题

采用 NodePort 方式暴露服务面临一个坑爹的问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 这思路很好,简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了

1.4、域名分配及动态更新问题

从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?这时候 “伟大而又正直勇敢的” Ingress 登场,如果不算上面的 Nginx,Ingress 只有两大组件:Ingress Controller 和 Ingress

Ingress 这个玩意,简单的理解就是 你原来要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yml 创建,每次不要去改 Nginx 了,直接改 yml 然后创建/更新就行了;那么问题来了:”Nginx 咋整?”

Ingress Controller 这东西就是解决 “Nginx 咋整” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下

当然在实际应用中,最新版本 Kubernetes 已经将 Nginx 与 Ingress Controller 合并为一个组件,所以 Nginx 无需单独部署,只需要部署 Ingress Controller 即可

1.5、使用 Ingress 时一般会有三个组件:

  • 反向代理负载均衡器
  • Ingress Controller
  • Ingress
1.5.1、反向代理负载均衡器

反向代理负载均衡器很简单,说白了就是 nginx、apache 什么的;在集群中反向代理负载均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等,不过个人喜欢以 DaemonSet 的方式部署,感觉比较方便

1.5.2、Ingress Controller

Ingress Controller 实质上可以理解为是个监视器,Ingress Controller 通过不断地跟 kubernetes API 打交道,实时的感知后端 service、pod 等变化,比如新增和减少 pod,service 增加与减少等;当得到这些变化信息后,Ingress Controller 再结合下文的 Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用

1.5.3、Ingress

Ingress 简单理解就是个规则定义;比如说某个域名对应某个 service,即当某个域名的请求进来时转发给某个 service;这个规则将与 Ingress Controller 结合,然后 Ingress Controller 将其动态写入到负载均衡器配置中,从而实现整体的服务发现和负载均衡

有点懵逼,那就看图

Ingress

从上图中可以很清晰的看到,实际上请求进来还是被负载均衡器拦截,比如 nginx,然后 Ingress Controller 通过跟 Ingress 交互得知某个域名对应哪个 service,再通过跟 kubernetes API 交互得知 service 地址等信息;综合以后生成配置文件实时写入负载均衡器,然后负载均衡器 reload 该规则便可实现服务发现,即动态映射

了解了以上内容以后,这也就很好的说明了我为什么喜欢把负载均衡器部署为 Daemon Set;因为无论如何请求首先是被负载均衡器拦截的,所以在每个 node 上都部署一下,同时 hostport 方式监听 80 端口;那么就解决了其他方式部署不确定 负载均衡器在哪的问题,同时访问每个 node 的 80 都能正确解析请求;如果前端再 放个 nginx 就又实现了一层负载均衡

实现:

  Ingress:就是能利用 Nginx(不常用)、Haproxy(不常用)、Traefik(常用)、Envoy(常用) 啥的负载均衡器暴露集群内服务的工具。

     Ingress为您提供七层负载均衡能力,您可以通过 Ingress 配置提供外部可访问的 URL、负载均衡、SSL、基于名称的虚拟主机等。作为集群流量接入层,Ingress 的高可靠性显得尤为重要。

    小知识:我们把k8s里面的pod服务发布到集群外部,可以用ingress,也可以用NodePort。 

    externalLB:外部的负载均衡器 

    service site:只是用来给pod分组归类的。

[root@master manifests]# kubectl explain ingress

  

创建名称空间:

[root@master manifests]# kubectl create namespace ingress-nginx
namespace/dev created
[root@master manifests]# kubectl get ns
NAME          STATUS    AGE
default       Active    17d
ingress-nginx   Active    8s
kube-public   Active    17d
kube-system   Active    17d

  

 访问 https://github.com/kubernetes/ingress-nginx,进入deploy目录,里面就有我们要用的yaml文件

各文件的作用:

configmap.yaml:提供configmap可以在线更行nginx的配置
default-backend.yaml:提供一个缺省的后台错误页面  404
namespace.yaml:创建一个独立的命名空间 ingress-nginx
rbac.yaml:创建对应的role rolebinding 用于rbac
tcp-services-configmap.yaml:修改L 4 负载均衡配置的configmap
udp-services-configmap.yaml:修改L 4 负载均衡配置的configmap
with-rbac.yaml:有应用rbac的nginx-ingress-controller组件
以上文件 我在做实验时发现,tcp和udp的已经合并到config里了,default也没了,default的pod也取消了。
访问https://kubernetes.github.io/ingress-nginx/deploy/#generice-deployment,里面是ingress的部署文档
 
[root@master ~]# mkdir  ingress-nginx
[root@master ~]# cd ingress-nginx

  

 部署ingress方法一(分步部署):

    下载如下配置文件: 

[root@master ingress-nginx]# for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml with-rbac.yaml udp-services-configmap.yaml; do wget  https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/$file; done

  

[root@master ingress-nginx]# ls
configmap.yaml  namespace.yaml  rbac.yaml  tcp-services-configmap.yaml  udp-services-configmap.yaml  with-rbac.yaml

  

1、创建名称空间: 删掉上面那个自己手动创建的。

[root@master ingress-nginx]# kubectl apply -f namespace.yaml 
namespace/ingress-nginx configured

  

2、把剩下的ymal文件全应用

[root@master ingress-nginx]# kubectl  apply -f ./
configmap/nginx-configuration created
namespace/ingress-nginx configured
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
configmap/tcp-services created
configmap/udp-services created
deployment.extensions/nginx-ingress-controller created

  

[root@master ingress-nginx]# kubectl get pods -n ingress-nginx -w
NAME                                        READY     STATUS              RESTARTS   AGE
default-http-backend-6586bc58b6-qd9fk       0/1       running    0          4m
nginx-ingress-controller-6bd7c597cb-zcbbz   0/1       running   0          1m

  

可以看到ingress-nginx名称空间里面有两个pod都处于running状态 

部署ingress方法二(一键部署): 

只下载mandatory.yaml文件,因为这个文件里面包含了上面所有yaml文件里面的内容。这是一键部署。

[root@master ingress-nginx]# wget 
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

  

[root@master ingress-nginx]#kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

  

[root@master ~]# kubectl get pods -n ingress-nginx -w  -o wide
NAME                                        READY     STATUS    RESTARTS   AGE       IP            NODE      NOMINATED NODE
default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          11h       10.244.1.95   node1     <none>
nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          11h       10.244.1.96   node1     <none>

  

可以看到ingress-nginx名称空间里面有两个pod都处于running状态

安装service-nodeport

    上面我们把ingress-nginx部署到了1号node上。接下来我们还需要部署一个service-nodeport服务,才能实现把集群外部流量接入到集群中来。 

[root@master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml

  

    我们为了不让service nodeport自动分配端口,我们自己指定一下nodeport,修改文件中加两个nodePort参数,最终如下:

[root@master ingress]# cat service-nodeport.yaml 
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
    nodePort: 30080
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
    nodePort: 30443
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

  

[root@master ingress]# kubectl apply -f service-nodeport.yaml 
service/ingress-nginx created

  

[root@master ingress]# kubectl get svc -n ingress-nginx
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
default-http-backend   ClusterIP   10.110.74.183   <none>        80/TCP                       12h
ingress-nginx          NodePort    10.102.78.188   <none>        80:30080/TCP,443:30443/TCP   2m

  

 上面我看到80对应30080,,43对应30443 

  我们直接通过node1节点的ip就可以访问到应用: 

[root@master ingress]# curl  http://172.16.1.101:30080
default backend - 404

  

定义myapp service

[root@master manifests]# mkdir /root/manifests/ingress
[root@master ~]# kubectl explain service.spec.ports

  

[root@master ingress]# cat deploy-demo.yaml 
apiVersion: v1
kind: Service
#必须设置为无头service
metadata:
 name: myapp
 namespace: default
spec:
  selector:
    app: myapp
    release: canary
  ports:
  - name: http
    targetPort: 80   #这是容器port
    port: 80  #这是service port
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

  

[root@master ingress]# kubectl apply -f deploy-demo.yaml 
service/myapp created
deployment.apps/myapp-deploy unchanged

  

[root@master ingress]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    17d
myapp        ClusterIP   10.108.177.62   <none>        80/TCP     1m

  

[root@master ingress]# kubectl get pods
NAME                            READY     STATUS             RESTARTS   AGE
myapp-deploy-69b47bc96d-79fqh   1/1       Running            0          1d
myapp-deploy-69b47bc96d-tc54k   1/1       Running            0          1d

  

把myapp service通过ingress发布出去

     下面我们再定义一个清单文件,把myapp应用通过Ingress(相当于nginx的反向代理功能)发布出去: 

[root@master ingress]# cat ingress-myapp.yaml 
apiVersion: extensions/v1beta1 
kind: Ingress
metadata:
  name: ingress-myapp
  namespace: default #要和deployment和要发布的service处于同一个名称空间
  annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: myapp.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
    http:
      paths: 
      - path:
        backend:
          serviceName: myapp
          servicePort: 80

  

[root@master ingress]# kubectl apply -f ingress-myapp.yaml 
ingress.extensions/ingress-myapp created

  

[root@master ingress]# kubectl get ingress
NAME            HOSTS              ADDRESS   PORTS     AGE
ingress-myapp   myapp.zhixin.com             80        8m

  

[root@master ingress]# kubectl describe ingress

  

[root@master ingress]# kubectl get pods -n ingress-nginx 
NAME                                        READY     STATUS    RESTARTS   AGE
default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          12h
nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          12h

  

   进入ingress-controller交互式命令行里面,可以清晰的看到nginx是怎么反向代理我们myapp.zhixin.com的: 

  

[root@master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-6bd7c597cb-jlqzp -- /bin/sh
$ cat nginx.conf
## start server myapp.zhixin.com
server {
server_name myapp.zhixin.com ;
listen 80;
set $proxy_upstream_name "-";
location / {
set $namespace      "default";
set $ingress_name   "ingress-myapp";
set $service_name   "myapp";
set $service_port   "80";
........

  

   测试,下面我们把myapp.zhixin.com域名解析到node1 ip 172.16.1.101上。
记得绑定host,并不是非得解析到node1上,直接到master我测的也可以,让master去往下代理

  

[root@master ingress]# curl myapp.zhixin.com:30080
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

  

把tomcat service通过ingress发布出去(新例子)

[root@master ingress]# cat tomcat-demo.yaml 
apiVersion: v1
kind: Service
#必须设置为无头service
metadata:
 name: tomcat
 namespace: default
spec:
  selector:
    app: tomcat
    release: canary
  ports:
  - name: http
    targetPort: 8080   #这是容器port
    port: 8080  #这是service port
  - name: ajp
    targetPort: 8009
    port: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deploy
  namespace: default
spec:
  replicas: 2
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: tomcat
      release: canary
  template:
    metadata:
      labels:
        app: tomcat #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5.34-jre8-alpine  #在https://hub.docker.com/r/library/tomcat/tags/上面找
        ports:
        - name: http
          containerPort: 8080
        - name: ajp
          containerPort: 8009

  

[root@master ingress]# kubectl apply -f tomcat-demo.yaml 
service/tomcat created
deployment.apps/tomcat-deploy created

  

[root@master ingress]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP             17d
tomcat       ClusterIP   10.109.76.87    <none>        8080/TCP,8009/TCP   1m

  

[root@master ingress]# kubectl get pods
NAME                             READY     STATUS             RESTARTS   AGE
tomcat-deploy-64c4d54df4-68sk8   1/1       Running            0          51s
tomcat-deploy-64c4d54df4-7b58g   1/1       Running            0          51s

  

[root@master ingress]# cat ingress-tomcat.yaml 
apiVersion: extensions/v1beta1 
kind: Ingress
metadata:
  name: ingress-tomcat
  namespace: default #要和deployment和要发布的service处于同一个名称空间
  annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: tomcat.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
    http:
      paths: 
      - path:
        backend:
          serviceName: tomcat
          servicePort: 8080

  

[root@master ingress]# kubectl apply -f ingress-tomcat.yaml 
ingress.extensions/ingress-myapp configured

  

[root@master ingress]# kubectl get ingress
NAME             HOSTS               ADDRESS   PORTS     AGE
ingress-tomcat   tomcat.zhixin.com             80        11s

  

[root@master ingress]# kubectl describe ingress ingress-tomcat
Name:             ingress-tomcat
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host               Path  Backends
  ----               ----  --------
  tomcat.zhixin.com  
                        tomcat:8080 (<none>)
Annotations:
  kubernetes.io/ingress.class:  nginx
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  CREATE  1m    nginx-ingress-controller  Ingress default/ingress-tomcat

  

   把tomcat.zhixin.com解析到node1上节点物理ip(我的是172.16.1.101),并不是要解析到node1上,作者理解错了

    测试,可以看到tomcat欢迎界面:

[root@master ingress]# curl tomcat.zhixin.com:30080

  

使用https访问(新例子)

1、先做个自签的证书(我们这里不演示CA的例子) 

[root@master ingress]# openssl genrsa -out tls.key 2048

  

[root@master ingress]# openssl req -new -x509 -key tls.key  -out tls.crt -subj /C=CN/ST=Beijing/O=DevOps/CN=tomcat.zhixin.com

  

2、通过secret把证书注入到pod中。 

[root@master ingress]# kubectl create secret tls tomcat-infress-secret --cert=tls.crt --key=tls.key 
secret/tomcat-infress-secret created

  

[root@master ingress]# kubectl get secret
NAME                    TYPE                                  DATA      AGE
default-token-5r85r     kubernetes.io/service-account-token   3         17d
tomcat-ingress-secret   kubernetes.io/tls                     2         41s

  

[root@master ingress]# kubectl describe secret tomcat-ingress-secret 
Name:         tomcat-ingress-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>
Type:  kubernetes.io/tls
Data
====
tls.crt:  1245 bytes
tls.key:  1679 bytes

  

3、配置ingress为tls方式

[root@master ingress]# cat ingress-tomcat-tls.yaml 
apiVersion: extensions/v1beta1 
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default #要和deployment和要发布的service处于同一个名称空间
  annotations: #这个注解说明我们要用到的ingress-controller是nginx,而不是traefic,enjoy
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - tomcat.zhixin.com
    secretName: tomcat-ingress-secret #kubectl get secret命令查到的名字
  rules:
  - host: tomcat.zhixin.com #表示访问这个域名,就会转发到后端myapp管理的pod上的服务:
    http:
      paths: 
      - path:
        backend:
          serviceName: tomcat
          servicePort: 8080

  

[root@master ingress]# kubectl get ingress
NAME                 HOSTS               ADDRESS   PORTS     AGE
ingress-tomcat       tomcat.zhixin.com             80        2h
ingress-tomcat-tls   tomcat.zhixin.com             80, 443   3m

  

[root@master ingress]# kubectl describe ingress ingress-tomcat-tls  
Name:             ingress-tomcat-tls
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<none>)
TLS:
  tomcat-ingress-secret terminates tomcat.zhixin.com
Rules:
  Host               Path  Backends
  ----               ----  --------
  tomcat.zhixin.com  
                        tomcat:8080 (<none>)
Annotations:
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-tomcat-tls","namespace":"default"},"spec":{"rules":[{"host":"tomcat.zhixin.com","http":{"paths":[{"backend":{"serviceName":"tomcat","servicePort":8080},"path":null}]}}],"tls":[{"hosts":["tomcat.zhixin.com"],"secretName":"tomcat-ingress-secret"}]}}
  kubernetes.io/ingress.class:  nginx
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  CREATE  4m    nginx-ingress-controller  Ingress default/ingress-tomcat-tls

  

4、连如ingress-controller查看nginx.conf的配置 

[root@master ingress]# kubectl get pods -n ingress-nginx
NAME                                        READY     STATUS    RESTARTS   AGE
default-http-backend-6586bc58b6-qd9fk       1/1       Running   0          16h
nginx-ingress-controller-6bd7c597cb-jlqzp   1/1       Running   3          16h

  

   看到有listen 443了。 

5、测试https 

浏览器访问,curl测不出来

猜你喜欢

转载自www.cnblogs.com/dribs/p/10286823.html