Kubernetes中自带的Service负载均衡,提供了两种负载分发策略:

  • RoundRobin:轮询模式

轮询将请求转发到后端的各个Pod上

  • SessionAffinity

基于客户端IP地址进行会话保持的模式,即第一次将某个客户端发起的请求转发到后端的某个Pod上,之后从相同的客户端发起的请求都被转发到后端相同的Pod上。


Kubernetes集群外部访问Pod或Service

1.将容器应用的端口号映射到物理机

cat pod-hostport.yaml

---

apiVersion: v1

kind: Pod

metadata:

 name: pod-hostport

 namespace: ops

 labels:

   app: pod-hostport


spec:

 containers:

 - name: pod-hostport

   image: harbor.ttsingops.com/nginx/nginx:1.16.0

   ports:

   - containerPort: 80

     hostPort: 8887

kubectl apply -f pod-hostport.yaml

kubectl get pods -n ops -o wide

clipboard.png

到访问curl -I http://node4-IP:port

curl -I http://192.168.1.212:8887

1.png

#注意

Pod级别的hostNetwork=true,该Pod中所有容器的端口号都被直接映射到物理机上。设置了hostNetwork=true时需要注意,在容器的ports定义部分如果不指定hostPort,则默认hostPort等于containerPort。如果指定了hostPort,则hostPort必须等于containerPort。


2.将Service的端口号映射到物理机

通过设置nodePort映射到物理机,同时设置Service的类型为NodePort

cat web-pod-svc.yaml

apiVersion: v1

kind: Pod

metadata:

 name: web

 namespace: ops

 labels:

   app: web

spec:

 containers:

 - name: app-web

   image: harbor.ttsingops.com/nginx/nginx:1.16.0

   ports:

   - containerPort: 80

---

apiVersion: v1

kind: Service

metadata:

 name: web-svc

 namespace: ops


spec:

 type: NodePort

 ports:

 - port: 8089

   targetPort: 80

   nodePort: 38888

 selector:

   app: web

kubectl get svc,pod -n ops -o wide

2.png

kubectl describe svc web-svc -n ops

3.png

#访问测试,使用Node节点的任一节点IP:NodePort即可访问

curl -I http://192.168.1.62:38888

4.png

#映射到云服务商LoadBalancer

#具体可查看云服务商的技术文档

例如:阿里云的LB配置Service

apiVersion: v1

kind: Service

metadata:

 labels:

   run: nignx

 name: nginx-01

 namespace: default

spec:

 ports:

 - port: 80

   protocol: TCP

   targetPort: 80

 selector:

   run: nginx

 type: LoadBalancer


#Ingress

ingress的出现是解决什么问题的呢?这要从Pod和Service说起,若外界想访问服务,如何访问呢?

以为Pod IP只能在Kubernetes的集群内部之间互通;Service的Cluster IP也只能在集群内部通信;

那Service不是有NodePort吗?映射到NodePort上不就可以了么?答案是可以的;若服务一旦多起来,上百上千个服务,这样端口就及其庞大,维护要命; 另外不是有云服务商的LoadBalancer么?但LB方式受限于云服务商的云平台;张三的同学说可以通过在每个Node上部署DaemonSet的nginx-pod,编写好规则,Nginx-pod绑定宿主机80端口(就像NodePort),这样直接转发到相应的Service IP就行了;这样确实是可以的;但也有问题;若后端的每次增加服务,ngx-pod规则都要重新编写,然后滚动更新ngx-pod。Ingress的出现就是解决上述诸多问题的。

#Ingress组件

Ingress

指的是Kubernetes中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。

Ingress Controller

具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求的转发


例如:

现在集群有api-server、index-server、admin-server 三个service,可以通过一个ingress对象来实现请求转发。

5.png

对http://www.zjsre.top/api的访问将被路由到后端名为api的service

对http://www.zjsre.top/index的访问将被路由到后端名为index的service

对http://www.zjsre.top/admin的访问将被路由到后端名为admin的service

Ingress规则时很灵活的,可以根据不同域名、不同请求路径转发到不同Service,并且也还支持https


部署Nginx-Ingress

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml


#部署微服务及Service

