kubernetes网络模式
一个K8s的集群中至少有三个网络:
-
集群节点所在的网络,这个网络就是你的主机所在的网络,通常情况下是你的网络基础设施提供。如果你的node处于不同的网段,那么你需要保证路由可达。如上图中的 192.168.10.0/24和10.0.0.0/8这两个网络
-
第二个网络是Pod的网络, K8s中一个Pod由多个容器组成,但是一个pod只有一个IP地址,Pod找那个所有的容器共享同一个IP。这个IP启动pod时从一个IP池中分配的, 叫做 pod CIDR, 或者叫network_cidr(如图,默认配置是10.1.0.0/16)。可以在配置文件中配置。
-
第三个网络是K8S服务网络, service_cluster_ip_range(如图,默认的配置是的10.0.0.1/24)
K8S中Container是如何互联互通的
1.Pod内部通信:
同一pod中的任何容器都将共享相同的名称空间和本地网络,容器可以容易地与其他容器在相同的容器中进行通信,k8s中每个pod中管理着一组容器,这些容器共享同一网络空间,他们之间可以通过localhost相互访问,(可见pod内部的通信是不经过数据ip数据通信网络的)。
2.同节点的pod之间通信:
不同pod之间的通信,就是使用Linux虚拟以太网设备或者说是由两个虚拟接口组成的以太网接口对使不同的网络命名空间连接起来,这些虚拟接口分布在多个pod上,通过网桥把不同的pod组成为一个以太网,直接进行二层以太网通信。
3.不同节点的pod之间通信:
当跨pod通信时,本节点内无法找到目的pod的MAC地址,则会查找三层路由表转发,这需要依靠不同节点的网络配置来实现,对于如何来配置网络,k8s在网络这块自身并没有实现网络规划的具体逻辑,而是制定了一套CNI接口规范,开放给社区来实现,目前主流的网络配置方案有:Flannl、weave、calico等。
4.外部网络与pod之间通信:
pod之间通过他们自己的ip地址进行通信,但是pod的ip地址是不持久的,当集群中pod的规模缩减或者pod故障或者node故障重启后,新的pod的ip就可能与之前的不一样的。每个service有一个虚拟ip,要访问service管理的pod上的服务只需要访问你这个虚拟ip就可以了,这个虚拟ip是固定的,当service下的pod规模改变、故障重启、node重启时候,对使用service的用户来说是无感知的,因为他们使用的service的ip没有变。当数据包到达service虚拟ip后,数据包会被通过k8s给service自动创建的负载均衡器路由到背后的pod容器。
Service有很多种类型,默认是ClusterIP
ClusterIP:一个Pod如果想和自己通信,只需要用localhost即可。如果想用别的Pod的服务,就要知道别的Pod对应的Serice的DNS名称,解析到期ClusterIP。ClusterIP会被每个Node上的Kube-Proxy修改iptables和ipvs等路由信息,这样保证发往ClusterIP的IP包,实际上被发往在这个Node上的Pod的IP地址和端口。
apiVersion: v1 kind: Service metadata: name: service-clusterip spec: ports: - port: 3000 protocol: TCP targetPort: 443 # clusterIP: 10.233.3.127 ##可配可不配,不配的话系统会分配一个随机的IP并保持不变 selector: app: pod-clusterip type: ClusterIP ##type可以不配,不配的话默认就是ClusterIP类型
NodePort:NodePort是在ClusterIP之上建造的Service。
如果想让外网访问Pod的业务,最简单的办法就是通过Node的公网地址,生成一个NodePort类型的Service. 本质就是把ClusterIP Service暴露到集群中所有Node的高端端口(default 30000-32767)。所有的Node都会监这个端口,即使这个Node中没有这个service的Pod,如果设置了.spec.externalTrafficPolicy属性是local,则只有运行Pod的Node会监听,这样就避免了多跳一次。
apiVersion: v1 kind: Service metadata: name: service-nodeport spec: ports: - port: 3000 protocol: TCP targetPort: 443 nodePort: 30080 ##可配可不配,不配的话系统会分配一个随机的端口并保持不变 selector: app: pod-nodeport type: NodePort
如果有一个4层负载均衡,并且要从外网方位K8S中的服务,就需要是指负载均衡,把业务数据分发到所有的有Pod的Node上对应的NodePord的端口,并且能够通过健康检查,来动态获得哪些工作Node上有对应的Pod。
LoadBalancer:是在NodePort之上建造的服务,他能够自动设置私有云或者公有云提供的负载均衡,把NodePort暴露给外网,并且动态监听那些pod在那些工作Node上。
apiVersion: v1 kind: Service metadata: name: service-loadbalancer spec: ports: - port: 3000 protocol: TCP targetPort: 443 nodePort: 30080 selector: run: pod-loadbalancer type: LoadBalancer
ExternalName: Service的ExternalName方式实现,即设置Service的type为ExternalName。这样做的好处就是内部服务访问外部服务的时候通过别名来访问的,屏蔽了外部服务的真实信息,外部服务对内部服务透明,外部服务的修改基本上不会影响到内部服务的访问,做到了内部服务和外部服务解耦合。
kind: Service apiVersion: v1 metadata: name: service-externalname spec: ports: - port: 3000 protocol: TCP targetPort: 443 type: ExternalName externalName: remote.server.url.com
K8S服务发现
k8s中,Pod如果想要与另一个pod通信,通常不会直接记住pod的ip(因为动态的),也不会记住pod形成的Service的ip(相对比较稳定,但也是动态的),因为IP不好记,通常情况是通过其对应的service名字来访问的。那么就需要一个服务,能够把service的名字翻译为ip,此服务就是kube-dns。
目前k8s的kube-dns通常使用CoreDNS
-
kubernetes的Service Name被解析成其ClusterIp(是服务网络中的ip,是内部的,不是Node的外部地址)
- 每个K8s网络在安装的时候指定一个Cluster Domain,默认是: cluster.local
- k8s中每个namespace对应一个子域
K8S中的Ingress:用于实现用域名的方式访问k8s内部应用。
k8s通过Ingress,把K8s集群中的服务,通过http和https路由暴露给外部用户。路径等信息通过Ingress的资源文件配置。
有了service为什么需要Ingress资源
Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,总之一句话,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上。
采用 NodePort 方式暴露服务面临一个问题,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护
Ingress 工作原理
-
ingress-controller通过和kubernetes APIServer交互,动态的去感知集群中ingress规则变化;
- 然后读取它,按照自定义的规则,规则就是写明了那个域名对应那个Service,生成一段配置;
- 在写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行着一个Nginx服务,控制器会把生成的Nginx配置写入/etc/nginx.conf中‘;
- 然后reload一下是配置生效。以此达到域名区分配置和动态更新的作用。
ingress 暴露服务的方式
wget https://github.com/kubernetes/ingress-nginx/archive/nginx-0.30.0.tar.gz
●Deployment+LoadBalancer 模式的 Service
如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个 type为 LoadBalancer 的 service 关联这组 pod。大部分公有云,都会为 LoadBalancer 的 service 自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向该地址,就实现了集群服务的对外暴露
●DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
[root@master1 static]# cat mandatory.yaml apiVersion: v1 kind: Namespace metadata: name: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses verbs: - get - list - watch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter # when launching the nginx-ingress-controller. - "ingress-controller-leader-nginx" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: nginx-ingress-role-nisa-binding namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: nginx-ingress-role subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: nginx-ingress-clusterrole-nisa-binding labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: apps/v1 kind: DaemonSet #kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: #replicas: 3 selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: # wait up to five minutes for the drain of connections terminationGracePeriodSeconds: 300 serviceAccountName: nginx-ingress-serviceaccount hostNetwork: true nodeSelector: kubernetes.io/os: linux containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 101 runAsUser: 101 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 lifecycle: preStop: exec: command: - /wait-shutdown --- apiVersion: v1 kind: LimitRange metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: limits: - min: memory: 90Mi cpu: 100m type: Container
●Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的service,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
apiVersion: v1 kind: Namespace metadata: name: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses verbs: - get - list - watch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter # when launching the nginx-ingress-controller. - "ingress-controller-leader-nginx" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: nginx-ingress-role-nisa-binding namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: nginx-ingress-role subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: nginx-ingress-clusterrole-nisa-binding labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: replicas: 3 selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: # wait up to five minutes for the drain of connections terminationGracePeriodSeconds: 300 serviceAccountName: nginx-ingress-serviceaccount # hostNetwork: true nodeSelector: kubernetes.io/os: linux containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 101 runAsUser: 101 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 lifecycle: preStop: exec: command: - /wait-shutdown --- apiVersion: v1 kind: LimitRange metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: limits: - min: memory: 90Mi cpu: 100m type: Container [root@master1 baremetal]# 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 nodePort: 83 protocol: TCP - name: https port: 443 targetPort: 443 nodePort: 443 protocol: TCP selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- service-nodeport映射80和443端口,nginx直接代理ingress server { listen 80; server_name h5.ypc.com; listen 443 ssl; access_log /etc/nginx/logs/wechat-wx.qasa.chtwm.com.acc.log main; error_log /etc/nginx/logs/wechat-wx.qasa.chtwm.com.err.log error; ssl_certificate /usr/local/nginx/sslkey/ssl.crt; #(证书公钥) ssl_certificate_key /usr/local/nginx/sslkey/ssl.key; # (证书私钥) ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL; ssl_prefer_server_ciphers on; location / { #add_header Access-Control-Allow-Origin*; add_header Access-Control-Allow-Headers Content-Type; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; add_header Access-Control-Allow-Credentials true; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forword-For $proxy_add_x_forwarded_for; proxy_set_header HOST www-h5.chtwm.com; proxy_pass http://10.70.5.10; } }
nginx代理参考:
https://www.cnblogs.com/kevingrace/p/8269955.html