openshift 4.3 Istio的搭建
本文檔覆蓋了官方文檔的Setup的所有章節
安裝Istio
本次安裝的Istio版本為1.7.0,環境為openshift 4.3
注:不建議使用openshift 1.11(即kubernetes 3.11)安裝istio,可能會出現如下兼容性問題,參見此issue
must only have "properties", "required" or "description" at the root if the status subresource is enabled
openshift安裝Istio
istio的安裝涉及到兩個文件:profile和manifest。前者用於控制組件的安裝和組件的參數,profile配置文件所在的目錄為manifests/profiles
;后者為安裝所使用的yaml文件,如service,deployment等,會用到profile提供的參數,manifest配置文件所在的目錄為manifests/charts
。因此可以通過兩種方式安裝istio,一種是通過profile進行安裝,istio默認使用這種方式,如:
$ istioctl install --set profile=demo
第二種是通過導出的manifest進行安裝(不推薦,見下),如:
$ kubectl apply -f $HOME/generated-manifest.yaml
參考不同平台可以參考對應的SetUp。在openshift下面部署istio需要注意版本:
OpenShift 4.1 and above use
nftables
, which is incompatible with the Istioproxy-init
container. Make sure to use CNI instead.
首先創建istio-system
命名空間
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: istio-system
labels:
istio-injection: disabled
EOF
允許istio的serviceaccount使用UID為0的用戶,使用的命名空間為istio-system
$ oc adm policy add-scc-to-group anyuid system:serviceaccounts:istio-system
istio默認會注入一個名為istio-init
的initContainer
,用於將pod的網絡流量導向istio的sidecar proxy,該initContainer
需要用到完整的NET_ADMIN
和NET_RAW
capabilities來配置網絡,由此可能造成安全問題,使用istio CNI插件可以替換istio-init
,且無需提升kubernetes RBAC權限,區別見下:
# with istio-cni
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsGroup: 1337
runAsNonRoot: true
runAsUser: 1337
# without istio-cni
capabilities:
add:
- NET_ADMIN
- NET_RAW
drop:
- ALL
privileged: false
readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
由於openshift 4.1以上版本不再使用iptables,轉而使用nftables,因此需要安裝istio CNI插件,否則在sidecar注入時會出現如下istio iptables-restore: unable to initialize table 'nat'
的錯誤,即無法執行iptables-resotre
命令。
執行如下命令安裝istio-cni並使用default類型的profile(見下)安裝istio,具體參數含義參見官方文檔。
cat <<'EOF' > cni-annotations.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
cni:
enabled: true
namespace: kube-system
values:
cni:
excludeNamespaces:
- istio-system
- kube-system
chained: false
cniBinDir: /var/lib/cni/bin
cniConfDir: /etc/cni/multus/net.d
cniConfFileName: istio-cni.conf
sidecarInjectorWebhook:
injectedAnnotations:
"k8s.v1.cni.cncf.io/networks": istio-cni
EOF
$ istioctl manifest install -f cni-annotations.yaml --set meshConfig.accessLogFile="/dev/stdout"
安裝結果如下:
# oc get pod -n istio-system
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-746548c687-wjc6j 1/1 Running 0 95s
istiod-6c5f6f55ff-htrss 1/1 Running 0 2m31s
# oc get pod -nkube-system
NAME READY STATUS RESTARTS AGE
istio-cni-node-44tx7 2/2 Running 0 112s
istio-cni-node-92qqk 2/2 Running 0 112s
istio-cni-node-gdg6g 2/2 Running 0 112s
istio-cni-node-pwtjh 2/2 Running 0 112s
istio-cni-node-z5p2z 2/2 Running 0 112s
為ingress gateway暴露router:
$ oc -n istio-system expose svc/istio-ingressgateway --port=http2
至此istio的基本組件已經安裝完畢,可以使用如下方式導出本次安裝的profile
$ istioctl profile dump -f cni-annotations.yaml > generated-profile.yaml
使用如下命令導出安裝istio的manefest
的內容
$ istioctl manifest generate -f cni-annotations.yaml > generated-manifest.yaml
校驗安裝結果
$ istioctl verify-install -f generated-manifest.yaml
istio會使用UID為1337的用戶將sidecar注入到應用中,openshift默認不允許使用該用戶,執行如下命令進行授權。target-namespace
為應用所在的命名空間。
$ oc adm policy add-scc-to-group privileged system:serviceaccounts:<target-namespace>
$ oc adm policy add-scc-to-group anyuid system:serviceaccounts:<target-namespace>
當清理應用pod后,需要刪除添加的權限
$ oc adm policy remove-scc-from-group privileged system:serviceaccounts:<target-namespace>
$ oc adm policy remove-scc-from-group anyuid system:serviceaccounts:<target-namespace>
openshift下使用multus
管理CNI,它需要在應用的命名空間中部署NetworkAttachmentDefinition
來使用istio-cni插件,使用如下命令創建NetworkAttachmentDefinition
,target-namespace
替換為實際應用所在的命名空間。
$ cat <<EOF | oc -n <target-namespace> create -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: istio-cni
EOF
移除應用后,使用如下方式移除NetworkAttachmentDefinition
$ oc -n <target-namespace> delete network-attachment-definition istio-cni
更新istio配置
例如可以使用如下方式卸載已經安裝的第三方工具Prometheus,注意必須帶上文件cni-annotations.yaml
,否則會使用默認的profile重新配置istio,這樣會導致刪除istio-cni。如果組件的配置沒有改變,則不會重新該組件的pod
$ istioctl manifest apply -f cni-annotations.yaml --set addonComponents.prometheus.enabled=false
openshif卸載istio
$ istioctl manifest generate -f cni-annotations.yaml | kubectl delete -f -
標准安裝istio
istioctl
使用內置的charts生成manifest,這些charts位於目錄manifests/charts
。
# ll
total 76
drwxr-xr-x. 5 root root 4096 Aug 22 03:00 base
drwxr-xr-x. 4 root root 4096 Aug 22 03:00 gateways
-rw-r--r--. 1 root root 16888 Aug 22 03:00 global.yaml
drwxr-xr-x. 3 root root 4096 Aug 22 03:00 istio-cni
drwxr-xr-x. 3 root root 4096 Aug 22 03:00 istio-control
drwxr-xr-x. 3 root root 4096 Aug 22 03:00 istiocoredns
drwxr-xr-x. 4 root root 4096 Aug 22 03:00 istiod-remote
drwxr-xr-x. 4 root root 4096 Aug 22 03:00 istio-operator
drwxr-xr-x. 3 root root 4096 Aug 22 03:00 istio-policy
drwxr-xr-x. 8 root root 4096 Aug 22 03:00 istio-telemetry
-rw-r--r--. 1 root root 2408 Aug 22 03:00 README-helm3.md
-rw-r--r--. 1 root root 8629 Aug 22 03:00 README.md
-rw-r--r--. 1 root root 2661 Aug 22 03:00 UPDATING-CHARTS.md
直接執行如下命令即可安裝官方默認配置的istio。
$ istioctl install --set profile=default
istio默認支持如下6種profile
# istioctl profile list
Istio configuration profiles:
demo
empty
minimal
preview
remote
default
安裝的組件的區別如下:
default | demo | minimal | remote | |
---|---|---|---|---|
Core components | ||||
istio-egressgateway |
X | |||
istio-ingressgateway |
X | X | ||
istiod |
X | X | X |
使用如下方式可以查看某個profile的配置信息,profile類型helm的values.yaml,用於給部署用的yaml提供配置參數。每個組件包含兩部分內容:components下的組件以及組件的參數value
istio提倡使用 IstioOperator API
進行定制化配置。
$ istioctl profile dump default
使用如下方式可以查看某個組件的配置:
$ istioctl profile dump --config-path components.pilot default
在安裝前可以使用如下方式導出需要安裝的所有yaml信息 ,包括CRD,deployment,service等
$ istioctl manifest generate --set profile=default --set hub=docker-local.com/openshift4 > $HOME/generated-manifest.yaml
kubectl apply
可以使用manifest generate
的輸出來安裝istio。但這種方式可能無法具有與istioctl install
相同的資源依賴,且不會在istio發行版中進行測試。
在進行確認或修改之后可以使用apply
命令執行安裝(不推薦)
$ kubectl apply -f $HOME/generated-manifest.yaml
如果嘗試使用
istioctl manifest generate
進行istio的安裝和管理,請注意以下事項:
- 必須手動創建istio命名空間(默認為istio-system)
- 雖然
istioctl install
會自動探測kubernetes上下文中的環境設置,但manifest generate
並不能脫機運行(即獨立於istio安裝環境運行),這可能導致非預期的結果。特別地,在kubernetes環境不支持第三方service account token的前提下,用戶必須遵守這些步驟。- 當依賴的資源不正確時,對生成的manifest執行
kubectl apply
時可能會顯示錯誤。- 當配置變更后(如移除一個gateway)
istioctl install
會自動清理所有的資源。當配合kubectl
執行istio manifest generate
時需要手動移除這些資源。
使用如下方式校驗安裝結果
$ istioctl verify-install -f $HOME/generated-manifest.yaml
自定義配置:
-
使用
--set
選項進行設置,如下面用於設置profile中的global.controlPlaneSecurityEnabled
為true$ istioctl install --set values.global.controlPlaneSecurityEnabled=true
-
如果修改的參數比較多,可以使用yaml文件統一進行配置,實際使用
IstioOperator API
進行profile的修改$ istioctl install -f samples/operator/pilot-k8s.yaml
istio的核心組件定義在 IstioOperator
API的components下面:
Field | Type | Description | Required |
---|---|---|---|
base |
BaseComponentSpec |
No | |
pilot |
ComponentSpec |
No | |
policy |
ComponentSpec |
No | |
telemetry |
ComponentSpec |
No | |
cni |
ComponentSpec |
No | |
istiodRemote |
ComponentSpec |
No | |
ingressGateways |
GatewaySpec[] |
No | |
egressGateways |
GatewaySpec[] |
No |
第三方插件可以在IstioOperator API
的addonComponents下指定,如:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
telemetry:
enabled: false
每個組件都有一個KubernetesResourceSpec
,用於設置如下k8s屬性
- Resources
- Readiness probes
- Replica count
- HorizontalPodAutoscaler
- PodDisruptionBudget
- Pod annotations
- Service annotations
- ImagePullPolicy
- Priority class name
- Node selector
- Affinity and anti-affinity
- Service
- Toleration
- Strategy
- Env
標准卸載istio
使用如下方式可以移除kubernetes中所有istio組件
$ istioctl x uninstall --purge
使用如下方式可以移除某個特定的istio控制面
$ istioctl x uninstall <your original installation options>
或
$ istioctl manifest generate <your original installation options> | kubectl delete -f -
自定義外部charts和profiles
istioctl
install
, manifest generate
和profile
命令都可以在charts和profiles中使用下面的資源:
- charts內置的資源。如果沒有設置
--manifests
選項,則為默認配置。charts內置的資源與Istio發行版.tgz
的manifests/
目錄中資源相同. - 本地文件系統的charts。如
istioctl install --manifests istio-1.7.0/manifests
- Github上的charts,如
istioctl install --manifests https://github.com/istio/istio/releases/download/1.7.0/istio-1.7.0-linux-arm64.tar.gz
本地文件系統charts和profiles可以通過編輯manifests/
目錄下的文件實現自定義。建議拷貝manifests
命令並對其進行修改。但必須保留manifests
目錄中的內容布局。
可以通過編輯manifests/profiles/
中的profile來創建新的profile文件。istioctl會掃描profiles子目錄以及可以被IstioOperatorSpec
profile字段引用的所有profile名稱。在用戶配置生效前會使用內置的profile作為默認的profile YAML。例如,可以創建一個名為custom1.yaml
的文件,該文件自定義了default
profile中的某些配置,然后應用該用戶自定義的配置:
$ istioctl manifest generate --manifests mycharts/ --set profile=custom1 -f path-to-user-overlay.yaml
這種情況下, custom1.yaml
和user-overlay.yaml
文件會覆蓋default.yaml
文件。
一般來說,不需要創建新的配置文件,因為可以通過傳遞多個文件來覆蓋獲得類似的結果。例如,如下命令等同於傳入了兩個用戶覆蓋的文件:
$ istioctl manifest generate --manifests mycharts/ -f manifests/profiles/custom1.yaml -f path-to-user-overlay.yaml
只有在需要通過istooperatorspec
按名稱引用profile文件時,才需要創建自定義profile文件。
更新Istio
金絲雀升級
revision
安裝方式支持同時部署多個版本的istio,在升級時可以將流量逐步轉移到新版本的istio上。每個修訂revision
都是一個完整的istio控制面,具有獨立的Deployment
, Service
等。
控制面升級
使用如下方式可以安裝一個名為canary
的istio修訂版本。下面方式默認會使用default
profile創建一套新的istio,如果新的istio和老的istio有組件重疊,則可能導致組件重建。從下面的AGE
字段可以看出,新的Prometheus
覆蓋了老的Prometheus
,ingressgateway
也一樣,因此最好的方式是指定文件,參見istio install
$ istioctl install --set revision=canary
注:revision中不能包含
.
命令執行成功后,可以看到存在2個控制面,每個控制面有各自的Deployment
,Service
等。
$ kubectl get pods -n istio-system -l app=istiod
NAME READY STATUS RESTARTS AGE
istiod-786779888b-p9s5n 1/1 Running 0 114m
istiod-canary-6956db645c-vwhsk 1/1 Running 0 1m
$ kubectl get svc -n istio-system -l app=istiod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istiod ClusterIP 10.32.5.247 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 33d
istiod-canary ClusterIP 10.32.6.58 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP,53/UDP,853/TCP 12m
sidecar注入配置也有2套
$ kubectl get mutatingwebhookconfigurations
NAME CREATED AT
istio-sidecar-injector 2020-03-26T07:09:21Z
istio-sidecar-injector-canary 2020-04-28T19:03:26Z
卸載老的控制面
使用如下命令卸載revision
為1-6-5
的控制面
$ istioctl x uninstall --revision 1-6-5
如果沒有revision標簽,則使用原始安裝它的選項進行卸載
$ istioctl x uninstall -f manifests/profiles/default.yaml
數據面升級
創建新的istio修訂版本並不會影響現有的代理。為了升級代理,需要將代理的配置指向新的控制面。通過命名空間標簽istio.io/rev
設置控制sidecar注入的控制面。
下面操作升級了test-ns
命名空間,移除標簽istio-injection
,並增加標簽istio.io/rev
,指向新的istio canary
。注意必須移除標簽istio-injection
,否則istio會優先處理istio-injection
(原因是為了向后兼容)
$ kubectl label namespace test-ns istio-injection- istio.io/rev=canary
在升級命名空間后,需要重啟pod來觸發sidecar的注入,如下使用滾動升級
$ kubectl rollout restart deployment -n test-ns
通過如下方式可以查看使用canary
istio修訂版的pod
$ kubectl get pods -n test-ns -l istio.io/rev=canary
為了驗證test-ns命名空間中的新pod使用了istiod-canary服務,可以選擇一個pod使用如下命令進行驗證。從輸出中可以看到其使用了istiod-canary
控制面
$ istioctl proxy-config endpoints ${pod_name}.test-ns --cluster xds-grpc -ojson | grep hostname
"hostname": "istiod-canary.istio-system.svc"
可以通過如下方式導出canary
修訂版的配置信息
$ istioctl manifest generate --revision=canary >canary.yaml
替換升級
升級過程中可能會造成流量中斷,為了最小化影響,需要確保istio中的各個組件(除Citadel)至少有兩個副本正在運行,此外需要通過PodDistruptionBudgets保證至少有一個可用的pod。
-
首先下載最新的istio
-
校驗當前環境中支持的升級到的版本,如下命令會給出推薦的版本
$ istioctl manifest versions
-
確認需要升級的cluster是否正確
$ kubectl config view
-
通過如下命令執行升級,
<your-custom-configuration-file>
為當前版本的 IstioOperator API 配置 文件$ istioctl upgrade -f `<your-custom-configuration-file>`
istioctl upgrade不支持
--set
命令 -
在更新完畢之后,需要手動重啟帶有istio sidecar的pod來更新istio數據面
$ kubectl rollout restart deployment
sidecar注入
sidecar不能注入到kube-system或kube-public名稱空間中
sidecar不能注入使用主機網絡的吊艙中
為了使用Istio的特性,pods必須運行在istio sidecar proxy的網格中。下面介紹兩種注入istio sidecar的方式:手動注入和自動注入。
手動注入通過直接修改,如deployment的配置信息,將proxy配置注入到配置中;當應用所在的命名空間啟用自動注入時,會在pod創建時通過mutating webhook admission controller 注入proxy配置。
sidecar的(手動或自動)注入會用到istio-sidecar-injector
configmap。
-
手動注入
當前版本手動注入時有一個問題,就是使用istio CNI之后無法將annotation
k8s.v1.cni.cncf.io/networks
注入(或導出)到配置文件中,導致出現如下問題,參見該issue:in new validator: 10.80.2.222 Listening on 127.0.0.1:15001 Listening on 127.0.0.1:15006 Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused Error connecting to 127.0.0.6:15002: dial tcp 127.0.0.1:0->127.0.0.6:15002: connect: connection refused
-
手動注入需要滿足一個條件,即在應用所在的命名空間中創建NetworkAttachmentDefinition
-
一種是直接使用
istio-sidecar-injector
的默認配置直接注入sidecar$ istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -
可以使用如下方式直接先導出注入sidecar的deployment,然后使用kubectl直接部署
$ istioctl kube-inject -f samples/sleep/sleep.yaml -o sleep-injected.yaml --injectConfigMapName istio-sidecar-injector $ kubectl apply -f deployment-injected.yaml
-
另一種是先導出
istio-sidecar-injector
的默認配置,可以修改后再手動注入sidecar導出配置:
$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml $ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' > inject-values.yaml $ kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml
手動注入:
$ istioctl kube-inject \ --injectConfigFile inject-config.yaml \ --meshConfigFile mesh-config.yaml \ --valuesFile inject-values.yaml \ --filename samples/sleep/sleep.yaml \ | kubectl apply -f -
-
-
自動注入
自動注入時需要滿足兩個條件:
-
給應用所在的命名空間打上標簽
istio-injection=enabled
$ kubectl label namespace <app-namespace> istio-injection=enabled
-
與手動注入相同,需要在應用所在的命名空間中創建NetworkAttachmentDefinition,然后在該命名空間下面正常創建(或刪除並重建)pod即可自動注入sidecar。需要注意的是自動注入發生在pod層,並不體現在deployment上面,可以使用
describe pod
查看注入的sidecar。自動注入通過mutatingwebhookconfiguration定義了注入sidecar的規則,當前是istio-injection=enabled
namespaceSelector: matchLabels: istio-injection: enabled
可以通過如下命令修改注入的規則,修改后需要重啟已經注入sidecar的pod,使規則生效
$ kubectl edit mutatingwebhookconfiguration istio-sidecar-injector
自動注入下,sidecar inject的webhook默認是打開的,如果要禁用該webhook,可以在上面cni-annotations.yaml文件中將
sidecarInjectorWebhook.enabled
置為false
,這樣就不會自動注入。
-
sidecar的注入控制
有兩種方式可以控制sidecar的注入:
-
第一種是修改pod template spec的
sidecar.istio.io/inject
annotation:當該annotation為true
時會進行自動注入sidecar,為false
則不會注入sidecar。默認為true
。這種情況需要修改應用的deployment。apiVersion: apps/v1 kind: Deployment metadata: name: ignored spec: template: metadata: annotations: sidecar.istio.io/inject: "false" spec: containers: - name: ignored image: tutum/curl command: ["/bin/sleep","infinity"]
-
第二種是修改
istio-sidecar-injector
configmap,通過在neverInjectSelector
數組中羅列出標簽,並禁止對匹配這些標簽的pod注入sidecar(各個匹配項的關系為OR
)。如下內容中不會對具有標簽openshift.io/build.name
或openshift.io/deployer-pod-for.name
的pod注入sidecar。這種方式不需要修改應用的deployment。類似地,可以使用alwaysInjectSelector
對某些具有特殊標簽的pod注入sidecarapiVersion: v1 kind: ConfigMap metadata: name: istio-sidecar-injector data: config: |- policy: enabled neverInjectSelector: - matchExpressions: - {key: openshift.io/build.name, operator: Exists} - matchExpressions: - {key: openshift.io/deployer-pod-for.name, operator: Exists} template: |- initContainers: ...
更多istio CNI與sidecar注入和流量重定向相關的參數參見官方文檔
卸載自動注入
使用如下方式可以卸載自動注入功能:
$ kubectl delete mutatingwebhookconfiguration istio-sidecar-injector
$ kubectl -n istio-system delete service istio-sidecar-injector
$ kubectl -n istio-system delete deployment istio-sidecar-injector
$ kubectl -n istio-system delete serviceaccount istio-sidecar-injector-service-account
$ kubectl delete clusterrole istio-sidecar-injector-istio-system
$ kubectl delete clusterrolebinding istio-sidecar-injector-admin-role-binding-istio-system
注意上面命令並不會卸載已經注入到pod的sidecar,需要通過滾動更新或直接刪除pod來生效
或者使用如下方式對某個命名空間禁用自動注入(推薦):
$ kubectl label namespace <target-namespace> istio-injection-
Istio CNI的兼容
與init容器的兼容
當使用istio CNI的時候,kubelet會按照如下步驟啟動注入sidecar的pod:
- 使用istio CNI插件進行配置,將流量導入到pod中的istio sidecar proxy容器
- 執行所有init容器,並成功運行結束
- 啟動pod中的istio sidecar proxy和其他容器
由於init容器會在sidecar proxy容器之前運行,因此可能導致應用本身的init容器的通信中斷。為了避免發生這種情況,可以通過如下配置避免重定向應用的init容器的流量:
- 設置
traffic.sidecar.istio.io/excludeOutboundIPRanges
annotation來禁用將流量重定向到與init容器通信的任何cidr。 - 設置
traffic.sidecar.istio.io/excludeOutboundPorts
annotation來禁止將流量重定向到init容器使用的出站端口
與其他CNI插件的兼容
istio CNI插件作為CNI插件鏈中的一環,當創建或刪除一個pod時,會按照順序啟動插件鏈上的每個插件,istio CNI插件僅僅(通過pod的網絡命名空間中的iptables)將應用的pod流量重定向到注入的istio proxy sidecar容器。
istio CNI插件不會干涉配置pod網絡的基本CNI插件。
更多細節參見CNI specification reference
TIPs:
-
不同平台下使用istio CNI執行initContainer時可能會出現istio-validation無法啟動的錯誤,這種情況下默認會導致kubelet刪除並重建pod,為了定位問題,可以將
repair.deletePods
配置為false,這樣就不會立即刪除podapiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: components: cni: ... values: cni: repair: enabled: true deletePods: false ...