0%

kubernetes 筆記 - Component 2

前言

上篇提到使用 Kubernetes 的一些基本元件。這次本篇主要在紀錄 Kubernetes 常用有關網路元件的介紹和如何使用:

  • Service
  • Ingress

Service

Service Discovery

Pod 重啟或重新部署都會產生新的 IP ,透過 Service 當作媒介,管理與監控這些 Pods 並對外暴露自己的 IP 供別人訪問存取。

Serivce 物件

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
# sessionAffinity: ClientIP # 根據需要來設定
ports:
- port: 80 # service 的 port
targetPort: 8080 # service 會將封包轉送的 port
selector:
app: kubia

  1. 在 cluster 中若需要 pod-to-pod 請求中,請使用 Service 的 name 作為 hostname 而非 Pod ip 。
    • 因為你非但不能在 Pod 被建立以前知道他的 IP ,即使可以 Pod 隨時都有可能重啟或重新部署而改變 IP。
    • http://kubia.<namespace>

  2. sessionAffinity 只有 ClientIP 和 None 兩種模式,並沒有 cookie-based 。因為 K8s Service 是在 L4 而非 L7 所以只有 TCP 和 UDP

多埠 Service 物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- name: http # 外部 80 轉送到內部 8080
port: 80
targetPort: 8080
- name: https # 443 轉送到 8443
port: 443
targetPort: 8443
selector:
app: kubia

使用命名埠

好處是萬一不是一個常見的 port 號,可以透過命名的方式讓結構更清晰

可以隨時更改底層 (Pod) 的 port 號而不會影響到上層的服務 (Service)

首先,先為 Pod 建立好 port 的名字

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
spec:
containers:
- name: kubia
ports:
- name: http # 容器的 port 號 8080 命名為 http
containerPort: 8080
- name: https # 容器的 port 號 8443 命名為 https
containerPort: 8443

再來是為 Pod 建立好 Service

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Service
spec:
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https

為什麼 ping 不到 Service 的 IP ?

  1. kube-proxy 負責監控 Endpoints 的改變
  2. kube-proxy 如有服務訪問這組 IP 就會被 iptables 修改並且 forward 掉

讓外部的用戶連線到 cluster 的 Service

讓外部來連線 Service 有以下幾種方式

  1. 將 Service 的類型設為 NodePort

    • 每一個在 cluster 裡面的 Node 都會開一個 Port ,然後把流量轉送到底層的 Service
    • 該 Service 不僅可以透過 ClusterIP 和 Port 來訪問,也可以透過每個 Node 上的 Port
  2. 將 Service 的類型設為 LoadBalancer

    • 是 NodePort 的擴充版
    • 是根據不同 cloud infrastructure 而定
    • 用戶通過 load balancer 的 IP 來訪問 service
  3. 建立 Ingress 資源,一種根本不同的機制,用於通過唯一 IP 公開多個服務

    • 它是在 Layer 7 上運作的

NodePort

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: kubia-nodeport
spec:
type: NodePort
ports:
- port: 80 # 這是內部 cluster IP 的 port
targetPort: 8080 # 這是 Pod 的 port
nodePort: 30123 # Service 可以從 Node 的 port 來被存取
selector:
app: kubia

可以使用以下指令來檢查 NodePort Service

kubectl get svc kubia-nodeport

可以看到 EXTERNAL-IP<nodes> ,也就是說該 Service 可以在每一個 node 上透過 30123 port 被存取。

LoadBalancer

  • 用在公有雲上, cloud providers 通常會支援該模式。
  • 與 NodePort 不同,它是透過唯一的 Public IP 來做存取。


1
2
3
4
5
6
7
#...
spec:
type: LoadBalancer
ports:
- port: 80 # 這是內部 cluster IP 的 port
targetPort: 8080 # 這是 Pod 的 port
#...

Ingress

單純定義一個 Service 並讓 Ingress 指向它

1
2
3
4
5
6
7
8
9
10
#...
kind: Service
metadata:
name: kubia
spec:
ports:
- port: 80 # service 的 port
targetPort: 8080 # service 會將封包轉送的 port
selector:
app: kubia

連接 cluster 外部的 Service

Service 與 Endpoints 的關係

  • Service 和 Pod 並不是直接有所連結的,而是有一個叫做 Endpoints 的資源在中間。
  • Endpoints 資源(複數)是一組一組可供 Service 做 loadbalance 的 Pod socket 清單

kubectl describe svc kubia

kubectl get endpoints kubia


  1. 如果 Service 有設定 Pod 的 label selector 就會自動產生 Endpoints 物件,並且幫你自動維護
  2. 反之,必須自己建立 Endpoints 物件,並且必須與 Service 同名

自己設定 Service Endpoints 的時機:連線到外部網路的服務

  1. 創建一個沒有 selector 的 Service

    1
    2
    3
    4
    5
    6
    7
    apiVersion: v1
    kind: Service
    metadata:
    name: google-map # Service 的名字必須和 Endpoints 一樣
    spec: # 無需定義 selector
    ports:
    - port: 80
  2. 為沒有 selector 的 Service 創建 Endpoints

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    apiVersion: v1
    kind: Endpoints
    metadata:
    name: google-map # Endpoints 的名字必須和 Service 的一樣
    subsets:
    - addresses:
    - ip: 11.11.11.11 # Service 將連接轉發到的端點的 IP
    - ip: 22.22.22.22
    ports:
    - port: 80


Service 和 Endpoints 建立起來後,就可以讓 Pods 透過 Service 存取具有兩個外部端點。


連線到外部網路服務的另一種方式:ExternalName Service

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
name: google-map
spec:
type: ExternalName # Service 的類型為 ExternalName
externalName: maps.googleapis.com # 真實服務的 FQDN
ports:
- port: 80
  • Pod 呼叫外部的 API 就使用 http://google-map
  • 不影響 Pod 的情況下,在 ExternalName Service 上改變存取的外部服務的網址

Ingress

為什麼一定需要 Ingress ?

每一個 LoadBalancer Service 都需要有自己的 IP,而 Ingress 只需要一個 IP。

Ingress 是在 Layer 7 上面運作,所以可以提供比 Service 更多的功能。

Ingress Controller

必須記得 K8s cluster 中必須要有 Ingress controller 才可以讓 Ingress 正常運作。不同的 K8s 環境在 controller 實作上也不同。

創建 Ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80
# - path: /foo
# backend:
# serviceName: bar
# servicePort: 80
# - host: bar.example.com
# http:
# paths:
# - path: /
# backend:
# serviceName: bar
# servicePort: 80

一個 client 向 K8s cluster 請求的基本流程