标签:work ack name creat conf 首页 gre 使用wget下载 bin
前言在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes中目前提供了以下几种方案:
在之前的博文中介绍过NodePort,简单来说,就是通过service这种资源对象,为后端pod提供一个统一的访问接口,然后将service的统一访问接口映射到群集节点上,最终实现client通过映射到群集节点上的端口访问到后端pod提供的服务。
但是,这种方式有一个弊端,就是当新生成一个pod服务就需要创建对应的service将其映射到节点端口,当运行的pod过多时,我们节点暴露给client端的端口也会随之增加,这样我们整个k8s群集的危险系数就会增加,因为我们在搭建群集之处,官方明确指出,必须关闭firewalld防火墙及清空iptables规则,现在我们又暴露了那么多端口给client,安全系数可想而知。
有没有更安全又简便的一种方法呢?答案是肯定的,就是来利用Ingress这种资源对象来实现。
博文大纲:
一、Ingress-nginx介绍
二、Ingress-nginx配置示例
- ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
- ingress资源对象:将Nginx的配置抽象成一个Ingress对象,每添加一个新的Service资源对象只需写一个新的Ingress规则的yaml文件即可(或修改已存在的ingress规则的yaml文件)
1)动态配置服务
如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress-nginx, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作。
2)减少不必要的端口映射
配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式
1)ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,
4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。
注:文中所有的yaml文件及镜像都可以通过我的网盘链接下载(httpd和tomcat除外)。
#运行registry私有仓库
[root@master ~]# docker run -tid --name registry -p 5000:5000 --restart always registry
[root@master ~]# vim /usr/lib/systemd/system/docker.service #修改配置文件,指定私有仓库
ExecStart=/usr/bin/dockerd -H unix:// --insecure-registry 192.168.20.6:5000
#将修改后的文件发送到k8s群集中的其他节点
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node01:/usr/lib/systemd/system/
docker.service 100% 1637 1.6KB/s 00:00
[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/
#在各个节点包括master上执行以下命令,重启docker,使更改生效
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
#上传测试所需的镜像到私有仓库
[root@master ~]# docker push 192.168.20.6:5000/httpd:v1
[root@master ~]# docker push 192.168.20.6:5000/tomcat:v1
[root@master ~]# kubectl create ns test-ns #创建名称空间test-ns
[root@master ~]# kubectl get ns #确认创建成功
[root@master test]# vim httpd-01.yaml #编写基于httpd服务的资源对象
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: web01
namespace: test-ns
spec:
replicas: 3
template:
metadata:
labels:
app: httpd01
spec:
containers:
- name: httpd
image: 192.168.20.6:5000/httpd:v1
---
apiVersion: v1
kind: Service
metadata:
name: httpd-svc
namespace: test-ns
spec:
selector:
app: httpd01
ports:
- protocol: TCP
port: 80
targetPort: 80
[root@master test]# kubectl apply -f httpd-01.yaml #执行yaml文件
[root@master test]# vim tomcat-01.yaml #编写yaml文件如下
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: web02
namespace: test-ns
spec:
replicas: 3
template:
metadata:
labels:
app: tomcat01
spec:
containers:
- name: tomcat
image: 192.168.20.6:5000/tomcat:v1
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
namespace: test-ns
spec:
selector:
app: tomcat01
ports:
- protocol: TCP
port: 8080
targetPort: 8080
[root@master test]# kubectl apply -f tomcat-01.yaml #执行yaml文件
[root@master test]# kubectl get po -n test-ns #确定pod是正常运行状态
NAME READY STATUS RESTARTS AGE
web01-757cfc547d-fmjnt 1/1 Running 0 8m24s
web01-757cfc547d-pjrrt 1/1 Running 0 9m30s
web01-757cfc547d-v7tdb 1/1 Running 0 8m24s
web02-57c46c759d-l9qzx 1/1 Running 0 4m9s
web02-57c46c759d-vs6mg 1/1 Running 0 4m9s
web02-57c46c759d-zknrw 1/1 Running 0 4m9s
[root@master test]# kubectl get svc -n test-ns #确认SVC创建成功
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP 10.107.211.219 <none> 80/TCP 10m
tomcat-svc ClusterIP 10.101.159.1 <none> 8080/TCP 5m8s
#访问SVC的clusterIP+端口,确定可以访问到后端Pod
[root@master test]# curl -I 10.101.159.1:8080 #访问tomcat
HTTP/1.1 200 #返回状态码为200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 22 Nov 2019 12:34:32 GMT
[root@master test]# curl -I 10.107.211.219:80 #访问httpd
HTTP/1.1 200 OK #状态码为200
Date: Fri, 22 Nov 2019 12:34:39 GMT
Server: Apache/2.4.41 (Unix) #版本号也有
Last-Modified: Sat, 16 Nov 2019 10:00:39 GMT
ETag: "1a-59773c95e7fc0"
Accept-Ranges: bytes
Content-Length: 26
Content-Type: text/html
#如果在上述访问测试中,没有访问到相应的pod,建议使用“kubectl describe svc”命令,
#查看相应的service中的Endpoints列中有没有关联后端pod。
下载我提供的镜像并导入到需要运行Ingress-nginx的节点上,也可以选择自行下载其他镜像。
方法1:去gitlab搜索Ingress-nginx,点击“deploy”,再点击页面下的跳转链接,即可看到如下命令:
#不要直接复制命令到终端执行,先将yaml文件下载下来
[root@master test]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
[root@master test]# vim mandatory.yaml #修改其yaml文件
#修改以下内容
spec: #这是在212行的spec字段
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.26.1
#上面是指定使用什么镜像,若需要更改镜像名称,改这里即可,我保持默认。
#修改后保存退出即可
[root@master test]# kubectl label nodes node01 Ingress=nginx
#对node01节点打相应的标签,以便指定Ingress-nginx运行在node01
#可以执行下面的命令,查看node01的标签是否存在
[root@master test]# kubectl get nodes node01 --show-labels
#在node01节点执行下面命令,导入Ingress-nginx镜像(自行上传这个包,我提供的网盘链接中有)
[root@node01 ~]# docker load < nginx-ingress-controller.0.26.1.tar
#手动将ingress-nginx镜像导入到node01节点
#回到master节点,执行yaml文件
[root@master test]# kubectl apply -f mandatory.yaml #执行ingress-nginx的yaml文件
关于上面yaml文件中写入的“hostNetwork: true”具体解释:如果使用此网络参数,那么pod中运行的应用程序可以直接使用Node节点端口,这样node节点主机所在的网络的其他主机,都可以通过访问到此应用程序。
[root@master test]# kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ingress-controller-77c8f6577b-6shdc 1/1 Running 0 107s 192.168.20.7 node01 <none> <none>
[root@master test]# vim ingress.yaml #编写yaml文件如下
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
namespace: test-ns
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: www.test01.com
http:
paths:
- path: /
backend:
serviceName: httpd-svc
servicePort: 80
- path: /tomcat
backend:
serviceName: tomcat-svc
servicePort: 8080
[root@master test]# kubectl apply -f ingress.yaml #执行ingress规则的yaml文件
[root@master test]# kubectl get ingresses -n test-ns #查看ingresses规则资源对象
NAME HOSTS ADDRESS PORTS AGE
test-ingress www.test01.com 80 28s
其实,至此已经实现了我们想要的功能,现在就可以通过www.test01.com 来访问到我们后端httpd容器提供的服务,通过www.test01.com/tomcat 来访问我们后端tomcat提供的服务,当然,前提是自行配置DNS解析,或者直接修改client的hosts文件。访问页面如下(注意:一定要自己解决域名解析的问题,若不知道域名对应的是哪个IP,请跳过这两个图,看下面的文字解释):
访问httpd服务(首页内容是我自定义的):
访问tomcat服务:
在上面的访问测试中,虽然访问到了对应的服务,但是有一个弊端,就是在做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.test01.com 绑定所有node节点,包括master节点的IP了,很是灵活。
就在刚才找到Ingress-nginx的yaml文件的页面,然后下拉页面,即可看到以下,可以根据k8s集群环境来选择适合自己的yaml文件,假如自己是在Azure云平台搭建的K8s集群,则选择复制Azure下面的命令即可,我这里是自己的测试环境,所以选择Bare-metal下面的yaml文件:
创建这个Service有两种方法,一是直接复制其web页面的命令到master节点上执行,二是将其链接地址复制到终端使用wget下载下来再执行,我选择第二种方法,因为我想看看里面的内容:
#将其下载到本地
[root@master test]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
[root@master test]# 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 test]# kubectl apply -f service-nodeport.yaml #执行下载下来的yaml文件
[root@master test]# kubectl get svc -n ingress-nginx #查看运行的service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.109.106.246 <none> 80:30465/TCP,443:32432/TCP 56s
#可以看到service分别将80和443端口映射到了节点的30645和32432端口(随机映射的,也可以修改yaml文件指定端口)。
至此,这个www.test01.com 的域名即可和群集中任意节点的30465/32432端口进行绑定了。
测试如下(域名解析对应的IP可以是k8s群集内的任意节点IP):
至此,就实现了最初的需求。
如果现在是另一种需求,我需要将www.test01.com 和www.test02.com 都对应上我后端的httpd容器提供的服务,那么此时应该怎么配置?
[root@master test]# vim ingress.yaml #修改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.test02.com #增加这一段host配置
http:
paths:
- path: /
backend:
serviceName: httpd-svc #绑定和www.test01相同的service名字即可
servicePort: 80
- host: www.test01.com
http:
paths:
- path: /
backend:
serviceName: httpd-svc
servicePort: 80
- path: /tomcat
backend:
serviceName: tomcat-svc
servicePort: 8080
#增加完上述的host字段保存退出即可
[root@master test]# kubectl apply -f ingress.yaml #重新执行yaml文件
至此,即可实现访问www.test01.com 和www.test02.com 都可以访问到后端的httpd提供的页面(自行解决域名解析问题),如下:
访问www.test01.com:30465
访问www.test02.com:30465
总结上述示例的pod是如何一步一步可以使client访问到的,总结如下:
后端pod===》service====》ingress规则====》写入Ingress-nginx-controller配置文件并自动重载使更改生效===》对Ingress-nginx创建service====》实现client无论通过哪个K8节点的IP+端口都可以访问到后端pod
———————— 本文至此结束,感谢阅读 ————————
标签:work ack name creat conf 首页 gre 使用wget下载 bin
原文地址:https://blog.51cto.com/14154700/2452707