Ingress资源对象用于将不同URL的访问请求转发到后端不同的Service,以实现HTTP层的业务路由机制。K8s使用了一个Ingress策略定义和一个具体的Ingress Controller实现了一个完整的Ingress负载均衡器。
例子:使用Nginx来实现一个Ingress Controller,需要实现的基本逻辑如下:
使用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
对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 Controller的访问请求都将被转发到后端唯一Service上,这种情况下无须定义任何rule
通过如下所示设置,对Ingress Controller的访问请求都将被转发到"myweb:8080"这个服务上。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: myweb
servicePort: 8080
这种配置常用于一个网站通过不同的路径提供不同的服务的场景,例如/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
这种配置常用于一个网站通过不同的域名或虚拟机主机名提供不同的服务的场景,例如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
这种配置用于一个网站不使用域名直接提供服务的场景,通过任意一台运行ingress-controller的Node都能访问到后端的服务。
以上节的后端服务webapp为例,下面的配置为将
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提供HTTPS的安全访问,可以为Ingress中的域名进行TLS安全证书的设置。设置的步骤如下:
使用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