目录

  • Ingress
  • 1.ingress的组成
  • 2.ingress 工作原理
  • 3.ingress的优点
  • ingress controller 部署
  • ingress和ingress-controller进行流量转发部署步骤
  • 给nginx-ingress-contorller授权创建名称空间并创建nginx-ingress-controller
  • 部署后端的服务,如tomcat,并通过service进行暴露
  • 编写tomcat的ingress规则,并创建ingress资源
  • 测试Ingress https代理tomcat
  • 构建TLS站点

Ingress

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务。Kubernetes提供了NodePort, LoadBalancer和IngressNginx。

1.ingress的组成

Ingress Controller:Ingress Controller 可以理解为控制器,它通过不断的跟 Kubernetes API 交互,实时获取后端 Service、Pod 的变化,比如新增、删除等,然后结合 Ingress 定义的规则生成配置,然后动态更新上边的 Nginx 或者trafik负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。
Ingress服务:ingress可以把进入到集群内部的请求转发到集群中的一些服务上,从而可以把服务暴露到集群外部。Ingress 能把集群内Service 配置成外网能够访问的URL,流量负载均衡,提供基于域名访问的虚拟主机等;ingress是k8s中的资源,当service关联的后端pod ip地址发生变化,就会把这些变化信息保存在ingress中,由ingress注入到七层负载均衡调度器ingress controller中,也就是把信息传入到七层负载均衡调度器的配置文件中,并且重新加载使配置生效,Ingress 可以用来规定HTTP/S请求应该被转发到哪个 Service 上,比如根据请求中不同的Host和url路径让请求落到不同的 Service 上

2.ingress 工作原理

ingress格式 kubernetes kubernetes ingress controller_Group

ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化。
然后读取它,按照自定义的规则,去集群当中寻找对应Service管理的Pod。
再将生成的Nginx配置写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中。
然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。

3.ingress的优点

1.动态配置服务
如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作.
2.减少不必要的端口暴露
配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题。
kubectl explain ingress.spec
Ingress中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:
rules:用于定义当前Ingress资源的转发规则列表;由rules定义规则,或没有匹配到规则时,所有的流量会转发到由backend定义的默认后端。
defaultBackend:默认的后端用于服务那些没有匹配到任何规则的请求;定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。
tls:TLS配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向不同的主机,则需要通过SNI TLS扩展机制来支持该功能。
backend对象的定义由2个必要的字段组成:serviceName和servicePort,分别用于指定流量转发的后端目标Service资源名称和端口。rules对象由一系列的配置的Ingress资源的host规则组成,这些host规则用于将一个主机上的某个URL映射到相关后端Service对象,其定义格式如下:
spec:
  rules:
  - hosts: <string>
    http:
      paths:
      - path:
        backend:
          serviceName: <string>
          servicePort: <string>
需要注意的是,.spec.rules.host属性值,目前暂不支持使用IP地址定义,也不支持IP:Port的格式,该字段留空,代表着通配所有主机名。tls对象由2个内嵌的字段组成,仅在定义TLS主机的转发规则上使用。
hosts:包含 于 使用 的 TLS 证书 之内 的 主机 名称 字符串 列表, 因此, 此处 使用 的 主机 名 必须 匹配 tlsSecret 中的 名称。
secretName: 用于 引用 SSL 会话 的 secret 对象 名称, 在 基于 SNI 实现 多 主机 路 由 的 场景 中, 此 字段 为 可选。

    serviceName <string> -required-
    	Specifies the name of the referenced service.
	servicePort <string> -required-
    	Specifies the name of the referenced service.
rules <Object>:A list of host rules used to configure the Ingress. If unspecified,or no rule matches,all traffic is sent to the default backend.
	host <string>:
	http <Object>:
		paths <[]Object> -required-:A collection of paths that map requests to backends.
tls <Object>:

集群附件:

coreDNS/Hepster/dashboard/ingress/controller

ingress controller 部署

ingress和ingress-controller进行流量转发部署步骤

从前面的部署过程中,可以再次进行总结部署的流程如下:
①下载Ingress-controller相关的YAML文件,并给Ingress-controller创建独立的名称空间;
②部署后端的服务,如tomcat,并通过service进行暴露;
③部署Ingress-controller的service,以实现接入集群外部流量;
④部署Ingress,进行定义规则,使Ingress-controller和后端服务的Pod组进行关联。

给nginx-ingress-contorller授权创建名称空间并创建nginx-ingress-controller

kubectl apply -f nginx-ingress-controller-rbac.yml

#apiVersion: v1
#kind: Namespace
#metadata:  #这里是创建一个namespace,因为此namespace早有了就不用再创建了
#  name: kube-system
---
apiVersion: v1
kind: ServiceAccount    
metadata:
  name: nginx-ingress-serviceaccount #创建一个serveerAcount
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole   #这个ServiceAcount所绑定的集群角色
rules:
  - apiGroups:
      - "" 
    resources:    #此集群角色的权限,它能操作的API资源 
      - 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/v1
