Kubernetes(三) 如何從外部訪問服務

  • 2019 年 12 月 20 日
  • 筆記

.example_responsive_1 { width: 200px; height: 50px; } @media(min-width: 290px) { .example_responsive_1 { width: 270px; height: 50px; } } @media(min-width: 370px) { .example_responsive_1 { width: 339px; height: 50px; } } @media(min-width: 500px) { .example_responsive_1 { width: 468px; height: 50px; } } @media(min-width: 720px) { .example_responsive_1 { width: 655px; height: 50px; } } @media(min-width: 800px) { .example_responsive_1 { width: 728px; height: 50px; } } (adsbygoogle = window.adsbygoogle || []).push({});

Kubernetes(三) 如何從外部訪問服務

目錄

Kubernetes教程之對外暴露服務 文章地址: https://blog.piaoruiqing.com/2019/10/20/kubernetes-3-access-service/

前言

通過前文的講解,《跟著官方文檔從零搭建K8S》《應用部署》相信讀者已經對Kubernetes安裝及部署應用有了一定的了解. 接下來, 本文將針對如何將服務暴露給外部進行講解.

閱讀這篇文章你能收穫到:

  • 了解Kubernetes暴露服務的幾種方案及其優缺點.

閱讀本文你需要:

  • 了解基本的Kubernetes命令.
  • 有一個Kubernetes環境

將服務暴露給外部客戶端的幾種方式

  • 通過port-forward轉發, 這種方式在之前的文章中有提到過, 操作方便、適合調試時使用, 不適用於生產環境.
  • 通過NodePort, 此時集群中每一個節點(Node)都會監聽指定埠, 我們通過任意節點的埠即可訪問到指定服務. 但過多的服務會開啟大量埠難以維護.
  • 通過LoadBalance來暴露服務. LoadBalance(負載均衡 LB)通常由雲服務商提供, 如果雲環境中不提供LB服務, 我們通常直接使用Ingress, 或使用MetalLB來自行配置LB.
  • 通過Ingress公開多個服務. Ingress公開了從群集外部到群集內 services 的HTTP和HTTPS路由. 流量路由由Ingress資源上定義的規則控制. 在雲服務商不提供LB服務的情況下, 我們可以直接使用Ingress來暴露服務. (另外, 使用LB + Ingress的部署方案可以避免過多LB應用帶來的花費).

準備

在開始之前, 筆者已經創建好了測試應用, 程式碼過長此處略去, 詳見附錄[1]附錄[2]

我們通過kubectl get pods查看pod列表.

指的一提的是, 我們可以通過--namespace參數查看指定命名空間的pod列表, 也可以通過--all-namespaces來查看全部命名空間的pod列表. 由於沒有指定命名空間,所以應用被放到default中了.

[root@nas-centos1 k8s-test]# kubectl get pods --namespace default  NAME                        READY   STATUS    RESTARTS   AGE  k8s-test-578b77cd47-sw5pd   1/1     Running   0          6m29s  k8s-test-578b77cd47-v6kmp   1/1     Running   0          6m29s

port-forward

port-forward這種方式訪問pod, 可以指定pod實例, 簡單方便, 很適合調試之用.

通過kubectl port-forward來配置轉發:

[root@nas-centos1 k8s-test]# kubectl port-forward --address 0.0.0.0 k8s-test-578b77cd47-sw5pd 9999:8080  Forwarding from 0.0.0.0:9999 -> 8080

此時, 我們可以通過通過訪問宿主機的9999埠來訪問到k8s-test-578b77cd47-sw5pd8080埠.

/k8s-test/timestamp是該示例應用唯一一個api, 用於獲取當前時間戳

[root@nas-centos1 k8s-test]# curl http://10.33.30.95:9999/k8s-test/timestamp  1571151584224

[版權聲明] 本文發佈於朴瑞卿的部落格, 允許非商業用途轉載, 但轉載必須保留原作者朴瑞卿 及鏈接:https://blog.piaoruiqing.com. 如有授權方面的協商或合作, 請聯繫郵箱: [email protected].

NodePort

集群中每一個節點(Node)都會監聽指定埠, 我們通過任意節點的埠即可訪問到指定服務. 但過多的服務會開啟大量埠難以維護. 參考文檔: https://kubernetes.io/docs/concepts/services-networking/service/#nodeport

創建一個Service, 並指定其類型為NodePort.

k8s-test-service.yaml

apiVersion: v1  kind: Service  metadata:    name: k8s-test-service  spec:    selector:      app: k8s-test      env: test    ports:      - port: 80              # 服務埠, 內部可訪問        targetPort: 8080      # 目標埠, 此處指的是pod的8080埠        nodePort: 30080       # 節點埠, 外部可訪問        protocol: TCP    type: NodePort

執行kubectl apply -f k8s-test-service.yaml發布這個Service.

通過kubectl get services可查看Service列表如下:

[root@nas-centos1 k8s-test]# kubectl get services  NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE  k8s-test-service   NodePort    10.244.234.143   <none>        80:30080/TCP   8s  kubernetes         ClusterIP   10.244.0.1       <none>        443/TCP        32d

我們可以看到, 30080埠已經被綁定到該服務的80埠.

嘗試通過node節點來訪問應用:

[root@nas-centos3 ~]# curl http://10.33.30.94:30080/k8s-test/timestamp  1571152525336

