iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 13
2
DevOps

k8s 不自賞系列 第 13

Day 13 - 別耍自閉開放你的應用吧:Ingress

  • 分享至 

  • xImage
  •  

Day 13 - 別耍自閉開放你的應用吧:Ingress

本日共賞

  • Ingress

希望你知道

Ingress

昨天我們已經可以透過 Service 物件連到 Pod,接下來的問題就如同 Day 11 - Service(1) 提到的如何存取 Pod 問題類似:難道我們需要使用者知道每個 Node 的 IP 嗎?

我們成功地利用 Service 把存取 Pod 的工作抽象化,即把存取 Pod 的工作轉換成存取 Service,我們可以透過 Node IP:Port 的方式存取 Pod,但是在 k8s 中 Node 是可以視需求隨時增加或減少的,也因此 Node IP 隨時有可能會有變動,因此 Ingress 物件就是再一次幫我們把存取 Service 抽象化的好東西。

我們用一張圖來描述

這裡要發揮一下想像力,想像一下整個 k8s 叢集由一群 Node 組成並提供多個不同的服務 (Service),就像圖中的四個不同顏色的 Service,我們希望使用者能夠從一個單一的入口就能夠存取 k8s 中不同的服務,而 Ingress 物件就能幫我們達到這樣的目的。

底下我們來實作一下,先看個圖

如上圖,我們希望在 k8s 中建立兩個 Service 分別是 red-servicegreen-service

red-service 綁定四個標記為 app: red-nginx 的 Pod 而 green-service 綁定兩個標記為 app: green-nginx 的 Pod。使用者可以透過 http://green.myweb.comhttp://red.myweb.com 來分別瀏覽 green-servicered-service

讓我們先看看 Deployment 的內容

# ingress.deployment.yaml

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: red-nginx
spec:
    replicas: 4   <=== 我們希望 red-service 有四個 Pod 運行 red-nginx
    template:
      metadata:
        labels: 
          app: red-nginx
      spec:
        containers:
        - name: nginx
          image: jlptf/red   <=== 預先做好的 Docker 映像檔
          ports:
          - containerPort: 80

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: green-nginx
spec:
    replicas: 2   <=== 我們希望 green-service 有兩個 Pod 運行 green-nginx
    template:
      metadata:
        labels: 
          app: green-nginx
      spec:
        containers:
        - name: nginx
          image: jlptf/green   <=== 預先做好的 Docker 映像檔
          ports:
          - containerPort: 80

部署到 k8s 並觀察

$ kubectl apply -f ingress.deployment.yaml 
deployment "red-nginx" created
deployment "green-nginx" created

$ kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
green-nginx-f5989dfd9-fcm5q   1/1       Running   0          47s
green-nginx-f5989dfd9-hzbq5   1/1       Running   0          47s
red-nginx-787f484d9c-grbsk    1/1       Running   0          34s
red-nginx-787f484d9c-h7pl6    1/1       Running   0          47s
red-nginx-787f484d9c-m897h    1/1       Running   0          29s
red-nginx-787f484d9c-n946g    1/1       Running   0          47s

很順利,運行了六個 Pod 預計分別給 red-servicegreen-service 使用,接著看看 Service 的內容

看 prefix 應該不難分辨哪個 Pod 是給哪個 Service 使用的吧!所以說名字取的好,爸爸沒煩惱!是吧~~

# ingress.service.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: green-service
spec:
  type: NodePort
  selector:
    app: green-nginx   <=== 綁定標記為 green-nginx 的 Pod
  ports:
    - protocol: TCP
      port: 80

---
apiVersion: v1
kind: Service
metadata:
  name: red-service
spec:
  type: NodePort
  selector:
    app: red-nginx   <=== 綁定標記為 red-nginx 的 Pod
  ports:
    - protocol: TCP
      port: 80

經過這幾天的練習,上面的 yaml 應該不難閱讀了吧

同樣部署到 k8s 並觀察狀態

$ kubectl apply -f ingress.service.yaml
service "green-service" created
service "red-service" created

$ kubectl get services
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
green-service   NodePort    10.0.0.133   <none>        80:30615/TCP   16s
kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        15d
red-service     NodePort    10.0.0.75    <none>        80:32101/TCP   16s

然後是今天的主角 Ingress

# ingress.yaml

---
apiVersion: extensions/v1beta1
kind: Ingress   <=== 指定物件種類為 Ingress
metadata:
  name: web
