k8s 如何對外提供服務


本文將介紹在 k8s 中向外界提供服務的幾種方法port-forwardNodePort,以及 更加常用的提供服務的資源ingress。本文要求對service資源有一定的了解,如果你還不清楚的話,可以點擊 k8s 中的服務如何溝通 簡單學習一下。

接下來的內容需要一些pod作為實際的服務處理者,你可以通過下面命令新建一個rs,這個rs會新建三個名為kubia-xxxx的 pod,其8080端口會開放一個服務,請求時會返回其所在節點名稱:

kubectl create -f https://raw.githubusercontent.com/luksa/kubernetes-in-action/master/Chapter04/kubia-replicaset.yaml 

port-forward 映射服務到端口

首先來看一下最簡單粗暴的方法,我們可以通過一條 k8s 命令來將指定的 pod 端口映射到本地的端口上,基本用法如下:

kubectl port-forward <資源類型>/<資源名> <本機端口>:<資源端口> 

例如,我有個 pod 叫做kubia,它通過80端口對外提供服務,那么我就可以使用kubectl port-forward pod/kubia 8080:80將其映射到本機的8080端口上。你可以使用kubectl port-forward -h查看更多用法。

啟用后會占用當前終端的標准輸出,可以在后面添加&來指定后台運行:

root@master1:~# k port-forward kubia-5k2zr 8080:8080 & [1] 13949 Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 root@master1:~# curl http://localhost:8080 Handling connection for 8080 You've hit kubia-5k2zr 

port-forward可以將 pod 臨時映射出來,一般用於測試資源是否可用,在生產環境並不會大規模應用。

NodePort 映射服務到節點端口

相對於上一種port-forward來說,這一種要正式的多,NodePort可以將其 轉發到所有 k8s 節點的指定端口上,並且不會像port-forward一樣在前台運行。我們先來新建一個NodePort,新建nodeport.yaml文件並填寫如下內容,然后使用kubectl create -f nodeport.yaml新建。:

apiVersion: v1
kind: Service
metadata:
  name: kubia-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30123
  selector:
    app: kubia

通過kind屬性可以看到NodePort本質上是一個svc資源,他通過指定spec.ports.nodePort來講服務映射到節點的端口上,接下來我們就可以訪問下試試,直接curl訪問節點ip + 端口號即可,你可以通過kubectl get nodes -o wide找到所有 k8s 節點的 ip:

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-m68bq

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-flg8w

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-flg8w

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-8r2cg

root@master1:~# curl http://192.168.56.11:30123
You've hit kubia-m68bq

可以看到,使用了nodePort之后,服務被正常的請求,並且也正常的被均衡到每一個 pod 上。

但是這里有個問題,假如我的 k8s 里運行了多個 web 應用服務器,我總不能讓用戶通過端口號http://domain:8081http://domain:8082來訪問不同的 web 服務吧。能不能處理成http://domain/web1http://domain/web2 ...這種形式呢。

當然可以,這個就是接下來要說的Ingress

通過 Ingress 暴露服務

ingress 是啥?其實,ingress 就是一個nginx服務器。從本質上說,我們可以直接通過配置nginx服務器來實現剛才說的訪問方式,但是這樣每次svc發生變更了我們就要重新手動配置一遍,好麻煩的,於是就有聰明的人想出來了,為什么我們不把復雜的配置操作抽象成一個文件,這樣有新的變更的話我們直接修改文件,不就可以避免直接操作nginx服務器了么?於是,ingress誕生了。記住,ingress本質上就是一個nginx和許多個配置文件

ingress 有兩部分構成,負責轉發服務的nginx-ingress-controller和每個服務的配置文件ingress資源,如下:

 
通過 ingress 配置 service 訪問

每個想要對外暴露的svc都需要有一個對應的ingress資源(配置文件)才能對外提供服務,ingress資源並不負責實際的流量轉發,它只是告訴nginx-ingress-controller應該把流量轉發到哪個svc

接下來,我們實踐一下,從頭部署一個可用的ingress

安裝 ingress

k8s 並不自帶 ingress,所以我們需要重新安裝,幸好安裝比較簡單,直接執行如下命令即可,k8s 會根據其內容安裝所有需要的資源。

kubectl apply -f https://raw.githubusercontent.com/StudyXX/google-containers/v1.10.2/install/ingress-nginx/ingress-nginx-controller.yaml 

如果出現了鏡像拉取失敗的情況可以先手動將命令中的配置文件下載下來,然后將其的鏡像地址從quay.io/替換成quay-mirror.qiniu.com/,重新kubectl apply即可。文件地址為 github - StudyXX/ingress-nginx-controller.yaml

安裝成功之后可以執行如下操作查看 ingress 是否安裝完成,輸入kubectl get namespaces,查看ingress-nginx(ingress相關的pod組) 的狀態是否為Active。輸入kubectl get pod -n ingress-nginx,查看nginx-ingress-controller(負責實際轉發流量的nginx) 的狀態是否為Running

root@master1:~# kubectl get namespaces NAME STATUS AGE default Active 34d ingress-nginx Active 27d kube-node-lease Active 34d kube-public Active 34d kube-system Active 34d root@master1:~# kubectl get pod -n ingress-nginx NAME READY STATUS RESTARTS AGE default-http-backend-7vg6q 1/1 Running 1 26d nginx-ingress-controller-5c4964c449-9ccbm 1/1 Running 2 26d 

這兩者正常基本可以斷定ingress安裝成功了,接下來我們來創建一個對外服務。

使用 ingress 創建對外服務

在"通過 ingress 配置 service 訪問"圖里我們可以看出,使用 ingress 暴露服務需要先新建一個svc,所以我們先使用如下內容創建一個,它會把 pod kubia端口8080上的服務轉發到自己的8080上,他控制的 pod 就是我們文章開頭時新建的那些

