# 地瓜のIstio學習筆記-1 ## 環境 Kubernates 1.18.2 CentOs 7 安裝 k8s 的部分就不詳細說明了,網路上教學很多,不想裝 k8s 的話 Istio 也很提供很多[安裝選項](https://istio.io/latest/docs/setup/platform-setup/)。 ## 安裝 Istio 因為我很懶,所以就下載 [Istio release](https://github.com/istio/istio/releases) 後用 istioctl 安裝,當然還有其他安裝方法,像是 Operator,不過實際上這兩種方法背後做的事情是一樣的。 ```bash $ curl -L https://istio.io/downloadIstio | sh - ``` 然後把 istioctl 加到 path 來啟用 istioctl 指令。 ```bash export PATH=/root/istio-1.7.0/bin:$PATH ``` 接著我們就能用 istioctl 的指令來對 k8s 安裝 istio 了! Istio 有提供很多 profile 供我們進行快速安裝,如下 ```bash [00:13:12]:root <3 ~ > istioctl profile list Istio configuration profiles: default demo empty minimal preview remote ``` 那這些 profile 到底會安裝那些東西呢?根據官方的說明 1) **default profile** 會根據 [`IstioOperator`API](https://istio.io/latest/docs/reference/config/istio.operator.v1alpha1/) 的預設值進行安裝 2) **demo profile** 顧名思義就是拿來做 demo 用的 3) **minial profile** 只安裝了 Istio traffic management 需要使用的組件,也就是 istiod 4) **remote profile** 拿來安裝在 multi-cluster 中設定 remote cluster 的 Istio 上面提到這四個 profile 安裝了那些組件用表格來表示的話會是這樣: <table> <thead> <tr> <th></th> <th>default</th> <th>demo</th> <th>minimal</th> <th>remote</th> </tr> </thead> <tbody> <tr><td><code>istio-egressgateway</code></td><td></td><td>X</td><td></td><td></td></tr> <tr><td><code>istio-ingressgateway</code></td><td>X</td><td>X</td><td></td><td></td></tr> <tr><td><code>istiod</code></td><td>X</td><td>X</td><td>X</td><td></td></tr> </tbody> </table> 那剩下的 **empty profile** 跟 **preview profile** 是拿來幹嘛用的呢?相信聰明的各位一定都猜的到,preview profile 就是 Istio 把正在實驗中的 feature 阿,全都放在這個 profile 裡面了。 那 empty profile 就比較特殊一些,他甚麼都不 deploy,因為 Istio 有提供客製化 profile 的功能,empty profile 就是拿來給我們自製 profile 時使用的基底。 那我們就直接來下指令吧 ```bash [00:19:27]:root <3 ~ > istioctl install --set profile=demo ✔ Istio core installed ✔ Istiod installed ✔ Egress gateways installed ✔ Ingress gateways installed ✔ Installation complete ``` 根據文件告訴我們,demo profile 應該會安裝三個組件,分別是 Istiod、Ingress gateway 與 Egress gateway,那我們就來確認看看吧! ```bash [00:19:53]:root <3 ~ > kubectl get pod -n istio-system NAME READY STATUS RESTARTS AGE istio-egressgateway-695f5944d8-xbr9m 1/1 Running 0 28s istio-ingressgateway-5c697d4cd7-2rsw8 1/1 Running 0 29s istiod-59747cbfdd-v9mzk 1/1 Running 0 34s ``` 到這邊 Istio 的安裝就算是告一個段落了,接下來我們會部屬一些服務,來體驗一下 Istio 許多的強大功能。 ## Demo - Book Application 接下來我們會先照 [Istio start](https://) 中的內容進行 demo,讓我們先看看 Istio 能做到那些事情之後,再來深入的看看 Istio 是如何做到的,好,那我們要開始囉! 我們先對 default namespece 打上 `istio-injection=enabled` 的 label,這樣 Istio 就會自動幫這個 namespace 裡面的 pod 注入 sidecar container。當然 Istio 也有提供其他方法注入 sidecar,例如用 `istioctl kube-inject` 指令修改 deployment yaml。 ``` [00:20:07]:root <3 ~ > kubectl label namespace default istio-injection=enabled namespace/default labeled ``` ### 部屬服務 在 demo 中,我們會部屬一系關於**書**的服務,分別是 detail-v1、ratings-v1、reviews-v1~v3、productpage-v1,總共會產生 6 個 pod。 ``` [00:20:07]:root <3 ~ > kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml service/details created serviceaccount/bookinfo-details created deployment.apps/details-v1 created service/ratings created serviceaccount/bookinfo-ratings created deployment.apps/ratings-v1 created service/reviews created serviceaccount/bookinfo-reviews created deployment.apps/reviews-v1 created deployment.apps/reviews-v2 created deployment.apps/reviews-v3 created service/productpage created serviceaccount/bookinfo-productpage created deployment.apps/productpage-v1 created ``` 接著我們來確認一下服務的狀態。 ``` [00:20:07]:root <3 ~ > kubectl get po -n default NAME READY STATUS RESTARTS AGE details-v1-558b8b4b76-rf2q9 2/2 Running 2 5d productpage-v1-6987489c74-kkgb6 2/2 Running 2 5d ratings-v1-7dc98c7588-lq5rd 2/2 Running 2 5d reviews-v1-7f99cc4496-kgnmt 2/2 Running 2 5d reviews-v2-7d79d5bd5d-fcn6h 2/2 Running 2 5d reviews-v3-7dbcdcbc56-jfpd8 2/2 Running 2 5d ``` 好的,我們可以看到服務都部屬好了,不知道各位有沒有發現哪裡有點不一樣。 是的,在 `READY` 那一行,我們會發現跟 Istio 幫我們注入了 sidecar,所以顯示 `2/2` 的狀態,那我們怎麼知道這是 Istio 幫我們做的呢?其實很簡單,直接來看一下 deployment 就可以知道答案了。 ``` [02:32:08]:root <3 ~ > kubectl describe deployments details Name: details-v1 Namespace: default CreationTimestamp: Thu, 10 Sep 2020 01:58:36 +0800 Labels: app=details version=v1 Annotations: deployment.kubernetes.io/revision: 1 Selector: app=details,version=v1 Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=details version=v1 Service Account: bookinfo-details Containers: details: Image: docker.io/istio/examples-bookinfo-details-v1:1.16.2 Port: 9080/TCP Host Port: 0/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Progressing True NewReplicaSetAvailable Available True MinimumReplicasAvailable OldReplicaSets: <none> NewReplicaSet: details-v1-558b8b4b76 (1/1 replicas created) Events: <none> ``` 從 details 這個 deployments 中,可以看到我們**只宣告了一個 container** ,但實際上 pod 裡面是有兩個 container 的,那多出來的那個 container 從哪裡來的應該就很清楚了。 那 Istio 是怎麼把這個 sidecar 塞進去的,大家先不要緊張,這邊賣個關子,後面會為各位詳細的解說。 接下來呢,我們來驗證一下服務是不是正常運作。 ``` [02:57:33]:root <3 ~ > kubectl get svc -l app=productpage NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE productpage ClusterIP 10.107.148.13 <none> 9080/TCP 5d [02:58:02]:root <3 ~ > curl -s 10.107.148.13:9080/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title> ``` ### 接入 Istio service mesh 在確認服務都運行成功之後,如果要讓 Kubernetes 能夠從 cluster 外面訪問 ,我們會需要設置一個 ingress,讓流量能從外部流入,這樣我們才能使用瀏覽器來看 demo 的頁面,在前面我們安裝 Istio 的 `demo profile` 的時候,就已經部屬了一個叫 `istio-ingressgateway` 的 pod,它呢是一個特殊的 Envoy proxy,對外開了一些 node port,除此之外其他跟 Envoy sidecar 的功能是一樣的。 所以呢,我們要找出能夠連入 Kubernetes 的 ip 和 port,在 namespace `istio-system` 裡面,我們找出 `istio-ingressgateway` 的 service,它的 `TYPE` 是 `LoadBalancer`,看一下這個 service 的 `EXTERNAL-IP` 的欄位,如果 `EXTERNAL-IP` 的值是 `<none>` 或是 `<pending>` ,說明這個 service 並沒有配置外部 IP,那我們就需要用 node port 的方式訪問 Kubernetes。 ```bash [01:30:40]:root <3 ~/istio-1.7.0 > kubectl get svc istio-ingressgateway -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.110.59.204 <pending> 15021:30734/TCP,80:32765/TCP,443:31940/TCP,31400:31906/TCP,15443:30246/TCP 5d23h ``` 目前呢,我的 Kubernetes 並沒有配置 ELB(External Loadbalancer),所以 `EXTERNAL-IP` 的值是空的,根據官方文件,我們可以下面的指令來找出 http2 與 https 對應的 node port 來訪問 Kubernetes。 ```bash $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}') $ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}') ``` 然後把 host ip 找出來 ```bash $ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}') ``` 把 ip 和 port 組合起來,就是我們的訪問 Kubernetes 的 Url 了。 ```bash $ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT $ echo $GATEWAY_URL 192.168.8.128:32765 ``` OK,這個 Url 呢,只代表了我們的流量能從外部流到 Kuberates,但是呢,這個流量並不會流入我們的 mesh 中,那我們要怎麼做到這件事情呢?Istio 提供一種 resource type 叫做 `Gateway`,它允許我們控制流量流入或是流出我們的 service mesh,我們可以這麼說,**通過 `Gateway` 前的流量,都算是在 service mesh 外,只有通過了 `Gateway` 之後,才算是進入了 service mesh**。 所以呢,為了要讓流量流進我們上面部屬的服務,勢必要有一個 `Gateway` 存在。 ``` $ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml gateway.networking.istio.io/bookinfo-gateway created virtualservice.networking.istio.io/bookinfo created ``` 藉由上面的指令呢,我們就成功的部屬了一個 `Gateway` 到 Istio 中,聰明的你們可能已經發現,上面的 `samples/bookinfo/networking/bookinfo-gateway.yaml` 好像不是只有建立 `Gateway` 而已,好像還偷偷建了一個叫做 `VirtualService` 的東西,阿剛剛不是說建 `Gateway` 就可以了,怎麼這裡又多了一個 `VirtualService` 呢? 好的,讓我們來看看官方怎麼說。 > The Gateway specification above describes the L4-L6 properties of a load balancer. A VirtualService can then be bound to a gateway to control the forwarding of traffic arriving at a particular host or gateway port. 官方文件告訴我們,`Gateway` 只負責 L4-L6 的 load balance,所以我們需要將 `VirtualService` 綁在 `Gateway` 上來補足 L7 的 load balance。 有這些觀念之後,我們就直接來看 `samples/bookinfo/networking/bookinfo-gateway.yaml` 裡面到底做了甚麼,相信看完內容大家應該就會清楚不少。 我們先來看 `Gateway` 的部分 ```yaml # samples/bookinfo/networking/bookinfo-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" ``` 那從上面的 yaml 可以看到,它 select 了有 istio=ingressgateway 這個 label 的 pod 去配置裡面的 Envoy 設定,它會配置這個 pod 的 Envoy 讓符合 servers 規則的流量能夠流進 service mesh 裡面。 這邊呢,它允許任意的 host name,只要是經由 HTTP protocol 的 80 port,流到 istio-system 中 istio-ingressgateway 這個 pod 的流量都能進入 service mesh。 搞懂了 `Gateway` 是如何允許流量流入 mesh 中之後,接下來我們要看,這些流入 mesh 中的流量,最終會被導去哪裡,讓我們來看 `VirtualService` 的 yaml。 ```yaml # samples/bookinfo/networking/bookinfo-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: bookinfo spec: hosts: - "*" gateways: - bookinfo-gateway http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: exact: /logout - uri: prefix: /api/v1/products route: - destination: host: productpage.default.svc.cluster.local # 這邊原本是只有寫 productpage 我為了方便大家理解直接寫 FQDN port: number: 9080 ``` 這個 `VirtualService` 相對簡單,我們可以看到它把自己 bind 在 `bookinfo-gateway` 上,接著根據 http 的 uri match 規則,將符合規則的流量導到對應的目的地,`productpage.default.svc.cluster.local` 的 9080 port。 ### View the result ! 不知道大家還記不記得我們上面找到用來從外部訪問 Kubernates 的 URL。 ```bash $ echo $GATEWAY_URL 192.168.8.128:32765 ``` 根據我們剛剛對 `Gateway` 以及 `VirtualService` 的理解,現在我們訪問 `$GATEWAY_URL/productpage` 的時候,這個流量應該就要被轉發到 `productpage.default.svc.cluster.local:9080/productpage` 上。 那我們來驗證一下是不是這樣 ```bash [02:03:58]:root <3 ~ > curl -s 10.107.148.13:9080/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title> [02:07:45]:root <3 ~ > curl -s 192.168.8.128:32765/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title> ``` 那我們也可以從 browser 直接看到我們部屬的服務頁面,大家如果多重整幾次的話,應該會發現 Reviewer 的星星會是紅色、黑色或是不出現。 ![](https://i.imgur.com/2l9It0e.png) 從 Kiali dashborad 也能看到我們服務的拓樸圖跟流量。 ![](https://i.imgur.com/OyQBdqI.png) 那 Kiali 等等 dashboard 的部屬,可以用下面的指令完成。 ```bash $ kubectl apply -f samples/addons $ while ! kubectl wait --for=condition=available --timeout=600s deployment/kiali -n istio-system; do sleep 1; done ``` 用 istioctl 帶起 Kiali dashboard 之後,就能訪問上面的 UI 了。 ```bash $ istioctl dashboard kiali ``` 那麼基礎的 Istio 安裝跟 application demo 就大概到這邊告一段落,下一篇應該會寫一下怎麼把 Kiali dashboard 給接出來到外面,利用上面有提到的東西應該就都能做到了,有興趣的大家可以先試試看喔。