引言
自上一篇文章【K8s 集群搭建系列(三)K8s 啟動】 到現(xiàn)在已經(jīng)過去很長時間了,而本篇文章在很早之前就該發(fā)布,但是每次寫了開頭都放棄了。因為我覺得作為普通使用者,其實沒必要去折騰,能用就可以了。但是還是想把之前的折騰經(jīng)歷分享出來,算是作個記錄吧。Istio 安裝很簡單,但是本地使用的話,由于沒有 EXTERNAL-IP,所以需要通過 NodePort 等方式暴露,我覺得不太好。如果能通過域名的方式訪問,那就比較完美了。但是本地安裝可不可以做到呢?我們回想一下 K8s 使用 ingress-nginx 不就是這樣嘛,如果用 ingress-nginx 將流量引入到 Istio gateway 那么應(yīng)該就可以了,那至于行不行呢,我們實踐一下!
版本
- K8s 版本:v1.19.0
- Istio 版本:1.8.1
- ingress-nginx 版本:3.19.0
- 域名 my.k8s.com 指向了 K8s Master 節(jié)點宿主機 ip,這里需要配置一下 hosts
準備測試服務(wù)
在開始之前,我們先安裝個 web 服務(wù)供測試,為了簡單起見,我們就裝個 nginx 吧!
創(chuàng)建命名空間
kubectl create ns test
安裝 yaml
kubectl apply -f -<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: test
labels:
app: nginx
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: test
labels:
app: nginx
spec:
type: ClusterIP
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
EOF
安裝好 nginx 對應(yīng)的 pod 跟 service 之后,我們接下來需要安裝 nginx-ingress 將 nginx 暴露出來。
安裝 ingress-nginx
配置文件修改
下載 ingress-nginx 并解壓之后,我們需要修改一下它的配置文件,即:value.yaml。主要涉及的內(nèi)容如下:
- 主機網(wǎng)絡(luò)模式開啟,這樣就能夠通過主機 ip 訪問它
hostNetwork: true
- 我們需要將它安裝到主節(jié)點,所以需要看下主節(jié)點的污點
kubectl describe node master
拿到它的污點:

- 修改 value.yaml 文件中關(guān)于 ingress-nginx 的容忍度
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
- 即使配置了容忍度也不能保證百分百調(diào)度到主節(jié)點,只是說有機會調(diào)度到主節(jié)點。接下來需要配置節(jié)點選擇器,讓它往主節(jié)點調(diào)度
nodeSelector: {
kubernetes.io/hostname: master
}
必要的參數(shù)已經(jīng)配好,接下來我們就可以安裝了!
安裝 controller
我這里通過 helm 進行安裝,安裝到 web 服務(wù)對應(yīng)的命名空間下(只是為了測試我們的 web 服務(wù)是否可用)
helm install -n test ingress-nginx ingress-nginx-3.19.0
配置 ingress-nginx 訪問規(guī)則
kubectl apply -f -<<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
namespace: test
spec:
rules:
- host: "my.k8s.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
EOF
查看是否暢通

