据我当下所学,对于 Kubernetes 如何对外暴露服务,一个字—**service**,只要是集群内部要访问 pod,通过创建 service,可以做到使用ip访问,那如果想要对互联网提供服务,应该怎么去做,也不能一直使用 IP 访问,而且对于集群来说也是不安全的。本文提到的 Ingress 就是为了弥补 NodePort 存在的不足而生。
Ingress
公开集群外部到集群内服务的 http 和 https 路由。流量路由由 Ingress 资源上定义的规则控制。
Ingress 主要实现集群内所有服务的入口,通过一系列的规则集合来允许外部的访问。可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。 而 ingress 的具体实现是由 ingress Controller 实现。
可以将 Ingress 理解为一个 nginx 应用,它的规则理解为nginx.conf中的server模块,可以指定访问哪些ip哪些域名的哪些端口,可以被转发到哪个service所关联的pod。
Ingress Controller
上述Ingress的功能都依赖与 Ingress Controller,Ingress Controller 才是负责具体转发的组件,外部对集群请求的流量会先到达 Ingress Controller,而 Ingress 就是为了给 Ingress Controller 添加规则,告诉它应该怎么转发,为集群提供全局的负载均衡的能力。
Ingress Controller 并不是Kubernetes自带的组件,用户可以选择不同的Ingress Controller来实现目的,在这里可以参考供使用的 Ingress Controller
部署Ingress Controller
这里以 Kubernetes 官方维护的 Ingress Controller —基于 nginx 的 Ingress Controller 为例
此方法为NodePort方式暴露Ingress的方法:无法访问 raw.githubsercontent 的同学,请点击这里
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.46.0/deploy/static/provider/baremetal/deploy.yaml
国内用户需要修改镜像地址
containers:
- name: controller
image: acicn/ingress-nginx-controller:v0.46.0
imagePullPolicy: IfNotPresent
还需要添加使用宿主机网络的参数:ingress-controller 将会使用宿主机网络的 80 和 443 端口。
hostNetwork: true
containers:
- name: controller
部署安装
kubectl apply -f deploy.yaml
查看安装
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-ptkwd 0/1 Completed 0 2m59s
ingress-nginx-admission-patch-zdqzp 0/1 Completed 0 2m59s
ingress-nginx-controller-76fc46c57b-t897c 0/1 Running 0 2m59s
验证使用 Ingress
如果集群中存在多台节点,要查看 ingress-controller 被调度到了哪个节点,就要将那个节点的 ip 做之后域名的解析
wget https://www.feiyiblog.com/files/practise/nginx.yaml
将我的示例部署后,可以访问 http://nodeip:30000
<html>
<body>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<h1 style="text-align:center;color:#1E90FF">Welcome to FeiYi's© Blog</h1>
</body>
</html>
创建 Ingress
$ vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: nginx # 我的示例所在namespace
spec:
rules:
- host: feiyi.yanjiang.chai
http:
paths:
- path: /healhtz # 我自己写的页面
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
运行该规则
kubectl apply -f ingress.yaml
查看规则
$ kubectl get ingress -n nginx
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress <none> feiyi.yanjiang.chai x.x.x.x 80 18s
一定要添加本地解析,任何访问验证
$ curl feiyi.yanjiang.chai/healthz/
<html>
<body>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<h1 style="text-align:center;color:#1E90FF">Healthz Check</h1>
</body>
</html>
TLS
再来测试一下使用 https
来访问
证书创建
# 生产私钥
openssl genrsa -out tls.key 2048
# 根据私钥生成tls证书,注意CN是域名的形式
openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=feiyi.yanjiang.chai
# 根据生成的key和cert创建secret
kubectl create secret tls -n nginx nginx-tls --cert=tls.cert --key=tls.key
修改 Ingress 规则
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: nginx
spec:
# 添加以下4行即可
tls:
- hosts:
- feiyi.yanjiang.chai
secretName: nginx-tls
...
重新应用配置并访问验证
$ kubectl apply -f ingress.yaml
$ curl https://feiyi.yanjiang.chai/healthz/ --cacert ./tls/tls.cert
<!-- --cacert ./tls/tls.cert 是刚才生成的https文件 -->
<html>
<body>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<h1 style="text-align:center;color:#1E90FF">Healthz Check</h1>
</body>
</html>
关于ingress规则的说明
如上例子中,我创建的规则中 path 字段只有 /healthz,该路径也必须是服务 pod 中真实存在的,所以使用域名访问时必须加 healthz 路径,否则会报错404,这是因为没有匹配其它路径的规则。如果 path 的值为 /
,则服务中网页根目录的所有子目录都可以访问。这是我摸索了一下午才搞明白的。