Kubernetes之Ingress-nginx部署使用

一、Ingress简介

在Kubernetes中,服务和Pod的IP地址仅在集群内部网络内部使用,对于集群的应用是不可见的。

为了使外部的应用能够访问集群内的服务,在Kubernetes目前提供了以下几种方案:
1)NodePort
2)LoadBalancer
3)Ingress

1)Ingress组成
Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上;
Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service;

2)Ingress工作原理
1)Ingress controller通过与Kubernetes api进行交互,动态的感知集群中Ingress规则的变化;
2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置;
3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中;
4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题;

3) Ingress可以解决什么问题?
1)动态配置服务
如果是按照传统方式,当新增加一个服务时,我们可能需要在流量入口部署一台反向代理服务器指向我们新的K8s服务,而如果使用了Ingress,则只需配置好这个服务,当服务启动时,便会自动注册到Ingress中,不需要额外的操作;
2)减少不必要的端口映射
配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不用NodePort方式;

二、配置Ingress-nginx

1)搭建registry私有仓库
搭建私有仓库的目的,仅仅是为了更快的获取镜像,如果网络稳定,也可跳过此步骤!

[root@master ~]# docker run -itd --name registry --restart=always  -p 5000:5000 -v /registry:/var/lib/registry registry:2
#搭建registry私有仓库
[root@master ~]#  vim /usr/lib/systemd/system/docker.service 
#修改docker的配置文件,指向私有仓库
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.10.52:5000
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node01:/usr/lib/systemd/system/
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/
#将修改好的配置文件发送到Kubernetes集群中的各个节点
[root@master ~]# systemctl daemon-reload 
[root@master ~]# systemctl restart docker
#所有节点都需重新启动服务
[root@master ~]# docker pull httpd
[root@master ~]# docker pull tomcat:8.5.45
[root@master ~]# docker tag httpd:latest 192.168.10.52:5000/httpd:v1
[root@master ~]# docker tag tomcat:8.5.45 192.168.10.52:5000/tomcat:v1
[root@master ~]# docker push 192.168.10.52:5000/httpd:v1
[root@master ~]# docker push 192.168.10.52:5000/tomcat:v1
#下载使用的镜像,并将其上传到私有仓库

2)创建用于测试的Pod

1)创建httpd服务及其service
[root@master ~]# vim httpd.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns
#创建名称空间test-ns
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpd01
  namespace: test-ns
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: httpd-01
    spec:
      containers:
      - name: httpd
        image: 192.168.10.52:5000/httpd:v1
#使用httpd的镜像创建Deployment资源,副本数量为2个,并打标签为httpd-01
---
apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
  namespace: test-ns
spec:
  selector:
    app: httpd-01
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
#创建service资源对象与Deployment资源使用标签的方式进行关联
[root@master ~]# kubectl apply -f httpd.yaml 

2)创建tomcat服务及其service

[root@master ~]# vim tomcat.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat01
  namespace: test-ns
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: tomcat-01
    spec:
      containers:
      - name: tomcat
        image: 192.168.10.52:5000/tomcat:v1
#使用tomcat的镜像创建Deployment资源,副本数量为2个,并打标签为tomcat-01
---
apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc
  namespace: test-ns
spec:
  selector:
    app: tomcat-01
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
#创建service资源对象与Deployment资源使用标签的方式进行关联
[root@master ~]# kubectl apply -f tomcat.yaml

3)确保以上资源对象成功创建

[root@master ~]# kubectl get pod -n test-ns   #确保pod正常运行
NAME                       READY   STATUS    RESTARTS   AGE
httpd01-84c6b66457-fkhf7   1/1     Running   0          3m2s
httpd01-84c6b66457-nlgmv   1/1     Running   0          3m2s
tomcat01-dcd778777-9sg2n   1/1     Running   0          2m20s
tomcat01-dcd778777-r62qd   1/1     Running   0          2m20s
[root@master ~]# kubectl get svc -n test-ns     #确保service创建成功
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
httpd-svc    ClusterIP   10.109.238.33           80/TCP     3m26s
tomcat-svc   ClusterIP   10.104.198.78           8080/TCP   2m44s
[root@master ~]# curl -I 10.109.238.33:80
HTTP/1.1 200 OK
Date: Sun, 23 Aug 2020 00:55:25 GMT
Server: Apache/2.4.46 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html
[root@master ~]# curl -I 10.104.198.78:8080
HTTP/1.1 200 
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 23 Aug 2020 00:55:32 GMT
#访问SVC的clusterIP+端口,确定可以访问到后端Pod

3)创建Ingress-controller资源对象
ingress-nginx资源所使用的镜像链接,
提取码:ltnx

