美文网首页
K8S 实战(十一)| Service 的 Service:In

K8S 实战(十一)| Service 的 Service:In

作者: 左程立 | 来源:发表于2020-09-29 09:47 被阅读0次

    前言

    ingress 可以理解为 Service 的 Service,即在现有 Service 的前面再搭建一层 Service,作为外部流量的统一入口,进行请求路由的转发。

    说白了就是在前端搭建一个 nginx或者haproxy,将不同 host 或 url 转发到对应的后端 Service,再由 Service 转给 Pod。只不过 ingress 对 nginx/haproxy 进行了一些解耦和抽象。

    更新历史

    Ingress 的意义

    ingress 弥补了默认 Service 暴露外网访问时候的一些缺陷,如不能进行统一入口处的7层 URL 规则,如一个默认 Service 只能对应一种后端服务。

    通常说的 ingress 包含 ingress-controller 和 ingress 对象两部分。

    ingress-controller 对应 nginx/haproxy 程序,以 Pod 形式运行。

    ingress 对象 对应 nginx/haproxy 配置文件。

    ingress-controller 使用 ingress 对象中描述的信息修改自身 Pod 中 nginx/haproxy 的规则。

    部署 ingress

    准备测试资源

    部署2个服务,
    访问服务1,返回 Version 1
    访问服务2,返回 Version 2
    

    两个服务的程序配置

    # cat deployment.yaml 
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-v1.0
    spec:
      selector:
        matchLabels:
          app: v1.0
      replicas: 3
      template:
        metadata:
          labels:
            app: v1.0
        spec:
          containers:
          - name: hello-v1
            image: anjia0532/google-samples.hello-app:1.0
            ports:
            - containerPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-v2.0
    spec:
      selector:
        matchLabels:
          app: v2.0
      replicas: 3
      template:
        metadata:
          labels:
            app: v2.0
        spec:
          containers:
          - name: hello-v2
            image: anjia0532/google-samples.hello-app:2.0
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: service-v1
    spec:
      selector:
        app: v1.0
      ports:
      - port: 8081
        targetPort: 8080
        protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: service-v2
    spec:
      selector:
        app: v2.0
      ports:
      - port: 8081
        targetPort: 8080
        protocol: TCP
    

    让容器运行在 8080 上,service 运行在 8081 上。

    启动两个服务和对应的 Pod

    # kubectl apply -f deployment.yaml    
    deployment.apps/hello-v1.0 created
    deployment.apps/hello-v2.0 created
    service/service-v1 created
    service/service-v2 created
    

    查看启动情况,每个服务对应3个 Pod

    # kubectl get pod,service -o wide
    NAME                              READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
    pod/hello-v1.0-6594bd8499-lt6nn   1/1     Running   0          37s   192.10.205.234   work01   <none>           <none>
    pod/hello-v1.0-6594bd8499-q58cw   1/1     Running   0          37s   192.10.137.190   work03   <none>           <none>
    pod/hello-v1.0-6594bd8499-zcmf4   1/1     Running   0          37s   192.10.137.189   work03   <none>           <none>
    pod/hello-v2.0-6bd99fb9cd-9wr65   1/1     Running   0          37s   192.10.75.89     work02   <none>           <none>
    pod/hello-v2.0-6bd99fb9cd-pnhr8   1/1     Running   0          37s   192.10.75.91     work02   <none>           <none>
    pod/hello-v2.0-6bd99fb9cd-sx949   1/1     Running   0          37s   192.10.205.236   work01   <none>           <none>
    
    NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
    service/service-v1   ClusterIP   192.20.92.221   <none>        8081/TCP   37s   app=v1.0
    service/service-v2   ClusterIP   192.20.255.0    <none>        8081/TCP   36s   app=v2.0
    

    查看 Service 后端 Pod 挂载情况

    [root@master01 ~]# kubectl get ep service-v1
    NAME         ENDPOINTS                                                     AGE
    service-v1   192.10.137.189:8080,192.10.137.190:8080,192.10.205.234:8080   113s
    [root@master01 ~]# kubectl get ep service-v2
    NAME         ENDPOINTS                                                 AGE
    service-v2   192.10.205.236:8080,192.10.75.89:8080,192.10.75.91:8080   113s
    

    可以看到两个服务均成功挂载了对应的 Pod。

    下面部署前端 ingress-controller。

    首先指定 work01/work02 两台服务器运行 ingress-controller

    kubectl label nodes work01 ingress-ready=true
    kubectl label nodes work02 ingress-ready=true
    

    ingress-controller 使用官方 nginx 版本

    wget -O ingress-controller.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/kind/deploy.yaml
    

    修改为启动 2 个 ingress-controller

    # vim ingress-controller.yaml
    
    apiVersion: apps/v1
    kind: Deployment
     。。。。。。
     。。。。。。
      revisionHistoryLimit: 10
      replicas: 2   # 新增该行
    

    修改为国内镜像

    # vim ingress-controller.yaml
    
        spec:
          dnsPolicy: ClusterFirst
          containers:
            - name: controller
              #image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
              image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.32.0
              imagePullPolicy: IfNotPresent
    

    部署 ingress-controller

    kubectl apply -f ingress-controller.yaml
    

    查看运行情况

    # kubectl get pod,service -n ingress-nginx -o wide 
    NAME                                            READY   STATUS      RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
    pod/ingress-nginx-admission-create-ld4nt        0/1     Completed   0          15m   192.10.137.188   work03   <none>           <none>
    pod/ingress-nginx-admission-patch-p5jmd         0/1     Completed   1          15m   192.10.75.85     work02   <none>           <none>
    pod/ingress-nginx-controller-75f89c4965-vxt4d   1/1     Running     0          15m   192.10.205.233   work01   <none>           <none>
    pod/ingress-nginx-controller-75f89c4965-zmjg2   1/1     Running     0          15m   192.10.75.87     work02   <none>           <none>
    
    NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP                   PORT(S)                      AGE   SELECTOR
    service/ingress-nginx-controller             NodePort    192.20.105.10   192.168.10.17,192.168.10.17   80:30698/TCP,443:31303/TCP   15m   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    service/ingress-nginx-controller-admission   ClusterIP   192.20.80.208   <none>                        443/TCP                      15m   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    

    可以看到 work01/02 上运行了 ingress-nginx-controller Pod。

    编写访问请求转发规则

    # cat ingress.yaml 
    
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: nginx-ingress
    spec:
      rules:
      - host: test-v1.com
        http:
          paths:
          - path: /
            backend:
              serviceName: service-v1
              servicePort: 8081
      - host: test-v2.com
        http:
          paths:
          - path: /
            backend:
              serviceName: service-v2
              servicePort: 8081
    

    启用规则

    # kubectl apply -f ingress.yaml
    ingress.networking.k8s.io/nginx-ingress created
    

    可以看到 ingress-controller Pod 里面 nginx 配置已经生效了

    # kubectl exec ingress-nginx-controller-75f89c4965-vxt4d -n ingress-nginx -- cat /etc/nginx/nginx.conf | grep -A 30 test-v1.com
    
            server {
                    server_name test-v1.com ;
                    
                    listen 80  ;
                    listen 443  ssl http2 ;
                    
                    set $proxy_upstream_name "-";
                    
                    ssl_certificate_by_lua_block {
                            certificate.call()
                    }
                    
                    location / {
                            
                            set $namespace      "default";
                            set $ingress_name   "nginx-ingress";
                            set $service_name   "service-v1";
                            set $service_port   "8081";
                            set $location_path  "/";
    
    

    我们在集群外部访问测试。

    首先解析域名到work01

    # cat /etc/hosts
    192.168.10.15 test-v1.com
    192.168.10.15 test-v2.com
    

    访问测试

    # curl test-v1.com
    Hello, world!
    Version: 1.0.0
    Hostname: hello-v1.0-6594bd8499-svjnf
    
    # curl test-v1.com
    Hello, world!
    Version: 1.0.0
    Hostname: hello-v1.0-6594bd8499-zqjtm
    
    # curl test-v1.com
    Hello, world!
    Version: 1.0.0
    Hostname: hello-v1.0-6594bd8499-www76
    
    # curl test-v2.com
    Hello, world!
    Version: 2.0.0
    Hostname: hello-v2.0-6bd99fb9cd-h8862
    
    # curl test-v2.com
    Hello, world!
    Version: 2.0.0
    Hostname: hello-v2.0-6bd99fb9cd-sn84j
    

    可以看到不同域名的请求去到了正确的 Service 下面的不同 Pod 中。

    再请求 work02

    # cat /etc/hosts
    192.168.10.16 test-v1.com
    192.168.10.16 test-v2.com
    
    # curl test-v1.com
    Hello, world!
    Version: 1.0.0
    Hostname: hello-v1.0-6594bd8499-www76
    
    # curl test-v1.com
    Hello, world!
    Version: 1.0.0
    Hostname: hello-v1.0-6594bd8499-zqjtm
    
    # curl test-v2.com
    Hello, world!
    Version: 2.0.0
    Hostname: hello-v2.0-6bd99fb9cd-sn84j
    
    # curl test-v2.com
    Hello, world!
    Version: 2.0.0
    Hostname: hello-v2.0-6bd99fb9cd-h8862
    
    

    也没问题。

    如何高可用

    在 work01 / work02 前面再挂2台 LVS+keepalived 就可以实现对 work01/02 的高可用访问了。
    也可以在 work01 / work02 上直接使用 keepalived 漂一个VIP,不需要额外机器,这样节约成本。
    

    结束语

    本文使用了 Deployment + NodePort Service 的方式部署 Ingress。

    用 Deployment 管理 ingress-controller 的 Pod,使用 NodePort 方式暴露 ingress Service。

    查看 ingress service

    # kubectl get service -o wide -n ingress-nginx
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP                   PORT(S)                      AGE   SELECTOR
    ingress-nginx-controller             NodePort    192.20.105.10   192.168.10.17,192.168.10.17   80:30698/TCP,443:31303/TCP   22m   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    

    可以看到对外暴露了 30698 端口,访问任何节点的 30698 端口即可访问到 v1/v2 版本的 Pod。

    但该端口是随机的,并且重建后会变化,我们可以直接访问运行 ingress-controller Pod 的 work01/02 的 80 端口。

    work01/02前面再弄一套 LVS+keepalived 进行高可用负载。

    work01/02 上使用 iptables -t nat -L -n -v 可以看到 80 端口是通过 NAT 模式开放的,高流量会有瓶颈。

    可以使用 DaemonSet + HostNetwork 的方式来部署 ingress-controller。

    这样 work01/02 上暴露的 80 端口直接使用宿主机的网络,不走NAT映射,可以避免性能问题。

    相关文章

      网友评论

          本文标题:K8S 实战(十一)| Service 的 Service:In

          本文链接:https://www.haomeiwen.com/subject/hmoyyktx.html