kubia-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: kubia

然后使用kubectl create -f kubia-svc.yaml創建該svc,接下來我們創建一個ingress。ingress 支持創建HTTPHTTPS的服務,接下來我們先來創建一個HTTP的:

創建 HTTP 協議的訪問

http協議的訪問比較簡單,直接創建如下配置文件即可,通過這個ingress配置文件,nginx-ingress-controller就知道如何對外開發服務了。

kubia-http-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
    # 將服務映射到該域名
  - host: kubia.example.com
    http:
      paths:
        # 通過 / 路徑就可以訪問該服務
      - path: /
        # 該服務后端 svc 的名稱及端口號
        backend:
          serviceName: kubia
          servicePort: 8080

然后使用kubectl create -f kubia-http-ingress.yaml就可以創建ingress了。我們可以使用kubectl describe ingress kubia來查看他的介紹:

root@master1:~# k describe ingress kubia Name: kubia Namespace: default Address: Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- kubia.example.com / kubia:8080 (10.244.1.59:8080,10.244.2.31:8080,10.244.3.30:8080) Annotations: Events: <none> 

ok,現在我們就可以通過http://kubia.example.com/來訪問目標svc啦,這時你可能會疑惑,我沒這個域名啊?沒關系,在系統的hosts文件里配置一下,將這個域名映射到nginx-ingress-controller的 ip 地址就可以了,詳情見下方:

配置域名到 ip 地址

首先獲取nginx-ingress-controller的 ip 地址,執行如下命令后按Tab補全名稱,然后在IP列就可以找到對應的 ip 了。

kubectl describe pod -n ingress-nginx nginx-ingress-controller-

我的 ip 地址為192.168.56.22,執行vi /etc/hosts,輸入以下內容即可:

192.168.56.22 kubia.example.com

修改完了之后,我們就可以進行訪問了,執行curl http://kubia.example.com/,就可以看到來自 svc kubia的響應了。

root@master1:~# curl http://kubia.example.com/
You've hit kubia-m68bq

root@master1:~# curl http://kubia.example.com/
You've hit kubia-8r2cg

root@master1:~# curl http://kubia.example.com/
You've hit kubia-flg8w

創建 HTTPS 協議的訪問

這里的 https 訪問是指從客戶端到 ingress 控制器之間的連接是加密的,而控制器與后端svcpod之間的連接則還是 http,如下所示:

 
https 請求鏈路

想要讓ingress可以提供https服務,我們首先需要有證書和私鑰,這里我們先來創建他們倆:

openssl genrsa -out tls.key 2048 openssl req -new -x509 \ -key tls.key \ -out tls.cert \ -days 360 \ -subj /CN=kubia.example.com 

執行完之后你就可以在當前文件夾下發現兩個文件,分別為tls.certtls.key。因為這種秘鑰比較敏感,不適合直接掛載到 pod 上,所以可以使用 k8s 提供的專門用於提供敏感數據的資源secret來存放它,我們先來新建一個名為tls-secretsecret資源:

kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key

什么是secret資源?

secret用於存放一些敏感的配置信息,如密碼、密鑰等,你可以把他理解成一個更安全的ConfigMap資源,k8s 提供了很多類型的secret,例如上文的kubectl create secret tls就是一個常用的secret

然后我們就可以修改上文中的kubia-http-ingress.yaml,將這個secret掛載上去:

kubia-https-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  # 添加 tls 字段來啟用 https
  tls:
  - hosts: 
      # 啟用 https 的域名
    - kubia.example.com
    # 給其分配的證書及密鑰,要求 tls 類型的 k8s secret 資源
    secretName: tls-secret
  rules:
  - host: kubia.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kubia
          servicePort: 8080

然后我們就可以通過以下命令來講剛才創建的http服務提升至httpskubectl apply依靠kindmetadata字段中的數據來尋找要修改的資源,所以改名字並不會造成什么影響

kubectl apply -f kubia-https-ingress.yaml

然后輸入curl -k -v https://kubia.example.com,就可以發現我們的服務已經啟用的https連接:

root@master1:~# curl -k -v https://kubia.example.com ... * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt ... * Server certificate: * subject: CN=kubia.example.com ... You've hit kubia-flg8w 

使用 ingress 暴露多個服務

kubia-ingress.yaml文件中可以看到,rulespaths都是數組,所以我們可以通過其暴露多個服務,如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
  - host: foo.example.com
    http:
      paths:
        # 通過指定不同的路徑來訪問不同的服務
      - path: /foo
        backend:
          serviceName: foo-svc
          servicePort: 8080
      - path: /bar
        backend:
          serviceName: bar-svc
          servicePort: 8080
  # 也可以通過指定多個 host 來配置不同的主機
  - host: foo.example.com
    http:
      paths:
      - path: /kubia
        backend:
          serviceName: kubia
          servicePort: 8080

但是哪怕在一個文件中可以配置多個規則,但是依舊推薦為每一個svc都創建一個自己專屬的ingress,這樣條理會比較清晰,也方便日后的管理。

總結

本文介紹了如何將服務暴露出去,最簡單的是port-forward命令,他可以將指定資源的端口轉發到本機,但是一般都用於測試。

其次是NodePort模式,NodePort本質上也是個svc,只不過他在完成svc本質工作的同時還將服務開放到了集群中所有節點的指定端口上。

但是用戶更傾向於通過子路徑訪問服務,而不是端口。為了實現這個目標,我們可以使用ingress資源,通過發布ingress配置文件,nginx-ingress-controller就可以將指定的服務發布到指定域名的指定路徑上,ingress支持發布HTTPHTTPS連接。



作者:HoPGoldy
鏈接:https://www.jianshu.com/p/58976bf0a8a4
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM