在kubernetes 集群中,一个服务安装以后怎么对外提供访问,外部用户怎么来访问我们容器中业务。
1、Ingress 介绍
Kubernetes 暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress;本文主要通过Ingress来访问
2、Ingress 是什么
Ingress 就是能利用 Nginx、Haproxy 啥的负载均衡器暴露集群内服务的工具问题来了,集群内服务想要暴露出去面临着几个问题:
Pod 漂移问题
众所周知 Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,总之一句话,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Service IP 上,如下图所示:端口管理问题
采用 NodePort 方式暴露服务面临一个坑爹的问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示域名分配及动态更新问题
从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?这时候 “伟大而又正直勇敢的” Ingress 登场,如果不算上面的 Nginx,Ingress 只有两大组件:Ingress Controller 和 Ingress
Ingress 简单的理解就是 你原来要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yml 创建,每次不要去改 Nginx 了,直接改 yml 然后创建/更新就行了;那么问题来了:”Nginx 咋整?”
Ingress Controller 这东西就是解决 “Nginx 咋整” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:
当然在实际应用中,最新版本 Kubernetes 已经将 Nginx 与 Ingress Controller 合并为一个组件,所以 Nginx 无需单独部署,只需要部署 Ingress Controller 即可。
3、Nginx Ingress
3.1、下载官方文件
官方的mandatory.yaml文件里面包含了ingress RBAC,重要的组件 Nginx+Ingres Controller
1 | # cat mandatory.yaml |
hostNetwork: true
是增加的, 官方的 Ingress Controller 有个坑,默认注释了hostNetwork 工作方式。以防止端口的在宿主机的冲突。没有绑定到宿主机 80 端口,也就是说前端 Nginx 没有监听宿主机 80 端口;所以需要把配置搞下来自己加一下 hostNetwork。
3.2、部署默认后端
我们知道 前端的 Nginx 最终要负载到后端 service 上,那么如果访问不存在的域名咋整?官方给出的建议是部署一个 默认后端,对于未知请求全部负载到这个默认后端上;这个后端啥也不干,就是返回 404,部署如下
1 | # cat default-backend.yaml |
3.3、执行创建,完成后可以看到
1 | # kubectl create -f mandatory.yaml |
1 | # kubectl get pods -n ingress-nginx |
4、部署 Ingress
从上面可以知道 Ingress 就是个规则,指定哪个域名转发到哪个 Service,所以说首先我们得有个 Service,当然 Service 去哪找这里就不管了;这里默认为已经有了两个可用的 Service,以下以 jenkins、Dashboard 为例
先写一个 Ingress 文件,语法格式啥的请参考 官方文档,由于我的 jenkins在kube-ops,Dashboard 在kube-system 这个命名空间,所以要指定 namespace.参考下面实例
4.1、部署jenkins实例
1 | # cat jenkins-ingress.yaml |
执行域名解析到ip地址,访问jenkins
4.2、部署kubernetes-dashboard
1 | # cat nginx-kubernetes-dashboard.yaml |
5、部署 Ingress TLS
上面已经做好了 Ingress,接下来配置TLS ;官方给出的样例很简单,大致步骤就两步:创建一个含有证书的 secret、在 Ingress 开启证书;但是官方的有坑,下面是操作步骤
5.1、创建证书
首先第一步当然要有个证书,由于我这个 Ingress 有两个服务域名,所以证书要支持两个域名;生成证书命令如下:
生成CA证书
1
# mkdir cert && cd cert
编辑 openssl 配置
1
# cp /etc/pki/tls/openssl.cnf .
修改主要配置
1
2
3# vi openssl.cnf
[req]
req_extensions = v3_req # 这行默认注释关着的 把注释删掉增加配置
1
2
3
4
5
6
7
8# vi openssl.cnf
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = dashboard.mritd.me #需要增加的域名
DNS.2 = kibana.mritd.me生成证书
1
2
3# openssl genrsa -out ingress-key.pem 2048
# openssl req -new -key ingress-key.pem -out ingress.csr -subj "/CN=kube-ingress" -config openssl.cnf
# openssl x509 -req -in ingress.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out ingress.pem -days 365 -extensions v3_req -extfile openssl.cnf查看生成后的证书
1
2# ls
ca-key.pem ca.pem ca.srl ingress-key.pem ingress.csr ingress.pem openssl.cnf
5.2、创建 secret
创建好证书以后,需要将证书内容放到 secret 中,secret 中全部内容需要 base64 编码,然后注意去掉换行符(变成一行);以下是我的 secret 样例(上一步中 ingress.pem 是证书crt,ingress-key.pem 是证书的 key)
1 | # vim ingress-secret.yml |
- 创建完成后 create
1
2# kubectl create -f ingress-secret.yml
secret/ingress-secret created
5.3、快速创建
5.2步骤可以简化创建,可以执行一条命令进行创建,
1 | # kubectl create secret tls ingress-secret --key cert/ingress-key.pem --cert cert/ingress.pem |
5.4、重新部署 Ingress
在tls生成完成后,需要重新部署Ingress,让Ingress能够家在tls。修改配置文件
5.4.1、jenkins tls
1 | # vi jenkins-ingress.yaml |
访问jenkins域名,这里输入http访问会强制跳转到https
5.4.2、kubernetes dashboard tls
1 | # vim nginx-kubernetes-dashboard.yaml |
6、ingress 高级用法
- lvs 反向代理到 物理nginx。完成https拆包,继承nginx所有功能
- nginx 反向代理到ingress-control。 ingress-control 有两种部署方式 。
- ingress-control 使用nodePort 方式暴漏服务
- ingress-control 使用hostNetwork 方式暴漏服务
7、总结分析
- ingress-control 在自己的所属的namespace=ingress, 是可以夸不同namespace提供反向代理服.
- 如果需要提供夸NS 访问ingress,先给 ingress-control创建RBAC
- ingress-control 使用hostnetwork 模式 性能比使用service nodePort 性能好很多。因为hostnetwork 是直接获取pod 的IP?