Ingress
管理群集中服务的外部访问的API对象,通常是HTTP。
Ingress可以提供负载平衡,SSL 终止和基于名称的虚拟主机。
Ingress是什么
Ingress, Kubernetes v1.1开始增加的,暴露集群 services 的 http和https的路由。流量路由规则的控制是定义在Ingress resource。
internet | [ Ingress ] --|-----|-- [ Services ]
Ingress可以给service提供集群外部访问的URL、负载均衡、SSL终止、基于名称的虚拟主机。 Ingress controller 负责实现Ingress的功能, 通常是一个负载均衡器, 它监听Ingress和service的变化,并根据规则配置负载均衡并提供访问入口。
Ingress不会暴露任意端口或协议。将HTTP和HTTPS以外的服务公开给Internet通常使用Service.Type = NodePort或Service.Type = LoadBalancer。
The Ingress Resource
最简单的Ingress Resource示例如下
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
与其他的Kubernetes resources一样,Ingress需要apiVersion
, kind
, 和 metadata
属性.
有关配置的其他属性配置,参见 deploying applications, configuring containers, managing resources.
Ingress经常使用注释来配置一些选项,具体取决于Ingress控制器, 参见例子 rewrite-target annotation.
不同的 Ingress controller 支持不同的注释. 阅读你选择的Ingress controller的文档,查看支持那些注释.
Ingress规范具有配置负载均衡器或代理服务器所需的所有信息。 最重要的是,它包含与所有传入请求匹配的规则列表。 Ingress资源仅支持HTTP流量的规则。
Ingress 规则
每个http规则都包含以下信息:
- 可选主机。 在此示例中,未指定主机,因此该规则适用于通过指定的IP地址的所有入站HTTP流量。 如果提供了主机(例如,foo.bar.com),则规则适用于该主机。
- 路径列表(例如,/ testpath),每个路径都会定义serviceName和servicePort关联后端。 主机和路径都必须与传入请求的内容匹配,以便负载均衡器能够直接引用到后端服务。
- 后端是在 services 文档中定义的服务名称和端口名称的组合. 对Ingress匹配的主机和路由规则的HTTP(和HTTPS)请求将被发送到列出的后端。
默认后端通常在Ingress控制器中配置,该控制器将为与规范中的路径不匹配的请求提供服务。
默认后端
没有规则的Ingress将所有流量发送到单个默认后端。 默认后端通常是Ingress控制器的一个配置选项,并且未在Ingress资源中指定。
Ingress类型
1、单服务Ingress
现有的Kubernetes概念允许公开单个服务 (参见 alternatives)。也可以通过指定没有规则的默认后端来使用Ingress执行此操作。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
如果你使用 kubectl apply -f
你将会看到如下信息:
kubectl get ingress test-ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 107.178.254.228 80 59s
其中107.178.254.228是Ingress controller为满足此Ingress而分配的IP。
2、路由到多服务的Ingress
多服务配置根据请求的HTTP URI将流量从单个IP地址路由到多个服务。Ingress允许将负载均衡器的数量降至最低。例如,设置如下:
foo.bar.com -> 178.91.123.132 -> / foo service1:4200
/ bar service2:8080
可以通过下面的Ingress来定义:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
使用kubectl create -f
创建完ingress后:
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
只要服务(s1,s2)存在,Ingress控制器就会提供满足Ingress特定实现的负载均衡器。创建完成后,可以在Address 字段中查看负载均衡器的地址。
3、基于名称的虚拟主机
虚拟主机Ingress即根据名字的不同转发到不同的后端服务上,而他们共用同一个的IP地址
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
下面是一个基于Host header路由请求的Ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
如果你创建的Ingress resouce 没有在rules中定义任何主机,然后,基于 Ingress controller 的IP地址的web请求能够匹配到没有名称的虚拟主机。例如,以下Ingress resource 会将first.bar.com
请求路由到service1
,将second.foo.com
路由到service2
,其他只有IP地址没有定义hostname(即没有在header中定义hostname)将会路由到service3
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: first.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: second.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
- http:
paths:
- backend:
serviceName: service3
servicePort: 80
4、TLS
您可以通过指定包含TLS私钥和证书的 secret 来加固Ingress。目前,Ingress仅支持一个TLS的端口 443,并假定TLS终止。如果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 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls
在Ingress引用此secret,就是告诉Ingress controller使用TLS保护从客户端到负载均衡器的信道。你需要确保你创建的TLS Secret来自包含sslexample.foo.com的CN的证书。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- sslexample.foo.com
secretName: testsecret-tls
rules:
- host: sslexample.foo.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80
不同Ingress controller支持的TLS功能不尽相同。 请参阅有关nginx,GCE或任何其他Ingress controller的文档,以了解TLS的支持情况。
4、负载均衡
Ingress controller通过一些负载均衡策略设置进行自举,该策略设置适用于所有Ingress,例如负载平衡算法,后端权重方案等。 其他的一些高级的负载平衡概念(例如,持久会话,动态权重)没有通过Ingress公布。 不过你仍然可以通过负载均衡器获得这些功能。
值得注意的是,即使健康检查没有直接通过Ingress公开,Kubernetes中也存在类似概念,例如readiness探针,它们可以实现相同的最终结果。你可以参阅controller的文档,了解它们如何处理健康检查 ( nginx, GCE)。
5、更新Ingress
要更新现有的Ingress以添加新主机,您可以通过编辑资源来更新它:
kubectl describe ingress test
Name: test
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 s1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
kubectl edit ingress test
这应该会弹出一个包含现有yaml的编辑器,修改它以包含新主机:
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
path: /foo
- host: bar.baz.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
path: /foo
..
保存yaml将更新API服务器中的资源,这会告诉Ingress controller重新配置负载均衡器。
kubectl describe ingress test
Name: test
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 s1:80 (10.8.0.90:80)
bar.baz.com
/foo s2:80 (10.8.0.91:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
你可以通过在修改的Ingress yaml文件,然后调用kubectl replace -f
来实现同样的目的。
Ingress Controllers
Ingress 正常工作需要集群中运行 Ingress Controller。Ingress Controller 与其他作为 kube-controller-manager 中的在集群创建时自动启动的 controller 成员不同,需要用户选择最适合自己集群的 Ingress Controller.
Kubernetes项目目前支持和维护GCE and nginx controllers。
Ingress Controller 以 Kubernetes Pod 的方式部署,以 daemon 方式运行,保持 watch Apiserver 的 /ingress 接口以更新 Ingress 资源,以满足 Ingress 的请求。比如可以使用 Nginx Ingress Controller:
其他 Ingress Controller 还有:
Ambassador API Gateway is an Envoy based ingress controller with community or commercial support from Datawire.
AppsCode Inc. offers support and maintenance for the most widely used HAProxy based ingress controller Voyager.
Contour is an Envoy based ingress controller provided and supported by Heptio.
Citrix provides an Ingress Controller for its hardware (MPX), virtualized (VPX) and free containerized (CPX) ADC for baremetal and cloud deployments.
F5 Networks provides support and maintenance for the F5 BIG-IP Controller for Kubernetes.
Gloo is an open-source ingress controller based on Envoy which offers API Gateway functionality with enterprise support from solo.io.
HAProxy based ingress controller jcmoraisjr/haproxy-ingress which is mentioned on the blog post HAProxy Ingress Controller for Kubernetes. HAProxy Technologies offers support and maintenance for HAProxy Enterprise and the ingress controller jcmoraisjr/haproxy-ingress.
Istio based ingress controller Control Ingress Traffic.
Kong offers community or commercial support and maintenance for the Kong Ingress Controller for Kubernetes.
NGINX, Inc. offers support and maintenance for the NGINX Ingress Controller for Kubernetes.
Traefik is a fully featured ingress controller (Let’s Encrypt, secrets, http2, websocket), and it also comes with commercial support by Containous.
使用多个Ingress controllers
你可以在集群中部署多个 any number of ingress controllers. 当你在集群中部署多个ingress controllers时,你创建ingress时需要使用注释指定 ingress.class
,这样集群才能选取正确的ingress controller.
当你没有指定ingress.class
,云提供商可能会使用默认的ingress 入口.
一般而言,所有Ingress controllers都应满足此规范,但各种Ingress controllers的运行方式略有不同。
查看Ingress controller的文档以了解选择它的注意事项
我们接下来会具体介绍kubernetes/ingress-nginx,以此作为一个示例来介绍Ingress controllers.
ingress-nginx
Kubernetes是一个开源容器调度和编排系统,最初由Google创建,然后捐赠给Cloud Native Computing Foundation。 Kubernetes自动调度容器在服务器集群中运行,解放了开发人员和运维人员容器编排的复杂的任务。 Kubernetes目前时最受欢迎的容器调度和编排系统。
NGINX Ingress Controller 为Kubernetes应用程序提供企业级交付服务,为开源NGINX和NGINX Plus的用户带来便捷.使用NGINX Ingress Controller 可以提供一下特性,负载平衡、SSL / TLS终止、URI重写、SSL / TLS加密。NGINX Plus还可以为有状态的应用提供session 持久化支持,API的jwt身份验证等功能。
ingress-nginx 安装
1、先决条件和通用部署命令
默认配置监视所有命名空间的Ingress对象。 要更改此行为,请使用--watch-namespace将范围限制为特定命名空间。
如果多个Ingress为同一主机定义不同的路径,则 ingress controller 将合并定义。
如果你正在使用GKE,则需要使用以下命令将当前用户初始化为集群管理员:kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin \ --user $(gcloud config get-value account)
yaml 文件:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
部署方式有两种,一种是创建service 使用NodePort暴露ingress-nginx,另外一种方式是使用本机网络,添加hostNetwork: true
我们接下来使用这两种方式进行部署:
1、创建ingress-nginx-service(官方文档)
1.1、首先根据mandatory.yaml 文件创建对应的ingress相关
[root@k8s ~]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
deployment.extensions/default-http-backend created
service/default-http-backend created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
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
deployment.extensions/nginx-ingress-controller created
验证安装
检查ingress controller pods 是否正常启动,请运行下面的命令:
kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
[root@k8s ~]# kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-65795b86d-28lfr 1/1 Running 0 2m55s
1.2、创建ingress-nginx-service.yaml文件,并apply
ingress-nginx-service.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
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@k8s ~]# kubectl apply -f ingress-nginx-service.yaml
service/ingress-nginx created
1.3、测试
Ingress Controller 部署部署好了,现在要写ingress的规则,注入到ingress-nginx pod的配置文件中
[root@k8s ~]# cat test-nginx-service.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
[root@k8s ~]# kubectl apply -f test-nginx-service.yaml
ingress.extensions/test-service-ingress created
查看ingress
[root@k8s ~]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
test-service-ingress ancs.nginx.com 80 33s
访问的客户端的机器配置下域名解析
现在我们可以通过ancs.nginx.com:30080来访问到后端代理的pod了
这里是使用http访问的,如果要用https,首先我们要创建一个证书,步骤如下:
自签证书
[root@k8s https]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=Beijing/L=Beijing/O=ancs/CN=ancs.nginx.com"
Generating a 2048 bit RSA private key
......................+++
...........................+++
writing new private key to 'tls.key'
-----
[root@k8s https]# ls
tls.crt tls.key
当然也可以使用cfssl自签证书。It‘s up to you!
创建 secret 资源, 证书生成好了,然后把证书转成secret
[root@k8s https]# kubectl create secret tls ancs-secret --key tls.key --cert tls.crt
secret/ancs-secret created
修改test-nginx-service.yaml文件
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
tls:
- hosts:
- ancs.nginx.cn
secretName: ancs-secret
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
现在我们可以通过https访问了
2、使用宿主机网络,增加 hostNetwork: true
2.1 修改mandatory.yaml配置文件,在container中增加配置项 hostNetwork: true 表示使用本机网络
注意事项:
在创建ingress-nginx-controller容器之前,需要修改kube-proxy配置
在/opt/kubernetes/cfg/kube-proxy配置文件里增加一行:--masquerade-all=true 然后重启kube-proxy 。
[root@k8s cfg]# cat kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true
--v=4
--hostname-override=10.0.52.14
--cluster-cidr=10.0.0.0/24
--proxy-mode=ipvs
--masquerade-all=true
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
配置项--masquerade-all的意思,参见官网说明kube-proxy,里面描述为:
--masquerade-all
If using the pure iptables proxy, SNAT all traffic sent via Service cluster IPs (this not commonly needed)
中文翻译:
--masquerade-all
如果使用纯 iptables 代理,SNAT 所有通过服务句群 IP 发送的流量(这通常不需要)
说人话的意思就是:
在kube-proxy中添加一个标志,以便为群集外流量维护伪装规则。 就像是:
iptables -t nat -I POSTROUTING ! -s "${CLUSTER_CIDR}" -j MASQUERADE
2.2、启动ingress-controller容器
[root@k8s ~]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx unchanged
deployment.extensions/default-http-backend unchanged
service/default-http-backend unchanged
configmap/nginx-configuration unchanged
configmap/tcp-services unchanged
configmap/udp-services unchanged
serviceaccount/nginx-ingress-serviceaccount unchanged
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole unchanged
role.rbac.authorization.k8s.io/nginx-ingress-role unchanged
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding unchanged
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding unchanged
deployment.extensions/nginx-ingress-controller configured
[root@k8s ~]# kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 0/1 ContainerCreating 0 31s
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 0/1 Running 0 43s
ingress-nginx nginx-ingress-controller-6b8cc9b76d-98szp 1/1 Running 0 47s
2.3、Ingress部署
2.3.1、 http部署和上面一样,参考上面就可以了。不再重复描述了。
2.3.2、https部署(使用cfssl)
利用cfssl颁发证书:
- 生成ca证书
cat << EOF | tee ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat << EOF | tee ca-csr.json
{
"CN": "www.ancs.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
- 生成server证书:
cat << EOF | tee ancs-csr.json
{
"CN": "www.ancs.com",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www ancs-csr.json | cfssljson -bare www.ancs.com
- 生成密钥
[root@k8s cfssl]# kubectl create secret tls ancs-secret --cert=www.ancs.com.pem --key=www.ancs.com-key.pem
secret/ancs-secret created
- 部署ingress
[root@k8s ~]# cat test-https-nginx-service.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service-ingress
namespace: default
spec:
tls:
- hosts:
- ancs.nginx.cn
secretName: ancs-secret
rules:
- host: ancs.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx
servicePort: 80
[root@k8s ~]# kubectl apply -f test-https-nginx-service.yaml
ingress.extensions/test-service-ingress created
[root@k8s ~]#
*配置hosts
-
浏览器访问
至此,我们ingress 部署就算完成了。