• K8S 暴露服务给*访问的三种方式



    1. NodePort

    kubectl run 创建 pod

    [root@master ~]#kubectl run nginx --image=nginx:1.14 --port=80 --replicas=3
    kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
    deployment.apps/nginx created
    [root@master ~]#kubectl get pods
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-59d795d786-5ln28   1/1     Running   0          34s
    nginx-59d795d786-xnfjq   1/1     Running   0          34s
    nginx-59d795d786-z86nn   1/1     Running   0          34s
    [root@master ~]#kubectl get all
    NAME                         READY   STATUS    RESTARTS   AGE
    pod/nginx-59d795d786-5ln28   1/1     Running   0          59s
    pod/nginx-59d795d786-xnfjq   1/1     Running   0          59s
    pod/nginx-59d795d786-z86nn   1/1     Running   0          59s
    
    NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   3d9h
    
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/nginx   3/3     3            3           59s
    
    NAME                               DESIRED   CURRENT   READY   AGE
    replicaset.apps/nginx-59d795d786   3         3         3       59s
    

    kubectl expose 发布容器

    [root@master ~]#kubectl expose deployment nginx --port=80 --target-port=80 --name=nginx-service --type=NodePort
    service/nginx-service exposed
    
    # 查看 Pod 网络状态详细信息和 Service 暴露的端口
    [root@master ~]#kubectl get svc,pod -o wide
    NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE     SELECTOR
    service/kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        3d9h    <none>
    service/nginx-service   NodePort    10.96.158.55   <none>        80:31083/TCP   3m37s   run=nginx
    
    NAME                         READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
    pod/nginx-59d795d786-5ln28   1/1     Running   0          7m48s   10.244.1.3   node01   <none>           <none>
    pod/nginx-59d795d786-xnfjq   1/1     Running   0          7m48s   10.244.2.3   node02   <none>           <none>
    pod/nginx-59d795d786-z86nn   1/1     Running   0          7m48s   10.244.2.4   node02   <none>           <none>
    

    K8S 模拟项目 pod 发布

    2. Loadbalancer

    k8s 之 PodIP、ClusterIP 和 ExternalIP
      在 k8s 中创建 service 时,需要指定 type 类型,可以分别指定 ClusterIP、NodePort、LoadBalancer 三种,其中前面两种无论在内网还是公网环境下使用都很常见,只有 LoadBalancer 大部分情况下只适用于支持外部负载均衡器的云提供商(AWS、阿里云、华为云等)使用。
      本地自己安装的 k8s 集群,默认是不支持 LoadBalancer 的,需要自己安装一个组件来支持。而云上的 k8s,肯定是都支持 LoadBalancer 的。如果自己公司搭建集群,那肯定也是需要安装 LoadBalancer 的,支持本地集群 LoadBalancer 的组件:

    • metalLB: Netlify 是一家位于旧金山的云计算公司,为 Web 应用程序和静态网站提供托管和无服务器后端服务。
    • openelb: 之前是 PorterLB,KubeSphere 公司开源的,是有中文文档的,不过改名的过程中, 有点乱。

    LoadBalancer 示意图

    2.1 确认 strictARP 模式

    如果你的网络是运行在 IPVS 模式下(默认是 iptables),那么需要设置 strictARP 模式。 链接

    [root@master ~]# curl localhost:10249/proxyMode
    ipvs
    [root@master ~]# kubectl edit configmap -n kube-system kube-proxy
    # 修改其中的 strictARP 为 true,下面字段不是连续的上下行,只展示了需要注意的行数
    ......
        apiVersion: kubeproxy.config.k8s.io/v1alpha1
        kind: KubeProxyConfiguration
        mode: "ipvs"
        ipvs:
          strictARP: true
    ......
    

    2.2 安装 metalLB

    官网可能执行不了
    kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/namespace.yaml
    kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/metallb.yaml

    [root@master ~]#kubectl apply -f http://49.232.8.65/yaml/metallb/namespace.yaml
    namespace/metallb-system created
    [root@master ~]#kubectl apply -f http://49.232.8.65/yaml/metallb/metallb.yaml
    ......
    [root@master ~]#kubectl get pods -n metallb-system
    NAME                          READY   STATUS    RESTARTS   AGE
    controller-857846f7df-l245m   1/1     Running   0          42s
    speaker-5ln28                 1/1     Running   0          42s
    speaker-xnfjq                 1/1     Running   0          42s
    speaker-z86nn                 1/1     Running   0          42s
    # metallb-system 命名空间下有 controller,speaker 等进程已经在 Running 状态,说明正常。
    # metallb-system/controller deployment。用于处理 IP 分配的控制器。
    # metallb-system/speakerdaemonset。集群中每个节点启动一个协议服务守护进程。
    

    2.3 配置 IP 池

    这里我们使用 layer2 协议,毕竟本地测试没有 BGP 设备,如果是正式用,还是要上 BGP 设备的。先申请预留的 IP 端,配置如下:

    [root@master ~]#vim metallb.ip.yaml
    [root@master ~]#cat metallb.ip.yaml
    # 添加一个 ConfigMap 配置 metallb IP 池
    apiVersion: v1
    kind: ConfigMap
    metadata:
      namespace: metallb-system
      name: config
    data:
      config: |
        address-pools:
        - name: default
          protocol: layer2
          addresses:
          - 192.168.10.170-192.168.10.200
    [root@master ~]#kubectl apply -f metallb.ip.yaml
    

    这样当我们创建一个 loadbalancer 类型的 service 时,EXTERNAL-IP 将会从地址池中获取一个用于外部访问的 IP,当外部流量进入时,ARP 将我们的请求地址广播以获取所属的 service,接着 k8s 内部通过 iptables 规则和 kube-proxy 将流量从服务端点引导到后端。
    BGP 类型参考官方文档:链接

    2.4 测试效果

    现在部署一个 Nginx 看看效果

    [root@master ~]#vim nginx-test.yaml
    [root@master ~]#cat nginx-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-metallb-test
    spec:
      selector:
        matchLabels:
          app: nginx-metallb-test
      template:
        metadata:
          labels:
            app: nginx-metallb-test
        spec:
          containers:
          - name: nginx
            image: nginx:1.8
            ports:
            - name: http
              containerPort: 80
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
    spec:
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-metallb-test
      type: LoadBalancer
    
    [root@master ~]#kubectl apply -f nginx-test.yaml 
    deployment.apps/nginx-metallb-test created
    service/nginx-service created
    

    上面声明的 Service 的类型为 LoadBalancer,无其他特殊设置。

    [root@master ~]#kubectl get svc -o wide
    NAME            TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE   SELECTOR
    kubernetes      ClusterIP      10.96.0.1      <none>           443/TCP        9d    <none>
    nginx-service   LoadBalancer   10.96.158.55   192.168.10.170   80:31083/TCP   70s   app=nginx-metallb-test
    

    打开浏览器,访问 EXTERNAL-IP 即可访问 nginx:http://192.168.10.170
    如果是正式环境,则使用 DNS 解析到此 IP,使用域名访问服务即可
    如果有多个服务,可以使用 Nginx Ingress 来通过域名和路径区分不同的服务

    负载均衡可以建立在 OSI 网络模型的不同级别上,主要是在 L4(传输层,例如 TCP/UDP)和 L7(应用层,例如 HTTP)上。在 Kubernetes 中,Services是 L4 的抽象,LoadBalancer 类型负载均衡依然有局限性,同时我们看到每创建一个 service 对应的负载均衡器都会消耗一个静态 IP,这并不合理。当然 k8s 中的另一种资源对象 ingress 可工作在 L7 层实现应用程序协议(HTTP/HTTPS)的负载均衡。

    [root@master ~]#curl 192.168.10.170  # 反应可能比较慢,我等待了几分钟,不知道为啥
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
             35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    

    3. Ingress

    K8s 网关选型初判:Nginx 还是 Envoy?
    我们所说的 Ingress 包含两个部分:

    • ingress 资源对象:流量路由规则的控制。提供 Ingress Kubernetes 对象,能够通过 yaml 进行创建和更新,将服务与域名对应起来。
    • ingress-controller 控制器:控制器的实现有非常多,可参考官方文档中列表 Ingress 控制器,这里我们使用 k8s 官方维护的控制器 NGINX Ingress Controller。

      外部流量进入集群时先经过 ingress-controller,然后根据 ingress 配置的路由规则将请求转发到后端 service。

    3.1 安装 ingress controller

      ingress-controller 其实就是守护进程加一个反向代理的应用,守护进程不断监听集群中资源的变化,将 ingress 中的配置信息生成反向代理配置。在 nginx-ingress controller 中即生成 nginx.conf 的配置文件。
      我们上面已经配置好了 loadbalancer 的服务,这样我们创建一个 type 为 LoadBalancer 的 service 关联这组 pod,再把域名解析指向该地址,就实现了集群服务的对外暴露。当然也可以使用 NodePort、Hostnetwork 的方式,本文不讨论。

    PS:先前实验用的 v1.17.0,做 ingress 实验的时候换成了 v1.22.5,LoadBalancer 实验按照这个链接重做了一下。

    ingress-controller 不是 k8s 内部组件,可以通过 helm 或资源清单方式安装。

    [root@master ~]#kubectl apply -f http://49.232.8.65/yaml/deploy.yaml
    ......
    [root@master ~]#kubectl get pods,svc -n ingress-nginx -o wide
    NAME                                            READY   STATUS      RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
    pod/ingress-nginx-admission-create--1-srl4n     0/1     Completed   0          2m12s   10.244.1.3   node01   <none>           <none>
    pod/ingress-nginx-admission-patch--1-vczxf      0/1     Completed   2          2m12s   10.244.2.3   node02   <none>           <none>
    pod/ingress-nginx-controller-867b8ccd99-7gdhf   1/1     Running     0          2m12s   10.244.2.4   node02   <none>           <none>
    
    NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE     SELECTOR
    service/ingress-nginx-controller             NodePort    10.101.83.140   <none>        80:31700/TCP,443:30401/TCP   2m12s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    service/ingress-nginx-controller-admission   ClusterIP   10.101.43.212   <none>        443/TCP                      2m12s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    

    编辑 service 修改 spec.type 为 LoadBalancer

    [root@master ~]#kubectl edit service/ingress-nginx-controller -n ingress-nginx
    ......
    spec:
      clusterIP: 10.101.83.140
      clusterIPs:
      - 10.101.83.140
    ......
      selector:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
      sessionAffinity: None
      type: LoadBalancer
    ......
    

    这样我们创建好了 nginx-ingress controller,下一步就要配置 ingress 路由规则。

    3.2 配置 ingress 路由规则

    host:http://k8s.com
    基于 url 的路由:
    /api/v1
    /api/v2

    这两个 url 分别路由到不同的 service 中。

    [root@master ~]#vim ingress.yaml
    [root@master ~]#cat ingress.yaml 
    apiVersion: networking.k8s.io/v1 
    kind: Ingress
    metadata:
      name: test
      namespace: training
      annotations:
        ingress.kubernetes.io/rewrite-target: /
    spec:
      rules:
      - host: k8s.com
        http:
          paths:
          - pathType: Prefix
            path: /api/v1
            backend:
              service:
                name: service-apiv1
                port: 
                  number: 80
          - pathType: Prefix
            path: /api/v2
            backend:
              service:
                name: service-apiv2
                port: 
                  number: 80
    [root@master ~]#kubectl create ns training
    namespace/training created
    [root@master ~]#kubectl apply -f ingress.yaml
    ingress.networking.k8s.io/test created
    [root@master ~]#kubectl get ingress -n training -o wide
    NAME   CLASS    HOSTS     ADDRESS   PORTS   AGE
    test   <none>   k8s.com             80      45s
    

    ingress.kubernetes.io/rewrite-target 是 nginx-ingress controller 的一个注解,当后端服务中暴露的 URL 与 Ingress 规则中指定的路径不同时可以通过此重定向。

    查看 svc 可以看到此时控制器已经获得了一个 EXTERNAL-IP
    现在 nginx-ingress controller 和 ingress 路由规则都有了
    通过 CCE 使用 K8S_Ingress

    [root@master ~]#kubectl get svc -n ingress-nginx    # 这个 EIP 是弹性 IP,我们是模拟出来的,在公有云上是公网的 IP,是购买的 LB 给的(假如我们用的百度云,这个 EIP 就是 BLB 给的,百度的公网负载均衡器,一个集群只需要一个 EIP,作为七层的集群入口。PS:在公有云上 ingress 一般是一台单独的机器,它和 nginx 类似,如果运行在 node 节点,流量太大可能接不住。可以将节点 IP 作为 EIP。)
    NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE
    ingress-nginx-controller             LoadBalancer   10.101.83.140   192.168.1.241   80:31700/TCP,443:30401/TCP   44m
    ingress-nginx-controller-admission   ClusterIP      10.101.43.212   <none>          443/TCP
    

    我们可以进入到 nginx-ingress controller pod 中查看 nginx.conf 可以看到此时我们的 ingress 配置已经被生成为路由规则

    [root@master ~]#kubectl get pods -n ingress-nginx
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create--1-srl4n     0/1     Completed   0          90m
    ingress-nginx-admission-patch--1-vczxf      0/1     Completed   2          90m
    ingress-nginx-controller-867b8ccd99-7gdhf   1/1     Running     0          90m
    [root@master ~]#kubectl exec -it ingress-nginx-controller-867b8ccd99-7gdhf -n ingress-nginx /bin/bash
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    bash-5.1$ ls
    fastcgi.conf            mime.types              scgi_params
    fastcgi.conf.default    mime.types.default      scgi_params.default
    fastcgi_params          modsecurity             template
    fastcgi_params.default  modules                 uwsgi_params
    geoip                   nginx.conf              uwsgi_params.default
    koi-utf                 nginx.conf.default      win-utf
    koi-win                 opentracing.json
    lua                     owasp-modsecurity-crs
    bash-5.1$ cat nginx.conf
    ......
    

    3.3 指定后端服务

    接下来就是指定我们的 backend,即上面的 server-apiv1/2。我们添加两个用于暴露的 service 和 deployment,和 loadbalancer 中测试清单一样,我们稍稍修改一下名称即可。

    [root@master ~]#vim backend1.yaml
    [root@master ~]#vim backend2.yaml
    [root@master ~]#cat backend1.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-apiv1
      namespace: training
    spec:
      selector:
        matchLabels:
          app: nginx-apiv1
      template:
        metadata:
          labels:
            app: nginx-apiv1
        spec:
          containers:
          - name: nginx-apiv1
            image: nginx:latest
            ports:
            - name: http
              containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      namespace: training
      name: service-apiv1
    spec:
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-apiv1
      type: NodePort
    [root@master ~]#cat backend2.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-apiv2
      namespace: training
    spec:
      selector:
        matchLabels:
          app: nginx-apiv2
      template:
        metadata:
          labels:
            app: nginx-apiv2
        spec:
          containers:
          - name: nginx-apiv2
            image: nginx:latest
            ports:
            - name: http
              containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      namespace: training
      name: service-apiv2
    spec:
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-apiv2
      type: NodePort
    [root@master ~]#kubectl apply -f backend1.yaml
    deployment.apps/nginx-apiv1 created
    service/service-apiv1 created
    [root@master ~]#kubectl apply -f backend2.yaml
    deployment.apps/nginx-apiv2 created
    service/service-apiv2 created
    [root@master ~]#kubectl get pods,svc -o wide -n training
    NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
    pod/nginx-apiv1-587fb4fd66-ndvhp   1/1     Running   0          48s   10.244.1.4   node01   <none>           <none>
    pod/nginx-apiv2-c55b5bf96-dkkfj    1/1     Running   0          45s   10.244.2.5   node02   <none>           <none>
    
    NAME                    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
    service/service-apiv1   NodePort   10.105.238.31   <none>        80:31845/TCP   48s   app=nginx-apiv1
    service/service-apiv2   NodePort   10.98.58.30     <none>        80:31481/TCP   45s   app=nginx-apiv2
    

    修改 hosts 解析,C:\Windows\System32\drivers\etc\hosts,我们是模拟的假的域名,所以需要修改,真的域名有公网的 DNS 解析

    修改后端访问的 nginx pod 的 index.html,不如访问会 404

    pod 中无法使用 vi 解决:
    apt-get update
    apt-get install vim

    [root@master ~]#kubectl get pods -n training
    NAME                           READY   STATUS    RESTARTS   AGE
    nginx-apiv1-587fb4fd66-ndvhp   1/1     Running   0          25m
    nginx-apiv2-c55b5bf96-dkkfj    1/1     Running   0          25m
    [root@master ~]#kubectl exec -it nginx-apiv1-587fb4fd66-ndvhp -n training /bin/bash
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    root@nginx-apiv1-587fb4fd66-ndvhp:/# ls
    bin  boot  dev	docker-entrypoint.d  docker-entrypoint.sh  etc	home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    root@nginx-apiv1-587fb4fd66-ndvhp:/# cd /usr/share/nginx/html/
    root@nginx-apiv1-587fb4fd66-ndvhp:/usr/share/nginx/html# ls
    50x.html  index.html
    

    注意:Linux 访问就修改 /etc/hosts,Windows 访问就修改 C:\Windows\System32\drivers\etc\hosts

    K8S ingress v1.1.3 部署


    K8S ingressv1.1.3 部署
    3 种发布策略,解决 K8s 中快速交付应用的难题
    k8s loadbalancer 与 ingress 实践


  • 相关阅读:
    jQuery基础【1】
    qTip2 精致的jQuery提示信息插件
    jquery tools 系列(三)——scrollable(2)
    JQuery常用函数及功能小结
    【转】JQ命令汇总 jQuery
    jquery tools系列(一)——tabs(选项卡/页签)
    jquery tools系列(四)——overlay
    肚子
    今天买了部数码相机NiKon S510
    《文渊阁四库全书》书目
  • 原文地址:https://www.cnblogs.com/shenyuanhaojie/p/16411524.html
Copyright © 2020-2023  润新知