kind: Role
metadata:         
  name: nginx-ingress-role  #这是一个角色,而非集群角色 
  namespace: kube-system
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
      - create
      - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding       #角色绑定
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount #绑定在这个用户 
    namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
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   #集群绑定到这个serviceacount
    namespace: kube-system   #集群角色是可以跨namespace,但是这里只指明给这个namespce来使用
kubectl apply -f default-backend.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: default-http-backend
  labels:
    k8s-app: default-http-backend
  namespace: kube-system
spec:
  replicas: 1
  selector:
   matchLabels:
     k8s-app: default-http-backend
  template:
    metadata:
      labels:
        k8s-app: default-http-backend
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: default-http-backend
        # Any image is permissable as long as:
        # 1. It serves a 404 page at /
        # 2. It serves 200 on a /healthz endpoint
        image: registry.cn-hangzhou.aliyuncs.com/hachikou/defaultbackend:1.0
        livenessProbe:
          httpGet:
            path: /healthz   #这个URI是 nginx-ingress-controller中nginx里配置好的localtion 
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 30   #30s检测一次/healthz
          timeoutSeconds: 5
        ports:
        - containerPort: 8080
#        resources:
#          limits:
#            cpu: 10m
#            memory: 20Mi
#          requests:
#            cpu: 10m
#            memory: 20Mi
      nodeName: worker01
---
apiVersion: v1
kind: Service     #为default backend 创建一个service
metadata:
  name: default-http-backend
  namespace: kube-system
  labels:
    k8s-app: default-http-backend
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    k8s-app: default-http-backend
kubectl apply -f nginx-ingress-controller.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  labels:
    k8s-app: nginx-ingress-controller
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
       k8s-app: nginx-ingress-controller
  template:
    metadata:
      labels:
        k8s-app: nginx-ingress-controller
    spec:
      # hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
      # however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
      # that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
      # like with kubeadm
      # hostNetwork: true #注释表示不使用宿主机的80口,
      terminationGracePeriodSeconds: 60
      hostNetwork: true  #表示容器使用和宿主机一样的网络
      serviceAccountName: nginx-ingress-serviceaccount #引用前面创建的serviceacount
      containers:   
      - image: registry.cn-hangzhou.aliyuncs.com/peter1009/nginx-ingress-controller:0.20.0      #容器使用的镜像
        name: nginx-ingress-controller  #容器名
        readinessProbe:   #启动这个服务时要验证/healthz 端口10254会在运行的node上监听。 
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10  #每隔10做健康检查 
          timeoutSeconds: 1
        ports:
        - containerPort: 80  
          hostPort: 80    #80映射到80
#        - containerPort: 443
#          hostPort: 443
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
#        - --default-ssl-certificate=$(POD_NAMESPACE)/ingress-secret    #这是启用Https时用的
#      nodeSelector:  #指明运行在哪,此IP要和default backend是同一个IP
#        kubernetes.io/hostname: 10.3.1.17   #上面映射到了hostport80,确保此IP80,443没有占用.
# 
      nodeName: worker01

部署后端的服务,如tomcat,并通过service进行暴露

kubectl apply -f tomcat-demo.yaml

apiVersion: v1
kind: Service
metadata:
  name: tomcat
  namespace: default
spec:
  selector:
    app: tomcat
    release: canary
  ports:
  - name: http
    targetPort: 8080
    port: 8080
  - name: ajp
    targetPort: 8009
port: 8009
- name: https
port: 443
targetPort: 443
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat
      release: canary
  template:
    metadata:
      labels:
        app: tomcat
        release: canary
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5.34-jre8-alpine   
        ports:
        - name: http
          containerPort: 8080
          name: ajp
          containerPort: 8009

编写tomcat的ingress规则,并创建ingress资源

kubectl apply -f ingress-tomcat.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: tomcat
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: tomcat.zhang.com    #主机域名
    http:
      paths:
      - path:
        backend:
          serviceName: tomcat
          servicePort: 8080

测试Ingress https代理tomcat

构建TLS站点

(1)准备证书,在k8s的master节点操作
openssl genrsa -out tls.key 2048

openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.lucky.com

(2)生成secret,在k8s的master节点操作
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key

(3)查看secret
kubectl get secret
显示如下:
tomcat-ingress-secret   kubernetes.io/tls                     2      56s
(4)查看tomcat-ingress-secret详细信息
kubectl describe secret tomcat-ingress-secret

显示如下:
Name:         tomcat-ingress-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>
Type:  kubernetes.io/tls
Data
====
tls.key:  1679 bytes
tls.crt:  1294 bytes

(5)创建ingress
cat ingress-tomcat-tls.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - tomcat.zhang.com
    secretName: tomcat-ingress-secret
  rules:
  - host: tomcat.zhang.com
    http:
      paths:
      - path:
        backend:
          serviceName: tomcat
          servicePort: 8080

更新yaml文件
kubectl apply -f ingress-tomcat-tls.yaml