#上传网盘提供的所有内容
[root@master ~]# vim mandatory.yaml 
#对下载的yaml文件进行简单的修改
    spec:                            #定位到212行,也就是该行
      hostNetwork: true             #添加该行,表示使用主机网络
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        Ingress: nginx               ##设置节点的标签选择器,指定在哪台节点上运行
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.29.0
#该资源使用的镜像,该镜像下载较慢,可使用步骤开头提供的网盘链接!
[root@master ~]# kubectl label nodes node01 Ingress=nginx
#对node01节点打相应的标签,以便指定Ingress-nginx运行在node01
[root@master ~]# kubectl get nodes node01 --show-labels
#查看node01的标签是否存在
[root@node01 ~]# docker load < nginx-ingress.tar 
#node01节点导入镜像(也可自行下载)
[root@master ~]# kubectl apply -f mandatory.yaml 

关于上面yaml文件中写入的“hostNetwork: true”具体解释:如果添加了此字段,意味着pod中运行的应用可以直接使用node节点的端口,这样node节点主机所在网络的其他主机,就可以通过访问该端口访问此应用。(类似于docker映射到宿主机的端口。)

[root@master ~]#  kubectl get pod -n ingress-nginx -o wide
NAME                                        READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
nginx-ingress-controller-577ffd8c54-x6nqj   1/1     Running   0          2m10s   192.168.10.53   node01              

4)创建Ingress资源对象

[root@master ~]# vim ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.123.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
#通过www.123.com 来访问到我们后端httpd容器提供的服务;
#通过www.123.com/tomcat 来访问我们后端tomcat提供的服务
[root@master ~]# kubectl apply -f ingress.yaml 
ingress.extensions/test-ingress created
[root@master ~]# kubectl get ingresses. -n test-ns 
NAME           HOSTS         ADDRESS   PORTS   AGE
test-ingress   www.123.com             80      41m

其实,至此已经实现了我们想要的功能,前提是要配置DNS解析,或者直接修改client的hosts文件。
Kubernetes之Ingress-nginx部署使用_第1张图片
Kubernetes之Ingress-nginx部署使用_第2张图片
这里的ip是:

[root@master ~]# kubectl get pod -n ingress-nginx -o wide
NAME                                        READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
nginx-ingress-controller-577ffd8c54-x6nqj   1/1     Running   0          51m   192.168.10.53   node01              

定义首页内容

[root@master ~]# kubectl get pod -n test-ns   #查看pod名称
NAME                       READY   STATUS    RESTARTS   AGE
httpd01-84c6b66457-fkhf7   1/1     Running   0          75m
httpd01-84c6b66457-nlgmv   1/1     Running   0          75m
tomcat01-dcd778777-9sg2n   1/1     Running   0          74m
tomcat01-dcd778777-r62qd   1/1     Running   0          74m

[root@master ~]# kubectl exec -it -n test-ns httpd01-84c6b66457-fkhf7 /bin/bash  #进入容器修改首页内容
root@httpd01-84c6b66457-fkhf7:/usr/local/apache2# echo apache1 > htdocs/index.html 
root@httpd01-84c6b66457-fkhf7:/usr/local/apache2# cat htdocs/index.html 
apache1

[root@master ~]# kubectl exec -it -n test-ns httpd01-84c6b66457-nlgmv /bin/bash
root@httpd01-84c6b66457-nlgmv:/usr/local/apache2# echo apache2 >   htdocs/index.html 
root@httpd01-84c6b66457-nlgmv:/usr/local/apache2# cat htdocs/index.html 
apache2

访问httpd服务
Kubernetes之Ingress-nginx部署使用_第3张图片
通过刷新可以看到不同的首页文件

访问tomcat服务
Kubernetes之Ingress-nginx部署使用_第4张图片
在上面的访问测试中,虽然访问到了对应的服务,但是有一个弊端,就是在做DNS解析的时候,只能指定Ingress-nginx容器所在的节点IP。而指定k8s集群内部的其他节点IP(包括master)都是不可以访问到的,如果这个节点一旦宕机,Ingress-nginx容器被转移到其他节点上运行(不考虑节点标签的问题,其实保持Ingress-nginx的yaml文件中默认的标签的话,那么每个节点都是有那个标签的)。随之还要我们手动去更改DNS解析的IP(要更改为Ingress-nginx容器所在节点的IP,通过命令“kubectl get pod -n ingress-nginx -o wide”可以查看到其所在节点),很是麻烦。
有没有更简单的一种方法呢?答案是肯定的,就是我们为Ingress-nginx规则再创建一个类型为nodePort的Service,这样,在配置DNS解析时,就可以使用www.123.com 绑定所有node节点,包括master节点的IP了,很是灵活。

5)为Ingress-controller资源对象创建一个service资源对象
这里上面的网盘中有这个service-nodeport.yaml ,直接运行一下就可以了

[root@master ~]# cat service-nodeport.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
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
[root@master ~]# kubectl apply -f service-nodeport.yaml 
[root@master ~]# kubectl get svc -n ingress-nginx 
#查看运行的service对象
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.110.148.71           80:30429/TCP,443:31382/TCP   6s
#可以看到service分别将80和443端口映射到了节点的30429和31382端口(随机映射的,也可以修改yaml文件指定端口)

