K8s系列之:HTTP7层路由机制Ingress

K8s系列之:HTTP7层路由机制Ingress

  • 一、创建Ingress Controller和默认的backend服务
  • 二、定义Ingress策略
  • 三、Ingress的策略配置技巧
    • 1.转发到单个后端服务上
    • 2.同一域名下,不同的URL路径被转发到不同的服务上
    • 3.不同的域名(虚拟主机名)被转发到不同的服务上
    • 4.不使用域名的转发规则
  • 四、Ingress的TLS安全配置

Ingress资源对象用于将不同URL的访问请求转发到后端不同的Service,以实现HTTP层的业务路由机制。K8s使用了一个Ingress策略定义和一个具体的Ingress Controller实现了一个完整的Ingress负载均衡器。

  • 使用Ingress进行负载分发时,Ingress Controller将基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(即Pod)上,这样会跳过kube-proxy的转发功能,kube-proxy不再起作用。
  • Ingress Controller提供的是对外服务,则实际上实现的是边缘路由器的功能。

一、创建Ingress Controller和默认的backend服务

  • 在定义Ingress策略之前,需要先部署Ingress Controller,以实现所有后端Service提供一个统一的入口。
  • Ingress Controller需要实现基于不同HTTP URL向后转发的负载分发规则,并可以设置7层的负载分发策略。
  • 在K8s中,Ingress Controller将以Pod形式运行,监控apiserver的ingress接口后端的backend service,如果service发生变化,则Ingress Controller应自动更新其转发规则。

例子:使用Nginx来实现一个Ingress Controller,需要实现的基本逻辑如下:

  • 监听apiserver,获取全部ingress的定义
  • 基于ingress的定义,生成Nginx所需的配置文件/etc/nginx/nginx.conf
  • 执行nginx -s relocad命令,重新加载nginx.conf配置文件的内容。

使用nginx-ingress-controller镜像来创建Ingress Controller。该Ingress Controller以daemonset的形式进行创建,在每个Node上都将启动一个Nginx服务。

为Nginx容器设置了hostPort,将容器应用监听的80和443端口号映射到物理机上,使得客户端应用可以通过URL地址"http://物理机IP:80"或"https://物理机IP:443"来访问该Ingress Controller。使得Nginx类似于通过NodePort映射到物理机的Service,成为代替kube-proxy的HTTP层的Load Balancer。

nginx-ingress-daemonset.yaml

apiVersion: extensions/v1beta1
kind: Daemonset
metadata:
  name: nginx-ingress-1b
  labels:
    name: nginx-ingress-1b
  namespace: kube-system
spec:
  template:
    metadata:
      labels:
        name: nginx-ingress-1b
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2
        name: nginx-ingress-1b
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        ports:
        - containerPort: 80
          hostPort: 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

为了让Ingress Controller能够正常启动,还需要配置一个默认的backend,用于在客户端访问的URL地址不存在时,能够返回一个正确的404应答。这个backend服务用任何应用实现都可以,只要满足默认对路径的访问返回404应答,并且提供/healthz路径以使kubelet完成对它的健康检查。由于Nginx通过default-backend-service的服务名称去访问它,所以需要DNS服务正确运行。

default-backend.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: default-http-backend
  labels:
    k8s-app: default-http-backend
  namespace: kube-system
spec:
  replicas: 1
  template:
    metadata:
      labels: 
        k8s-app: default-http-backend
      spec:
        terminationGracePeriodSeconds: 60
        containers:
        - name: default
          image: gcr.io/google_containers/defaultbackend:1.0
          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: kube-system
  labels:
    k8s-app: default-http-backend
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    k8s-app: default-http-backend

通过kubectl create命令创建backend服务

kubectl create -f default-backend.yaml

创建nginx-ingress-controller:

kubectl create -f nginx-ingress-daemonset.yaml

查看default-http-backend和nginx-ingress-controller容器是否正确运行:

kubectl get po --namespace=kube-system
NAME        READY            STATUS        RESTARTS    AGE
default-http-backend-1132503640-841nv  1/1   Running  0 3m
kube-dns-v11-z3cb0       4/4        Running   0   10m
nginx-ingress-1b-5jbwv    1/1       Running   0    3m
nginx-ingress-1b-60j7h    1/1       Running   0    3m
nginx-ingress-1b-dttr9    1/1       Running   0    3m

用curl访问任意Node的80端口号,验证nginx-ingress-controller和default-http-backend服务正常工作:

curl k8s-node-2
default backend - 404

二、定义Ingress策略

对mywebsite.com网站的访问设置Ingress策略,定义对/demo路径的访问转发到后端webapp Service的规则:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: mywebsite-ingress
spec:
  rules:
  - host: mywebsite.com
    http:
      paths:
      - path: /demo
        backend:
          serviceName: webapp
          servicePort: 8080

这个Ingress的定义,说明对目标地址http://mywebsite.com/demo的访问将被转发到集群中的Service webapp即webapp:8080/demo上。

