k8s 如何對(duì)外提供服務(wù)

本文將介紹在 k8s 中向外界提供服務(wù)的幾種方法port-forward、NodePort,以及 更加常用的提供服務(wù)的資源ingress。本文要求對(duì)service資源有一定的了解,如果你還不清楚的話,可以點(diǎn)擊 k8s 中的服務(wù)如何溝通 簡單學(xué)習(xí)一下。

接下來的內(nèi)容需要一些pod作為實(shí)際的服務(wù)處理者,你可以通過下面命令新建一個(gè)rs,這個(gè)rs會(huì)新建三個(gè)名為kubia-xxxx的 pod,其8080端口會(huì)開放一個(gè)服務(wù),請(qǐng)求時(shí)會(huì)返回其所在節(jié)點(diǎn)名稱:

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

port-forward 映射服務(wù)到端口

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

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

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

啟用后會(huì)占用當(dāng)前終端的標(biāo)準(zhǔn)輸出,可以在后面添加&來指定后臺(tái)運(yùn)行:

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 臨時(shí)映射出來,一般用于測(cè)試資源是否可用,在生產(chǎn)環(huán)境并不會(huì)大規(guī)模應(yīng)用。

NodePort 映射服務(wù)到節(jié)點(diǎn)端口

相對(duì)于上一種port-forward來說,這一種要正式的多,NodePort可以將其 轉(zhuǎn)發(fā)到所有 k8s 節(jié)點(diǎn)的指定端口上,并且不會(huì)像port-forward一樣在前臺(tái)運(yùn)行。我們先來新建一個(gè)NodePort,新建nodeport.yaml文件并填寫如下內(nèi)容,然后使用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本質(zhì)上是一個(gè)svc資源,他通過指定spec.ports.nodePort來講服務(wù)映射到節(jié)點(diǎn)的端口上,接下來我們就可以訪問下試試,直接curl訪問節(jié)點(diǎn)ip + 端口號(hào)即可,你可以通過kubectl get nodes -o wide找到所有 k8s 節(jié)點(diǎn)的 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之后,服務(wù)被正常的請(qǐng)求,并且也正常的被均衡到每一個(gè) pod 上。

但是這里有個(gè)問題,假如我的 k8s 里運(yùn)行了多個(gè) web 應(yīng)用服務(wù)器,我總不能讓用戶通過端口號(hào)http://domain:8081http://domain:8082來訪問不同的 web 服務(wù)吧。能不能處理成http://domain/web1、http://domain/web2 ...這種形式呢。

當(dāng)然可以,這個(gè)就是接下來要說的Ingress

通過 Ingress 暴露服務(wù)

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

ingress 有兩部分構(gòu)成,負(fù)責(zé)轉(zhuǎn)發(fā)服務(wù)的nginx-ingress-controller和每個(gè)服務(wù)的配置文件ingress資源,如下:

通過 ingress 配置 service 訪問

每個(gè)想要對(duì)外暴露的svc都需要有一個(gè)對(duì)應(yīng)的ingress資源(配置文件)才能對(duì)外提供服務(wù),ingress資源并不負(fù)責(zé)實(shí)際的流量轉(zhuǎn)發(fā),它只是告訴nginx-ingress-controller應(yīng)該把流量轉(zhuǎn)發(fā)到哪個(gè)svc。

接下來,我們實(shí)踐一下,從頭部署一個(gè)可用的ingress

安裝 ingress

k8s 并不自帶 ingress,所以我們需要重新安裝,幸好安裝比較簡單,直接執(zhí)行如下命令即可,k8s 會(huì)根據(jù)其內(nèi)容安裝所有需要的資源。

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

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

安裝成功之后可以執(zhí)行如下操作查看 ingress 是否安裝完成,輸入kubectl get namespaces,查看ingress-nginx(ingress相關(guān)的pod組) 的狀態(tài)是否為Active。輸入kubectl get pod -n ingress-nginx,查看nginx-ingress-controller(負(fù)責(zé)實(shí)際轉(zhuǎn)發(fā)流量的nginx) 的狀態(tài)是否為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

這兩者正?;究梢詳喽?code>ingress安裝成功了,接下來我們來創(chuàng)建一個(gè)對(duì)外服務(wù)。

使用 ingress 創(chuàng)建對(duì)外服務(wù)

在"通過 ingress 配置 service 訪問"圖里我們可以看出,使用 ingress 暴露服務(wù)需要先新建一個(gè)svc,所以我們先使用如下內(nèi)容創(chuàng)建一個(gè),它會(huì)把 pod kubia端口8080上的服務(wù)轉(zhuǎn)發(fā)到自己的8080上,他控制的 pod 就是我們文章開頭時(shí)新建的那些。

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創(chuàng)建該svc,接下來我們創(chuàng)建一個(gè)ingress。ingress 支持創(chuàng)建HTTPHTTPS的服務(wù),接下來我們先來創(chuàng)建一個(gè)HTTP的:

