kubernetes ingress 在物理机上的nodePort和hostNetwork两种部署方式解析及比较

ingress controller在物理机上的两种部署方式

ingress controller(ingress-nginx)负责k8s中的7层负载均衡。其在物理机中有多种部署方式。本文中主要选择了nodePort和hostNetwork两种部署方式进行介绍。主要缘由是这两种部署方式不须要借助于其余组件,直接使用的是k8s的基础组件和使用方式,较为容易理解和排障。html

注:本文中的kube-proxy使用的是iptablesnode

本文使用的ingress-nginx的commit版本是51ad0bc54b1475384b67bee9e8a8e41e26b18bc4。该版本的部署方式是在NGINX: 0.24.1版本后重构了deploy文件夹中的ingress-nginx的部署相关文件。采用了kustomize进行部署配置。所以推荐使用kubectl 1.14以上的版本。且特别注意,下面的命令都是使用了kubectl apply -k的方式运行,而不是-f参数。nginx

deploy各个文件夹走读

ingress-nginx项目deploy文件夹下有多个文件夹,为不一样的环境提供支持。这里咱们主要介绍的是与在物理机部署相关的几个文件夹。git

cluster-wide
├── cluster-wide
│   ├── cluster-role-binding.yaml
│   ├── cluster-role.yaml
│   └── kustomization.yaml

cluster-wide文件夹主要用于建立cluster-role和cluster-role-binding,为ingress-controller提供apiserver的cluster访问权限。这里cluster-role-binding.yaml要做一下修改,指定namespace: ingress-nginx。由于在后面建立的ServiceAccount等其余资源都是默认在该namespace下。github

[root@local cluster-wide]# cat cluster-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx
cloud-generic
├── cloud-generic
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   ├── role-binding.yaml
│   ├── role.yaml
│   ├── service-account.yaml
│   └── service.yaml

cloud-generic文件夹提供了通用的一些部署文件。其中deployment.yaml是负责建立ingress-controller的deployment,默认副本数为1,能够进行调节。service.yaml是为ingress-controller建立的service。其余的主要是与帐户相关的内容。web

baremetal
├── baremetal
│   ├── kustomization.yaml
│   └── service-nodeport.yaml

baremetal文件夹主要是建立了一个NodePort类型的svc,而后向ingress-controller的容器进行导流的。由于该部署方式须要依赖cloud-generic里的资源,所以在kustomization.yaml中描述了对cloud-generic的依赖。能够参看kustomization.yaml中的bases。api

[root@local baremetal]# cat deploy/baremetal/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../cloud-generic
patchesStrategicMerge:
- service-nodeport.yaml

大体了解了相关部署文件的功能,那么结合具体的两种部署图(部署图来自官网),来进行一下具体介绍。网络

nodePort部署

nodePort

nodePort的部署思路就是经过在每一个节点上开辟nodePort的端口,将流量引入进来,然后经过iptables首先转发到ingress-controller容器中(图中的nginx容器),然后由nginx根据ingress的规则进行判断,将其转发到对应的应用web容器中。所以采用nodePort部署较为简单,直接使用如下命令便可。app

kubectl apply -k deploy/baremetal/
kubectl apply -k deploy/cluster-wide/

hostNetwork部署

hostNetwork

相比较起来,hostNetwork模式再也不须要建立一个nodePort的svc,而是直接在每一个节点都建立一个ingress-controller的容器,并且将该容器的网络模式设为hostNetwork。也就是说每一个节点物理机的80和443端口将会被ingress-controller中的nginx容器占用。当流量经过80/443端口进入时,将直接进入到nginx中。然后nginx根据ingress规则再将流量转发到对应的web应用容器中。负载均衡

这里须要对cloud-generic/deployment.yaml进行一下改动,将其资源类型从deployment改成daemonset,而且在spec中添加hostNetwork: true,从而使其能够使用物理机网络。

[root@local deploy]# cat cloud-generic/deployment.yaml 
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
spec:
  template:
    metadata:
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
      labels:
        nginx-ingress-controller: 0.24.1
    spec:
      serviceAccountName: nginx-ingress-serviceaccount
      hostNetwork: true
      ...

修改完成后,使用如下命令便可完成hostNetwork模式的部署。

kubectl apply -k deploy/cloud-generic/
kubectl apply -k deploy/cluster-wide/

两种部署方式的比较

相比较起来,nodePort部署模式中须要部署的ingress-controller容器较少。一个集群能够部署几个就能够了。而hostNetwork模式须要在每一个节点部署一个ingress-controller容器,所以总起来消耗资源较多。另一个比较直观的区别,nodePort模式主要占用的是svc的nodePort端口。而hostNetwork则须要占用物理机的80和443端口。

从网络流转来讲,经过nodePort访问时,该node节点不必定部署了ingress-controller容器。所以还须要iptables将其转发到部署有ingress-controller的节点上去,多了一层流转。

另外,经过nodePort访问时,nginx接收到的http请求中的source ip将会被转换为接受该请求的node节点的ip,而非真正的client端ip。

而使用hostNetwork的方式,ingress-controller将会使用的是物理机的DNS域名解析(即物理机的/etc/resolv.conf)。而没法使用内部的好比coredns的域名解析。

所以具体使用哪一种部署方式,须要根据实际状况和需求进行选择。

ingress controller试用

在部署好ingress controller后,能够经过一个样例进行测试使用。首选建立一个应用容器和以及一个对应的svc。

kubectl run web --image=gcr.azk8s.cn/google-samples/hello-app:1.0 --port=8080
kubectl expose deployment web --target-port=8080

而后建立ingress,将经过hello-world.info域名访问ingress的请求转发到该容器中去。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
 rules:
 - host: hello-world.info
   http:
     paths:
     - path: /*
       backend:
         serviceName: web
         servicePort: 8080

这一切完成后,在/etc/hosts里绑定域名,127.0.0.1 hello-world.info

sed -i '$a 127.0.0.1 hello-world.info' /etc/hosts

而后经过curl命令进行测试。

root@i-5i2mhmaus9v67pz19zmahp07u:~# curl 127.0.0.1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.10</center>
</body>
</html>

root@i-5i2mhmaus9v67pz19zmahp07u:~# curl hello-world.info 
Hello, world!
Version: 1.0.0
Hostname: web-77f97c6cc7-g7qft

这里能够看到,咱们访问本地127.0.0.1的时候,会返回404错误。而访问绑定的域名,就能够正确导流了,返回正确结果。

参考资料

相关文章
相关标签/搜索