这里自己写了简单的demo微服务,api、index、admin的三个服务

访问http形式基本:域名/服务名、域名/服务名/getip、域名/服务名/status

例如:api服务 ,则为

域名/api、域名/api/status、域名/api/getip

getip #是获取后端的实际IP地址


cat api.yaml

---

apiVersion: apps/v1

kind: Deployment

metadata:

 name: hello-api-server

 namespace: ops

spec:

 selector:

   matchLabels:

     app: hello-api-server

 replicas: 2

 template:

   metadata:

     labels:

       app: hello-api-server

   spec:

     imagePullSecrets:

     - name: cd-registry

     containers:

     - image: harbor.ttsingops.com/hello/hello-api-server:2

       name : hello-api-server

       imagePullPolicy: Always

       ports:

       - containerPort: 8080

       livenessProbe:

         httpGet:

           path: /api/status

           port: 8080

           scheme: HTTP

         initialDelaySeconds: 60

         timeoutSeconds: 5

         successThreshold: 1

         failureThreshold: 5        

       readinessProbe:

         httpGet:

           path: /api/status

           port: 8080

           scheme: HTTP


       volumeMounts:

       - name: host-time

         mountPath: /etc/localtime

       - name: etc-resolv

         mountPath: /etc/resolv.conf

     volumes:

     - name: host-time

       hostPath:

         path: /etc/localtime

     - name: etc-resolv

       hostPath:

         path: /etc/resolv.conf

---

#Service

apiVersion: v1

kind: Service

metadata:

 name: hello-api-server

 namespace: ops

spec:

 ports:

 - port: 8080

   protocol: TCP

   targetPort: 8080

   #nodePort: 38082

 selector:

   app: hello-api-server


kubectl apply -f api.yaml  


#配置ingress 规则

cat hello-ingress.yaml

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

 name: hello-ingress

 namespace: ops

 annotations:

   kubernetes.io/ingress.class: "nginx"

spec:

 rules:

 - host: ops-k8s.ttsingops.com

   http:

     paths:

     - path: /api

       backend:

         serviceName: hello-api-server

         servicePort: 8080


     - path: /admin

       backend:

         serviceName: hello-admin-server

         servicePort: 8080


kubectl apply -f hello-ingress.yaml


#配置ingress-svc

cat ingress-svc.yaml

apiVersion: v1

kind: Service

metadata:

 name: ingress-nginx

 namespace: ops

 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

     nodePort: 30080

   - name: https

     port: 443

     targetPort: 443

     protocol: TCP

     nodePort: 30443

 selector:

   app.kubernetes.io/name: ingress-nginx

   app.kubernetes.io/part-of: ingress-nginx

kubectl apply -f ingress-svc.yaml

7.png

#这里Ingress的暴露方式,可以根据具体实际需求来考虑决定

主要有:

  • Deployment + LB模式的Service

一般多用在共有云上多,直接创建type类型为LB,然后关联service和pod即可

  • Deployment + NodePort模式的Service

这个需要暴露在特定的IP地址上,且NodePort上多了一层NAT,这个一般用在自建K8S中

  • DaemonSet + HostNetwork +NodeSelector

比较适合大并发的生产环境使用,因为pod与Node的网络互通,直接使用Node的80/443端口就能访问服务。相对比NodePort性能好,但缺点是直接利用了宿主机节点的网络和端口,一个Node只能部署一个ingress控制器 的Pod。


#查看Service及Pod、Ingress信息

kubectl get all -n ops

6.png

kubectl get ingress -n ops  -o wide



#访问验证

1.先访问api及其ip地址

http://ops-k8s.ttsingops.com:30080/api/

8.png

http://ops-k8s.ttsingops.com:30080/api/getip

9.png

2.再访问admin

http://ops-k8s.ttsingops.com:30080/admin

10.png


http://ops-k8s.ttsingops.com:30080/admin/getip

11.png


3.访问一个不存在的接口

http://ops-k8s.ttsingops.com:30080/index

12.png

#我们来查看Ingress-Controller的nginx配置信息

因文件内容太长,这里只列出了一大部分