在Ingress生效前,需要先将webapp服务部署完成。同时需要注意Ingress中path的定义,需要与后端真实Service提供的path一致,否则将会转发到一个不存在的path上,引发错误。

创建service webapp

apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 1
  selector:
    app: myweb
  template:
    metadata:
      labels:
        name: myweb
    spec:
      containers:
      - name: myweb
        image: kubeguide/tomcat-app:v1
        ports:
        - containerPort: 8080
        env:
        - name: MYSQL_SERVICE_HOST
          value: 'mysql'
        - name: MYSQL_SERVICE_PORT
          value: '3306'
apiVersion: v1
kind: Service
metadata:
  name: myweb
spec:
  selector:
    app: myweb

创建Ingress:

kubectl create -f ingress.yaml

kubectl get ingress -o wide
NAME        HOSTS         ADDRESS       PORTS     AGE
mywebsite-ingress  mywebsite.com 192.168.18.3,192.168.18.4,192.168.18.5  80  59s

在成功创建该Ingress后,查看ADDRESS列,显示了所有nginx-ingress-controller Pod的IP地址,表示Nginx已经设置好后端Service的Endpoint,该Ingress可以正常工作。如果ADDRESS列为空,通常说明Nginx未能正确连接到后端Service。

登陆任一nginx-ingress-controller Pod,查看其自动生成的nginx.conf配置文件内容,可以看到对mywebsite.com/demo的转发规则的正确配置。

三、Ingress的策略配置技巧

1.转发到单个后端服务上

基于这种设置,客户端到Ingress Controller的访问请求都将被转发到后端唯一Service上,这种情况下无须定义任何rule

通过如下所示设置,对Ingress Controller的访问请求都将被转发到"myweb:8080"这个服务上。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  backend:
    serviceName: myweb
    servicePort: 8080

2.同一域名下,不同的URL路径被转发到不同的服务上

这种配置常用于一个网站通过不同的路径提供不同的服务的场景,例如/web表示访问web页面,/api表示访问API接口,对应到后端的两个服务,通过Ingress的设置很容易就能将基于URL路径转发规则定义出来。

通过如下所示的设置,对mywebsite.com/web的访问请求将被转发到web-service:80服务上,对mywebsite.com/api的访问请求将被转发到api-service:80服务上。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  rules:
  - host: mywebsite.com
    http:
      path: /web
      backend:
        serviceName: web-service
        servicePort: 80
      - path: /api
        backend:
          serviceName: api-service
          servicePort: 8081

3.不同的域名(虚拟主机名)被转发到不同的服务上

这种配置常用于一个网站通过不同的域名或虚拟机主机名提供不同的服务的场景,例如foo.bar.com域名由service1提供服务,too.bar.com域名由service2提供服务。

通过如下所示的设置,对foo.bar.com的访问请求将被转发到service1:80服务上,对too.bar.com的访问请求将被转发到service2:80服务上。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: service1
          servicePort: 80
   - host: too.bar.com
     http:
       paths:
       - backend:
           serviceName: service2
           servicePort: 80

4.不使用域名的转发规则

这种配置用于一个网站不使用域名直接提供服务的场景,通过任意一台运行ingress-controller的Node都能访问到后端的服务。

以上节的后端服务webapp为例,下面的配置为将/demo的访问请求转发到webapp:8080/demo服务上。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  rules:
  - http:
      paths:
      - path: /demo
        backend:
          serviceName: webapp
          servicePort: 8080

使用无域名的Ingress转发规则时,将默认禁用非安全HTTP,强制启用HTTP,HTTP的访问请求直接返回301错误。

可以在Ingress的定义中设置一个annotation "ingress.kubernetes.io/ssl-redirect=false"来关闭强制启用HTTPS的设置。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
  	ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - http:
      paths:
      - path: /demo
        backend:
          serviceName: webapp
          servicePort: 8080

四、Ingress的TLS安全配置

为了使得Ingress提供HTTPS的安全访问,可以为Ingress中的域名进行TLS安全证书的设置。设置的步骤如下:

  • 创建自签名的密钥和SSL证书文件
  • 将证书保存到K8s中的一个Secret资源对象上
  • 将该Secret对象设置到Ingress中

使用OpenSSL工具直接生成密钥和证书文件,将命令行参数-subj中的/CN设置为网站域名。

openssl req -x509 -nodes -days 5000 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=mywebsite.com"

方式一:通过kubectl create secret tls命令直接通过tls.key和tls.crt文件创建secret对象。

kubectl create secret tls mywebsite-ingress-secret --key tls.key --cert tls.crt

方式二:编辑mywebsite-ingress-secret.yaml文件,将tls.key和tls.crt文件的内容复制进去,使用kubectl create命令进行创建。
mywebsite-ingress-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mywebsite-ingress-secret
type: kubernetes.io/tls
data:
  tls.crt:
  tls.key:
kubectl create -f mywebsite-ingress-secret.yaml

你可能感兴趣的:(日常分享专栏,K8s系列,HTTP7层路由机制,Ingress)