創(chuàng)建 HTTP 協(xié)議的訪問

http協(xié)議的訪問比較簡單,直接創(chuàng)建如下配置文件即可,通過這個(gè)ingress配置文件,nginx-ingress-controller就知道如何對(duì)外開發(fā)服務(wù)了。

kubia-http-ingress.yaml

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

然后使用kubectl create -f kubia-http-ingress.yaml就可以創(chuàng)建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,現(xiàn)在我們就可以通過http://kubia.example.com/來訪問目標(biāo)svc啦,這時(shí)你可能會(huì)疑惑,我沒這個(gè)域名?。繘]關(guān)系,在系統(tǒng)的hosts文件里配置一下,將這個(gè)域名映射到nginx-ingress-controller的 ip 地址就可以了,詳情見下方:

配置域名到 ip 地址

首先獲取nginx-ingress-controller的 ip 地址,執(zhí)行如下命令后按Tab補(bǔ)全名稱,然后在IP列就可以找到對(duì)應(yīng)的 ip 了。

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

我的 ip 地址為192.168.56.22,執(zhí)行vi /etc/hosts,輸入以下內(nèi)容即可:

192.168.56.22 kubia.example.com

修改完了之后,我們就可以進(jìn)行訪問了,執(zhí)行curl http://kubia.example.com/,就可以看到來自 svc kubia的響應(yīng)了。

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

創(chuàng)建 HTTPS 協(xié)議的訪問

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

https 請(qǐng)求鏈路

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

openssl genrsa -out tls.key 2048

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

執(zhí)行完之后你就可以在當(dāng)前文件夾下發(fā)現(xiàn)兩個(gè)文件,分別為tls.certtls.key。因?yàn)檫@種秘鑰比較敏感,不適合直接掛載到 pod 上,所以可以使用 k8s 提供的專門用于提供敏感數(shù)據(jù)的資源secret來存放它,我們先來新建一個(gè)名為tls-secretsecret資源:

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

什么是secret資源?

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

然后我們就可以修改上文中的kubia-http-ingress.yaml,將這個(gè)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

然后我們就可以通過以下命令來講剛才創(chuàng)建的http服務(wù)提升至https,kubectl apply依靠kindmetadata字段中的數(shù)據(jù)來尋找要修改的資源,所以改名字并不會(huì)造成什么影響

kubectl apply -f kubia-https-ingress.yaml

然后輸入curl -k -v https://kubia.example.com,就可以發(fā)現(xiàn)我們的服務(wù)已經(jīng)啟用的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 暴露多個(gè)服務(wù)

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

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

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

總結(jié)

本文介紹了如何將服務(wù)暴露出去,最簡單的是port-forward命令,他可以將指定資源的端口轉(zhuǎn)發(fā)到本機(jī),但是一般都用于測(cè)試。

其次是NodePort模式,NodePort本質(zhì)上也是個(gè)svc,只不過他在完成svc本質(zhì)工作的同時(shí)還將服務(wù)開放到了集群中所有節(jié)點(diǎn)的指定端口上。

但是用戶更傾向于通過子路徑訪問服務(wù),而不是端口。為了實(shí)現(xiàn)這個(gè)目標(biāo),我們可以使用ingress資源,通過發(fā)布ingress配置文件,nginx-ingress-controller就可以將指定的服務(wù)發(fā)布到指定域名的指定路徑上,ingress支持發(fā)布HTTPHTTPS連接。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、基礎(chǔ)架構(gòu) 1.1 Master Master節(jié)點(diǎn)上面主要由四個(gè)模塊組成:APIServer、scheduler...
    阿斯蒂芬2閱讀 11,141評(píng)論 0 44
  • 一、Ingress概念 Kubernetes關(guān)于服務(wù)的暴露主要是通過NodePort方式,通過綁定宿主機(jī)的某個(gè)端口...
    沉淪2014閱讀 11,101評(píng)論 0 6
  • 9.集群中測(cè)試啟用一個(gè)nginx實(shí)例1.在1臺(tái)master上執(zhí)行以下命令[root@master1 ~]# kub...
    goearth1501閱讀 544評(píng)論 0 0
  • Ingress 管理群集中服務(wù)的外部訪問的API對(duì)象,通常是HTTP。Ingress可以提供負(fù)載平衡,SSL 終止...
    bern85閱讀 2,600評(píng)論 0 5
  • 一個(gè)人, 看見一只小鳥飛過天空, 落在不遠(yuǎn)處的屋脊。 靜靜望著我陪著我一樣寂寞。 一個(gè)人, 走在十字街頭, 如潮的...
    A區(qū)四十五號(hào)庫閱讀 178評(píng)論 1 3

友情鏈接更多精彩內(nèi)容