一、Ingress 简介
在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:
NodePort
LoadBalancer(负载均衡)
Ingress(入口)
-----------------------------------------
Ingress 组成:ingress controller、ingress服务
ingress controller:
将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务:
将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可
Ingress 工作原理
1. ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
2. 然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置
3. 再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
4. 然后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文件。
```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文件,可以查看都做了什么,也方便我们后期管理
//这里使用的镜像,是国外的镜像,需要提前下载获得。
#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 ... ... 330 hostNetwork: true #添加本行 331 dnsPolicy: ClusterFirst 332 containers: 333 - name: controller 334 image: k8s.gcr.io/ingress-nginx/controller:v0.35.0 #修改本行 335 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 ingress-nginx-admission-patch-qzkfc 0/1 Completed 1 20s 10.244.2.98 node02 ingress-nginx-controller-6995cf966b-c5mvd 1/1 Running 0 20s 10.244.1.63 node01 [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 80:30105/TCP,443:32457/TCP 3m33s ingress-nginx-controller-admission ClusterIP 10.104.13.179 443/TCP 3m33s ```
//注意:Ingress-controller服务运行之后,还有一个manatora-svc.yaml文件,这个文件,是将
Ingress-controller的Deployment资源对象关联在一起了,也就是说,访问mandatora-svc就能否访问Ingress-controller的Depoyment资源的Pod的了。
//查看其yaml文件,发现它暴露的是NodePort类型。
```yaml [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 9m42 [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规则 ```yaml 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资源。
```yaml 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这个域名所依赖的资源。
```yaml 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规则,这个是最重要的一环。
```yaml 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 () 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 () 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
```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规则。
```yaml 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