spec:
  rules:
  - host: green.myweb.com   <=== 指定 host 名稱為 green.myweb.com
    http:
      paths:
      - backend:
          serviceName: green-service  <=== 綁定名稱為 green-service 的 Service 物件
          servicePort: 80
  - host: red.myweb.com   <=== 指定另一個 host 名稱為 red.myweb.com
    http:
      paths:
      - backend:
          serviceName: red-service   <=== 綁定名稱為 red-service 的 Service 物件
          servicePort: 80

類似 Service 綁定 Pod 的概念,Ingress 透過 serviceName 指定需要綁定的 Service。接著部署到 k8s

$ kubectl apply -f ingress.yaml 
ingress "web" created

$ kubectl get ingress
NAME      HOSTS                           ADDRESS          PORTS     AGE
web       green.myweb.com,red.myweb.com   192.168.99.100   80        43s

這裡就會看到 green.myweb.comred.myweb.com 都被綁定到 192.168.99.100 的位置

如果在雲端提供商上建立 Ingress,你可以在 ADDRESS 看到被分配的 IP

另外,你可能需要執行 minikube addons enable ingress 啟用 Ingress。感謝 changec大大的提醒,更詳細的內容可以參考https://medium.com/@Oskarr3/setting-up-ingress-on-minikube-6ae825e98f82

由於 green.myweb.comred.myweb.com 這兩個網址並非真正存在,因此,如果你在瀏覽器上打上這兩個網址,並不會有任何內容。

我們要讓自己的電腦能夠理解這兩個網址的 IP 位置,在 Mac/Linux 環境下可以將以下內容加到 /etc/hosts

Windows 請修改 \WINDOWS\system32\drivers\etc\hosts

192.168.99.100   green.myweb.com  <=== 192.168.99.100 是 Ingress 分配的 IP
192.168.99.100   red.myweb.com

你可以使用以下指令將上面的內容加到 /etc/hosts

$ echo 192.168.99.100   green.myweb.com >> /etc/hosts
$ echo 192.168.99.100   red.myweb.com >> /etc/hosts

你也可以透過 vim 編輯,可能需要 sudo 權限

打開瀏覽器並鍵入網址,一切順利的話你會看到

http://green.myweb.com

http://red.myweb.com

本文與部署檔案同步發表於 https://jlptf.github.io/ironman2018-day13/

另外,建立 jlptf/redjlptf/green 這兩個映像檔用到的 Dockerfile 你可以在 ingressDocker 資料夾裡面找到,如果你想要自己動手建立映像檔可以參考使用。

建立映像檔參考指令如下:

$ docker build --build-arg HTML=green.html -t jlptf/green .

$ docker build --build-arg HTML=red.html -t jlptf/red .

這邊就不對 Docker 內容說明,請自行參考文章

yangj26952用30天來介紹和使用 Docker

jia_hong讓我們來玩玩Docker吧


上一篇
Day 12 - 帶上你的Pod見人了:Service (2)
下一篇
Day 14 - 別再遺失資料了:Volume (1)
系列文
k8s 不自賞32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
changec
iT邦新手 5 級 ‧ 2018-03-28 17:34:30

您好:有一個問題想要請教一下,我在這頁面操作到最後,輸入http://green.myweb.com
會找不到頁面,必須加上port才可以,不曉得是哪邊的設定有問題。謝謝您
https://ithelp.ithome.com.tw/upload/images/20180328/20109281gBGmYUvgfJ.pnghttps://ithelp.ithome.com.tw/upload/images/20180328/20109281UHwTA5P0M3.png

看更多先前的回應...收起先前的回應...
James iT邦新手 5 級 ‧ 2018-03-28 17:44:40 檢舉

直接從圖上判斷,Service 應該是有跑起來不然你應該沒辦法存取 port 31346,而且你的 hosts 應該也有改成功,不然應該沒辦法存取 http://green.myweb.com ,所以我想問題應該是出在 Ingress,請問你是直接拿我分享git檔案部署的嗎?你可以執行一下 kubectl describe ingress web 觀察一下 Event Section 有沒有描述任何問題

changec iT邦新手 5 級 ‧ 2018-03-28 17:48:57 檢舉

我不是直接拿git耶,我是一步一步操作的XD

Name:             web
Namespace:        default
Address:
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host             Path  Backends
  ----             ----  --------
  green.myweb.com
                      green-service:80 (<none>)
  red.myweb.com
                      red-service:80 (<none>)