LoadBalance

參考文檔:

  1. https://metallb.universe.tf/
  2. https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer

LoadBalance(負載均衡 LB)通常由雲服務商提供. 如果環境不支援LB, 那麼創建的LoadBalance將始終處於<pending>狀態:

[root@nas-centos1 k8s-test]# kubectl get services  NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE  k8s-test-service   LoadBalancer   10.244.29.126   <pending>     80:32681/TCP   13s  kubernetes         ClusterIP      10.244.0.1      <none>        443/TCP        33d

如果想要在本地開發環境測試LB, 我們可以選擇MetalLB. 它是一個負載均衡實現. 安裝方式此處不進行展開, 可參考官方文檔

當我們的環境支援LB時, 我們可以創建如下Service, 來暴露服務:

apiVersion: v1  kind: Service  metadata:    name: k8s-test-service  spec:    selector:      app: k8s-test      env: test    ports:      - port: 80          # 服務埠        targetPort: 8080  # 目標埠, 此處指的是pod的8080埠        protocol: TCP    type: LoadBalancer

執行kubectl apply -f k8s-test-lb.yaml 命令發布配置. 此時可以查看到Service已經有了EXTERNAL-IP(10.33.30.2). 如下:

[root@nas-centos1 k8s-test]# kubectl get services  NAME               TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE  k8s-test-service   LoadBalancer   10.244.151.128   10.33.30.2    80:31277/TCP   2s  kubernetes         ClusterIP      10.244.0.1       <none>        443/TCP        33d

嘗試通過LB的IP來訪問應用, 如下:

[root@nas-centos1 k8s-test]# curl http://10.33.30.2/k8s-test/timestamp  1571235898264

Ingress

Ingress公開了從群集外部到群集內 services 的HTTP和HTTPS路由. 流量路由由Ingress資源上定義的規則控制. 參考文檔: https://kubernetes.github.io/ingress-nginx/deploy/

我們使用ingress controller的nginx實現來進行測試. 首先下載部署文件:

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

編輯文件vim mandatory.yaml, 加入以下內容:

template:    spec:      hostNetwork: true
  • hostNetwork: 開啟hostNetwork, 可以使ingress綁定到主機的80和443埠.
  • 訪問ingress有多種方式, (1). 通過hostNetwork直接綁定到80和443埠, (2). 通過NodePort在Node上暴露埠(但這種方式只能綁定固定範圍的埠, 默認值 30000-32767), (3). 通過LoadBalance, 這種方式和NodePort其實都是通過Service來暴露, 只不過是Service的不同類型.
  • mandatory.yaml中template只有一個, 很好找. (tips: 在vim中可以用/進行查找).
  • Ingress Controller: 是一個反向代理程式, 它負責解析 Ingress 的反向代理規則.
  • Ingress: Ingress 是反向代理規則. 不要混淆Ingress ControllerIngress的概念.

發布完成後, 我們創建一個Ingress來測試, 內容如下:

apiVersion: networking.k8s.io/v1beta1  kind: Ingress  metadata:    name: test-ingress    annotations:      nginx.ingress.kubernetes.io/rewrite-target: /k8s-test  spec:    rules:      - http:          paths:            - path: /k8s-test              backend:                serviceName: k8s-test-service                servicePort: 80

嘗試訪問:

[root@nas-centos1 ingress]# curl http://10.33.30.94/k8s-test/timestamp  1571321623058

小結

通常地, 我們會考慮 LoadBalanceIngress配合使用. 一方面是只是用LB會產生大量的花費, 另一方面大量的LB同樣會提高維護成本. 而LB配合Ingress使用, 通過不同的path來區分服務能達到很棒的效果. (這裡和通過Nginx來暴露多個服務的原理基本相同)

參考文獻

附錄

[1] Deployment.yaml

apiVersion: apps/v1  kind: Deployment  metadata:    name: k8s-test    labels:      app: k8s-test  spec:    replicas: 2    template:      metadata:        name: k8s-test        labels:          app: k8s-test          env: test      spec:        containers:          - name: k8s-test            image: registry.cn-hangzhou.aliyuncs.com/piaoruiqing/k8s-test:0.0.1            imagePullPolicy: IfNotPresent            ports:              - name: http-port                containerPort: 8080        imagePullSecrets:          - name: docker-registry-secret        restartPolicy: Always    selector:      matchLabels:        app: k8s-test

[2] K8sTestApplication.java

/**   * @author piaoruiqing   * @description: k8s test   * @date: 2019/09/22 10:01   * @since JDK 1.8   */  @RestController  @RequestMapping(value = "/k8s-test")  @SpringBootApplication  public class K8sTestApplication {      /**       * get timestamp       * @return       */      @GetMapping(value = "/timestamp")      public ResponseEntity<?> getTimestamp() {          return ResponseEntity.ok(System.currentTimeMillis() + "n");      }        public static void main(String[] args) {          SpringApplication.run(K8sTestApplication.class, args);      }  }

推薦閱讀:

© 2019, 朴瑞卿.

[版權聲明] 本文發佈於朴瑞卿的部落格, 允許非商業用途轉載, 但轉載必須保留原作者朴瑞卿 及鏈接:https://blog.piaoruiqing.com. 如有授權方面的協商或合作, 請聯繫郵箱: [email protected].