一、Ingress 简介
在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:
NodePort
LoadBalancer(负载均衡)
Ingress(入口)
Ingress 组成:ingress controller、ingress服务
ingress controller:
将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务:
将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可
Ingress 工作原理
- ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
- 然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置
- 再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
- 然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。
Ingress参考网站:
https://github.com/kubernetes/ingress-nginx
https://kubernetes.github.io/ingress-nginx/
Ingress 可以解决什么问题
1.动态配置服务
如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作.
2.减少不必要的端口暴露
配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式
实验需求:
创建2个Deployment,
第一个: nginx镜像,replicas:3
第二个: httpd镜像,replicas:4
创建2个SVC资源,
第一个和第一个Deploy绑定。
第二个和第二个Deploy绑定。
//这里是deploy1,deploy2的yaml文件。
kind: Deployment
apiVersion: apps/v1
metadata:
name: deploy1
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
```yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: deploy2
spec:
selector:
matchLabels:
app: httpd
replicas: 4
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd
imagePullPolicy: IfNotPresent
//创建对应的SVC资源,并与上述Deployment相互关联。
```yaml
kind: Service
apiVersion: v1
metadata:
name: svc1
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
```yaml
kind: Service
apiVersion: v1
metadata:
name: svc2
spec:
selector:
app: httpd
ports:
- protocol: TCP
port: 80
targetPort: 80
二、部署Ingress
//部署Ingress-controller.可以在GitHub:https://github.com/kubernetes/ingress-nginx上找到,这里我们部署的是Ingress:0.35.0版本
//这里我们可以先保存Ingress的yaml文件,可以查看都做了什么,也方便我们后期管理
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.35.0/deploy/static/provider/baremetal/deploy.yaml
//这里使用的镜像,是国外的镜像,需要提前下载获得。
#docker pull pollyduan/ingress-nginx-controller:v0.35.0
#docker tag pollyduan/ingress-nginx-controller:v0.35.0 k8s.gcr.io/ingress-nginx/controller:v0.35.0
//复制并编辑这个文件deploy.yaml。启用hostNetwork网络,添加 hostNetwork: true即可。 如果在Pod中使用hostNetwork:true配置网络,那么Pod中运行的应用程序可以直 接使用node节点的端口,这样node节点主机所在网络的其他主机,都可以通过该端 口访问到此应用程序。
[root@master ingress]# vim deploy.yaml
... ...
327 hostNetwork: true #添加本行
328 dnsPolicy: ClusterFirst
329 containers:
330 - name: controller
331 image: k8s.gcr.io/ingress-nginx/controller:v0.35.0 #修改本行
332 imagePullPolicy: IfNotPresent
... ...
PS: 添加hostNetwork: true,和更改可用镜像
kubectl apply -f deploy.yaml
//确保Pod正常运行。
[root@master ingress]# kubectl get po -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-qp6jq 0/1 Completed 0 20s 10.244.1.62 node01 <none> <none>
ingress-nginx-admission-patch-qzkfc 0/1 Completed 1 20s 10.244.2.98 node02 <none> <none>
ingress-nginx-controller-6995cf966b-c5mvd 1/1 Running 0 20s 10.244.1.63 node01 <none> <none>
[root@master ingress]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.109.23.90 <none> 80:30105/TCP,443:32457/TCP 3m33s
ingress-nginx-controller-admission ClusterIP 10.104.13.179 <none> 443/TCP 3m33s
//注意:Ingress-controller服务运行之后,还有一个manatora-svc.yaml文件,这个文件,是将
Ingress-controller的Deployment资源对象关联在一起了,也就是说,访问mandatora-svc就能否访问Ingress-controller的Depoyment资源的Pod的了。
//查看其yaml文件,发现它暴露的是NodePort类型。
[root@master ingress]# vim mandatory-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
//查看Ingress-nginx-controller容器内部详情:可以看到,它现在已经有一个模板,用来描述Ingress资源能够收集到的信息了。
```sh
[root@master ingress]# kubectl get po -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-9b4479c74-n6trz 1/1 Running 0 9m42s
[root@master ingress]#kubectl exec -it ingress-nginx-controller-9b4479c74-n6trz sh -n ingress-nginx
/etc/nginx $ cat nginx.conf
...
location / {
set $namespace "";
set $ingress_name "";
set $service_name "";
set $service_port "";
set $location_path "/";
...
基于httpd的访问
//创建对应的Ingress规则
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: bdqn-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: ingress.bdqn.com
http:
paths:
- path: /nginx
backend:
serviceName: svc1
servicePort: 80
- path: /httpd
backend:
serviceName: svc2
servicePort: 80
//查看对应规则的详细信息
[root@master ingress]# kubectl describe ingresses. bdqn-ingress
Name: bdqn-ingress
Namespace: default
Address: 10.106.32.255
Default backend: default-http-backend:80 ()
Rules:
Host Path Backends
ingress.bdqn.com
/nginx svc1:80 (10.244.1.98:80,10.244.1.99:80,10.244.2.104:80)
/httpd svc2:80 (10.244.1.100:80,10.244.1.101:80,10.244.2.105:80 + 1 more…)
//查看对应Pod内,也应该能够解析到对应的:SVC信息
[root@master ingress]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-9b4479c74-n6trz 1/1 Running 0 59m
[root@master ingress]# kubectl exec -it -n ingress-nginx ingress-nginx-controller-9b4479c74-n6trz sh
/etc/nginx $ vi nginx.conf
...
location ~* "^/nginx" {
set $namespace "default";
set $ingress_name "bdqn-ingress";
set $service_name "svc1";
set $service_port "80";
set $location_path "/nginx";
...
location ~* "^/httpd" {
set $namespace "default";
set $ingress_name "bdqn-ingress";
set $service_name "svc2";
set $service_port "80";
set $location_path "/httpd";
...
//来模拟访问,这里我们用Windows的浏览器直接访问,因为我们是模拟的域名所以,需要我们在hosts文件内写入对应的域名解析。Windows10的域名解析文件地址:C:\Windows\System32\drivers\etc,更改这个文件的时候,需要提供管理员权限。
//添加域名解析内容,当然,如果你的mandatory没有做对应的svc的话,需要解析IP是ingress-nginx-controller这个Pod运行所在的节点,如果运行了mandatory-svc.yaml的话,就可以解析为集群的任何一个节点的IP地址。这里我们解析为集群的master节点的IP(因为上边我们运行了mandatory-svc.yaml文件)
192.168.8.30 ingress.bdqn.com
//然后使用浏览器访问:http://ingress.bdqn.com/nginx
//对应httpd的访问:http://ingress.bdqn.com/httpd
总结: Mandatory-svc,这个SVC,就等于是将nginx-ingress-controller做了一个NodePort类型的SVC,提供了一个统一的访问入口,这样可以避免暴露端口过多的情况。
基于http实现虚拟机主机的访问
//此实验的前提是: Ingress-nginx-controller服务在集群中,已经完成部署。
[root@master vhost]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-9b4479c74-n6trz 1/1 Running 0 21h
//编辑ingress1.bdqn.io域名所需要的Deployment和SVC资源。
kind: Deployment
apiVersion: apps/v1
metadata:
name: deploy3
spec:
selector:
matchLabels:
app: httpd1
replicas: 2
template:
metadata:
labels:
app: httpd1
spec:
containers:
- name: httpd1
image: httpd
imagePullPolicy: IfNotPresent
---
kind: Service
apiVersion: v1
metadata:
name: svc3
spec:
selector:
app: httpd1
ports:
- port: 80
targetPort: 80
//验证上述资源没有问题之后,可以直接复制其yaml文件,更改相应名称即可得到ingress2.bdqn.io这个域名所依赖的资源。
kind: Deployment
apiVersion: apps/v1
metadata:
name: deploy4
spec:
selector:
matchLabels:
app: httpd2
replicas: 2
template:
metadata:
labels:
app: httpd2
spec:
containers:
- name: httpd2
image: httpd
imagePullPolicy: IfNotPresent
---
kind: Service
apiVersion: v1
metadata:
name: svc4
spec:
selector:
app: httpd2
ports:
- port: 80
targetPort: 80
//访问各SVC资源的ClusterIP,验证服务
[root@master vhost]# curl 10.103.181.125
[root@master vhost]# curl 10.110.230.221
//创建对应的Ingress规则,这个是最重要的一环。
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: ingress1
spec:
rules:
- host: ingress1.bdqn.io
http:
paths:
- path: /
backend:
serviceName: svc3
servicePort: 80
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: ingress2
spec:
rules:
- host: ingress2.bdqn.io
http:
paths:
- path: /
backend:
serviceName: svc4
servicePort: 80
//查看对应Ingress规则的相信信息。
[root@master vhost]# kubectl describe ingresses. ingress1
Name: ingress1
Namespace: default
Address: 10.106.32.255
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
ingress1.bdqn.io
/ svc1:80 (10.244.1.102:80,10.244.2.107:80)
...
[root@master vhost]# kubectl describe ingresses. ingress2
Name: ingress2
Namespace: default
Address: 10.106.32.255
Default backend: default-http-backend:80 (<none>)
Rules:
Host Path Backends
---- ---- --------
ingress2.bdqn.io
/ svc2:80 (10.244.1.103:80,10.244.2.108:80)
...
//在Windows上,做对应的域名解析,用浏览器访问验证。
192.168.8.20 ingress1.bdqn.io
192.168.8.20 ingress2.bdqn.io
-----------------------------------------------------
基于https的访问
//创建证书
mkdir -p /root/yaml/ingress/https
cd /root/yaml/ingress/https
[root@master https]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
...............+++
.......................................................................+++
writing new private key to 'tls.key'
-----
[root@master https]# ls
tls.crt tls.key
//创建secret资源,将证书保存到k8s集群中
[root@master https]# kubectl create secret tls tls-secret --key=tls.key --cert tls.crt
//创建新的Deploy5.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: deploy5
spec:
selector:
matchLabels:
app: nginx5
replicas: 2
template:
metadata:
labels:
app: nginx5
spec:
containers:
- name: nginx5
image: nginx
imagePullPolicy: IfNotPresent
---
kind: Service
apiVersion: v1
metadata:
name: svc-5
spec:
selector:
app: nginx5
ports:
- protocol: TCP
port: 80
targetPort: 80
//创建对应Ingress规则。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: https
spec:
tls:
- hosts:
- ingress5.bdqn.com
secretName: tls-secret
rules:
- host: ingress5.bdqn.com
http:
paths:
- path: /
backend:
serviceName: svc-5
servicePort: 80
//域名访问测试https