server {

               server_name ops-k8s.ttsingops.com ;


               listen 80  ;

               listen [::]:80  ;

               listen 443  ssl http2 ;

               listen [::]:443  ssl http2 ;


               set $proxy_upstream_name "-";


               ssl_certificate_by_lua_block {

                       certificate.call()

               }


               location /admin {


                       set $namespace      "ops";

                       set $ingress_name   "hello-ingress";

                       set $service_name   "hello-admin-server";

                       set $service_port   "8080";

                       set $location_path  "/admin";


                       rewrite_by_lua_block {

                               lua_ingress.rewrite({

                                       force_ssl_redirect = false,

                                       ssl_redirect = true,

                                       force_no_ssl_redirect = false,

                                       use_port_in_redirects = false,

                               })

                               balancer.rewrite()

                               plugins.run()

                       }



                       header_filter_by_lua_block {

                               lua_ingress.header()

                               plugins.run()

                       }


                       body_filter_by_lua_block {

                       }


                       log_by_lua_block {

                               balancer.log()


                               monitor.call()


                               plugins.run()

                       }


                       port_in_redirect off;


                       set $balancer_ewma_score -1;

                       set $proxy_upstream_name "ops-hello-admin-server-8080";

                       set $proxy_host          $proxy_upstream_name;

                       set $pass_access_scheme  $scheme;


                       set $pass_server_port    $server_port;


                       set $best_http_host      $http_host;

                       set $pass_port           $pass_server_port;


                       set $proxy_alternative_upstream_name "";


                       client_max_body_size                    1m;


                       proxy_set_header Host                   $best_http_host;



                       proxy_set_header                        Upgrade           $http_upgrade;


                       proxy_set_header                        Connection        $connection_upgrade;


                       proxy_set_header X-Request-ID           $req_id;

                       proxy_set_header X-Real-IP              $remote_addr;


                       proxy_set_header X-Forwarded-For        $remote_addr;


                       proxy_set_header X-Forwarded-Host       $best_http_host;

                       proxy_set_header X-Forwarded-Port       $pass_port;

                       proxy_set_header X-Forwarded-Proto      $pass_access_scheme;


                       proxy_set_header X-Scheme               $pass_access_scheme;


                       proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;


                       proxy_set_header Proxy                  "";



                       proxy_connect_timeout                   5s;

                       proxy_send_timeout                      60s;

                       proxy_read_timeout                      60s;


                       proxy_buffering                         off;

                       proxy_buffer_size                       4k;

                       proxy_buffers                           4 4k;


                       proxy_max_temp_file_size                1024m;


                       proxy_request_buffering                 on;

                       proxy_http_version                      1.1;


                       proxy_cookie_domain                     off;

                       proxy_cookie_path                       off;


                       proxy_next_upstream                     error timeout;

                       proxy_next_upstream_timeout             0;

                       proxy_next_upstream_tries               3;


                       proxy_pass http://upstream_balancer;


                       proxy_redirect                          off;


               }


               location /api {


                       set $namespace      "ops";

                       set $ingress_name   "hello-ingress";

                       set $service_name   "hello-api-server";

                       set $service_port   "8080";

                       set $location_path  "/api";


                       rewrite_by_lua_block {

                               lua_ingress.rewrite({

                                       force_ssl_redirect = false,

                                       ssl_redirect = true,

                                       force_no_ssl_redirect = false,

                                       use_port_in_redirects = false,

                               })

                               balancer.rewrite()

                               plugins.run()

                       }



                       header_filter_by_lua_block {

                               lua_ingress.header()

                               plugins.run()

                       }


                       body_filter_by_lua_block {

                       }


                       log_by_lua_block {

                               balancer.log()


                               monitor.call()


                               plugins.run()

                       }


                       port_in_redirect off;


                       set $balancer_ewma_score -1;

                       set $proxy_upstream_name "ops-hello-api-server-8080";

                       set $proxy_host          $proxy_upstream_name;

                       set $pass_access_scheme  $scheme;


                       set $pass_server_port    $server_port;


                       set $best_http_host      $http_host;

                       set $pass_port           $pass_server_port;


                       set $proxy_alternative_upstream_name "";


                       client_max_body_size                    1m;


                       proxy_set_header Host                   $best_http_host;



                       proxy_set_header                        Upgrade           $http_upgrade;


                       proxy_set_header                        Connection        $connection_upgrade;


                       proxy_set_header X-Request-ID           $req_id;

                       proxy_set_header X-Real-IP              $remote_addr;


                       proxy_set_header X-Forwarded-For        $remote_addr;


                       proxy_set_header X-Forwarded-Host       $best_http_host;

                       proxy_set_header X-Forwarded-Port       $pass_port;

                       proxy_set_header X-Forwarded-Proto      $pass_access_scheme;


                       proxy_set_header X-Scheme               $pass_access_scheme;


                       proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;


                       proxy_set_header Proxy                  "";



                       proxy_connect_timeout                   5s;

                       proxy_send_timeout                      60s;

                       proxy_read_timeout                      60s;


                       proxy_buffering                         off;

                       proxy_buffer_size                       4k;

                       proxy_buffers                           4 4k;


                       proxy_max_temp_file_size                1024m;


                       proxy_request_buffering                 on;

                       proxy_http_version                      1.1;


                       proxy_cookie_domain                     off;

                       proxy_cookie_path                       off;


                       proxy_next_upstream                     error timeout;

                       proxy_next_upstream_timeout             0;

                       proxy_next_upstream_tries               3;


                       proxy_pass http://upstream_balancer;


                       proxy_redirect                          off;


               }


               location / {


                       set $namespace      "";

                       set $ingress_name   "";

                       set $service_name   "";

                       set $service_port   "";

                       set $location_path  "/";


                       rewrite_by_lua_block {

                               lua_ingress.rewrite({

                                       force_ssl_redirect = false,

                                       ssl_redirect = true,

                                       force_no_ssl_redirect = false,

                                       use_port_in_redirects = false,

                               })

                               balancer.rewrite()

                               plugins.run()

                       }



                       header_filter_by_lua_block {

                               lua_ingress.header()

                               plugins.run()

                       }


                       body_filter_by_lua_block {

                       }


                       log_by_lua_block {

                               balancer.log()


                               monitor.call()


                               plugins.run()

                       }


                       port_in_redirect off;


                       set $balancer_ewma_score -1;

                       set $proxy_upstream_name "upstream-default-backend";

                       set $proxy_host          $proxy_upstream_name;

                       set $pass_access_scheme  $scheme;


                       set $pass_server_port    $server_port;


                       set $best_http_host      $http_host;

                       set $pass_port           $pass_server_port;


                       set $proxy_alternative_upstream_name "";


                       client_max_body_size                    1m;


                       proxy_set_header Host                   $best_http_host;



                       proxy_set_header                        Upgrade           $http_upgrade;


                       proxy_set_header                        Connection        $connection_upgrade;


                       proxy_set_header X-Request-ID           $req_id;

                       proxy_set_header X-Real-IP              $remote_addr;


                       proxy_set_header X-Forwarded-For        $remote_addr;


                       proxy_set_header X-Forwarded-Host       $best_http_host;

                       proxy_set_header X-Forwarded-Port       $pass_port;

                       proxy_set_header X-Forwarded-Proto      $pass_access_scheme;


                       proxy_set_header X-Scheme               $pass_access_scheme;


                       proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;


                       proxy_set_header Proxy                  "";



                       proxy_connect_timeout                   5s;

                       proxy_send_timeout                      60s;

                       proxy_read_timeout                      60s;


                       proxy_buffering                         off;

                       proxy_buffer_size                       4k;

                       proxy_buffers                           4 4k;


                       proxy_max_temp_file_size                1024m;


                       proxy_request_buffering                 on;

                       proxy_http_version                      1.1;


                       proxy_cookie_domain                     off;

                       proxy_cookie_path                       off;


                       proxy_next_upstream                     error timeout;

                       proxy_next_upstream_timeout             0;

                       proxy_next_upstream_tries               3;


                       proxy_pass http://upstream_balancer;


                       proxy_redirect                          off;


               }


       }


       server {

               listen 8181 default_server reuseport backlog=511;

               listen [::]:8181 default_server reuseport backlog=511;

               set $proxy_upstream_name "internal";


               access_log off;


               location / {

                       return 404;

               }

       }