今天講 Pod 為什麼能用 Service Name 就跟 Service 連接上,然後補一下 Namespace 的 Overview。
在 Kubernetes 中,Namespace 是個虛擬的概念 (不是 linux 中的 Namespace。題外話:service 這個名字的使用個人覺得也滿容易混淆),用來隔離同個 Cluster 中的資源。以使用情境來看,多個團隊或是不同的專案都可能使用同一個 Cluster,但避免不同的資源互相干擾或是做權限的控管就可使用 Namespace 來隔絕資源。
在同一個 Namespace 中,同一個種類的資源名字必須要是獨特的,不過不同 Namespace 中可以同名。
在 Cluster 建立的時候會有幾個 Initial Namespaces -
Lease
objects,每個 node 會有對應的 lease object 在這個 namespace 中。Node 上的 kubelet 會定期向 API server 發送 hearbeats,同時也更新對應的 node lease object,讓 control plane 可以確認 Node 的存活狀況Namespace 相關的指令 -
# ns: namespace
kubectl create ns new-ns
kubectl get ns
kubectl delete ns
要注意刪除 namespace,其中的所有資源都會一起被刪掉。
使用 yaml 來建立 -
apiVersion: v1
kind: Namespace
metadata:
name: new-ns
在同一個 namespace 的 Pod 可以透過 service 的名字互相連接,而不需要知道 service IP & port。
當 service 被建立時,Kubernetes 會為這個 service 建立一個 DNS record,這個 DNS record 格式會是<service name>.<namespace>.svc.<domain name>
。例如在 default
namespacce 中建立了一個名為 db-service
的 service,那這個 DNS record 就會是 db-service.default.svc.cluster.local
現在來對應一下:<service name>
: =db-service
, service 名稱<namespace>
: =default
, namespace 名稱svc
: service 的意思<domain name>
: kubernetes cluster 的預設域名,通常會是 cluster.local
在 Kubernetes 中,會有 DNS server 來幫忙做 DNS 解析。當 Pod 對 Service Name 做 DNS 查詢時,DNS server 就能透過 Service Name 去找出相關的 DNS record,解析出對應的Service IP。Pod 就能連接到對應的 Service。
例如:
# psedo code
mysql.connect("db-service")
mysql.connect("db-service.default.svc.cluster.local")
這兩種寫法都能連接到 default
namespace 中的 db-service
service。
對同一個 Namespace 的 Pod 來說,它可以只使用 service name 就找到對應的服務,不用指定 namespace。因為 Pod 在建立時,kubelet 會設置 Container 內部的 /etc/resolv.conf
檔案,添加 Pod 所在的 namespace 的網域名稱,例如:
# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.43.0.10
options ndots:5
當 Pod 用 service name 進行 DNS 查詢的時候,就能帶上這邊定義的網域,找到正確的 Service。
先前也有提到 Service 是可以供所有 Cluster 中的 Pod 訪問的,只不過要訪問別的 Namespace 的 Service 的話,就必須帶上正確的域名,才能找到正確的 Service。
預設的 namespace 為 default,所以當我們下 kubectl get ...
的指令,若沒有指定 namespace 則是會列出 default namespace 中的資源。如果想要看目前的 namespace 是什麼、更改當前 namespace,可以使用下面的指令:
kubectl config view
kubectl config set-context --current --namespace=test
還沒更改 namespace 前,kubectl config view
的 output,沒有特地寫 namespace 但使用上沒下 tag 會是 default
接著建立一個 namespace test
,並運行一個 Pod;更改 name space 後 kubectl 就不用再下 -n
tag 就會列出 test
namespace 中的資源
Kubernetes 的資源有些是定義在某個 Namespace 之中,但有些資源則是不屬於任何 Namespace 的,建立及管理是在 Cluster level,可以在不同的 Namespace 中被使用。常見的 pods、services、deployments … 都是需要在同個 Namespace 之中;不過像 storage class、node、persistent volume 這類就不是 namespace level objects。
可使用以下指令來看有哪些 objects 是在 Namespace 之中 -
# In a namespace
kubectl api-resources --namespaced=true
# Not in a namespace
kubectl api-resources --namespaced=false
最後再釐清一下 Namespace & Node。一開始看到 Namespace 的概念的時候其實有點混淆,這跟 Node 的關係是什麼。
→ Node 是實際的主機(伺服器),可以是實體或是虛擬的,Pod 運行在 Node 上
→ Namespace 是一種 Kubernetes 資源,是一個虛擬的隔離環境。不同 Node 上面跑的 Pods 可以是屬於同一個 Namespace 的,同一個 Node 上面跑的 Pods 也可以是屬於不同 Namespace 的
透過 Namespace 的方式可以做到資源隔離、資源管理,像是前面提到的 Resource Quota & LimitRange 就是 Namespace level objects。另外在權限的控制上,可設置 Role 來操作特定 Namespace 中的特定資源。
Reference
https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
https://kubernetes.io/docs/reference/kubectl/cheatsheet/