至此,这个www.123.com 的域名即可和群集中任意节点的30429/31382端口进行绑定了。

测试如下(域名解析对应的IP可以是k8s群集内的任意节点IP):
还记得上面hosts里写的是
Kubernetes之Ingress-nginx部署使用_第5张图片
现在改为群集里的任意ip
Kubernetes之Ingress-nginx部署使用_第6张图片
Kubernetes之Ingress-nginx部署使用_第7张图片
Kubernetes之Ingress-nginx部署使用_第8张图片
6)创建基于虚拟主机的Ingress规则
如果需要将www.123.com 和www.321.com 都对应上后端的pod容器所运行的服务。应进行以下配置:

[root@master ~]# vim ingress.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.123.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
  - host: www.321.com             #就是将原本的域名对应的svc服务复制一份,更改一下域名而已!
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
[root@master ~]# kubectl apply -f ingress.yaml

至此,即可实现访问www.123.com 和www.321.com 都可以访问到后端的httpd提供的页面(先要解决域名解析问题),如下:
Kubernetes之Ingress-nginx部署使用_第9张图片

Kubernetes之Ingress-nginx部署使用_第10张图片
Kubernetes之Ingress-nginx部署使用_第11张图片
Ingress-nginx资源的流程总结,如图:
Kubernetes之Ingress-nginx部署使用_第12张图片
从图中可以看出:后端有多个pod,pod与service进行关联,service又被ingress规则发现并动态写入到ingress-nginx-controller容器中,然后又为ingress-nginx-controller创建了一个Service映射到群集节点上的端口,来供client来访问。

在真正的生产环境中,创建Ingress Controller肯定使用的是DaemonSet资源类型,来保证Ingress Controller的高可用!

三、配置HTTPS

在上面的操作中,实现了使用ingress-nginx为后端所有pod提供一个统一的入口,那么,有一个非常严肃的问题需要考虑,就是如何为我们的pod配置CA证书来实现HTTPS访问?在pod中直接配置CA么?那需要进行多少重复性的操作?而且,pod是随时可能被kubelet杀死再创建的。当然这些问题有很多解决方法,比如直接将CA配置到镜像中,但是这样又需要很多个CA证书。

在上面的一系列流程中,关键的点就在于ingress规则,我们只需要在ingress的yaml文件中,为域名配置CA证书即可,只要可以通过HTTPS访问到域名,至于这个域名是怎么关联到后端提供服务的pod,这就是属于k8s群集内部的通信了,即便是使用http来通信,也无伤大雅。

配置如下:
为了简单起见,以下配置在上述环境下执行以下配置:

[root@master ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
#创建CA证书
[root@master ~]# ls | grep tls               #确认产生了以下两个文件
tls.crt
tls.key
[root@master ~]# kubectl create secret tls tls-secret --key=tls.key --cert tls.crt
#创建secret资源对象
[root@master ~]# kubectl describe secrets tls-secret 
#查看secret资源对象详细信息
Name:         tls-secret
Namespace:    default
Labels:       
Annotations:  

Type:  kubernetes.io/tls

Data
====
tls.key:  1704 bytes
tls.crt:  1143 bytes
[root@master ~]# vim ingress.yaml
#对Ingresss资源对象进行修改
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test-ns
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:                     #在原本的基础上添加以下内容即可
  - hosts:
    - www.123.com
    - www.321.com
    secretName: tls-secret                     #填写须使用该证书的域名及证书的名称
  rules:
  - host: www.123.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
  - host: www.321.com
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080
[root@master ~]# kubectl apply -f ingress.yaml
[root@master ~]# kubectl describe ingresses.  test-ingress -n test-ns 
#查看Ingress-nginx的详细信息
Name:             test-ingress
Namespace:        test-ns
Address:          10.110.148.71
Default backend:  default-http-backend:80 ()
TLS:
  tls-secret terminates www.123.com,www.321.com
Rules:
  Host         Path  Backends
  ----         ----  --------
  www.123.com  
               /         httpd-svc:80 (10.244.1.2:80,10.244.2.2:80)
               /tomcat   tomcat-svc:8080 (10.244.1.3:8080,10.244.2.3:8080)
  www.321.com  
               /         httpd-svc:80 (10.244.1.2:80,10.244.2.2:80)
               /tomcat   tomcat-svc:8080 (10.244.1.3:8080,10.244.2.3:8080)

访问时应注意433对应的端口进行访问!查看端口

[root@master ~]# kubectl get svc -n ingress-nginx 
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.110.148.71           80:30429/TCP,443:31382/TCP   4h55m

访问测试:Kubernetes之Ingress-nginx部署使用_第13张图片

Kubernetes之Ingress-nginx部署使用_第14张图片

Kubernetes之Ingress-nginx部署使用_第15张图片
Kubernetes之Ingress-nginx部署使用_第16张图片

你可能感兴趣的:(kubernetes(k8s),Ingress简介,配置Ingress-nginx,配置HTTPS,kubernetes)