Annotations:
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"web","namespace":"default"},"spec":{"rules":[{"host":"green.myweb.com","http":{"paths":[{"backend":{"serviceName":"green-service","servicePort":80}}]}},{"host":"red.myweb.com","http":{"paths":[{"backend":{"serviceName":"red-service","servicePort":80}}]}}]}}

Events:  <none>
changec iT邦新手 5 級 ‧ 2018-03-28 17:54:47 檢舉

我在這一頁的操作,大概是底下兩個跟您的有差異,部署ingress的回應多了extensions,以及get ingress ADDRESS是空的,不曉得這有沒有影響

$ kubectl apply -f ingress.yaml                     
ingress.extensions "web" created
$ kubectl get ingress                               
NAME      HOSTS                           ADDRESS   PORTS     AGE
web       green.myweb.com,red.myweb.com             80        7s
James iT邦新手 5 級 ‧ 2018-03-28 21:12:15 檢舉

正常情況下 Address 應該會有值,你可以下載我分享的yaml試試,方便的話可以把你的 yaml 貼一下嗎?

changec iT邦新手 5 級 ‧ 2018-03-28 22:10:18 檢舉

好的,我刪除再試試看,另外附上yaml,其實也是把“<===”拿掉囉

# ingress.deployment.yaml

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: red-nginx
spec:
    replicas: 4   
    template:
      metadata:
        labels: 
          app: red-nginx
      spec:
        containers:
        - name: nginx
          image: jlptf/red   
          ports:
          - containerPort: 80

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: green-nginx
spec:
    replicas: 2   
    template:
      metadata:
        labels: 
          app: green-nginx
      spec:
        containers:
        - name: nginx
          image: jlptf/green   
          ports:
          - containerPort: 80
# ingress.service.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: green-service
spec:
  type: NodePort
  selector:
    app: green-nginx   
  ports:
    - protocol: TCP
      port: 80

---
apiVersion: v1
kind: Service
metadata:
  name: red-service
spec:
  type: NodePort
  selector:
    app: red-nginx  
  ports:
    - protocol: TCP
      port: 80
# ingress.yaml

---
apiVersion: extensions/v1beta1
kind: Ingress   
metadata:
  name: web
spec:
  rules:
  - host: green.myweb.com   
    http:
      paths:
      - backend:
          serviceName: green-service  
          servicePort: 80
  - host: red.myweb.com   
    http:
      paths:
      - backend:
          serviceName: red-service   
          servicePort: 80
James iT邦新手 5 級 ‧ 2018-03-28 22:50:38 檢舉

神奇了,我用你的yaml部署上去是ok的!你的 minikube 是幾版的?

changec iT邦新手 5 級 ‧ 2018-03-28 23:07:58 檢舉

v0.25.2 太新了嗎 囧

James iT邦新手 5 級 ‧ 2018-03-28 23:19:02 檢舉

我現在用的是 v0.25.0 應該沒差那麼多才是,我再想想有沒有其他可能。你是用 mac 還是 windows? 你在台北嗎?有機會碰個面嗎?挺好奇你的環境發生什麼事了...

changec iT邦新手 5 級 ‧ 2018-03-29 00:08:39 檢舉

大大!我找到解法了,我參考這篇文章
https://medium.com/@Oskarr3/setting-up-ingress-on-minikube-6ae825e98f82

minikube addons enable ingress

然後

$ kubectl get ing
NAME      HOSTS                           ADDRESS          PORTS     AGE
web       green.myweb.com,red.myweb.com   192.168.99.100   80        4m

ADDRESS有值後,http://red.myweb.com/ 也沒問題了。
謝謝您的熱心回覆,真的就是ADDRESS的問題。
再一次感謝大大

James iT邦新手 5 級 ‧ 2018-03-29 09:11:59 檢舉

的確忽略這個了,感謝你提出這個問題。我順便把它更新到文章裡面好了,免得之後又忘記了!

0
ray2211
iT邦新手 5 級 ‧ 2021-10-06 03:37:20

先感謝大大的文章 讓我進步神速!!!
但有個問題...我的ingress address欄位也是沒有出現IP
變成要輸入hostname:port才連的到
而我不是使用minikube是使用RKE K8S
沒有minikube addons enable ingress這個指令
不知道大大知道怎麼解

我要留言

立即登入留言