至此,說明我們的測試項目跑起來了。只不過是通過 ingress-nginx 訪問的方式,接下來,我們要通過 Istio 用同樣的域名方式訪問。好,現(xiàn)在就可以卸載 ingress-nginx 了,只不過稍后會再裝回來。
卸載 ingress-nginx
helm uninstall ingress-nginx -n test
刪除 ingress 資源
kubectl delete ing -n test nginx-ingress
安裝 Istio
直接去 【GitHub】 上下載壓縮包,然后解壓配置 istioctl 命令的環(huán)境變量即可。
安裝默認的配置就可以了
istioctl install --set profile=default -y
安裝成功之后,我們看下它的 pod:
kubectl get po -n istio-system
---
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-64589668d7-tmvld 1/1 Running 0 99s
istiod-5d744fdd4f-969js 1/1 Running 0 106s
看到了熟悉的 istio-ingressgateway-64589668d7-tmvld ,之所以熟悉是因為它也是個 ingress。那么這樣就好辦了。
安裝 ingress-nginx
我們再一次安裝 ingress-nginx,只不過我們把它放到 istio-system 命名空間中。
helm install -n istio-system ingress-nginx ingress-nginx-3.19.0
配置 ingress 規(guī)則
kubectl apply -f -<<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
namespace: istio-system
spec:
defaultBackend:
service:
name: istio-ingressgateway
port:
number: 80
EOF
?? Tips
如上 ingress 配置,我們只添加了一個 defaultBackend,也就是說,所有的流量全部引進來,并把該流量指給網(wǎng)關(guān) istio-ingressgateway。同時還要注意,該 ingress 的命名空間同 gateway。
配置 gateway
kubectl apply -f -<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: k8s-gateway
namespace: istio-system
spec:
servers:
- hosts:
- '*'
port:
number: 80
name: http
protocol: HTTP
EOF
?? Tips
讓網(wǎng)關(guān)接管所有流量,即:域名 * 的。
配置 virtual service
kubectl apply -f -<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx
namespace: test
spec:
gateways:
- k8s-gateway.istio-system.svc.cluster.local
- mesh
hosts:
- my.k8s.com
http:
- fault:
abort:
httpStatus: 400
percentage:
value: 50
match:
- uri:
prefix: /nginx
rewrite:
uri: /
route:
- destination:
host: nginx
EOF
?? Tips
我們通過 http://my.k8s.com/nginx 來訪問我們的 nginx web 服務(wù)。但是由于 nginx 的訪問路徑是 "/" 而不是 "/nginx",所以我們需要對 url 進行重寫。注意,我們這里添加了一個 50% 概率的 400 錯誤響應(yīng),以便驗證我們的流量管控是否生效。
配置 destination rule
kubectl apply -f -<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: nginx
namespace: test
spec:
host: nginx.test.svc.cluster.local
# Disable the tls for all ports
trafficPolicy:
tls:
mode: DISABLE
subsets:
- labels:
version: v1
name: v1
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
# You can config the tls for each rules
tls:
mode: DISABLE
EOF
?? Tips
這里我們需要關(guān)閉 tls 功能。
查看 istio-system 下的 service
kubectl get svc -n istio-system
---
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.106.58.208 <pending> 80:31241/TCP,443:31603/TCP 10m
ingress-nginx-controller-admission ClusterIP 10.96.93.161 <none> 443/TCP 10m
istio-ingressgateway LoadBalancer 10.98.218.30 <pending> 15021:31234/TCP,80:31748/TCP,443:31819/TCP,15012:31734/TCP,15443:30830/TCP 17m
istiod ClusterIP 10.101.252.30 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 17m
我們發(fā)現(xiàn) istio-ingressgateway 的 TYPE 是 LoadBalancer 類型,顯然這不是我們想要的,刪掉:
kubectl delete svc -n istio-system istio-ingressgateway
配置 gateway service
kubectl apply -f -<<EOF
apiVersion: v1
kind: Service
metadata:
name: istio-ingressgateway
namespace: istio-system
labels:
app: istio-ingressgateway
istio: ingressgateway
release: istio
spec:
type: ClusterIP
selector:
app: istio-ingressgateway
istio: ingressgateway
ports:
- name: status-port
port: 15021
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
- name: tcp
port: 31400
- name: tls
port: 15443
EOF
?? Tips
這里我們重新配置了一下 gateway 的 service,修改的地方有三點:
一、將 IP 類型該為 ClusterIP
二、將 80 端口映射到 8080
三、關(guān)閉無用的端口映射
為命名空間開啟自動注入
kubectl label namespace test istio-injection=enabled
刪除我們先前創(chuàng)建的 pod
kubectl delete po -n test nginx-55df9cfb4b-xjvcv
查看注入是否成功
kubectl get po -n test -w
---
NAME READY STATUS RESTARTS AGE
nginx-55df9cfb4b-wwddn 0/2 Init:0/1 0 25s
驗證
成功頁面

400 頁面

至此,完成。后續(xù)添加服務(wù),只需要配置好對應(yīng)的 deployment、service、virtual service、destination rule 即可。我們就可以通過域名的方式訪問我們的服務(wù)了。
卸載 Istio
istioctl manifest generate --set profile=default | kubectl delete --ignore-not-found=true -f -