iT邦幫忙

2022 iThome 鐵人賽

DAY 15
1

可愛鯨魚

我們這裡有一些很酷的貨櫃要來看看嗎~

圖片來源:Docker (@Docker) / Twitter

前一篇以最簡單的 nodePort Service 公開服務,今天來更仔細的看看 Service

Service

Pod 生命週期短,每次重新部署後都會重新分配一個內部 ip,而且 Pod 在啟動時才會被分配到 ip,沒辦法寫死綁定連線位置

pod lifecycle
圖片來源:Kubernetes: A Pod's Life

Pod 在被斷定為 unhealthy 或是 Deployment 要升級版本都會直接把 Pod 砍掉,幫可憐豆莢 QQ

所以 Kubernetes 就提供了 Service 來解決這些問題

簡單舉例

以一個 web 架構為例

  1. 外部使用者可以透過 Service 設定的外部 ip 連到 frontend Pod
  2. frontend 可以透過 Service 設定的 cluster ip 連到 backend Pod


Service Type

Service type 分為四種

  • ClusterIP: 最基本的 Service,自動分配一個 cluster IP 給 Service 供內部使用
  • NodePort: 在所有 Node 上開 Port 供 cluster 外部使用,Port 範圍限定 30000~32768
  • LoadBalancer: 有一個外部的 LoadBalancer 會透過配發 ip 將流量導向 cluster 內部的 Service,但只有雲端平台有內建這種 LoadBalancer...
  • ExternalName: 將外部服務包裝成 Service 給 cluster 內部使用,會傳 CNAME record 給 externalName DNS

接著會以使用方式來分類講解不同的 Type /images/emoticon/emoticon13.gif


發佈 Service 到 cluster 外

一般 ClusterIP Service 只能在 cluster 內部使用,那要怎麼將 Service 發佈到 cluster 外?

方法大致上分三種:

  1. 使用 Service type NodePort
  2. 使用 Service type LoadBalancer
  3. 搭配 resource Ingress

NodePort

根據 Service nodePort 的設定會在所有 Node 上開出同樣的 port

  • port 預設限定範圍 30000-32767
  • 若要指定特定 Node 處理,使用 kube-proxy --nodeport-addresses
  • 配置完成能透過所有 Node 對此 Service 進行存取
  • 存取方式可透過主機 ip 搭配 nodePort<NodeIP>:nodePort,或是在 cluster 使用內部 ip 搭配原始 Service port<ClusterIP>:port
apiVersion: v1
kind: Service
metadata:
  name: test-service1
  namespace: test
spec:
  type: NodePort
  selector:
    name: test-pod
  ports:
  - name: foo
    port: 80
    targetPort: 80
    nodePort: 30080

LoadBalancer

雲端平台會提供 cluster 外部的 LoadBalancer,因為 NodePort Service 依賴 Node 需要外部的分流導向,雲端的 LoadBalancer 就提供了 Node 之間的附載平衡


cluster 內部連接外部服務

Service 還有一種 Type ExternalName ,用來將外部服務轉換成內部的 DNS 方便內部的使用

例如:
我想要接到 opendata 中央氣象局的 api

apiVersion: v1
kind: Service
metadata:
  name: opendata-api
  namespace: test
spec:
  type: ExternalName
  externalName: opendata.cwb.gov.tw
  ports:
  - port: 443

這樣 cluster 內部就能透過 https://opendata-api.test.svc.cluster.local/api 存取到 https://opendata.cwb.gov.tw/api


接著來看看 Service 和 Pod 之間的聯繫~ /images/emoticon/emoticon06.gif


Pod 怎麼找到 Service?

先來簡單架設個 Pod 和 Service 觀察...

完整檔案到 github Day 15 - test-service.yaml 上參考

透過 env 取得上層 Service

在建立 Pod 的時候自動將 Service 相關設定傳進 container 內部使用 env 儲存

可以看到 Pod env 傳入的設定:

  1. Kubernetes api server
  2. 同個 Namespace 下的 Service
$ kubectl exec -n test test-pod1 -- env | sort
HOME=/root
HOSTNAME=test-pod1
KUBERNETES_PORT_443_TCP_ADDR=192.168.192.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://192.168.192.1:443
KUBERNETES_PORT=tcp://192.168.192.1:443
KUBERNETES_SERVICE_HOST=192.168.192.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
NGINX_VERSION=1.23.1
NJS_VERSION=0.7.6
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PKG_RELEASE=1~bullseye
TEST_SERVICE1_PORT_80_TCP_ADDR=192.168.195.169
TEST_SERVICE1_PORT_80_TCP_PORT=80
TEST_SERVICE1_PORT_80_TCP_PROTO=tcp
TEST_SERVICE1_PORT_80_TCP=tcp://192.168.195.169:80
TEST_SERVICE1_PORT=tcp://192.168.195.169:80
TEST_SERVICE1_SERVICE_HOST=192.168.195.169
TEST_SERVICE1_SERVICE_PORT=80

測試看看 Service ~

$ kubectl exec -n test test-pod1 -- sh -c 'curl -s http:// $TEST_SERVICE1_PORT_80_TCP_ADDR'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 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>

透過 CoreDNS

在 Kubernetes 安裝 CoreDNS plugin (預設已安裝),CoreDNS 會協助處理 cluster 內部的 DNS 服務

可以在 Pod 查看 /etc/resolv.conf

$ kubectl exec -n test test-pod1 -- cat /etc/resolv.conf
nameserver 192.168.192.10
search test.svc.cluster.local svc.cluster.local cluster.local external.dns.tw
options ndots:5
  • nameserver 對應到 kube-dns Service ip
kubectl get svc -n kube-system kube-dns
NAME       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   192.168.192.10   <none>        53/UDP,53/TCP,9153/TCP   45h
  • search cluster.local 對應到 kubelet-config clusterDomain
$ kubectl get cm -n kube-system kubelet-config -o yaml | grep clusterDomain
    clusterDomain: cluster.local

CoreDNS 也是 CNCF Project

使用 FQDN

Pod 可使用 FQDN svc.cluster.local 存取 cluster 內部的 Service

# FQDN
$ kubectl exec -n test test-pod1 -- curl http://test-service1.test.svc.cluster.local
# 同一個 cluster 可省略 cluster domain
$ kubectl exec -n test test-pod1 -- curl http://test-service1.test
# 同一個 namespace 可省略
$ kubectl exec -n test test-pod1 -- curl http://test-service1

Pod 為實體 ip,Service 為虛擬 ip。
kube-proxy 透過 iptables 設定將 Service 虛擬 ip 轉派到對應 Pod 實體 ip。
Service IP addresses | Kubernetes


Ref


明天在繼續介紹基於 Service 的 resource Ingress


上一篇
Day 14 — 有個私人的港口還好吧:私有儲存庫 Harbor (一)(使用 nodePort)
下一篇
Day 16 — 艦艇訪客參觀動線:Ingress & Ingress Controller
系列文
前端轉生~到了實驗室就要養幾隻可愛鯨魚:自架 Kubernetes 迷航日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言