├── .gitignore ├── Dockerfile ├── InternalGateway.png ├── LICENSE ├── NOTiCE ├── README.md ├── build.sh ├── cmd └── main.go ├── communication-group.jpg ├── docs └── canal.yaml ├── go.mod ├── go.sum ├── manifests └── charts │ ├── base │ ├── Chart.yaml │ ├── README.md │ ├── crds │ │ ├── crd-all.gen.yaml │ │ └── crd-operator.yaml │ ├── files │ │ └── gen-istio-cluster.yaml │ ├── kustomization.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── crds.yaml │ │ ├── default.yaml │ │ ├── endpoints.yaml │ │ ├── reader-serviceaccount.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ ├── serviceaccount.yaml │ │ └── services.yaml │ └── values.yaml │ ├── canal-control │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── deployment.yaml │ │ └── serviceaccount.yaml │ └── values.yaml │ ├── canal │ ├── Chart.yaml │ ├── NOTES.txt │ ├── templates │ │ ├── _affinity.tpl │ │ ├── autoscale.yaml │ │ ├── deployment.yaml │ │ ├── injected-deployment.yaml │ │ ├── poddisruptionbudget.yaml │ │ ├── role.yaml │ │ ├── rolebindings.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ └── values.yaml │ └── istio-discovery │ ├── Chart.yaml │ ├── README.md │ ├── files │ ├── gateway-injection-template.yaml │ ├── gen-istio.yaml │ ├── grpc-agent.yaml │ ├── grpc-simple.yaml │ └── injection-template.yaml │ ├── kustomization.yaml │ ├── templates │ ├── NOTES.txt │ ├── autoscale.yaml │ ├── clusterrole.yaml │ ├── clusterrolebinding.yaml │ ├── configmap-jwks.yaml │ ├── configmap.yaml │ ├── deployment.yaml │ ├── istiod-injector-configmap.yaml │ ├── mutatingwebhook.yaml │ ├── poddisruptionbudget.yaml │ ├── reader-clusterrole.yaml │ ├── reader-clusterrolebinding.yaml │ ├── revision-tags.yaml │ ├── role.yaml │ ├── rolebinding.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ ├── telemetryv2_1.11.yaml │ ├── telemetryv2_1.12.yaml │ ├── telemetryv2_1.13.yaml │ └── validatingwebhookconfiguration.yaml │ └── values.yaml ├── pkg ├── controller │ └── controller.go ├── coredns │ ├── coredns_process.go │ ├── debug_info.go │ └── service_map.go ├── signal │ ├── signal.go │ ├── signal_posix.go │ └── signal_windows.go └── tools │ └── tool.go └── samples └── helloworld ├── README.md ├── gen-helloworld.sh ├── helloworld-gateway.yaml ├── helloworld.yaml ├── loadgen.sh └── src ├── Dockerfile ├── app.py ├── build_service.sh └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go template 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | .idea/ 18 | 19 | # Dependency directories (remove the comment below to include it) 20 | # vendor/ 21 | 22 | cannalcontroller 23 | 24 | push.sh 25 | 26 | bin/canal-controller 27 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS builder 2 | WORKDIR /build 3 | ADD go.mod . 4 | COPY . . 5 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/canal-controller cmd/main.go 6 | 7 | FROM alpine:3.11.6 8 | WORKDIR /build 9 | COPY --from=builder /build/bin/canal-controller /canal-controller 10 | CMD /canal-controller --logtostderr=true -------------------------------------------------------------------------------- /InternalGateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/alibaba-centralized-mesh-gateway/efc875b54e40a801b0657ebde0b511f6d5755b01/InternalGateway.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "{}" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2016-2020 Istio Authors 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTiCE: -------------------------------------------------------------------------------- 1 | alibaba-centralized-mesh-gateway is developed by Alibaba and based on the Istio project 2 | Copyright (c) 2021, Alibaba Group 3 | Copyright (c) 2017-2020 The Apache Software Foundation 4 | Licensed under the Apache License, Version 2.0 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![avatar](./InternalGateway.png) 2 | 3 | # Table of Contents 4 | 5 | - [Introduction](#introduction) 6 | - [Build](#build) 7 | - [Prerequisite](#prerequisite) 8 | - [Install](#install) 9 | - [Usage](#usage) 10 | - [License](#license) 11 | 12 | # Introduction 13 | The east-west traffic in Istio is carried by envoy sidecars, which are deployed in every pod together with the application containers. Sidecars provide the functions of secure service-to-service communication, load balancing for various protocols, flexible traffic control and policy, and complete tracing. 14 | 15 | However, there are also a few disadvantages of sidecars. First of all, deploying one sidecar to every pod can be resource-consuming and introduce complexity, especially when the number of pods is huge. Not only must those resources be provisioned to the sidecars, but also the control plane to manage the sidecar and to push configurations can be demanding. Second, a query needs to go through two sidecars, one in the source pod and the other one in the destination pod, in order to reach the destination. For delay-sensitive applications, sometimes, the extra time spent in the sidecars is not acceptable. 16 | 17 | We noted that, for the majority of our HTTP applications, many of the rich features in sidecars are unused. That's why we want to propose a light-weighted way to serve east-west traffic without the drawbacks mentioned in the previous paragraph. Our focus is on the HTTP applications that do not require advanced security features, like mTLS. 18 | 19 | We propose the centralized east-west traffic gateway, which moves the sidecars and the functionalities they carry to nodes that are dedicated for sidecars, and no application container shares those nodes. This way, no modifications are required on the nodes, and we can save on the resources and the delay. In addition, we can decouple the network management from application management, and also avoid the resource competition between application and networking. However, because we move the sidecars out of the nodes of applications, we at the same time lose some of the security and tracing abilities provided by the original sidecars. Our observation is that the majority of our applications do not require those features. 20 | 21 | # Build 22 | 1. Dependency management(Optional) 23 | ``` 24 | go mod vendor 25 | ``` 26 | 2. Build 27 | ``` 28 | go build -o bin/canal-controller cmd/main.go 29 | ``` 30 | 3. Build cross-platform images(Optional) 31 | ``` 32 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/canal-controller cmd/main.go 33 | ``` 34 | 4. Get a base image 35 | ``` 36 | docker pull docker.io/library/alpine:3.11.6 37 | ``` 38 | 5. Build the image with the following Dockerfile 39 | ``` 40 | FROM alpine:3.11.6 41 | COPY bin/canal-controller /canal-controller 42 | CMD /canal-controller --logtostderr=true 43 | ``` 44 | 6. Build the docker image 45 | ``` 46 | docker build -f /path/to/your/Dockerfile . -t ${region}/${namespce}/canal:${tag} 47 | ``` 48 | 7. Push the image to the remote repository 49 | ``` 50 | docker push ${region}/${namespce}/canal:${tag} 51 | ``` 52 | 53 | # Prerequisite 54 | 1. Only one Gateway can be attached to InternalGateway. 55 | 2. The VirtualService managed by InternalGateway must be attached to the Gateway mention in 1. 56 | 3. CoreDNS is required. 57 | 58 | 59 | # Install 60 | 61 | 1. Install the Istio base chart which contains cluster-wide resources used by the Istio control plane 62 | ``` 63 | helm install istio-base ./base -n istio-system 64 | ``` 65 | 2. Install the Istio discovery chart which deploys the istiod service 66 | ``` 67 | helm install istiod ./istio-discovery/ -n istio-system 68 | ``` 69 | 3. Install the Canal Gateway(router mode Envoy) 70 | ``` 71 | helm install canal-gateway ./canal -n istio-system 72 | ``` 73 | 4. Install the Canal Controller 74 | ``` 75 | helm install canal-control ./canal-control -n istio-system \ 76 | --set global.hub=${your hub} \ 77 | --set global.imagePullSecrets[0]=${your secret} \ 78 | --set global.tag=${your tag} 79 | ``` 80 | 81 | # Usage 82 | ## Use centralized east-west traffic gateway to handle east-west traffic 83 | 1. Deploy Canal Service. 84 | 85 | 2. Create HelloWorld service. Note that the port opened must be consistent with the port opened on the gateway. 86 | ``` 87 | apiVersion: v1 88 | kind: Service 89 | metadata: 90 | name: helloworld 91 | labels: 92 | app: helloworld 93 | spec: 94 | ports: 95 | - port: 5000 96 | name: http 97 | selector: 98 | app: helloworld 99 | --- 100 | ``` 101 | 3. Create Gateway, and attach it to Canal Gateway. 102 | ``` 103 | kind: Gateway 104 | metadata: 105 | name: canal 106 | namespace: istio-system 107 | spec: 108 | selector: 109 | app: canal-gateway 110 | servers: 111 | - port: 112 | number: 5000 113 | name: http 114 | protocol: HTTP 115 | hosts: 116 | - "*" 117 | --- 118 | ``` 119 | 4. Create VirtualService. 120 | ``` 121 | apiVersion: networking.istio.io/v1alpha3 122 | kind: VirtualService 123 | metadata: 124 | name: helloworld 125 | namespace: istio-system 126 | spec: 127 | hosts: 128 | - "*" 129 | gateways: 130 | - canal 131 | http: 132 | - match: 133 | - uri: 134 | exact: /hello 135 | route: 136 | - destination: 137 | host: helloworld.default.svc.cluster.local 138 | --- 139 | ``` 140 | 5. Execute the following command. You should find the IP address of the HelloWorld service changed to the gateway's IP. 141 | ``` 142 | dig helloworld.default.svc.cluster.local 143 | ``` 144 | 145 | ## Move existing traffic to centralized east-west traffic gateway 146 | 147 | ### Approach 1: move only the traffic, and keep the service 148 | 149 | 1. Deploy Canal Service. 150 | 151 | 2. Create Gateway, and attach it to Canal Gateway. 152 | ``` 153 | kind: Gateway 154 | metadata: 155 | name: canal 156 | namespace: istio-system 157 | spec: 158 | selector: 159 | app: canal-gateway 160 | servers: 161 | - port: 162 | number: 5000 163 | name: http 164 | protocol: HTTP 165 | hosts: 166 | - "*" 167 | --- 168 | ``` 169 | 3. Create VirtualService. 170 | ``` 171 | apiVersion: networking.istio.io/v1alpha3 172 | kind: VirtualService 173 | metadata: 174 | name: helloworld 175 | namespace: istio-system 176 | spec: 177 | hosts: 178 | - "*" 179 | gateways: 180 | - canal 181 | http: 182 | - match: 183 | - uri: 184 | exact: /hello 185 | route: 186 | - destination: 187 | host: helloworld.default.svc.cluster.local 188 | --- 189 | ``` 190 | 4. Un-inject sidecars by removing the injection command. 191 | ``` 192 | kubectl label namespace your-namespace istio-injection=disabled 193 | ``` 194 | 195 | ### Approach 2: replace the existing service 196 | Note that we can also create a new replacement service, and attach the new service with InternalGateway, and remove the old service. 197 | 198 | 1. Create a new service and attach it to the internal gateway as instructed before. 199 | ``` 200 | kind: Gateway 201 | metadata: 202 | name: canal 203 | namespace: istio-system 204 | spec: 205 | selector: 206 | app: canal-gateway 207 | servers: 208 | - port: 209 | number: 5000 210 | name: http 211 | protocol: HTTP 212 | hosts: 213 | - "*" 214 | --- 215 | ``` 216 | ``` 217 | apiVersion: v1 218 | kind: Service 219 | metadata: 220 | name: helloworld-on-canal 221 | labels: 222 | app: helloworld-on-canal 223 | spec: 224 | ports: 225 | - port: 5000 226 | name: http 227 | selector: 228 | app: helloworld-on-canal 229 | --- 230 | ``` 231 | ``` 232 | apiVersion: networking.istio.io/v1alpha3 233 | kind: VirtualService 234 | metadata: 235 | name: helloworld-on-canal 236 | namespace: istio-system 237 | spec: 238 | hosts: 239 | - "*" 240 | gateways: 241 | - canal 242 | http: 243 | - match: 244 | - uri: 245 | exact: /hello 246 | route: 247 | - destination: 248 | host: helloworld-on-canal.default.svc.cluster.local 249 | ``` 250 | 2. remove the old service. 251 | 252 | # License 253 | [Apache License 2.0](./LICENSE) 254 | 255 | # Welcome to communicate with us 256 | ![avatar](./communication-group.jpg) 257 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build -t canal-controller:v1 . -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "cannalcontroller/pkg/controller" 19 | "cannalcontroller/pkg/coredns" 20 | "cannalcontroller/pkg/signal" 21 | "flag" 22 | "github.com/golang/glog" 23 | versionedclient "istio.io/client-go/pkg/clientset/versioned" 24 | "istio.io/client-go/pkg/informers/externalversions" 25 | "k8s.io/client-go/kubernetes" 26 | restclient "k8s.io/client-go/rest" 27 | "k8s.io/client-go/tools/clientcmd" 28 | "time" 29 | ) 30 | 31 | var ( 32 | masterURL string 33 | kubeConfig string 34 | ) 35 | 36 | func main() { 37 | flag.Parse() 38 | 39 | stopCh := signal.SetupSignalHandler() 40 | var cfg *restclient.Config 41 | var err error 42 | if kubeConfig != "" { 43 | cfg, err = clientcmd.BuildConfigFromFlags(masterURL, kubeConfig) 44 | if err != nil { 45 | glog.Fatalf("Error building kubeConfig: %s", err.Error()) 46 | } 47 | } else { 48 | cfg, err = restclient.InClusterConfig() 49 | if err != nil { 50 | panic(err.Error()) 51 | } 52 | } 53 | 54 | clientSet, err := kubernetes.NewForConfig(cfg) 55 | if err != nil { 56 | glog.Fatalf("Error building kubernetes clientSet: %s", err.Error()) 57 | } 58 | 59 | client, err := versionedclient.NewForConfig(cfg) 60 | if err != nil { 61 | glog.Fatalf("Failed to create istio client: %s", err) 62 | } 63 | 64 | factory := externalversions.NewSharedInformerFactory(client, time.Second*30) 65 | virtualServiceInformer := factory.Networking().V1alpha3().VirtualServices() 66 | gatewaysInformer := factory.Networking().V1alpha3().Gateways() 67 | 68 | canalController := controller.NewController(virtualServiceInformer, gatewaysInformer, clientSet, client) 69 | 70 | factory.Start(stopCh) 71 | coredns.StartDebugServer() 72 | 73 | if err = canalController.Run(1, stopCh); err != nil { 74 | glog.Fatalf("Error running controller: %s", err.Error()) 75 | } 76 | } 77 | 78 | func init() { 79 | flag.StringVar(&kubeConfig, "kubeConfig", "", "Path to a kubeConfig. Only required if out-of-cluster.") 80 | flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeConfig. Only required if out-of-cluster.") 81 | } 82 | -------------------------------------------------------------------------------- /communication-group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/alibaba-centralized-mesh-gateway/efc875b54e40a801b0657ebde0b511f6d5755b01/communication-group.jpg -------------------------------------------------------------------------------- /docs/canal.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: canalcontroller 5 | rules: 6 | - apiGroups: 7 | - "" 8 | resources: 9 | - configmaps 10 | verbs: 11 | - get 12 | - list 13 | - watch 14 | - create 15 | - update 16 | - patch 17 | - apiGroups: 18 | - networking.istio.io 19 | resources: 20 | - gateways 21 | - virtualservices 22 | verbs: 23 | - get 24 | - list 25 | - watch 26 | - create 27 | - update 28 | - patch 29 | --- 30 | apiVersion: v1 31 | kind: ServiceAccount 32 | metadata: 33 | name: canalcontroller 34 | namespace: istio-system 35 | --- 36 | kind: ClusterRoleBinding 37 | apiVersion: rbac.authorization.k8s.io/v1 38 | metadata: 39 | name: canalcontroller 40 | roleRef: 41 | apiGroup: rbac.authorization.k8s.io 42 | kind: ClusterRole 43 | name: canalcontroller 44 | subjects: 45 | - kind: ServiceAccount 46 | name: canalcontroller 47 | namespace: istio-system 48 | --- 49 | apiVersion: apps/v1 50 | kind: Deployment 51 | metadata: 52 | labels: 53 | app: canalcontroller 54 | name: canalcontroller 55 | namespace: istio-system 56 | spec: 57 | progressDeadlineSeconds: 600 58 | replicas: 1 59 | revisionHistoryLimit: 10 60 | selector: 61 | matchLabels: 62 | app: canalcontroller 63 | strategy: 64 | rollingUpdate: 65 | maxSurge: 100% 66 | maxUnavailable: 25% 67 | type: RollingUpdate 68 | template: 69 | metadata: 70 | annotations: 71 | sidecar.istio.io/inject: "false" 72 | labels: 73 | app: canalcontroller 74 | sidecar.istio.io/inject: "false" 75 | spec: 76 | dnsPolicy: ClusterFirst 77 | enableServiceLinks: true 78 | imagePullSecrets: 79 | - name: aliyun-secret 80 | containers: 81 | - name: canalcontroller 82 | image: registry-vpc.us-west-1.aliyuncs.com/wg/canalcontroller:latest 83 | imagePullPolicy: Always 84 | serviceAccountName: canalcontroller 85 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module cannalcontroller 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b 7 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 8 | istio.io/client-go v1.14.0 9 | k8s.io/api v0.24.2 10 | k8s.io/apimachinery v0.24.2 11 | k8s.io/client-go v0.24.2 12 | ) 13 | 14 | require ( 15 | github.com/PuerkitoBio/purell v1.1.1 // indirect 16 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/emicklei/go-restful v2.9.5+incompatible // indirect 19 | github.com/go-logr/logr v1.2.0 // indirect 20 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 21 | github.com/go-openapi/jsonreference v0.19.5 // indirect 22 | github.com/go-openapi/swag v0.19.14 // indirect 23 | github.com/gogo/protobuf v1.3.2 // indirect 24 | github.com/golang/protobuf v1.5.2 // indirect 25 | github.com/google/gnostic v0.5.7-v3refs // indirect 26 | github.com/google/go-cmp v0.5.6 // indirect 27 | github.com/google/gofuzz v1.1.0 // indirect 28 | github.com/imdario/mergo v0.3.5 // indirect 29 | github.com/josharian/intern v1.0.0 // indirect 30 | github.com/json-iterator/go v1.1.12 // indirect 31 | github.com/mailru/easyjson v0.7.6 // indirect 32 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 33 | github.com/modern-go/reflect2 v1.0.2 // indirect 34 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 35 | github.com/spf13/pflag v1.0.5 // indirect 36 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect 37 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect 38 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect 39 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 40 | golang.org/x/text v0.3.7 // indirect 41 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect 42 | google.golang.org/appengine v1.6.7 // indirect 43 | google.golang.org/genproto v0.0.0-20220531134929-86cf59382f1b // indirect 44 | google.golang.org/protobuf v1.28.0 // indirect 45 | gopkg.in/inf.v0 v0.9.1 // indirect 46 | gopkg.in/yaml.v2 v2.4.0 // indirect 47 | gopkg.in/yaml.v3 v3.0.1 // indirect 48 | istio.io/api v0.0.0-20220627132838-080342889567 // indirect 49 | k8s.io/klog/v2 v2.60.1 // indirect 50 | k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect 51 | k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect 52 | sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect 53 | sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect 54 | sigs.k8s.io/yaml v1.2.0 // indirect 55 | ) 56 | -------------------------------------------------------------------------------- /manifests/charts/base/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: base 3 | # This version is never actually shipped. istio/release-builder will replace it at build-time 4 | # with the appropriate version 5 | version: 1.0.0 6 | appVersion: 1.0.0 7 | tillerVersion: ">=2.7.2" 8 | description: Helm chart for deploying Istio cluster resources and CRDs 9 | keywords: 10 | - istio 11 | sources: 12 | - http://github.com/istio/istio 13 | engine: gotpl 14 | icon: https://istio.io/latest/favicons/android-192x192.png 15 | -------------------------------------------------------------------------------- /manifests/charts/base/README.md: -------------------------------------------------------------------------------- 1 | # Istio base Helm Chart 2 | 3 | This chart installs resources shared by all Istio revisions. This includes Istio CRDs. 4 | 5 | ## Setup Repo Info 6 | 7 | ```console 8 | helm repo add istio https://istio-release.storage.googleapis.com/charts 9 | helm repo update 10 | ``` 11 | 12 | _See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ 13 | 14 | ## Installing the Chart 15 | 16 | To install the chart with the release name `istio-base`: 17 | 18 | ```console 19 | kubectl create namespace istio-system 20 | helm install istio-base istio/base -n istio-system 21 | ``` 22 | -------------------------------------------------------------------------------- /manifests/charts/base/crds/crd-operator.yaml: -------------------------------------------------------------------------------- 1 | # SYNC WITH manifests/charts/istio-operator/templates 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: istiooperators.install.istio.io 6 | labels: 7 | release: istio 8 | spec: 9 | conversion: 10 | strategy: None 11 | group: install.istio.io 12 | names: 13 | kind: IstioOperator 14 | listKind: IstioOperatorList 15 | plural: istiooperators 16 | singular: istiooperator 17 | shortNames: 18 | - iop 19 | - io 20 | scope: Namespaced 21 | versions: 22 | - additionalPrinterColumns: 23 | - description: Istio control plane revision 24 | jsonPath: .spec.revision 25 | name: Revision 26 | type: string 27 | - description: IOP current state 28 | jsonPath: .status.status 29 | name: Status 30 | type: string 31 | - description: 'CreationTimestamp is a timestamp representing the server time 32 | when this object was created. It is not guaranteed to be set in happens-before 33 | order across separate operations. Clients may not set this value. It is represented 34 | in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for 35 | lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' 36 | jsonPath: .metadata.creationTimestamp 37 | name: Age 38 | type: date 39 | subresources: 40 | status: {} 41 | name: v1alpha1 42 | schema: 43 | openAPIV3Schema: 44 | type: object 45 | x-kubernetes-preserve-unknown-fields: true 46 | served: true 47 | storage: true 48 | --- 49 | -------------------------------------------------------------------------------- /manifests/charts/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - files/gen-istio-cluster.yaml 6 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Istio base successfully installed! 2 | 3 | To learn more about the release, try: 4 | $ helm status {{ .Release.Name }} 5 | $ helm get all {{ .Release.Name }} 6 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 2 | # DO NOT EDIT! 3 | # THIS IS A LEGACY CHART HERE FOR BACKCOMPAT 4 | # UPDATED CHART AT manifests/charts/istio-control/istio-discovery 5 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRole 8 | metadata: 9 | name: istiod-{{ .Values.global.istioNamespace }} 10 | labels: 11 | app: istiod 12 | release: {{ .Release.Name }} 13 | rules: 14 | # sidecar injection controller 15 | - apiGroups: ["admissionregistration.k8s.io"] 16 | resources: ["mutatingwebhookconfigurations"] 17 | verbs: ["get", "list", "watch", "update", "patch"] 18 | 19 | # configuration validation webhook controller 20 | - apiGroups: ["admissionregistration.k8s.io"] 21 | resources: ["validatingwebhookconfigurations"] 22 | verbs: ["get", "list", "watch", "update"] 23 | 24 | # istio configuration 25 | # removing CRD permissions can break older versions of Istio running alongside this control plane (https://github.com/istio/istio/issues/29382) 26 | # please proceed with caution 27 | - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io"] 28 | verbs: ["get", "watch", "list"] 29 | resources: ["*"] 30 | {{- if .Values.global.istiod.enableAnalysis }} 31 | - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io"] 32 | verbs: ["update"] 33 | # TODO: should be on just */status but wildcard is not supported 34 | resources: ["*"] 35 | {{- end }} 36 | - apiGroups: ["networking.istio.io"] 37 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 38 | resources: [ "workloadentries" ] 39 | - apiGroups: ["networking.istio.io"] 40 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 41 | resources: [ "workloadentries/status" ] 42 | 43 | # auto-detect installed CRD definitions 44 | - apiGroups: ["apiextensions.k8s.io"] 45 | resources: ["customresourcedefinitions"] 46 | verbs: ["get", "list", "watch"] 47 | 48 | # discovery and routing 49 | - apiGroups: [""] 50 | resources: ["pods", "nodes", "services", "namespaces", "endpoints"] 51 | verbs: ["get", "list", "watch"] 52 | - apiGroups: ["discovery.k8s.io"] 53 | resources: ["endpointslices"] 54 | verbs: ["get", "list", "watch"] 55 | 56 | # ingress controller 57 | {{- if .Values.global.istiod.enableAnalysis }} 58 | - apiGroups: ["extensions", "networking.k8s.io"] 59 | resources: ["ingresses"] 60 | verbs: ["get", "list", "watch"] 61 | - apiGroups: ["extensions", "networking.k8s.io"] 62 | resources: ["ingresses/status"] 63 | verbs: ["*"] 64 | {{- end}} 65 | - apiGroups: ["networking.k8s.io"] 66 | resources: ["ingresses", "ingressclasses"] 67 | verbs: ["get", "list", "watch"] 68 | - apiGroups: ["networking.k8s.io"] 69 | resources: ["ingresses/status"] 70 | verbs: ["*"] 71 | 72 | # required for CA's namespace controller 73 | - apiGroups: [""] 74 | resources: ["configmaps"] 75 | verbs: ["create", "get", "list", "watch", "update"] 76 | 77 | # Istiod and bootstrap. 78 | - apiGroups: ["certificates.k8s.io"] 79 | resources: 80 | - "certificatesigningrequests" 81 | - "certificatesigningrequests/approval" 82 | - "certificatesigningrequests/status" 83 | verbs: ["update", "create", "get", "delete", "watch"] 84 | - apiGroups: ["certificates.k8s.io"] 85 | resources: 86 | - "signers" 87 | resourceNames: 88 | - "kubernetes.io/legacy-unknown" 89 | verbs: ["approve"] 90 | 91 | # Used by Istiod to verify the JWT tokens 92 | - apiGroups: ["authentication.k8s.io"] 93 | resources: ["tokenreviews"] 94 | verbs: ["create"] 95 | 96 | # Used by Istiod to verify gateway SDS 97 | - apiGroups: ["authorization.k8s.io"] 98 | resources: ["subjectaccessreviews"] 99 | verbs: ["create"] 100 | 101 | # Use for Kubernetes Service APIs 102 | - apiGroups: ["networking.x-k8s.io", "gateway.networking.k8s.io"] 103 | resources: ["*"] 104 | verbs: ["get", "watch", "list"] 105 | - apiGroups: ["networking.x-k8s.io", "gateway.networking.k8s.io"] 106 | resources: ["*"] # TODO: should be on just */status but wildcard is not supported 107 | verbs: ["update"] 108 | 109 | # Needed for multicluster secret reading, possibly ingress certs in the future 110 | - apiGroups: [""] 111 | resources: ["secrets"] 112 | verbs: ["get", "watch", "list"] 113 | 114 | # Used for MCS serviceexport management 115 | - apiGroups: ["multicluster.x-k8s.io"] 116 | resources: ["serviceexports"] 117 | verbs: ["get", "watch", "list", "create", "delete"] 118 | 119 | # Used for MCS serviceimport management 120 | - apiGroups: ["multicluster.x-k8s.io"] 121 | resources: ["serviceimports"] 122 | verbs: ["get", "watch", "list"] 123 | --- 124 | apiVersion: rbac.authorization.k8s.io/v1 125 | kind: ClusterRole 126 | metadata: 127 | name: istio-reader-{{ .Values.global.istioNamespace }} 128 | labels: 129 | app: istio-reader 130 | release: {{ .Release.Name }} 131 | rules: 132 | - apiGroups: 133 | - "config.istio.io" 134 | - "security.istio.io" 135 | - "networking.istio.io" 136 | - "authentication.istio.io" 137 | - "rbac.istio.io" 138 | resources: ["*"] 139 | verbs: ["get", "list", "watch"] 140 | - apiGroups: [""] 141 | resources: ["endpoints", "pods", "services", "nodes", "replicationcontrollers", "namespaces", "secrets"] 142 | verbs: ["get", "list", "watch"] 143 | - apiGroups: ["networking.istio.io"] 144 | verbs: [ "get", "watch", "list" ] 145 | resources: [ "workloadentries" ] 146 | - apiGroups: ["apiextensions.k8s.io"] 147 | resources: ["customresourcedefinitions"] 148 | verbs: ["get", "list", "watch"] 149 | - apiGroups: ["discovery.k8s.io"] 150 | resources: ["endpointslices"] 151 | verbs: ["get", "list", "watch"] 152 | - apiGroups: ["apps"] 153 | resources: ["replicasets"] 154 | verbs: ["get", "list", "watch"] 155 | - apiGroups: ["authentication.k8s.io"] 156 | resources: ["tokenreviews"] 157 | verbs: ["create"] 158 | - apiGroups: ["authorization.k8s.io"] 159 | resources: ["subjectaccessreviews"] 160 | verbs: ["create"] 161 | - apiGroups: ["multicluster.x-k8s.io"] 162 | resources: ["serviceexports"] 163 | verbs: ["get", "watch", "list"] 164 | - apiGroups: ["multicluster.x-k8s.io"] 165 | resources: ["serviceimports"] 166 | verbs: ["get", "watch", "list"] 167 | {{- if or .Values.global.externalIstiod }} 168 | - apiGroups: [""] 169 | resources: ["configmaps"] 170 | verbs: ["create", "get", "list", "watch", "update"] 171 | - apiGroups: ["admissionregistration.k8s.io"] 172 | resources: ["mutatingwebhookconfigurations"] 173 | verbs: ["get", "list", "watch", "update", "patch"] 174 | - apiGroups: ["admissionregistration.k8s.io"] 175 | resources: ["validatingwebhookconfigurations"] 176 | verbs: ["get", "list", "watch", "update"] 177 | {{- end}} 178 | --- 179 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 2 | # DO NOT EDIT! 3 | # THIS IS A LEGACY CHART HERE FOR BACKCOMPAT 4 | # UPDATED CHART AT manifests/charts/istio-control/istio-discovery 5 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRoleBinding 8 | metadata: 9 | name: istio-reader-{{ .Values.global.istioNamespace }} 10 | labels: 11 | app: istio-reader 12 | release: {{ .Release.Name }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: ClusterRole 16 | name: istio-reader-{{ .Values.global.istioNamespace }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: istio-reader-service-account 20 | namespace: {{ .Values.global.istioNamespace }} 21 | --- 22 | apiVersion: rbac.authorization.k8s.io/v1 23 | kind: ClusterRoleBinding 24 | metadata: 25 | name: istiod-{{ .Values.global.istioNamespace }} 26 | labels: 27 | app: istiod 28 | release: {{ .Release.Name }} 29 | roleRef: 30 | apiGroup: rbac.authorization.k8s.io 31 | kind: ClusterRole 32 | name: istiod-{{ .Values.global.istioNamespace }} 33 | subjects: 34 | - kind: ServiceAccount 35 | name: istiod-service-account 36 | namespace: {{ .Values.global.istioNamespace }} 37 | --- 38 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/crds.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.base.enableCRDTemplates }} 2 | {{ .Files.Get "crds/crd-all.gen.yaml" }} 3 | {{ .Files.Get "crds/crd-operator.yaml" }} 4 | {{- end }} 5 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/default.yaml: -------------------------------------------------------------------------------- 1 | {{- if not (eq .Values.defaultRevision "") }} 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | name: istiod-default-validator 6 | labels: 7 | app: istiod 8 | release: {{ .Release.Name }} 9 | istio: istiod 10 | istio.io/rev: {{ .Values.defaultRevision }} 11 | webhooks: 12 | - name: validation.istio.io 13 | clientConfig: 14 | {{- if .Values.base.validationURL }} 15 | url: {{ .Values.base.validationURL }} 16 | {{- else }} 17 | service: 18 | {{- if (eq .Values.defaultRevision "default") }} 19 | name: istiod 20 | {{- else }} 21 | name: istiod-{{ .Values.defaultRevision }} 22 | {{- end }} 23 | namespace: {{ .Values.global.istioNamespace }} 24 | path: "/validate" 25 | {{- end }} 26 | rules: 27 | - operations: 28 | - CREATE 29 | - UPDATE 30 | apiGroups: 31 | - security.istio.io 32 | - networking.istio.io 33 | apiVersions: 34 | - "*" 35 | resources: 36 | - "*" 37 | # Fail open until the validation webhook is ready. The webhook controller 38 | # will update this to `Fail` and patch in the `caBundle` when the webhook 39 | # endpoint is ready. 40 | failurePolicy: Ignore 41 | sideEffects: None 42 | admissionReviewVersions: ["v1beta1", "v1"] 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/endpoints.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.remotePilotAddress }} 2 | {{- if .Values.pilot.enabled }} 3 | apiVersion: v1 4 | kind: Endpoints 5 | metadata: 6 | name: istiod-remote 7 | namespace: {{ .Release.Namespace }} 8 | subsets: 9 | - addresses: 10 | - ip: {{ .Values.global.remotePilotAddress }} 11 | ports: 12 | - port: 15012 13 | name: tcp-istiod 14 | protocol: TCP 15 | {{- else if regexMatch "^([0-9]*\\.){3}[0-9]*$" .Values.global.remotePilotAddress }} 16 | apiVersion: v1 17 | kind: Endpoints 18 | metadata: 19 | name: istiod 20 | namespace: {{ .Release.Namespace }} 21 | subsets: 22 | - addresses: 23 | - ip: {{ .Values.global.remotePilotAddress }} 24 | ports: 25 | - port: 15012 26 | name: tcp-istiod 27 | protocol: TCP 28 | {{- end }} 29 | --- 30 | {{- end }} 31 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/reader-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | # This service account aggregates reader permissions for the revisions in a given cluster 2 | # Should be used for remote secret creation. 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | {{- if .Values.global.imagePullSecrets }} 6 | imagePullSecrets: 7 | {{- range .Values.global.imagePullSecrets }} 8 | - name: {{ . }} 9 | {{- end }} 10 | {{- end }} 11 | metadata: 12 | name: istio-reader-service-account 13 | namespace: {{ .Values.global.istioNamespace }} 14 | labels: 15 | app: istio-reader 16 | release: {{ .Release.Name }} 17 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/role.yaml: -------------------------------------------------------------------------------- 1 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 2 | # DO NOT EDIT! 3 | # THIS IS A LEGACY CHART HERE FOR BACKCOMPAT 4 | # UPDATED CHART AT manifests/charts/istio-control/istio-discovery 5 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: Role 8 | metadata: 9 | name: istiod-{{ .Values.global.istioNamespace }} 10 | namespace: {{ .Values.global.istioNamespace }} 11 | labels: 12 | app: istiod 13 | release: {{ .Release.Name }} 14 | rules: 15 | # permissions to verify the webhook is ready and rejecting 16 | # invalid config. We use --server-dry-run so no config is persisted. 17 | - apiGroups: ["networking.istio.io"] 18 | verbs: ["create"] 19 | resources: ["gateways"] 20 | 21 | # For storing CA secret 22 | - apiGroups: [""] 23 | resources: ["secrets"] 24 | # TODO lock this down to istio-ca-cert if not using the DNS cert mesh config 25 | verbs: ["create", "get", "watch", "list", "update", "delete"] 26 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 2 | # DO NOT EDIT! 3 | # THIS IS A LEGACY CHART HERE FOR BACKCOMPAT 4 | # UPDATED CHART AT manifests/charts/istio-control/istio-discovery 5 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: RoleBinding 8 | metadata: 9 | name: istiod-{{ .Values.global.istioNamespace }} 10 | namespace: {{ .Values.global.istioNamespace }} 11 | labels: 12 | app: istiod 13 | release: {{ .Release.Name }} 14 | roleRef: 15 | apiGroup: rbac.authorization.k8s.io 16 | kind: Role 17 | name: istiod-{{ .Values.global.istioNamespace }} 18 | subjects: 19 | - kind: ServiceAccount 20 | name: istiod-service-account 21 | namespace: {{ .Values.global.istioNamespace }} 22 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 2 | # DO NOT EDIT! 3 | # THIS IS A LEGACY CHART HERE FOR BACKCOMPAT 4 | # UPDATED CHART AT manifests/charts/istio-control/istio-discovery 5 | # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | {{- if .Values.global.imagePullSecrets }} 9 | imagePullSecrets: 10 | {{- range .Values.global.imagePullSecrets }} 11 | - name: {{ . }} 12 | {{- end }} 13 | {{- end }} 14 | metadata: 15 | name: istiod-service-account 16 | namespace: {{ .Values.global.istioNamespace }} 17 | labels: 18 | app: istiod 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /manifests/charts/base/templates/services.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.remotePilotAddress }} 2 | {{- if .Values.pilot.enabled }} 3 | # when local istiod is enabled, we can't use istiod service name to reach the remote control plane 4 | apiVersion: v1 5 | kind: Service 6 | metadata: 7 | name: istiod-remote 8 | namespace: {{ .Release.Namespace }} 9 | spec: 10 | ports: 11 | - port: 15012 12 | name: tcp-istiod 13 | protocol: TCP 14 | clusterIP: None 15 | {{- else }} 16 | # when local istiod isn't enabled, we can use istiod service name to reach the remote control plane 17 | apiVersion: v1 18 | kind: Service 19 | metadata: 20 | name: istiod 21 | namespace: {{ .Release.Namespace }} 22 | spec: 23 | ports: 24 | - port: 15012 25 | name: tcp-istiod 26 | protocol: TCP 27 | # if the remotePilotAddress is IP addr, we use clusterIP: None. 28 | # else, we use externalName 29 | {{- if regexMatch "^([0-9]*\\.){3}[0-9]*$" .Values.global.remotePilotAddress }} 30 | clusterIP: None 31 | {{- else }} 32 | type: ExternalName 33 | externalName: {{ .Values.global.remotePilotAddress }} 34 | {{- end }} 35 | {{- end }} 36 | --- 37 | {{- end }} 38 | -------------------------------------------------------------------------------- /manifests/charts/base/values.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | 3 | # ImagePullSecrets for control plane ServiceAccount, list of secrets in the same namespace 4 | # to use for pulling any images in pods that reference this ServiceAccount. 5 | # Must be set for any cluster configured with private docker registry. 6 | imagePullSecrets: [] 7 | 8 | # Used to locate istiod. 9 | istioNamespace: istio-system 10 | 11 | istiod: 12 | enableAnalysis: false 13 | 14 | configValidation: true 15 | externalIstiod: false 16 | remotePilotAddress: "" 17 | 18 | base: 19 | # Used for helm2 to add the CRDs to templates. 20 | enableCRDTemplates: false 21 | 22 | # Validation webhook configuration url 23 | # For example: https://$remotePilotAddress:15017/validate 24 | validationURL: "" 25 | 26 | # For istioctl usage to disable istio config crds in base 27 | enableIstioConfigCRDs: true 28 | 29 | defaultRevision: "default" 30 | -------------------------------------------------------------------------------- /manifests/charts/canal-control/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /manifests/charts/canal-control/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: canal-control 3 | # This version is never actually shipped. istio/release-builder will replace it at build-time 4 | # with the appropriate version 5 | version: 1.0.0 6 | appVersion: 1.0.0 7 | tillerVersion: ">=2.7.2" 8 | description: Helm chart for canal control plane 9 | keywords: 10 | - istio 11 | - canal-controller 12 | sources: 13 | - git@gitlab.alibaba-inc.com:yuri.lcy/Canal.git 14 | engine: gotpl 15 | icon: https://istio.io/latest/favicons/android-192x192.png 16 | -------------------------------------------------------------------------------- /manifests/charts/canal-control/templates/NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/alibaba-centralized-mesh-gateway/efc875b54e40a801b0657ebde0b511f6d5755b01/manifests/charts/canal-control/templates/NOTES.txt -------------------------------------------------------------------------------- /manifests/charts/canal-control/templates/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "canal-controller" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: {{ $gateway.name }}-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app: canal-controller 9 | rules: 10 | - apiGroups: [ "" ] 11 | resources: [ "configmaps" ] 12 | verbs: [ "create", "get", "list", "watch", "update" ] 13 | - apiGroups: [ "networking.istio.io" ] 14 | resources: [ "gateways", "virtualservices" ] 15 | verbs: [ "get", "list", "watch", "patch" ] 16 | --- -------------------------------------------------------------------------------- /manifests/charts/canal-control/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "canal-controller" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: canal-controller-{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 6 | labels: 7 | app: canal-controller 8 | release: {{ .Release.Name }} 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: ClusterRole 12 | name: {{ $gateway.name }}-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 13 | subjects: 14 | - kind: ServiceAccount 15 | name: {{ $gateway.name }}-service-account 16 | namespace: {{ .Release.Namespace }} 17 | --- -------------------------------------------------------------------------------- /manifests/charts/canal-control/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "canal-controller" }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: canal-controller{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app: canal-controller 9 | spec: 10 | {{- if not .Values.controller.autoscaleEnabled }} 11 | {{- if .Values.controller.replicaCount }} 12 | replicas: {{ .Values.controller.replicaCount }} 13 | {{- end }} 14 | {{- end }} 15 | strategy: 16 | rollingUpdate: 17 | maxSurge: {{ .Values.controller.rollingMaxSurge }} 18 | maxUnavailable: {{ .Values.controller.rollingMaxUnavailable }} 19 | selector: 20 | matchLabels: 21 | app: canal-controller 22 | template: 23 | metadata: 24 | annotations: 25 | sidecar.istio.io/inject: "false" 26 | labels: 27 | app: canal-controller 28 | sidecar.istio.io/inject: "false" 29 | spec: 30 | dnsPolicy: ClusterFirst 31 | enableServiceLinks: true 32 | containers: 33 | - name: canal-controller 34 | {{- if contains "/" .Values.controller.image }} 35 | image: "{{ .Values.controller.image }}" 36 | {{- else }} 37 | image: "{{ .Values.global.hub | default .Values.global.hub }}/{{ .Values.controller.image | default "canalcontroller" }}:{{ .Values.global.tag | default .Values.global.tag }}" 38 | {{- end }} 39 | imagePullPolicy: Always 40 | serviceAccountName: {{ $gateway.name }}-service-account 41 | -------------------------------------------------------------------------------- /manifests/charts/canal-control/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "canal-controller" }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | {{- if .Values.global.imagePullSecrets }} 5 | imagePullSecrets: 6 | {{- range .Values.global.imagePullSecrets }} 7 | - name: {{ . }} 8 | {{- end }} 9 | {{- end }} 10 | metadata: 11 | name: {{ $gateway.name }}-service-account 12 | namespace: {{ .Release.Namespace }} -------------------------------------------------------------------------------- /manifests/charts/canal-control/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for canal-control. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | gateways: 6 | canal-controller: 7 | name: canal-controller 8 | istioNamespace: istio-system 9 | 10 | revision: "" 11 | 12 | global: 13 | imagePullSecrets: [] 14 | hub: "" 15 | tag: "" 16 | imagePullPolicy: "" 17 | 18 | controller: 19 | revision: "" 20 | replicaCount: 1 21 | autoscaleEnabled: true 22 | rollingMaxSurge: 100% 23 | rollingMaxUnavailable: 25% 24 | image: "" -------------------------------------------------------------------------------- /manifests/charts/canal/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: canal-gateway 3 | # This version is never actually shipped. istio/release-builder will replace it at build-time 4 | # with the appropriate version 5 | version: 1.0.0 6 | appVersion: 1.0.0 7 | tillerVersion: ">=2.7.2" 8 | description: Helm chart for deploying gateways 9 | keywords: 10 | - gateways 11 | sources: 12 | - http://github.com/istio/istio 13 | engine: gotpl 14 | icon: https://istio.io/latest/favicons/android-192x192.png 15 | -------------------------------------------------------------------------------- /manifests/charts/canal/NOTES.txt: -------------------------------------------------------------------------------- 1 | 2 | Changes: 3 | - separate namespace allows: 4 | -- easier reconfig of just the gateway 5 | -- TLS secrets and domain name management is isolated, for better security 6 | -- simplified configuration 7 | -- multiple versions of the ingress can be used, to minimize upgrade risks 8 | 9 | - the new chart uses the default namespace service account, and doesn't require 10 | additional RBAC permissions. 11 | 12 | - simplified label and chart structure. 13 | - ability to run a pilot dedicated for the gateway, isolated from the main pilot. This is more robust, safer on upgrades 14 | and allows a bit more flexibility. 15 | - the dedicated pilot-per-ingress is required if the gateway needs to support k8s-style ingress. 16 | 17 | # Port and basic host configuration 18 | 19 | In order to configure the Service object, the install/upgrade needs to provide a list of all ports. 20 | In the past, this was done when installing/upgrading full istio, and involved some duplication - ports configured 21 | both in upgrade, Gateway and VirtualService. 22 | 23 | The new Ingress chart uses a 'values.yaml' (see user-example-ingress), which auto-generates Service ports, 24 | Gateways and basic VirtualService. It is still possible to only configure the ports in Service, and do manual 25 | config for the rest. 26 | 27 | All internal services ( telemetry, pilot debug ports, mesh expansion ) can now be configured via the new mechanism. 28 | 29 | # Migration from istio-system 30 | 31 | Istio 1.0 includes the gateways in istio-system. Since the external IP is associated 32 | with the Service and bound to the namespace, it is recommended to: 33 | 34 | 1. Install the new gateway in a new namespace. 35 | 2. Copy any TLS certificate to the new namespace, and configure the domains. 36 | 3. Checking the new gateway work - for example by overriding the IP in /etc/hosts 37 | 4. Modify the DNS server to add the A record of the new namespace 38 | 5. Check traffic 39 | 6. Delete the A record corresponding to the gateway in istio-system 40 | 7. Upgrade istio-system, disabling the ingressgateway 41 | 8. Delete the domain TLS certs from istio-system. 42 | 43 | If using certmanager, all Certificate and associated configs must be moved as well. 44 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/_affinity.tpl: -------------------------------------------------------------------------------- 1 | {{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} 2 | 3 | {{ define "nodeaffinity" }} 4 | nodeAffinity: 5 | requiredDuringSchedulingIgnoredDuringExecution: 6 | {{- include "nodeAffinityRequiredDuringScheduling" . }} 7 | preferredDuringSchedulingIgnoredDuringExecution: 8 | {{- include "nodeAffinityPreferredDuringScheduling" . }} 9 | {{- end }} 10 | 11 | {{- define "nodeAffinityRequiredDuringScheduling" }} 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: kubernetes.io/arch 15 | operator: In 16 | values: 17 | {{- range $key, $val := .global.arch }} 18 | {{- if gt ($val | int) 0 }} 19 | - {{ $key | quote }} 20 | {{- end }} 21 | {{- end }} 22 | {{- $nodeSelector := default .global.defaultNodeSelector .nodeSelector -}} 23 | {{- range $key, $val := $nodeSelector }} 24 | - key: {{ $key }} 25 | operator: In 26 | values: 27 | - {{ $val | quote }} 28 | {{- end }} 29 | {{- end }} 30 | 31 | {{- define "nodeAffinityPreferredDuringScheduling" }} 32 | {{- range $key, $val := .global.arch }} 33 | {{- if gt ($val | int) 0 }} 34 | - weight: {{ $val | int }} 35 | preference: 36 | matchExpressions: 37 | - key: kubernetes.io/arch 38 | operator: In 39 | values: 40 | - {{ $key | quote }} 41 | {{- end }} 42 | {{- end }} 43 | {{- end }} 44 | 45 | {{- define "podAntiAffinity" }} 46 | {{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} 47 | podAntiAffinity: 48 | {{- if .podAntiAffinityLabelSelector }} 49 | requiredDuringSchedulingIgnoredDuringExecution: 50 | {{- include "podAntiAffinityRequiredDuringScheduling" . }} 51 | {{- end }} 52 | {{- if .podAntiAffinityTermLabelSelector }} 53 | preferredDuringSchedulingIgnoredDuringExecution: 54 | {{- include "podAntiAffinityPreferredDuringScheduling" . }} 55 | {{- end }} 56 | {{- end }} 57 | {{- end }} 58 | 59 | {{- define "podAntiAffinityRequiredDuringScheduling" }} 60 | {{- range $index, $item := .podAntiAffinityLabelSelector }} 61 | - labelSelector: 62 | matchExpressions: 63 | - key: {{ $item.key }} 64 | operator: {{ $item.operator }} 65 | {{- if $item.values }} 66 | values: 67 | {{- $vals := split "," $item.values }} 68 | {{- range $i, $v := $vals }} 69 | - {{ $v | quote }} 70 | {{- end }} 71 | {{- end }} 72 | topologyKey: {{ $item.topologyKey }} 73 | {{- if $item.namespaces }} 74 | namespaces: 75 | {{- $ns := split "," $item.namespaces }} 76 | {{- range $i, $n := $ns }} 77 | - {{ $n | quote }} 78 | {{- end }} 79 | {{- end }} 80 | {{- end }} 81 | {{- end }} 82 | 83 | {{- define "podAntiAffinityPreferredDuringScheduling" }} 84 | {{- range $index, $item := .podAntiAffinityTermLabelSelector }} 85 | - podAffinityTerm: 86 | labelSelector: 87 | matchExpressions: 88 | - key: {{ $item.key }} 89 | operator: {{ $item.operator }} 90 | {{- if $item.values }} 91 | values: 92 | {{- $vals := split "," $item.values }} 93 | {{- range $i, $v := $vals }} 94 | - {{ $v | quote }} 95 | {{- end }} 96 | {{- end }} 97 | topologyKey: {{ $item.topologyKey }} 98 | weight: 100 99 | {{- end }} 100 | {{- end }} 101 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/autoscale.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | {{- if and $gateway.autoscaleEnabled $gateway.autoscaleMin $gateway.autoscaleMax }} 3 | apiVersion: autoscaling/v2beta1 4 | kind: HorizontalPodAutoscaler 5 | metadata: 6 | name: {{ $gateway.name }} 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | {{ $gateway.labels | toYaml | indent 4 }} 10 | release: {{ .Release.Name }} 11 | istio.io/rev: {{ .Values.revision | default "default" }} 12 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 13 | operator.istio.io/component: "IngressGateways" 14 | spec: 15 | maxReplicas: {{ $gateway.autoscaleMax }} 16 | minReplicas: {{ $gateway.autoscaleMin }} 17 | scaleTargetRef: 18 | apiVersion: apps/v1 19 | kind: Deployment 20 | name: {{ $gateway.name }} 21 | metrics: 22 | - type: Resource 23 | resource: 24 | name: cpu 25 | targetAverageUtilization: {{ $gateway.cpu.targetAverageUtilization }} 26 | --- 27 | {{- end }} 28 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | {{- if eq $gateway.injectionTemplate "" }} 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: {{ $gateway.name }} 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | {{ $gateway.labels | toYaml | indent 4 }} 10 | release: {{ .Release.Name }} 11 | istio.io/rev: {{ .Values.revision | default "default" }} 12 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 13 | operator.istio.io/component: "IngressGateways" 14 | spec: 15 | {{- if not $gateway.autoscaleEnabled }} 16 | {{- if $gateway.replicaCount }} 17 | replicas: {{ $gateway.replicaCount }} 18 | {{- end }} 19 | {{- end }} 20 | selector: 21 | matchLabels: 22 | {{ $gateway.labels | toYaml | indent 6 }} 23 | strategy: 24 | rollingUpdate: 25 | maxSurge: {{ $gateway.rollingMaxSurge }} 26 | maxUnavailable: {{ $gateway.rollingMaxUnavailable }} 27 | template: 28 | metadata: 29 | labels: 30 | {{ $gateway.labels | toYaml | indent 8 }} 31 | {{- if eq .Release.Namespace "istio-system"}} 32 | heritage: Tiller 33 | release: istio 34 | chart: gateways 35 | {{- end }} 36 | service.istio.io/canonical-name: {{ $gateway.name }} 37 | {{- if not (eq .Values.revision "") }} 38 | service.istio.io/canonical-revision: {{ .Values.revision }} 39 | {{- else}} 40 | service.istio.io/canonical-revision: latest 41 | {{- end }} 42 | istio.io/rev: {{ .Values.revision | default "default" }} 43 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 44 | operator.istio.io/component: "IngressGateways" 45 | sidecar.istio.io/inject: "false" 46 | annotations: 47 | {{- if .Values.meshConfig.enablePrometheusMerge }} 48 | prometheus.io/port: "15020" 49 | prometheus.io/scrape: "true" 50 | prometheus.io/path: "/stats/prometheus" 51 | {{- end }} 52 | sidecar.istio.io/inject: "false" 53 | {{- if $gateway.podAnnotations }} 54 | {{ toYaml $gateway.podAnnotations | indent 8 }} 55 | {{ end }} 56 | spec: 57 | {{- if not $gateway.runAsRoot }} 58 | securityContext: 59 | runAsUser: 1337 60 | runAsGroup: 1337 61 | runAsNonRoot: true 62 | fsGroup: 1337 63 | {{- end }} 64 | serviceAccountName: {{ $gateway.name }}-service-account 65 | {{- if .Values.global.priorityClassName }} 66 | priorityClassName: "{{ .Values.global.priorityClassName }}" 67 | {{- end }} 68 | {{- if .Values.global.proxy.enableCoreDump }} 69 | initContainers: 70 | - name: enable-core-dump 71 | {{- if contains "/" .Values.global.proxy.image }} 72 | image: "{{ .Values.global.proxy.image }}" 73 | {{- else }} 74 | image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" 75 | {{- end }} 76 | {{- if .Values.global.imagePullPolicy }} 77 | imagePullPolicy: {{ .Values.global.imagePullPolicy }} 78 | {{- end }} 79 | command: 80 | - /bin/sh 81 | args: 82 | - -c 83 | - sysctl -w kernel.core_pattern=/var/lib/istio/data/core.proxy && ulimit -c unlimited 84 | securityContext: 85 | runAsUser: 0 86 | runAsGroup: 0 87 | runAsNonRoot: false 88 | privileged: true 89 | {{- end }} 90 | containers: 91 | - name: istio-proxy 92 | {{- if contains "/" .Values.global.proxy.image }} 93 | image: "{{ .Values.global.proxy.image }}" 94 | {{- else }} 95 | image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" 96 | {{- end }} 97 | {{- if .Values.global.imagePullPolicy }} 98 | imagePullPolicy: {{ .Values.global.imagePullPolicy }} 99 | {{- end }} 100 | ports: 101 | {{- range $key, $val := $gateway.ports }} 102 | - containerPort: {{ $val.targetPort | default $val.port }} 103 | protocol: {{ $val.protocol | default "TCP" }} 104 | {{- end }} 105 | - containerPort: 15090 106 | protocol: TCP 107 | name: http-envoy-prom 108 | args: 109 | - proxy 110 | - router 111 | - --domain 112 | - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} 113 | {{- if .Values.global.proxy.logLevel }} 114 | - --proxyLogLevel={{ .Values.global.proxy.logLevel }} 115 | {{- end}} 116 | {{- if .Values.global.proxy.componentLogLevel }} 117 | - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} 118 | {{- end}} 119 | {{- if .Values.global.logging.level }} 120 | - --log_output_level={{ .Values.global.logging.level }} 121 | {{- end}} 122 | {{- if .Values.global.logAsJson }} 123 | - --log_as_json 124 | {{- end }} 125 | {{- if .Values.global.sts.servicePort }} 126 | - --stsPort={{ .Values.global.sts.servicePort }} 127 | {{- end }} 128 | {{- if not $gateway.runAsRoot }} 129 | securityContext: 130 | allowPrivilegeEscalation: false 131 | capabilities: 132 | drop: 133 | - ALL 134 | privileged: false 135 | readOnlyRootFilesystem: true 136 | {{- end }} 137 | readinessProbe: 138 | failureThreshold: 30 139 | httpGet: 140 | path: /healthz/ready 141 | port: 15021 142 | scheme: HTTP 143 | initialDelaySeconds: 1 144 | periodSeconds: 2 145 | successThreshold: 1 146 | timeoutSeconds: 1 147 | resources: 148 | {{- if $gateway.resources }} 149 | {{ toYaml $gateway.resources | indent 12 }} 150 | {{- else }} 151 | {{ toYaml .Values.global.defaultResources | indent 12 }} 152 | {{- end }} 153 | env: 154 | - name: JWT_POLICY 155 | value: {{ .Values.global.jwtPolicy }} 156 | - name: PILOT_CERT_PROVIDER 157 | value: {{ .Values.global.pilotCertProvider }} 158 | - name: CA_ADDR 159 | {{- if .Values.global.caAddress }} 160 | value: {{ .Values.global.caAddress }} 161 | {{- else }} 162 | value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 163 | {{- end }} 164 | - name: NODE_NAME 165 | valueFrom: 166 | fieldRef: 167 | apiVersion: v1 168 | fieldPath: spec.nodeName 169 | - name: POD_NAME 170 | valueFrom: 171 | fieldRef: 172 | apiVersion: v1 173 | fieldPath: metadata.name 174 | - name: POD_NAMESPACE 175 | valueFrom: 176 | fieldRef: 177 | apiVersion: v1 178 | fieldPath: metadata.namespace 179 | - name: INSTANCE_IP 180 | valueFrom: 181 | fieldRef: 182 | apiVersion: v1 183 | fieldPath: status.podIP 184 | - name: HOST_IP 185 | valueFrom: 186 | fieldRef: 187 | apiVersion: v1 188 | fieldPath: status.hostIP 189 | - name: SERVICE_ACCOUNT 190 | valueFrom: 191 | fieldRef: 192 | fieldPath: spec.serviceAccountName 193 | - name: ISTIO_META_WORKLOAD_NAME 194 | value: {{ $gateway.name }} 195 | - name: ISTIO_META_OWNER 196 | value: kubernetes://apis/apps/v1/namespaces/{{ .Release.Namespace }}/deployments/{{ $gateway.name }} 197 | {{- if $.Values.global.meshID }} 198 | - name: ISTIO_META_MESH_ID 199 | value: "{{ $.Values.global.meshID }}" 200 | {{- else if .Values.meshConfig.trustDomain }} 201 | - name: ISTIO_META_MESH_ID 202 | value: "{{ .Values.meshConfig.trustDomain }}" 203 | {{- end }} 204 | {{- if .Values.meshConfig.trustDomain }} 205 | - name: TRUST_DOMAIN 206 | value: "{{ .Values.meshConfig.trustDomain }}" 207 | {{- end }} 208 | {{- if not $gateway.runAsRoot }} 209 | - name: ISTIO_META_UNPRIVILEGED_POD 210 | value: "true" 211 | {{- end }} 212 | {{- range $key, $val := $gateway.env }} 213 | - name: {{ $key }} 214 | value: "{{ $val }}" 215 | {{- end }} 216 | {{- range $key, $value := .Values.meshConfig.defaultConfig.proxyMetadata }} 217 | - name: {{ $key }} 218 | value: "{{ $value }}" 219 | {{- end }} 220 | {{- $network_set := index $gateway.env "ISTIO_META_NETWORK" }} 221 | {{- if and (not $network_set) .Values.global.network }} 222 | - name: ISTIO_META_NETWORK 223 | value: "{{ .Values.global.network }}" 224 | {{- end }} 225 | - name: ISTIO_META_CLUSTER_ID 226 | value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}" 227 | volumeMounts: 228 | - name: istio-envoy 229 | mountPath: /etc/istio/proxy 230 | - name: config-volume 231 | mountPath: /etc/istio/config 232 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 233 | - mountPath: /var/run/secrets/istio 234 | name: istiod-ca-cert 235 | {{- end }} 236 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 237 | - name: istio-token 238 | mountPath: /var/run/secrets/tokens 239 | readOnly: true 240 | {{- end }} 241 | {{- if .Values.global.mountMtlsCerts }} 242 | # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. 243 | - name: istio-certs 244 | mountPath: /etc/certs 245 | readOnly: true 246 | {{- end }} 247 | - mountPath: /var/lib/istio/data 248 | name: istio-data 249 | - name: podinfo 250 | mountPath: /etc/istio/pod 251 | {{- range $gateway.secretVolumes }} 252 | - name: {{ .name }} 253 | mountPath: {{ .mountPath | quote }} 254 | readOnly: true 255 | {{- end }} 256 | {{- range $gateway.configVolumes }} 257 | {{- if .mountPath }} 258 | - name: {{ .name }} 259 | mountPath: {{ .mountPath | quote }} 260 | readOnly: true 261 | {{- end }} 262 | {{- end }} 263 | {{- if $gateway.additionalContainers }} 264 | {{ toYaml $gateway.additionalContainers | indent 8 }} 265 | {{- end }} 266 | volumes: 267 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 268 | - name: istiod-ca-cert 269 | configMap: 270 | name: istio-ca-root-cert 271 | {{- end }} 272 | - name: podinfo 273 | downwardAPI: 274 | items: 275 | - path: "labels" 276 | fieldRef: 277 | fieldPath: metadata.labels 278 | - path: "annotations" 279 | fieldRef: 280 | fieldPath: metadata.annotations 281 | - name: istio-envoy 282 | emptyDir: {} 283 | - name: istio-data 284 | emptyDir: {} 285 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 286 | - name: istio-token 287 | projected: 288 | sources: 289 | - serviceAccountToken: 290 | path: istio-token 291 | expirationSeconds: 43200 292 | audience: {{ .Values.global.sds.token.aud }} 293 | {{- end }} 294 | {{- if .Values.global.mountMtlsCerts }} 295 | # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. 296 | - name: istio-certs 297 | secret: 298 | secretName: istio.istio-ingressgateway-service-account 299 | optional: true 300 | {{- end }} 301 | - name: config-volume 302 | configMap: 303 | name: istio{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 304 | optional: true 305 | {{- range $gateway.secretVolumes }} 306 | - name: {{ .name }} 307 | secret: 308 | secretName: {{ .secretName | quote }} 309 | optional: true 310 | {{- end }} 311 | {{- range $gateway.configVolumes }} 312 | - name: {{ .name }} 313 | configMap: 314 | name: {{ .configMapName | quote }} 315 | optional: true 316 | {{- end }} 317 | affinity: 318 | {{ include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | trim | indent 8 }} 319 | {{- include "podAntiAffinity" $gateway | indent 6 }} 320 | {{- if $gateway.tolerations }} 321 | tolerations: 322 | {{ toYaml $gateway.tolerations | indent 6 }} 323 | {{- else if .Values.global.defaultTolerations }} 324 | tolerations: 325 | {{ toYaml .Values.global.defaultTolerations | indent 6 }} 326 | {{- end }} 327 | {{- end }} 328 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/injected-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | {{- if ne $gateway.injectionTemplate "" }} 3 | {{/* This provides a minimal gateway, ready to be injected. 4 | Any settings from values.gateways should be here - these are options specific to the gateway. 5 | Global settings, like the image, various env vars and volumes, etc will be injected. 6 | The normal Deployment is not suitable for this, as the original pod spec will override the injection template. */}} 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | metadata: 10 | name: {{ $gateway.name | default "istio-ingressgateway" }} 11 | namespace: {{ .Release.Namespace }} 12 | labels: 13 | {{ $gateway.labels | toYaml | indent 4 }} 14 | release: {{ .Release.Name }} 15 | istio.io/rev: {{ .Values.revision | default "default" }} 16 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 17 | operator.istio.io/component: "IngressGateways" 18 | spec: 19 | {{- if not $gateway.autoscaleEnabled }} 20 | {{- if $gateway.replicaCount }} 21 | replicas: {{ $gateway.replicaCount }} 22 | {{- end }} 23 | {{- end }} 24 | selector: 25 | matchLabels: 26 | {{ $gateway.labels | toYaml | indent 6 }} 27 | strategy: 28 | rollingUpdate: 29 | maxSurge: {{ $gateway.rollingMaxSurge }} 30 | maxUnavailable: {{ $gateway.rollingMaxUnavailable }} 31 | template: 32 | metadata: 33 | labels: 34 | {{ $gateway.labels | toYaml | indent 8 }} 35 | {{- if eq .Release.Namespace "istio-system"}} 36 | heritage: Tiller 37 | release: istio 38 | chart: gateways 39 | {{- end }} 40 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 41 | operator.istio.io/component: "IngressGateways" 42 | sidecar.istio.io/inject: "true" 43 | {{- with .Values.revision }} 44 | istio.io/rev: {{ . }} 45 | {{- end }} 46 | annotations: 47 | {{- if .Values.meshConfig.enablePrometheusMerge }} 48 | prometheus.io/port: "15020" 49 | prometheus.io/scrape: "true" 50 | prometheus.io/path: "/stats/prometheus" 51 | {{- end }} 52 | sidecar.istio.io/inject: "true" 53 | inject.istio.io/templates: "{{ $gateway.injectionTemplate }}" 54 | {{- if $gateway.podAnnotations }} 55 | {{ toYaml $gateway.podAnnotations | indent 8 }} 56 | {{ end }} 57 | spec: 58 | {{- if not $gateway.runAsRoot }} 59 | securityContext: 60 | runAsUser: 1337 61 | runAsGroup: 1337 62 | runAsNonRoot: true 63 | fsGroup: 1337 64 | {{- end }} 65 | serviceAccountName: {{ $gateway.name | default "istio-ingressgateway" }}-service-account 66 | {{- if .Values.global.priorityClassName }} 67 | priorityClassName: "{{ .Values.global.priorityClassName }}" 68 | {{- end }} 69 | containers: 70 | - name: istio-proxy 71 | image: auto 72 | ports: 73 | {{- range $key, $val := $gateway.ports }} 74 | - containerPort: {{ $val.targetPort | default $val.port }} 75 | protocol: {{ $val.protocol | default "TCP" }} 76 | {{- end }} 77 | - containerPort: 15090 78 | protocol: TCP 79 | name: http-envoy-prom 80 | {{- if not $gateway.runAsRoot }} 81 | securityContext: 82 | allowPrivilegeEscalation: false 83 | capabilities: 84 | drop: 85 | - ALL 86 | privileged: false 87 | readOnlyRootFilesystem: true 88 | {{- end }} 89 | resources: 90 | {{- if $gateway.resources }} 91 | {{ toYaml $gateway.resources | indent 12 }} 92 | {{- else }} 93 | {{ toYaml .Values.global.defaultResources | indent 12 }} 94 | {{- end }} 95 | env: 96 | {{- if not $gateway.runAsRoot }} 97 | - name: ISTIO_META_UNPRIVILEGED_POD 98 | value: "true" 99 | {{- end }} 100 | {{- range $key, $val := $gateway.env }} 101 | - name: {{ $key }} 102 | value: {{ $val | quote }} 103 | {{- end }} 104 | volumeMounts: 105 | {{- range $gateway.secretVolumes }} 106 | - name: {{ .name }} 107 | mountPath: {{ .mountPath | quote }} 108 | readOnly: true 109 | {{- end }} 110 | {{- range $gateway.configVolumes }} 111 | {{- if .mountPath }} 112 | - name: {{ .name }} 113 | mountPath: {{ .mountPath | quote }} 114 | readOnly: true 115 | {{- end }} 116 | {{- end }} 117 | {{- if $gateway.additionalContainers }} 118 | {{ toYaml $gateway.additionalContainers | indent 8 }} 119 | {{- end }} 120 | volumes: 121 | {{- range $gateway.secretVolumes }} 122 | - name: {{ .name }} 123 | secret: 124 | secretName: {{ .secretName | quote }} 125 | optional: true 126 | {{- end }} 127 | {{- range $gateway.configVolumes }} 128 | - name: {{ .name }} 129 | configMap: 130 | name: {{ .configMapName | quote }} 131 | optional: true 132 | {{- end }} 133 | affinity: 134 | {{ include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | trim | indent 8 }} 135 | {{- include "podAntiAffinity" $gateway | indent 6 }} 136 | {{- if $gateway.tolerations }} 137 | tolerations: 138 | {{ toYaml $gateway.tolerations | indent 6 }} 139 | {{- else if .Values.global.defaultTolerations }} 140 | tolerations: 141 | {{ toYaml .Values.global.defaultTolerations | indent 6 }} 142 | {{- end }} 143 | {{- end }} 144 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/poddisruptionbudget.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.defaultPodDisruptionBudget.enabled }} 2 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 3 | apiVersion: policy/v1beta1 4 | kind: PodDisruptionBudget 5 | metadata: 6 | name: {{ $gateway.name }} 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | {{ $gateway.labels | toYaml | trim | indent 4 }} 10 | release: {{ .Release.Name }} 11 | istio.io/rev: {{ .Values.revision | default "default" }} 12 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 13 | operator.istio.io/component: "IngressGateways" 14 | spec: 15 | minAvailable: 1 16 | selector: 17 | matchLabels: 18 | {{ $gateway.labels | toYaml | trim | indent 6 }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: {{ $gateway.name }}-sds 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | release: {{ .Release.Name }} 9 | istio.io/rev: {{ .Values.revision | default "default" }} 10 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 11 | operator.istio.io/component: "IngressGateways" 12 | rules: 13 | - apiGroups: [""] 14 | resources: ["secrets"] 15 | verbs: ["get", "watch", "list"] 16 | --- 17 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/rolebindings.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ $gateway.name }}-sds 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | release: {{ .Release.Name }} 9 | istio.io/rev: {{ .Values.revision | default "default" }} 10 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 11 | operator.istio.io/component: "IngressGateways" 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: {{ $gateway.name }}-sds 16 | subjects: 17 | - kind: ServiceAccount 18 | name: {{ $gateway.name }}-service-account 19 | --- 20 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | {{- if not $gateway.customService }} 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | name: {{ $gateway.name }} 7 | namespace: {{ .Release.Namespace }} 8 | annotations: 9 | {{- range $key, $val := $gateway.serviceAnnotations }} 10 | {{ $key }}: {{ $val | quote }} 11 | {{- end }} 12 | labels: 13 | {{ $gateway.labels | toYaml | indent 4 }} 14 | release: {{ .Release.Name }} 15 | istio.io/rev: {{ .Values.revision | default "default" }} 16 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 17 | operator.istio.io/component: "IngressGateways" 18 | spec: 19 | {{- if $gateway.loadBalancerIP }} 20 | loadBalancerIP: "{{ $gateway.loadBalancerIP }}" 21 | {{- end }} 22 | {{- if $gateway.loadBalancerSourceRanges }} 23 | loadBalancerSourceRanges: 24 | {{ toYaml $gateway.loadBalancerSourceRanges | indent 4 }} 25 | {{- end }} 26 | {{- if $gateway.externalTrafficPolicy }} 27 | externalTrafficPolicy: {{$gateway.externalTrafficPolicy }} 28 | {{- end }} 29 | type: {{ $gateway.type }} 30 | selector: 31 | {{ $gateway.labels | toYaml | indent 4 }} 32 | ports: 33 | 34 | {{- range $key, $val := $gateway.ports }} 35 | - 36 | {{- range $pkey, $pval := $val }} 37 | {{ $pkey}}: {{ $pval }} 38 | {{- end }} 39 | {{- end }} 40 | 41 | {{ range $app := $gateway.ingressPorts }} 42 | - 43 | port: {{ $app.port }} 44 | name: {{ $app.name }} 45 | {{- end }} 46 | --- 47 | {{ end }} 48 | -------------------------------------------------------------------------------- /manifests/charts/canal/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{ $gateway := index .Values "gateways" "istio-ingressgateway" }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | {{- if .Values.global.imagePullSecrets }} 5 | imagePullSecrets: 6 | {{- range .Values.global.imagePullSecrets }} 7 | - name: {{ . }} 8 | {{- end }} 9 | {{- end }} 10 | metadata: 11 | name: {{ $gateway.name }}-service-account 12 | namespace: {{ .Release.Namespace }} 13 | labels: 14 | {{ $gateway.labels | toYaml | trim | indent 4 }} 15 | release: {{ .Release.Name }} 16 | istio.io/rev: {{ .Values.revision | default "default" }} 17 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 18 | operator.istio.io/component: "IngressGateways" 19 | {{- with $gateway.serviceAccount.annotations }} 20 | annotations: 21 | {{- toYaml . | nindent 4 }} 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /manifests/charts/canal/values.yaml: -------------------------------------------------------------------------------- 1 | # A-la-carte istio ingress gateway. 2 | # Must be installed in a separate namespace, to minimize access to secrets. 3 | 4 | gateways: 5 | istio-ingressgateway: 6 | name: canal 7 | labels: 8 | app: canal-gateway 9 | istio: gateway 10 | ports: 11 | ## You can add custom gateway ports in user values overrides, but it must include those ports since helm replaces. 12 | # Note that AWS ELB will by default perform health checks on the first port 13 | # on this list. Setting this to the health check port will ensure that health 14 | # checks always work. https://github.com/istio/istio/issues/12503 15 | - port: 15021 16 | targetPort: 15021 17 | name: status-port 18 | protocol: TCP 19 | - port: 80 20 | targetPort: 8080 21 | name: http2 22 | protocol: TCP 23 | - port: 443 24 | targetPort: 8443 25 | name: https 26 | protocol: TCP 27 | 28 | # Scalability tuning 29 | # replicaCount: 1 30 | rollingMaxSurge: 100% 31 | rollingMaxUnavailable: 25% 32 | autoscaleEnabled: true 33 | autoscaleMin: 1 34 | autoscaleMax: 5 35 | 36 | cpu: 37 | targetAverageUtilization: 80 38 | 39 | resources: 40 | requests: 41 | cpu: 100m 42 | memory: 128Mi 43 | limits: 44 | cpu: 2000m 45 | memory: 1024Mi 46 | 47 | loadBalancerIP: "" 48 | loadBalancerSourceRanges: [] 49 | serviceAnnotations: {} 50 | 51 | # To generate an internal load balancer: 52 | # --set serviceAnnotations.cloud.google.com/load-balancer-type=internal 53 | #serviceAnnotations: 54 | # cloud.google.com/load-balancer-type: "internal" 55 | 56 | podAnnotations: {} 57 | type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be 58 | 59 | ############## 60 | secretVolumes: 61 | - name: ingressgateway-certs 62 | secretName: istio-ingressgateway-certs 63 | mountPath: /etc/istio/ingressgateway-certs 64 | - name: ingressgateway-ca-certs 65 | secretName: istio-ingressgateway-ca-certs 66 | mountPath: /etc/istio/ingressgateway-ca-certs 67 | 68 | customService: false 69 | externalTrafficPolicy: "" 70 | 71 | ingressPorts: [] 72 | additionalContainers: [] 73 | configVolumes: [] 74 | 75 | serviceAccount: 76 | # Annotations to add to the service account 77 | annotations: {} 78 | 79 | ### Advanced options ############ 80 | env: {} 81 | nodeSelector: {} 82 | tolerations: [] 83 | 84 | # Specify the pod anti-affinity that allows you to constrain which nodes 85 | # your pod is eligible to be scheduled based on labels on pods that are 86 | # already running on the node rather than based on labels on nodes. 87 | # There are currently two types of anti-affinity: 88 | # "requiredDuringSchedulingIgnoredDuringExecution" 89 | # "preferredDuringSchedulingIgnoredDuringExecution" 90 | # which denote "hard" vs. "soft" requirements, you can define your values 91 | # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" 92 | # correspondingly. 93 | # For example: 94 | # podAntiAffinityLabelSelector: 95 | # - key: security 96 | # operator: In 97 | # values: S1,S2 98 | # topologyKey: "kubernetes.io/hostname" 99 | # This pod anti-affinity rule says that the pod requires not to be scheduled 100 | # onto a node if that node is already running a pod with label having key 101 | # "security" and value "S1". 102 | podAntiAffinityLabelSelector: [] 103 | podAntiAffinityTermLabelSelector: [] 104 | 105 | # whether to run the gateway in a privileged container 106 | runAsRoot: false 107 | 108 | # The injection template to use for the gateway. If not set, no injection will be performed. 109 | injectionTemplate: "" 110 | 111 | # Revision is set as 'version' label and part of the resource names when installing multiple control planes. 112 | revision: "" 113 | 114 | # For Helm compatibility. 115 | ownerName: "" 116 | 117 | global: 118 | # set the default set of namespaces to which services, service entries, virtual services, destination 119 | # rules should be exported to. Currently only one value can be provided in this list. This value 120 | # should be one of the following two options: 121 | # * implies these objects are visible to all namespaces, enabling any sidecar to talk to any other sidecar. 122 | # . implies these objects are visible to only to sidecars in the same namespace, or if imported as a Sidecar.egress.host 123 | defaultConfigVisibilitySettings: [] 124 | 125 | # Default node selector to be applied to all deployments so that all pods can be 126 | # constrained to run a particular nodes. Each component can overwrite these default 127 | # values by adding its node selector block in the relevant section below and setting 128 | # the desired values. 129 | defaultNodeSelector: {} 130 | 131 | # enable pod disruption budget for the control plane, which is used to 132 | # ensure Istio control plane components are gradually upgraded or recovered. 133 | defaultPodDisruptionBudget: 134 | enabled: true 135 | 136 | # A minimal set of requested resources to applied to all deployments so that 137 | # Horizontal Pod Autoscaler will be able to function (if set). 138 | # Each component can overwrite these default values by adding its own resources 139 | # block in the relevant section below and setting the desired resources values. 140 | defaultResources: 141 | requests: 142 | cpu: 10m 143 | # memory: 128Mi 144 | # limits: 145 | # cpu: 100m 146 | # memory: 128Mi 147 | 148 | # Default node tolerations to be applied to all deployments so that all pods can be 149 | # scheduled to a particular nodes with matching taints. Each component can overwrite 150 | # these default values by adding its tolerations block in the relevant section below 151 | # and setting the desired values. 152 | # Configure this field in case that all pods of Istio control plane are expected to 153 | # be scheduled to particular nodes with specified taints. 154 | defaultTolerations: [] 155 | 156 | # Default hub for Istio images. 157 | # Releases are published to docker hub under 'istio' project. 158 | # Dev builds from prow are on gcr.io 159 | hub: docker.io/istio 160 | 161 | # Default tag for Istio images. 162 | tag: 1.13.3 163 | 164 | # Specify image pull policy if default behavior isn't desired. 165 | # Default behavior: latest images will be Always else IfNotPresent. 166 | imagePullPolicy: "" 167 | 168 | # ImagePullSecrets for all ServiceAccount, list of secrets in the same namespace 169 | # to use for pulling any images in pods that reference this ServiceAccount. 170 | # For components that don't use ServiceAccounts (i.e. grafana, servicegraph, tracing) 171 | # ImagePullSecrets will be added to the corresponding Deployment(StatefulSet) objects. 172 | # Must be set for any cluster configured with private docker registry. 173 | imagePullSecrets: [] 174 | # - private-registry-key 175 | 176 | # To output all istio components logs in json format by adding --log_as_json argument to each container argument 177 | logAsJson: false 178 | 179 | # Specify pod scheduling arch(amd64, ppc64le, s390x, arm64) and weight as follows: 180 | # 0 - Never scheduled 181 | # 1 - Least preferred 182 | # 2 - No preference 183 | # 3 - Most preferred 184 | arch: 185 | amd64: 2 186 | s390x: 2 187 | ppc64le: 2 188 | arm64: 2 189 | 190 | # Comma-separated minimum per-scope logging level of messages to output, in the form of :,: 191 | # The control plane has different scopes depending on component, but can configure default log level across all components 192 | # If empty, default scope and level will be used as configured in code 193 | logging: 194 | level: "default:info" 195 | 196 | # Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and 197 | # system-node-critical, it is better to configure this in order to make sure your Istio pods 198 | # will not be killed because of low priority class. 199 | # Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass 200 | # for more detail. 201 | priorityClassName: "" 202 | 203 | proxy: 204 | image: proxyv2 205 | 206 | # CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value 207 | # cluster domain. Default value is "cluster.local". 208 | clusterDomain: "cluster.local" 209 | 210 | # Per Component log level for proxy, applies to gateways and sidecars. If a component level is 211 | # not set, then the global "logLevel" will be used. 212 | componentLogLevel: "misc:error" 213 | 214 | # If set, newly injected sidecars will have core dumps enabled. 215 | enableCoreDump: false 216 | 217 | # Log level for proxy, applies to gateways and sidecars. 218 | # Expected values are: trace|debug|info|warning|error|critical|off 219 | logLevel: warning 220 | 221 | ############################################################################################## 222 | # The following values are found in other charts. To effectively modify these values, make # 223 | # make sure they are consistent across your Istio helm charts # 224 | ############################################################################################## 225 | 226 | # The customized CA address to retrieve certificates for the pods in the cluster. 227 | # CSR clients such as the Istio Agent and ingress gateways can use this to specify the CA endpoint. 228 | caAddress: "" 229 | 230 | # Used to locate istiod. 231 | istioNamespace: istio-system 232 | 233 | # Configure the policy for validating JWT. 234 | # Currently, two options are supported: "third-party-jwt" and "first-party-jwt". 235 | jwtPolicy: "third-party-jwt" 236 | 237 | # Mesh ID means Mesh Identifier. It should be unique within the scope where 238 | # meshes will interact with each other, but it is not required to be 239 | # globally/universally unique. For example, if any of the following are true, 240 | # then two meshes must have different Mesh IDs: 241 | # - Meshes will have their telemetry aggregated in one place 242 | # - Meshes will be federated together 243 | # - Policy will be written referencing one mesh from the other 244 | # 245 | # If an administrator expects that any of these conditions may become true in 246 | # the future, they should ensure their meshes have different Mesh IDs 247 | # assigned. 248 | # 249 | # Within a multicluster mesh, each cluster must be (manually or auto) 250 | # configured to have the same Mesh ID value. If an existing cluster 'joins' a 251 | # multicluster mesh, it will need to be migrated to the new mesh ID. Details 252 | # of migration TBD, and it may be a disruptive operation to change the Mesh 253 | # ID post-install. 254 | # 255 | # If the mesh admin does not specify a value, Istio will use the value of the 256 | # mesh's Trust Domain. The best practice is to select a proper Trust Domain 257 | # value. 258 | meshID: "" 259 | 260 | # Use the user-specified, secret volume mounted key and certs for Pilot and workloads. 261 | mountMtlsCerts: false 262 | 263 | multiCluster: 264 | # Set to true to connect two kubernetes clusters via their respective 265 | # ingressgateway services when pods in each cluster cannot directly 266 | # talk to one another. All clusters should be using Istio mTLS and must 267 | # have a shared root CA for this model to work. 268 | enabled: false 269 | # Should be set to the name of the cluster this installation will run in. This is required for sidecar injection 270 | # to properly label proxies 271 | clusterName: "" 272 | # The suffix for global service names 273 | globalDomainSuffix: "global" 274 | # Enable envoy filter to translate `globalDomainSuffix` to cluster local suffix for cross cluster communication 275 | includeEnvoyFilter: true 276 | 277 | # Network defines the network this cluster belong to. This name 278 | # corresponds to the networks in the map of mesh networks. 279 | network: "" 280 | 281 | # Configure the certificate provider for control plane communication. 282 | # Currently, two providers are supported: "kubernetes" and "istiod". 283 | # As some platforms may not have kubernetes signing APIs, 284 | # Istiod is the default 285 | pilotCertProvider: istiod 286 | 287 | sds: 288 | # The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3. 289 | # When a CSR is sent from Citadel Agent to the CA (e.g. Citadel), this aud is to make sure the 290 | # JWT is intended for the CA. 291 | token: 292 | aud: istio-ca 293 | 294 | sts: 295 | # The service port used by Security Token Service (STS) server to handle token exchange requests. 296 | # Setting this port to a non-zero value enables STS server. 297 | servicePort: 0 298 | 299 | 300 | meshConfig: 301 | enablePrometheusMerge: true 302 | 303 | # The trust domain corresponds to the trust root of a system 304 | # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain 305 | trustDomain: "cluster.local" 306 | 307 | defaultConfig: 308 | proxyMetadata: {} 309 | tracing: 310 | # tlsSettings: 311 | # mode: DISABLE # DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL 312 | # clientCertificate: # example: /etc/istio/tracer/cert-chain.pem 313 | # privateKey: # example: /etc/istio/tracer/key.pem 314 | # caCertificates: # example: /etc/istio/tracer/root-cert.pem 315 | # sni: # example: tracer.somedomain 316 | # subjectAltNames: [] 317 | # - tracer.somedomain 318 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: istiod 3 | # This version is never actually shipped. istio/release-builder will replace it at build-time 4 | # with the appropriate version 5 | version: 1.0.0 6 | appVersion: 1.0.0 7 | tillerVersion: ">=2.7.2" 8 | description: Helm chart for istio control plane 9 | keywords: 10 | - istio 11 | - istiod 12 | - istio-discovery 13 | sources: 14 | - http://github.com/istio/istio 15 | engine: gotpl 16 | icon: https://istio.io/latest/favicons/android-192x192.png 17 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/README.md: -------------------------------------------------------------------------------- 1 | # Istiod Helm Chart 2 | 3 | This chart installs an Istiod deployment. 4 | 5 | ## Setup Repo Info 6 | 7 | ```console 8 | helm repo add istio https://istio-release.storage.googleapis.com/charts 9 | helm repo update 10 | ``` 11 | 12 | _See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ 13 | 14 | ## Installing the Chart 15 | 16 | Before installing, ensure CRDs are installed in the cluster (from the `istio/base` chart). 17 | 18 | To install the chart with the release name `istiod`: 19 | 20 | ```console 21 | kubectl create namespace istio-system 22 | helm install istiod istio/istiod --namespace istio-system 23 | ``` 24 | 25 | ## Uninstalling the Chart 26 | 27 | To uninstall/delete the `istiod` deployment: 28 | 29 | ```console 30 | helm delete istiod --namespace istio-system 31 | ``` 32 | 33 | ## Configuration 34 | 35 | To view support configuration options and documentation, run: 36 | 37 | ```console 38 | helm show values istio/istiod 39 | ``` 40 | 41 | ### Examples 42 | 43 | #### Configuring mesh configuration settings 44 | 45 | Any [Mesh Config](https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/) options can be configured like below: 46 | 47 | ```yaml 48 | meshConfig: 49 | accessLogFile: /dev/stdout 50 | ``` 51 | 52 | #### Revisions 53 | 54 | Control plane revisions allow deploying multiple versions of the control plane in the same cluster. 55 | This allows safe [canary upgrades](https://istio.io/latest/docs/setup/upgrade/canary/) 56 | 57 | ```yaml 58 | revision: my-revision-name 59 | ``` 60 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/files/gateway-injection-template.yaml: -------------------------------------------------------------------------------- 1 | {{- $containers := list }} 2 | {{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}} 3 | metadata: 4 | labels: 5 | service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }} 6 | service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }} 7 | istio.io/rev: {{ .Revision | default "default" | quote }} 8 | annotations: { 9 | {{- if eq (len $containers) 1 }} 10 | kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}", 11 | kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}", 12 | {{ end }} 13 | } 14 | spec: 15 | containers: 16 | - name: istio-proxy 17 | {{- if contains "/" .Values.global.proxy.image }} 18 | image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" 19 | {{- else }} 20 | image: "{{ .ProxyImage }}" 21 | {{- end }} 22 | ports: 23 | - containerPort: 15090 24 | protocol: TCP 25 | name: http-envoy-prom 26 | args: 27 | - proxy 28 | - router 29 | - --domain 30 | - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} 31 | - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }} 32 | - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }} 33 | - --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }} 34 | {{- if .Values.global.sts.servicePort }} 35 | - --stsPort={{ .Values.global.sts.servicePort }} 36 | {{- end }} 37 | {{- if .Values.global.logAsJson }} 38 | - --log_as_json 39 | {{- end }} 40 | {{- if .Values.global.proxy.lifecycle }} 41 | lifecycle: 42 | {{ toYaml .Values.global.proxy.lifecycle | indent 6 }} 43 | {{- end }} 44 | env: 45 | - name: JWT_POLICY 46 | value: {{ .Values.global.jwtPolicy }} 47 | - name: PILOT_CERT_PROVIDER 48 | value: {{ .Values.global.pilotCertProvider }} 49 | - name: CA_ADDR 50 | {{- if .Values.global.caAddress }} 51 | value: {{ .Values.global.caAddress }} 52 | {{- else }} 53 | value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 54 | {{- end }} 55 | - name: POD_NAME 56 | valueFrom: 57 | fieldRef: 58 | fieldPath: metadata.name 59 | - name: POD_NAMESPACE 60 | valueFrom: 61 | fieldRef: 62 | fieldPath: metadata.namespace 63 | - name: INSTANCE_IP 64 | valueFrom: 65 | fieldRef: 66 | fieldPath: status.podIP 67 | - name: SERVICE_ACCOUNT 68 | valueFrom: 69 | fieldRef: 70 | fieldPath: spec.serviceAccountName 71 | - name: HOST_IP 72 | valueFrom: 73 | fieldRef: 74 | fieldPath: status.hostIP 75 | - name: PROXY_CONFIG 76 | value: | 77 | {{ protoToJSON .ProxyConfig }} 78 | - name: ISTIO_META_POD_PORTS 79 | value: |- 80 | [ 81 | {{- $first := true }} 82 | {{- range $index1, $c := .Spec.Containers }} 83 | {{- range $index2, $p := $c.Ports }} 84 | {{- if (structToJSON $p) }} 85 | {{if not $first}},{{end}}{{ structToJSON $p }} 86 | {{- $first = false }} 87 | {{- end }} 88 | {{- end}} 89 | {{- end}} 90 | ] 91 | - name: ISTIO_META_APP_CONTAINERS 92 | value: "{{ $containers | join "," }}" 93 | - name: ISTIO_META_CLUSTER_ID 94 | value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" 95 | - name: ISTIO_META_INTERCEPTION_MODE 96 | value: "{{ .ProxyConfig.InterceptionMode.String }}" 97 | {{- if .Values.global.network }} 98 | - name: ISTIO_META_NETWORK 99 | value: "{{ .Values.global.network }}" 100 | {{- end }} 101 | {{- if .DeploymentMeta.Name }} 102 | - name: ISTIO_META_WORKLOAD_NAME 103 | value: "{{ .DeploymentMeta.Name }}" 104 | {{ end }} 105 | {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} 106 | - name: ISTIO_META_OWNER 107 | value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} 108 | {{- end}} 109 | {{- if .Values.global.meshID }} 110 | - name: ISTIO_META_MESH_ID 111 | value: "{{ .Values.global.meshID }}" 112 | {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} 113 | - name: ISTIO_META_MESH_ID 114 | value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" 115 | {{- end }} 116 | {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} 117 | - name: TRUST_DOMAIN 118 | value: "{{ . }}" 119 | {{- end }} 120 | {{- range $key, $value := .ProxyConfig.ProxyMetadata }} 121 | - name: {{ $key }} 122 | value: "{{ $value }}" 123 | {{- end }} 124 | {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} 125 | readinessProbe: 126 | httpGet: 127 | path: /healthz/ready 128 | port: 15021 129 | initialDelaySeconds: {{.Values.global.proxy.readinessInitialDelaySeconds }} 130 | periodSeconds: {{ .Values.global.proxy.readinessPeriodSeconds }} 131 | timeoutSeconds: 3 132 | failureThreshold: {{ .Values.global.proxy.readinessFailureThreshold }} 133 | volumeMounts: 134 | {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} 135 | - name: gke-workload-certificate 136 | mountPath: /var/run/secrets/workload-spiffe-credentials 137 | readOnly: true 138 | {{- end }} 139 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 140 | - mountPath: /var/run/secrets/istio 141 | name: istiod-ca-cert 142 | {{- end }} 143 | - mountPath: /var/lib/istio/data 144 | name: istio-data 145 | # SDS channel between istioagent and Envoy 146 | - mountPath: /etc/istio/proxy 147 | name: istio-envoy 148 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 149 | - mountPath: /var/run/secrets/tokens 150 | name: istio-token 151 | {{- end }} 152 | {{- if .Values.global.mountMtlsCerts }} 153 | # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. 154 | - mountPath: /etc/certs/ 155 | name: istio-certs 156 | readOnly: true 157 | {{- end }} 158 | - name: istio-podinfo 159 | mountPath: /etc/istio/pod 160 | volumes: 161 | {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} 162 | - name: gke-workload-certificate 163 | csi: 164 | driver: workloadcertificates.security.cloud.google.com 165 | {{- end }} 166 | # SDS channel between istioagent and Envoy 167 | - emptyDir: 168 | medium: Memory 169 | name: istio-envoy 170 | - name: istio-data 171 | emptyDir: {} 172 | - name: istio-podinfo 173 | downwardAPI: 174 | items: 175 | - path: "labels" 176 | fieldRef: 177 | fieldPath: metadata.labels 178 | - path: "annotations" 179 | fieldRef: 180 | fieldPath: metadata.annotations 181 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 182 | - name: istio-token 183 | projected: 184 | sources: 185 | - serviceAccountToken: 186 | path: istio-token 187 | expirationSeconds: 43200 188 | audience: {{ .Values.global.sds.token.aud }} 189 | {{- end }} 190 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 191 | - name: istiod-ca-cert 192 | configMap: 193 | name: istio-ca-root-cert 194 | {{- end }} 195 | {{- if .Values.global.mountMtlsCerts }} 196 | # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. 197 | - name: istio-certs 198 | secret: 199 | optional: true 200 | {{ if eq .Spec.ServiceAccountName "" }} 201 | secretName: istio.default 202 | {{ else -}} 203 | secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} 204 | {{ end -}} 205 | {{- end }} 206 | {{- if .Values.global.imagePullSecrets }} 207 | imagePullSecrets: 208 | {{- range .Values.global.imagePullSecrets }} 209 | - name: {{ . }} 210 | {{- end }} 211 | {{- end }} 212 | {{- if eq (env "ENABLE_LEGACY_FSGROUP_INJECTION" "true") "true" }} 213 | securityContext: 214 | fsGroup: 1337 215 | {{- end }} 216 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/files/grpc-agent.yaml: -------------------------------------------------------------------------------- 1 | {{- $containers := list }} 2 | {{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}} 3 | metadata: 4 | labels: 5 | service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }} 6 | service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }} 7 | annotations: { 8 | {{- if eq (len $containers) 1 }} 9 | kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}", 10 | kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}", 11 | {{ end }} 12 | sidecar.istio.io/rewriteAppHTTPProbers: "false", 13 | } 14 | spec: 15 | containers: 16 | {{- range $index, $container := .Spec.Containers }} 17 | {{ if not (eq $container.Name "istio-proxy") }} 18 | - name: {{ $container.Name }} 19 | env: 20 | - name: "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT" 21 | value: "true" 22 | - name: "GRPC_XDS_BOOTSTRAP" 23 | value: "/etc/istio/proxy/grpc-bootstrap.json" 24 | volumeMounts: 25 | - mountPath: /var/lib/istio/data 26 | name: istio-data 27 | # UDS channel between istioagent and gRPC client for XDS/SDS 28 | - mountPath: /etc/istio/proxy 29 | name: istio-xds 30 | {{- end }} 31 | {{- end }} 32 | - name: istio-proxy 33 | {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} 34 | image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" 35 | {{- else }} 36 | image: "{{ .ProxyImage }}" 37 | {{- end }} 38 | args: 39 | - proxy 40 | - sidecar 41 | - --domain 42 | - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} 43 | - --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }} 44 | {{- if .Values.global.sts.servicePort }} 45 | - --stsPort={{ .Values.global.sts.servicePort }} 46 | {{- end }} 47 | {{- if .Values.global.logAsJson }} 48 | - --log_as_json 49 | {{- end }} 50 | env: 51 | - name: ISTIO_META_GENERATOR 52 | value: grpc 53 | - name: OUTPUT_CERTS 54 | value: /var/lib/istio/data 55 | {{- if eq (env "PILOT_ENABLE_INBOUND_PASSTHROUGH" "true") "false" }} 56 | - name: REWRITE_PROBE_LEGACY_LOCALHOST_DESTINATION 57 | value: "true" 58 | {{- end }} 59 | - name: JWT_POLICY 60 | value: {{ .Values.global.jwtPolicy }} 61 | - name: PILOT_CERT_PROVIDER 62 | value: {{ .Values.global.pilotCertProvider }} 63 | - name: CA_ADDR 64 | {{- if .Values.global.caAddress }} 65 | value: {{ .Values.global.caAddress }} 66 | {{- else }} 67 | value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 68 | {{- end }} 69 | - name: POD_NAME 70 | valueFrom: 71 | fieldRef: 72 | fieldPath: metadata.name 73 | - name: POD_NAMESPACE 74 | valueFrom: 75 | fieldRef: 76 | fieldPath: metadata.namespace 77 | - name: INSTANCE_IP 78 | valueFrom: 79 | fieldRef: 80 | fieldPath: status.podIP 81 | - name: SERVICE_ACCOUNT 82 | valueFrom: 83 | fieldRef: 84 | fieldPath: spec.serviceAccountName 85 | - name: HOST_IP 86 | valueFrom: 87 | fieldRef: 88 | fieldPath: status.hostIP 89 | - name: PROXY_CONFIG 90 | value: | 91 | {{ protoToJSON .ProxyConfig }} 92 | - name: ISTIO_META_POD_PORTS 93 | value: |- 94 | [ 95 | {{- $first := true }} 96 | {{- range $index1, $c := .Spec.Containers }} 97 | {{- range $index2, $p := $c.Ports }} 98 | {{- if (structToJSON $p) }} 99 | {{if not $first}},{{end}}{{ structToJSON $p }} 100 | {{- $first = false }} 101 | {{- end }} 102 | {{- end}} 103 | {{- end}} 104 | ] 105 | - name: ISTIO_META_APP_CONTAINERS 106 | value: "{{ $containers | join "," }}" 107 | - name: ISTIO_META_CLUSTER_ID 108 | value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" 109 | - name: ISTIO_META_INTERCEPTION_MODE 110 | value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" 111 | {{- if .Values.global.network }} 112 | - name: ISTIO_META_NETWORK 113 | value: "{{ .Values.global.network }}" 114 | {{- end }} 115 | {{- if .DeploymentMeta.Name }} 116 | - name: ISTIO_META_WORKLOAD_NAME 117 | value: "{{ .DeploymentMeta.Name }}" 118 | {{ end }} 119 | {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} 120 | - name: ISTIO_META_OWNER 121 | value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} 122 | {{- end}} 123 | {{- if .Values.global.meshID }} 124 | - name: ISTIO_META_MESH_ID 125 | value: "{{ .Values.global.meshID }}" 126 | {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} 127 | - name: ISTIO_META_MESH_ID 128 | value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" 129 | {{- end }} 130 | {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} 131 | - name: TRUST_DOMAIN 132 | value: "{{ . }}" 133 | {{- end }} 134 | {{- range $key, $value := .ProxyConfig.ProxyMetadata }} 135 | - name: {{ $key }} 136 | value: "{{ $value }}" 137 | {{- end }} 138 | # grpc uses xds:/// to resolve – no need to resolve VIP 139 | - name: ISTIO_META_DNS_CAPTURE 140 | value: "false" 141 | - name: DISABLE_ENVOY 142 | value: "true" 143 | {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} 144 | {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} 145 | readinessProbe: 146 | httpGet: 147 | path: /healthz/ready 148 | port: {{ .Values.global.proxy.statusPort }} 149 | initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} 150 | periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} 151 | timeoutSeconds: 3 152 | failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} 153 | {{ end -}} 154 | resources: 155 | {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} 156 | {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }} 157 | requests: 158 | {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} 159 | cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" 160 | {{ end }} 161 | {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} 162 | memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" 163 | {{ end }} 164 | {{- end }} 165 | {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} 166 | limits: 167 | {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}} 168 | cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}" 169 | {{ end }} 170 | {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}} 171 | memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}" 172 | {{ end }} 173 | {{- end }} 174 | {{- else }} 175 | {{- if .Values.global.proxy.resources }} 176 | {{ toYaml .Values.global.proxy.resources | indent 6 }} 177 | {{- end }} 178 | {{- end }} 179 | volumeMounts: 180 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 181 | - mountPath: /var/run/secrets/istio 182 | name: istiod-ca-cert 183 | {{- end }} 184 | - mountPath: /var/lib/istio/data 185 | name: istio-data 186 | # UDS channel between istioagent and gRPC client for XDS/SDS 187 | - mountPath: /etc/istio/proxy 188 | name: istio-xds 189 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 190 | - mountPath: /var/run/secrets/tokens 191 | name: istio-token 192 | {{- end }} 193 | - name: istio-podinfo 194 | mountPath: /etc/istio/pod 195 | {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} 196 | {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} 197 | - name: "{{ $index }}" 198 | {{ toYaml $value | indent 6 }} 199 | {{ end }} 200 | {{- end }} 201 | volumes: 202 | # UDS channel between istioagent and gRPC client for XDS/SDS 203 | - emptyDir: 204 | medium: Memory 205 | name: istio-xds 206 | - name: istio-data 207 | emptyDir: {} 208 | - name: istio-podinfo 209 | downwardAPI: 210 | items: 211 | - path: "labels" 212 | fieldRef: 213 | fieldPath: metadata.labels 214 | - path: "annotations" 215 | fieldRef: 216 | fieldPath: metadata.annotations 217 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 218 | - name: istio-token 219 | projected: 220 | sources: 221 | - serviceAccountToken: 222 | path: istio-token 223 | expirationSeconds: 43200 224 | audience: {{ .Values.global.sds.token.aud }} 225 | {{- end }} 226 | {{- if eq .Values.global.pilotCertProvider "istiod" }} 227 | - name: istiod-ca-cert 228 | configMap: 229 | name: istio-ca-root-cert 230 | {{- end }} 231 | {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} 232 | {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} 233 | - name: "{{ $index }}" 234 | {{ toYaml $value | indent 4 }} 235 | {{ end }} 236 | {{ end }} 237 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/files/grpc-simple.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | sidecar.istio.io/rewriteAppHTTPProbers: "false" 3 | spec: 4 | initContainers: 5 | - name: grpc-bootstrap-init 6 | image: busybox:1.28 7 | volumeMounts: 8 | - mountPath: /var/lib/grpc/data/ 9 | name: grpc-io-proxyless-bootstrap 10 | env: 11 | - name: INSTANCE_IP 12 | valueFrom: 13 | fieldRef: 14 | fieldPath: status.podIP 15 | - name: POD_NAME 16 | valueFrom: 17 | fieldRef: 18 | fieldPath: metadata.name 19 | - name: POD_NAMESPACE 20 | valueFrom: 21 | fieldRef: 22 | fieldPath: metadata.namespace 23 | - name: ISTIO_NAMESPACE 24 | value: | 25 | {{ .Values.global.istioNamespace }} 26 | command: 27 | - sh 28 | - "-c" 29 | - |- 30 | NODE_ID="sidecar~${INSTANCE_IP}~${POD_NAME}.${POD_NAMESPACE}~cluster.local" 31 | SERVER_URI="dns:///istiod.${ISTIO_NAMESPACE}.svc:15010" 32 | echo ' 33 | { 34 | "xds_servers": [ 35 | { 36 | "server_uri": "'${SERVER_URI}'", 37 | "channel_creds": [{"type": "insecure"}], 38 | "server_features" : ["xds_v3"] 39 | } 40 | ], 41 | "node": { 42 | "id": "'${NODE_ID}'", 43 | "metadata": { 44 | "GENERATOR": "grpc" 45 | } 46 | } 47 | }' > /var/lib/grpc/data/bootstrap.json 48 | containers: 49 | {{- range $index, $container := .Spec.Containers }} 50 | - name: {{ $container.Name }} 51 | env: 52 | - name: GRPC_XDS_BOOTSTRAP 53 | value: /var/lib/grpc/data/bootstrap.json 54 | - name: GRPC_GO_LOG_VERBOSITY_LEVEL 55 | value: "99" 56 | - name: GRPC_GO_LOG_SEVERITY_LEVEL 57 | value: info 58 | volumeMounts: 59 | - mountPath: /var/lib/grpc/data/ 60 | name: grpc-io-proxyless-bootstrap 61 | {{- end }} 62 | volumes: 63 | - name: grpc-io-proxyless-bootstrap 64 | emptyDir: {} 65 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - files/gen-istio.yaml 6 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | "istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}" successfully installed! 2 | 3 | To learn more about the release, try: 4 | $ helm status {{ .Release.Name }} 5 | $ helm get all {{ .Release.Name }} 6 | 7 | Next steps: 8 | * Deploy a Gateway: https://istio.io/latest/docs/setup/additional-setup/gateway/ 9 | * Try out our tasks to get started on common configurations: 10 | * https://istio.io/latest/docs/tasks/traffic-management 11 | * https://istio.io/latest/docs/tasks/security/ 12 | * https://istio.io/latest/docs/tasks/policy-enforcement/ 13 | * https://istio.io/latest/docs/tasks/policy-enforcement/ 14 | * Review the list of actively supported releases, CVE publications and our hardening guide: 15 | * https://istio.io/latest/docs/releases/supported-releases/ 16 | * https://istio.io/latest/news/security/ 17 | * https://istio.io/latest/docs/ops/best-practices/security/ 18 | 19 | For further documentation see https://istio.io website 20 | 21 | Tell us how your install/upgrade experience went at https://forms.gle/pzWZpAvMVBecaQ9h9 22 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/autoscale.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.pilot.autoscaleEnabled .Values.pilot.autoscaleMin .Values.pilot.autoscaleMax }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app: istiod 9 | release: {{ .Release.Name }} 10 | istio.io/rev: {{ .Values.revision | default "default" }} 11 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 12 | operator.istio.io/component: "Pilot" 13 | spec: 14 | maxReplicas: {{ .Values.pilot.autoscaleMax }} 15 | minReplicas: {{ .Values.pilot.autoscaleMin }} 16 | scaleTargetRef: 17 | apiVersion: apps/v1 18 | kind: Deployment 19 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 20 | metrics: 21 | - type: Resource 22 | resource: 23 | name: cpu 24 | targetAverageUtilization: {{ .Values.pilot.cpu.targetAverageUtilization }} 25 | --- 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | {{ $mcsAPIGroup := or .Values.pilot.env.MCS_API_GROUP "multicluster.x-k8s.io" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: istiod-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 6 | labels: 7 | app: istiod 8 | release: {{ .Release.Name }} 9 | rules: 10 | # sidecar injection controller 11 | - apiGroups: ["admissionregistration.k8s.io"] 12 | resources: ["mutatingwebhookconfigurations"] 13 | verbs: ["get", "list", "watch", "update", "patch"] 14 | 15 | # configuration validation webhook controller 16 | - apiGroups: ["admissionregistration.k8s.io"] 17 | resources: ["validatingwebhookconfigurations"] 18 | verbs: ["get", "list", "watch", "update"] 19 | 20 | # istio configuration 21 | # removing CRD permissions can break older versions of Istio running alongside this control plane (https://github.com/istio/istio/issues/29382) 22 | # please proceed with caution 23 | - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io", "extensions.istio.io"] 24 | verbs: ["get", "watch", "list"] 25 | resources: ["*"] 26 | {{- if .Values.global.istiod.enableAnalysis }} 27 | - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io", "extensions.istio.io"] 28 | verbs: ["update"] 29 | # TODO: should be on just */status but wildcard is not supported 30 | resources: ["*"] 31 | {{- end }} 32 | - apiGroups: ["networking.istio.io"] 33 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 34 | resources: [ "workloadentries" ] 35 | - apiGroups: ["networking.istio.io"] 36 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 37 | resources: [ "workloadentries/status" ] 38 | 39 | # auto-detect installed CRD definitions 40 | - apiGroups: ["apiextensions.k8s.io"] 41 | resources: ["customresourcedefinitions"] 42 | verbs: ["get", "list", "watch"] 43 | 44 | # discovery and routing 45 | - apiGroups: [""] 46 | resources: ["pods", "nodes", "services", "namespaces", "endpoints"] 47 | verbs: ["get", "list", "watch"] 48 | - apiGroups: ["discovery.k8s.io"] 49 | resources: ["endpointslices"] 50 | verbs: ["get", "list", "watch"] 51 | 52 | # ingress controller 53 | {{- if .Values.global.istiod.enableAnalysis }} 54 | - apiGroups: ["extensions", "networking.k8s.io"] 55 | resources: ["ingresses"] 56 | verbs: ["get", "list", "watch"] 57 | - apiGroups: ["extensions", "networking.k8s.io"] 58 | resources: ["ingresses/status"] 59 | verbs: ["*"] 60 | {{- end}} 61 | - apiGroups: ["networking.k8s.io"] 62 | resources: ["ingresses", "ingressclasses"] 63 | verbs: ["get", "list", "watch"] 64 | - apiGroups: ["networking.k8s.io"] 65 | resources: ["ingresses/status"] 66 | verbs: ["*"] 67 | 68 | # required for CA's namespace controller 69 | - apiGroups: [""] 70 | resources: ["configmaps"] 71 | verbs: ["create", "get", "list", "watch", "update"] 72 | 73 | # Istiod and bootstrap. 74 | - apiGroups: ["certificates.k8s.io"] 75 | resources: 76 | - "certificatesigningrequests" 77 | - "certificatesigningrequests/approval" 78 | - "certificatesigningrequests/status" 79 | verbs: ["update", "create", "get", "delete", "watch"] 80 | - apiGroups: ["certificates.k8s.io"] 81 | resources: 82 | - "signers" 83 | resourceNames: 84 | - "kubernetes.io/legacy-unknown" 85 | verbs: ["approve"] 86 | 87 | # Used by Istiod to verify the JWT tokens 88 | - apiGroups: ["authentication.k8s.io"] 89 | resources: ["tokenreviews"] 90 | verbs: ["create"] 91 | 92 | # Used by Istiod to verify gateway SDS 93 | - apiGroups: ["authorization.k8s.io"] 94 | resources: ["subjectaccessreviews"] 95 | verbs: ["create"] 96 | 97 | # Use for Kubernetes Service APIs 98 | - apiGroups: ["networking.x-k8s.io", "gateway.networking.k8s.io"] 99 | resources: ["*"] 100 | verbs: ["get", "watch", "list"] 101 | - apiGroups: ["networking.x-k8s.io", "gateway.networking.k8s.io"] 102 | resources: ["*"] # TODO: should be on just */status but wildcard is not supported 103 | verbs: ["update", "patch"] 104 | 105 | # Needed for multicluster secret reading, possibly ingress certs in the future 106 | - apiGroups: [""] 107 | resources: ["secrets"] 108 | verbs: ["get", "watch", "list"] 109 | 110 | # Used for MCS serviceexport management 111 | - apiGroups: ["{{ $mcsAPIGroup }}"] 112 | resources: ["serviceexports"] 113 | verbs: [ "get", "watch", "list", "create", "delete"] 114 | 115 | # Used for MCS serviceimport management 116 | - apiGroups: ["{{ $mcsAPIGroup }}"] 117 | resources: ["serviceimports"] 118 | verbs: ["get", "watch", "list"] 119 | --- 120 | {{- if not (eq (toString .Values.pilot.env.PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER) "false") }} 121 | apiVersion: rbac.authorization.k8s.io/v1 122 | kind: ClusterRole 123 | metadata: 124 | name: istiod-gateway-controller{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 125 | labels: 126 | app: istiod 127 | release: {{ .Release.Name }} 128 | rules: 129 | - apiGroups: ["apps"] 130 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 131 | resources: [ "deployments" ] 132 | - apiGroups: [""] 133 | verbs: [ "get", "watch", "list", "update", "patch", "create", "delete" ] 134 | resources: [ "services" ] 135 | {{- end }} 136 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: istiod-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 5 | labels: 6 | app: istiod 7 | release: {{ .Release.Name }} 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: istiod-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 12 | subjects: 13 | - kind: ServiceAccount 14 | name: istiod{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }} 15 | namespace: {{ .Values.global.istioNamespace }} 16 | --- 17 | {{- if not (eq (toString .Values.pilot.env.PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER) "false") }} 18 | apiVersion: rbac.authorization.k8s.io/v1 19 | kind: ClusterRoleBinding 20 | metadata: 21 | name: istiod-gateway-controller{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 22 | labels: 23 | app: istiod 24 | release: {{ .Release.Name }} 25 | roleRef: 26 | apiGroup: rbac.authorization.k8s.io 27 | kind: ClusterRole 28 | name: istiod-gateway-controller{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 29 | subjects: 30 | - kind: ServiceAccount 31 | name: istiod{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }} 32 | namespace: {{ .Values.global.istioNamespace }} 33 | {{- end }} -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/configmap-jwks.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.pilot.jwksResolverExtraRootCA }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | release: {{ .Release.Name }} 9 | istio.io/rev: {{ .Values.revision | default "default" }} 10 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 11 | operator.istio.io/component: "Pilot" 12 | data: 13 | extra.pem: {{ .Values.pilot.jwksResolverExtraRootCA | quote }} 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- define "mesh" }} 2 | # The trust domain corresponds to the trust root of a system. 3 | # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain 4 | trustDomain: "cluster.local" 5 | 6 | # The namespace to treat as the administrative root namespace for Istio configuration. 7 | # When processing a leaf namespace Istio will search for declarations in that namespace first 8 | # and if none are found it will search in the root namespace. Any matching declaration found in the root namespace 9 | # is processed as if it were declared in the leaf namespace. 10 | rootNamespace: {{ .Values.meshConfig.rootNamespace | default .Values.global.istioNamespace }} 11 | 12 | defaultConfig: 13 | {{- if .Values.global.meshID }} 14 | meshId: {{ .Values.global.meshID }} 15 | {{- end }} 16 | tracing: 17 | {{- if eq .Values.global.proxy.tracer "lightstep" }} 18 | lightstep: 19 | # Address of the LightStep Satellite pool 20 | address: {{ .Values.global.tracer.lightstep.address }} 21 | # Access Token used to communicate with the Satellite pool 22 | accessToken: {{ .Values.global.tracer.lightstep.accessToken }} 23 | {{- else if eq .Values.global.proxy.tracer "zipkin" }} 24 | zipkin: 25 | # Address of the Zipkin collector 26 | address: {{ .Values.global.tracer.zipkin.address | default (print "zipkin." .Values.global.istioNamespace ":9411") }} 27 | {{- else if eq .Values.global.proxy.tracer "datadog" }} 28 | datadog: 29 | # Address of the Datadog Agent 30 | address: {{ .Values.global.tracer.datadog.address | default "$(HOST_IP):8126" }} 31 | {{- else if eq .Values.global.proxy.tracer "stackdriver" }} 32 | stackdriver: 33 | # enables trace output to stdout. 34 | {{- if $.Values.global.tracer.stackdriver.debug }} 35 | debug: {{ $.Values.global.tracer.stackdriver.debug }} 36 | {{- end }} 37 | {{- if $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} 38 | # The global default max number of attributes per span. 39 | maxNumberOfAttributes: {{ $.Values.global.tracer.stackdriver.maxNumberOfAttributes | default "200" }} 40 | {{- end }} 41 | {{- if $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} 42 | # The global default max number of annotation events per span. 43 | maxNumberOfAnnotations: {{ $.Values.global.tracer.stackdriver.maxNumberOfAnnotations | default "200" }} 44 | {{- end }} 45 | {{- if $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} 46 | # The global default max number of message events per span. 47 | maxNumberOfMessageEvents: {{ $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents | default "200" }} 48 | {{- end }} 49 | {{- else if eq .Values.global.proxy.tracer "openCensusAgent" }} 50 | {{/* Fill in openCensusAgent configuration from meshConfig so it isn't overwritten below */}} 51 | {{ toYaml $.Values.meshConfig.defaultConfig.tracing | indent 8 }} 52 | {{- else }} 53 | {} 54 | {{- end }} 55 | {{- if .Values.global.remotePilotAddress }} 56 | {{- if .Values.pilot.enabled }} 57 | discoveryAddress: {{ printf "istiod-remote.%s.svc" .Release.Namespace }}:15012 58 | {{- else }} 59 | discoveryAddress: {{ printf "istiod.%s.svc" .Release.Namespace }}:15012 60 | {{- end }} 61 | {{- else }} 62 | discoveryAddress: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{.Release.Namespace}}.svc:15012 63 | {{- end }} 64 | {{- end }} 65 | 66 | {{/* We take the mesh config above, defined with individual values.yaml, and merge with .Values.meshConfig */}} 67 | {{/* The intent here is that meshConfig.foo becomes the API, rather than re-inventing the API in values.yaml */}} 68 | {{- $originalMesh := include "mesh" . | fromYaml }} 69 | {{- $mesh := mergeOverwrite $originalMesh .Values.meshConfig }} 70 | 71 | {{- if .Values.pilot.configMap }} 72 | apiVersion: v1 73 | kind: ConfigMap 74 | metadata: 75 | name: istio{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 76 | namespace: {{ .Release.Namespace }} 77 | labels: 78 | istio.io/rev: {{ .Values.revision | default "default" }} 79 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 80 | operator.istio.io/component: "Pilot" 81 | release: {{ .Release.Name }} 82 | data: 83 | 84 | # Configuration file for the mesh networks to be used by the Split Horizon EDS. 85 | meshNetworks: |- 86 | {{- if .Values.global.meshNetworks }} 87 | networks: 88 | {{ toYaml .Values.global.meshNetworks | trim | indent 6 }} 89 | {{- else }} 90 | networks: {} 91 | {{- end }} 92 | 93 | mesh: |- 94 | {{- if .Values.meshConfig }} 95 | {{ $mesh | toYaml | indent 4 }} 96 | {{- else }} 97 | {{- include "mesh" . }} 98 | {{- end }} 99 | --- 100 | {{- end }} 101 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app: istiod 8 | istio.io/rev: {{ .Values.revision | default "default" }} 9 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 10 | operator.istio.io/component: "Pilot" 11 | istio: pilot 12 | release: {{ .Release.Name }} 13 | {{- range $key, $val := .Values.pilot.deploymentLabels }} 14 | {{ $key }}: "{{ $val }}" 15 | {{- end }} 16 | spec: 17 | {{- if not .Values.pilot.autoscaleEnabled }} 18 | {{- if .Values.pilot.replicaCount }} 19 | replicas: {{ .Values.pilot.replicaCount }} 20 | {{- end }} 21 | {{- end }} 22 | strategy: 23 | rollingUpdate: 24 | maxSurge: {{ .Values.pilot.rollingMaxSurge }} 25 | maxUnavailable: {{ .Values.pilot.rollingMaxUnavailable }} 26 | selector: 27 | matchLabels: 28 | {{- if ne .Values.revision "" }} 29 | app: istiod 30 | istio.io/rev: {{ .Values.revision | default "default" }} 31 | {{- else }} 32 | istio: pilot 33 | {{- end }} 34 | template: 35 | metadata: 36 | labels: 37 | app: istiod 38 | istio.io/rev: {{ .Values.revision | default "default" }} 39 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 40 | sidecar.istio.io/inject: "false" 41 | operator.istio.io/component: "Pilot" 42 | {{- if ne .Values.revision "" }} 43 | istio: istiod 44 | {{- else }} 45 | istio: pilot 46 | {{- end }} 47 | {{- range $key, $val := .Values.pilot.podLabels }} 48 | {{ $key }}: "{{ $val }}" 49 | {{- end }} 50 | annotations: 51 | {{- if .Values.meshConfig.enablePrometheusMerge }} 52 | prometheus.io/port: "15014" 53 | prometheus.io/scrape: "true" 54 | {{- end }} 55 | sidecar.istio.io/inject: "false" 56 | {{- if .Values.pilot.podAnnotations }} 57 | {{ toYaml .Values.pilot.podAnnotations | indent 8 }} 58 | {{- end }} 59 | spec: 60 | {{- if .Values.pilot.nodeSelector }} 61 | nodeSelector: 62 | {{ toYaml .Values.pilot.nodeSelector | indent 8 }} 63 | {{- end }} 64 | {{- with .Values.pilot.affinity }} 65 | affinity: 66 | {{- toYaml . | nindent 8 }} 67 | {{- end }} 68 | {{- with .Values.pilot.tolerations }} 69 | tolerations: 70 | {{- toYaml . | nindent 8 }} 71 | {{- end }} 72 | serviceAccountName: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 73 | {{- if .Values.global.priorityClassName }} 74 | priorityClassName: "{{ .Values.global.priorityClassName }}" 75 | {{- end }} 76 | securityContext: 77 | fsGroup: 1337 78 | containers: 79 | - name: discovery 80 | {{- if contains "/" .Values.pilot.image }} 81 | image: "{{ .Values.pilot.image }}" 82 | {{- else }} 83 | image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Values.global.tag }}" 84 | {{- end }} 85 | {{- if .Values.global.imagePullPolicy }} 86 | imagePullPolicy: {{ .Values.global.imagePullPolicy }} 87 | {{- end }} 88 | args: 89 | - "discovery" 90 | - --monitoringAddr=:15014 91 | {{- if .Values.global.logging.level }} 92 | - --log_output_level={{ .Values.global.logging.level }} 93 | {{- end}} 94 | {{- if .Values.global.logAsJson }} 95 | - --log_as_json 96 | {{- end }} 97 | - --domain 98 | - {{ .Values.global.proxy.clusterDomain }} 99 | {{- if .Values.global.oneNamespace }} 100 | - "-a" 101 | - {{ .Release.Namespace }} 102 | {{- end }} 103 | {{- if .Values.pilot.plugins }} 104 | - --plugins={{ .Values.pilot.plugins }} 105 | {{- end }} 106 | - --keepaliveMaxServerConnectionAge 107 | - "{{ .Values.pilot.keepaliveMaxServerConnectionAge }}" 108 | ports: 109 | - containerPort: 8080 110 | protocol: TCP 111 | - containerPort: 15010 112 | protocol: TCP 113 | - containerPort: 15017 114 | protocol: TCP 115 | readinessProbe: 116 | httpGet: 117 | path: /ready 118 | port: 8080 119 | initialDelaySeconds: 1 120 | periodSeconds: 3 121 | timeoutSeconds: 5 122 | env: 123 | - name: REVISION 124 | value: "{{ .Values.revision | default `default` }}" 125 | - name: JWT_POLICY 126 | value: {{ .Values.global.jwtPolicy }} 127 | - name: PILOT_CERT_PROVIDER 128 | value: {{ .Values.global.pilotCertProvider }} 129 | - name: POD_NAME 130 | valueFrom: 131 | fieldRef: 132 | apiVersion: v1 133 | fieldPath: metadata.name 134 | - name: POD_NAMESPACE 135 | valueFrom: 136 | fieldRef: 137 | apiVersion: v1 138 | fieldPath: metadata.namespace 139 | - name: SERVICE_ACCOUNT 140 | valueFrom: 141 | fieldRef: 142 | apiVersion: v1 143 | fieldPath: spec.serviceAccountName 144 | - name: KUBECONFIG 145 | value: /var/run/secrets/remote/config 146 | {{- if .Values.pilot.env }} 147 | {{- range $key, $val := .Values.pilot.env }} 148 | - name: {{ $key }} 149 | value: "{{ $val }}" 150 | {{- end }} 151 | {{- end }} 152 | {{- if .Values.pilot.traceSampling }} 153 | - name: PILOT_TRACE_SAMPLING 154 | value: "{{ .Values.pilot.traceSampling }}" 155 | {{- end }} 156 | - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND 157 | value: "{{ .Values.pilot.enableProtocolSniffingForOutbound }}" 158 | - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND 159 | value: "{{ .Values.pilot.enableProtocolSniffingForInbound }}" 160 | - name: ISTIOD_ADDR 161 | value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Release.Namespace }}.svc:15012 162 | - name: PILOT_ENABLE_ANALYSIS 163 | value: "{{ .Values.global.istiod.enableAnalysis }}" 164 | - name: CLUSTER_ID 165 | value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}" 166 | resources: 167 | {{- if .Values.pilot.resources }} 168 | {{ toYaml .Values.pilot.resources | trim | indent 12 }} 169 | {{- else }} 170 | {{ toYaml .Values.global.defaultResources | trim | indent 12 }} 171 | {{- end }} 172 | securityContext: 173 | allowPrivilegeEscalation: false 174 | readOnlyRootFilesystem: true 175 | runAsUser: 1337 176 | runAsGroup: 1337 177 | runAsNonRoot: true 178 | capabilities: 179 | drop: 180 | - ALL 181 | volumeMounts: 182 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 183 | - name: istio-token 184 | mountPath: /var/run/secrets/tokens 185 | readOnly: true 186 | {{- end }} 187 | - name: local-certs 188 | mountPath: /var/run/secrets/istio-dns 189 | - name: cacerts 190 | mountPath: /etc/cacerts 191 | readOnly: true 192 | - name: istio-kubeconfig 193 | mountPath: /var/run/secrets/remote 194 | readOnly: true 195 | {{- if .Values.pilot.jwksResolverExtraRootCA }} 196 | - name: extracacerts 197 | mountPath: /cacerts 198 | {{- end }} 199 | volumes: 200 | # Technically not needed on this pod - but it helps debugging/testing SDS 201 | # Should be removed after everything works. 202 | - emptyDir: 203 | medium: Memory 204 | name: local-certs 205 | {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} 206 | - name: istio-token 207 | projected: 208 | sources: 209 | - serviceAccountToken: 210 | audience: {{ .Values.global.sds.token.aud }} 211 | expirationSeconds: 43200 212 | path: istio-token 213 | {{- end }} 214 | # Optional: user-generated root 215 | - name: cacerts 216 | secret: 217 | secretName: cacerts 218 | optional: true 219 | - name: istio-kubeconfig 220 | secret: 221 | secretName: istio-kubeconfig 222 | optional: true 223 | {{- if .Values.pilot.jwksResolverExtraRootCA }} 224 | - name: extracacerts 225 | configMap: 226 | name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 227 | {{- end }} 228 | --- 229 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/istiod-injector-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if not .Values.global.omitSidecarInjectorConfigMap }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | istio.io/rev: {{ .Values.revision | default "default" }} 9 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 10 | operator.istio.io/component: "Pilot" 11 | release: {{ .Release.Name }} 12 | data: 13 | {{/* Scope the values to just top level fields used in the template, to reduce the size. */}} 14 | values: |- 15 | {{ pick .Values "global" "istio_cni" "sidecarInjectorWebhook" "revision" | toPrettyJson | indent 4 }} 16 | 17 | # To disable injection: use omitSidecarInjectorConfigMap, which disables the webhook patching 18 | # and istiod webhook functionality. 19 | # 20 | # New fields should not use Values - it is a 'primary' config object, users should be able 21 | # to fine tune it or use it with kube-inject. 22 | config: |- 23 | # defaultTemplates defines the default template to use for pods that do not explicitly specify a template 24 | {{- if .Values.sidecarInjectorWebhook.defaultTemplates }} 25 | defaultTemplates: 26 | {{- range .Values.sidecarInjectorWebhook.defaultTemplates}} 27 | - {{ . }} 28 | {{- end }} 29 | {{- else }} 30 | defaultTemplates: [sidecar] 31 | {{- end }} 32 | policy: {{ .Values.global.proxy.autoInject }} 33 | alwaysInjectSelector: 34 | {{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | trim | indent 6 }} 35 | neverInjectSelector: 36 | {{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | trim | indent 6 }} 37 | injectedAnnotations: 38 | {{- range $key, $val := .Values.sidecarInjectorWebhook.injectedAnnotations }} 39 | "{{ $key }}": "{{ $val }}" 40 | {{- end }} 41 | {{- /* If someone ends up with this new template, but an older Istiod image, they will attempt to render this template 42 | which will fail with "Pod injection failed: template: inject:1: function "Istio_1_9_Required_Template_And_Version_Mismatched" not defined". 43 | This should make it obvious that their installation is broken. 44 | */}} 45 | template: {{ `{{ Template_Version_And_Istio_Version_Mismatched_Check_Installation }}` | quote }} 46 | templates: 47 | {{- if not (hasKey .Values.sidecarInjectorWebhook.templates "sidecar") }} 48 | sidecar: | 49 | {{ .Files.Get "files/injection-template.yaml" | trim | indent 8 }} 50 | {{- end }} 51 | {{- if not (hasKey .Values.sidecarInjectorWebhook.templates "gateway") }} 52 | gateway: | 53 | {{ .Files.Get "files/gateway-injection-template.yaml" | trim | indent 8 }} 54 | {{- end }} 55 | {{- if not (hasKey .Values.sidecarInjectorWebhook.templates "grpc-simple") }} 56 | grpc-simple: | 57 | {{ .Files.Get "files/grpc-simple.yaml" | trim | indent 8 }} 58 | {{- end }} 59 | {{- if not (hasKey .Values.sidecarInjectorWebhook.templates "grpc-agent") }} 60 | grpc-agent: | 61 | {{ .Files.Get "files/grpc-agent.yaml" | trim | indent 8 }} 62 | {{- end }} 63 | {{- with .Values.sidecarInjectorWebhook.templates }} 64 | {{ toYaml . | trim | indent 6 }} 65 | {{- end }} 66 | 67 | {{- end }} 68 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/mutatingwebhook.yaml: -------------------------------------------------------------------------------- 1 | {{- /* Core defines the common configuration used by all webhook segments */}} 2 | {{- define "core" }} 3 | {{- /* Kubernetes unfortunately requires a unique name for the webhook in some newer versions, so we assign 4 | a unique prefix to each. */}} 5 | - name: {{.Prefix}}sidecar-injector.istio.io 6 | clientConfig: 7 | {{- if .Values.istiodRemote.injectionURL }} 8 | url: "{{ .Values.istiodRemote.injectionURL }}" 9 | {{- else }} 10 | service: 11 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 12 | namespace: {{ .Release.Namespace }} 13 | path: "{{ .Values.istiodRemote.injectionPath }}" 14 | port: 443 15 | {{- end }} 16 | caBundle: "" 17 | sideEffects: None 18 | rules: 19 | - operations: [ "CREATE" ] 20 | apiGroups: [""] 21 | apiVersions: ["v1"] 22 | resources: ["pods"] 23 | failurePolicy: Fail 24 | admissionReviewVersions: ["v1beta1", "v1"] 25 | {{- end }} 26 | {{- /* Installed for each revision - not installed for cluster resources ( cluster roles, bindings, crds) */}} 27 | {{- if not .Values.global.operatorManageWebhooks }} 28 | apiVersion: admissionregistration.k8s.io/v1 29 | kind: MutatingWebhookConfiguration 30 | metadata: 31 | {{- if eq .Release.Namespace "istio-system"}} 32 | name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 33 | {{- else }} 34 | name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 35 | {{- end }} 36 | labels: 37 | istio.io/rev: {{ .Values.revision | default "default" }} 38 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 39 | operator.istio.io/component: "Pilot" 40 | app: sidecar-injector 41 | release: {{ .Release.Name }} 42 | webhooks: 43 | {{- /* Set up the selectors. First section is for revision, rest is for "default" revision */}} 44 | 45 | {{- /* Case 1: namespace selector matches, and object doesn't disable */}} 46 | {{- /* Note: if both revision and legacy selector, we give precedence to the legacy one */}} 47 | {{- include "core" (mergeOverwrite (deepCopy .) (dict "Prefix" "rev.namespace.") ) }} 48 | namespaceSelector: 49 | matchExpressions: 50 | - key: istio.io/rev 51 | operator: In 52 | values: 53 | {{- if (eq .Values.revision "") }} 54 | - "default" 55 | {{- else }} 56 | - "{{ .Values.revision }}" 57 | {{- end }} 58 | - key: istio-injection 59 | operator: DoesNotExist 60 | objectSelector: 61 | matchExpressions: 62 | - key: sidecar.istio.io/inject 63 | operator: NotIn 64 | values: 65 | - "false" 66 | 67 | {{- /* Case 2: No namespace selector, but object selects our revision (and doesn't disable) */}} 68 | {{- include "core" (mergeOverwrite (deepCopy .) (dict "Prefix" "rev.object.") ) }} 69 | namespaceSelector: 70 | matchExpressions: 71 | - key: istio.io/rev 72 | operator: DoesNotExist 73 | - key: istio-injection 74 | operator: DoesNotExist 75 | objectSelector: 76 | matchExpressions: 77 | - key: sidecar.istio.io/inject 78 | operator: NotIn 79 | values: 80 | - "false" 81 | - key: istio.io/rev 82 | operator: In 83 | values: 84 | {{- if (eq .Values.revision "") }} 85 | - "default" 86 | {{- else }} 87 | - "{{ .Values.revision }}" 88 | {{- end }} 89 | 90 | 91 | {{- /* Webhooks for default revision */}} 92 | {{- if (eq .Values.revision "") }} 93 | 94 | {{- /* Case 1: Namespace selector enabled, and object selector is not injected */}} 95 | {{- include "core" (mergeOverwrite (deepCopy .) (dict "Prefix" "namespace.") ) }} 96 | namespaceSelector: 97 | matchExpressions: 98 | - key: istio-injection 99 | operator: In 100 | values: 101 | - enabled 102 | objectSelector: 103 | matchExpressions: 104 | - key: sidecar.istio.io/inject 105 | operator: NotIn 106 | values: 107 | - "false" 108 | 109 | {{- /* Case 2: no namespace label, but object selector is enabled (and revision label is not, which has priority) */}} 110 | {{- include "core" (mergeOverwrite (deepCopy .) (dict "Prefix" "object.") ) }} 111 | namespaceSelector: 112 | matchExpressions: 113 | - key: istio-injection 114 | operator: DoesNotExist 115 | - key: istio.io/rev 116 | operator: DoesNotExist 117 | objectSelector: 118 | matchExpressions: 119 | - key: sidecar.istio.io/inject 120 | operator: In 121 | values: 122 | - "true" 123 | - key: istio.io/rev 124 | operator: DoesNotExist 125 | 126 | {{- if .Values.sidecarInjectorWebhook.enableNamespacesByDefault }} 127 | {{- /* Special case 3: no labels at all */}} 128 | {{- include "core" (mergeOverwrite (deepCopy .) (dict "Prefix" "auto.") ) }} 129 | namespaceSelector: 130 | matchExpressions: 131 | - key: istio-injection 132 | operator: DoesNotExist 133 | - key: istio.io/rev 134 | operator: DoesNotExist 135 | objectSelector: 136 | matchExpressions: 137 | - key: sidecar.istio.io/inject 138 | operator: DoesNotExist 139 | - key: istio.io/rev 140 | operator: DoesNotExist 141 | {{- end }} 142 | 143 | {{- end }} 144 | {{- end }} 145 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/poddisruptionbudget.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.defaultPodDisruptionBudget.enabled }} 2 | apiVersion: policy/v1beta1 3 | kind: PodDisruptionBudget 4 | metadata: 5 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app: istiod 9 | istio.io/rev: {{ .Values.revision | default "default" }} 10 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 11 | operator.istio.io/component: "Pilot" 12 | release: {{ .Release.Name }} 13 | istio: pilot 14 | spec: 15 | minAvailable: 1 16 | selector: 17 | matchLabels: 18 | app: istiod 19 | {{- if ne .Values.revision "" }} 20 | istio.io/rev: {{ .Values.revision }} 21 | {{- else }} 22 | istio: pilot 23 | {{- end }} 24 | --- 25 | {{- end }} 26 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/reader-clusterrole.yaml: -------------------------------------------------------------------------------- 1 | {{ $mcsAPIGroup := or .Values.pilot.env.MCS_API_GROUP "multicluster.x-k8s.io" }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: istio-reader-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 6 | labels: 7 | app: istio-reader 8 | release: {{ .Release.Name }} 9 | rules: 10 | - apiGroups: 11 | - "config.istio.io" 12 | - "security.istio.io" 13 | - "networking.istio.io" 14 | - "authentication.istio.io" 15 | - "rbac.istio.io" 16 | resources: ["*"] 17 | verbs: ["get", "list", "watch"] 18 | - apiGroups: [""] 19 | resources: ["endpoints", "pods", "services", "nodes", "replicationcontrollers", "namespaces", "secrets"] 20 | verbs: ["get", "list", "watch"] 21 | - apiGroups: ["networking.istio.io"] 22 | verbs: [ "get", "watch", "list" ] 23 | resources: [ "workloadentries" ] 24 | - apiGroups: ["apiextensions.k8s.io"] 25 | resources: ["customresourcedefinitions"] 26 | verbs: ["get", "list", "watch"] 27 | - apiGroups: ["discovery.k8s.io"] 28 | resources: ["endpointslices"] 29 | verbs: ["get", "list", "watch"] 30 | - apiGroups: ["{{ $mcsAPIGroup }}"] 31 | resources: ["serviceexports"] 32 | verbs: ["get", "list", "watch", "create", "delete"] 33 | - apiGroups: ["{{ $mcsAPIGroup }}"] 34 | resources: ["serviceimports"] 35 | verbs: ["get", "list", "watch"] 36 | - apiGroups: ["apps"] 37 | resources: ["replicasets"] 38 | verbs: ["get", "list", "watch"] 39 | - apiGroups: ["authentication.k8s.io"] 40 | resources: ["tokenreviews"] 41 | verbs: ["create"] 42 | - apiGroups: ["authorization.k8s.io"] 43 | resources: ["subjectaccessreviews"] 44 | verbs: ["create"] 45 | {{- if .Values.global.externalIstiod }} 46 | - apiGroups: [""] 47 | resources: ["configmaps"] 48 | verbs: ["create", "get", "list", "watch", "update"] 49 | - apiGroups: ["admissionregistration.k8s.io"] 50 | resources: ["mutatingwebhookconfigurations"] 51 | verbs: ["get", "list", "watch", "update", "patch"] 52 | - apiGroups: ["admissionregistration.k8s.io"] 53 | resources: ["validatingwebhookconfigurations"] 54 | verbs: ["get", "list", "watch", "update"] 55 | {{- end}} 56 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/reader-clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: istio-reader-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 5 | labels: 6 | app: istio-reader 7 | release: {{ .Release.Name }} 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: istio-reader-clusterrole{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} 12 | subjects: 13 | - kind: ServiceAccount 14 | name: istio-reader-service-account 15 | namespace: {{ .Values.global.istioNamespace }} 16 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/revision-tags.yaml: -------------------------------------------------------------------------------- 1 | # Adapted from istio-discovery/templates/mutatingwebhook.yaml 2 | # Removed paths for legacy and default selectors since a revision tag 3 | # is inherently created from a specific revision 4 | {{- define "core" }} 5 | - name: {{.Prefix}}sidecar-injector.istio.io 6 | clientConfig: 7 | {{- if .Values.istiodRemote.injectionURL }} 8 | url: "{{ .Values.istiodRemote.injectionURL }}" 9 | {{- else }} 10 | service: 11 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 12 | namespace: {{ .Release.Namespace }} 13 | path: "{{ .Values.istiodRemote.injectionPath }}" 14 | {{- end }} 15 | caBundle: "" 16 | sideEffects: None 17 | rules: 18 | - operations: [ "CREATE" ] 19 | apiGroups: [""] 20 | apiVersions: ["v1"] 21 | resources: ["pods"] 22 | failurePolicy: Fail 23 | admissionReviewVersions: ["v1beta1", "v1"] 24 | {{- end }} 25 | 26 | {{- range $tagName := $.Values.revisionTags }} 27 | apiVersion: admissionregistration.k8s.io/v1 28 | kind: MutatingWebhookConfiguration 29 | metadata: 30 | {{- if eq $.Release.Namespace "istio-system"}} 31 | name: istio-revision-tag-{{ $tagName }} 32 | {{- else }} 33 | name: istio-revision-tag-{{ $tagName }}-{{ $.Release.Namespace }} 34 | {{- end }} 35 | labels: 36 | istio.io/tag: {{ $tagName }} 37 | istio.io/rev: {{ $.Values.revision | default "default" }} 38 | install.operator.istio.io/owning-resource: {{ $.Values.ownerName | default "unknown" }} 39 | operator.istio.io/component: "Pilot" 40 | app: sidecar-injector 41 | release: {{ $.Release.Name }} 42 | webhooks: 43 | {{- include "core" (mergeOverwrite (deepCopy $) (dict "Prefix" "rev.namespace.") ) }} 44 | namespaceSelector: 45 | matchExpressions: 46 | - key: istio.io/rev 47 | operator: In 48 | values: 49 | - "{{ $tagName }}" 50 | - key: istio-injection 51 | operator: DoesNotExist 52 | objectSelector: 53 | matchExpressions: 54 | - key: sidecar.istio.io/inject 55 | operator: NotIn 56 | values: 57 | - "false" 58 | {{- include "core" (mergeOverwrite (deepCopy $) (dict "Prefix" "rev.object.") ) }} 59 | namespaceSelector: 60 | matchExpressions: 61 | - key: istio.io/rev 62 | operator: DoesNotExist 63 | - key: istio-injection 64 | operator: DoesNotExist 65 | objectSelector: 66 | matchExpressions: 67 | - key: sidecar.istio.io/inject 68 | operator: NotIn 69 | values: 70 | - "false" 71 | - key: istio.io/rev 72 | operator: In 73 | values: 74 | - "{{ $tagName }}" 75 | 76 | {{- /* When the tag is "default" we want to create webhooks for the default revision */}} 77 | {{- /* These webhooks should be kept in sync with istio-discovery/templates/mutatingwebhook.yaml */}} 78 | {{- if (eq $tagName "default") }} 79 | 80 | {{- /* Case 1: Namespace selector enabled, and object selector is not injected */}} 81 | {{- include "core" (mergeOverwrite (deepCopy $) (dict "Prefix" "namespace.") ) }} 82 | namespaceSelector: 83 | matchExpressions: 84 | - key: istio-injection 85 | operator: In 86 | values: 87 | - enabled 88 | objectSelector: 89 | matchExpressions: 90 | - key: sidecar.istio.io/inject 91 | operator: NotIn 92 | values: 93 | - "false" 94 | 95 | {{- /* Case 2: no namespace label, but object selector is enabled (and revision label is not, which has priority) */}} 96 | {{- include "core" (mergeOverwrite (deepCopy $) (dict "Prefix" "object.") ) }} 97 | namespaceSelector: 98 | matchExpressions: 99 | - key: istio-injection 100 | operator: DoesNotExist 101 | - key: istio.io/rev 102 | operator: DoesNotExist 103 | objectSelector: 104 | matchExpressions: 105 | - key: sidecar.istio.io/inject 106 | operator: In 107 | values: 108 | - "true" 109 | - key: istio.io/rev 110 | operator: DoesNotExist 111 | 112 | {{- if $.Values.sidecarInjectorWebhook.enableNamespacesByDefault }} 113 | {{- /* Special case 3: no labels at all */}} 114 | {{- include "core" (mergeOverwrite (deepCopy $) (dict "Prefix" "auto.") ) }} 115 | namespaceSelector: 116 | matchExpressions: 117 | - key: istio-injection 118 | operator: DoesNotExist 119 | - key: istio.io/rev 120 | operator: DoesNotExist 121 | objectSelector: 122 | matchExpressions: 123 | - key: sidecar.istio.io/inject 124 | operator: DoesNotExist 125 | - key: istio.io/rev 126 | operator: DoesNotExist 127 | {{- end }} 128 | 129 | {{- end }} 130 | {{- end }} 131 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: istiod{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }} 5 | namespace: {{ .Values.global.istioNamespace }} 6 | labels: 7 | app: istiod 8 | release: {{ .Release.Name }} 9 | rules: 10 | # permissions to verify the webhook is ready and rejecting 11 | # invalid config. We use --server-dry-run so no config is persisted. 12 | - apiGroups: ["networking.istio.io"] 13 | verbs: ["create"] 14 | resources: ["gateways"] 15 | 16 | # For storing CA secret 17 | - apiGroups: [""] 18 | resources: ["secrets"] 19 | # TODO lock this down to istio-ca-cert if not using the DNS cert mesh config 20 | verbs: ["create", "get", "watch", "list", "update", "delete"] 21 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: istiod{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }} 5 | namespace: {{ .Values.global.istioNamespace }} 6 | labels: 7 | app: istiod 8 | release: {{ .Release.Name }} 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: Role 12 | name: istiod{{- if not (eq .Values.revision "")}}-{{ .Values.revision }}{{- end }} 13 | subjects: 14 | - kind: ServiceAccount 15 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 16 | namespace: {{ .Values.global.istioNamespace }} 17 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 5 | namespace: {{ .Release.Namespace }} 6 | {{- if .Values.pilot.serviceAnnotations }} 7 | annotations: 8 | {{ toYaml .Values.pilot.serviceAnnotations | indent 4 }} 9 | {{- end }} 10 | labels: 11 | istio.io/rev: {{ .Values.revision | default "default" }} 12 | install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }} 13 | operator.istio.io/component: "Pilot" 14 | app: istiod 15 | istio: pilot 16 | release: {{ .Release.Name }} 17 | spec: 18 | ports: 19 | - port: 15010 20 | name: grpc-xds # plaintext 21 | protocol: TCP 22 | - port: 15012 23 | name: https-dns # mTLS with k8s-signed cert 24 | protocol: TCP 25 | - port: 443 26 | name: https-webhook # validation and injection 27 | targetPort: 15017 28 | protocol: TCP 29 | - port: 15014 30 | name: http-monitoring # prometheus stats 31 | protocol: TCP 32 | selector: 33 | app: istiod 34 | {{- if ne .Values.revision "" }} 35 | istio.io/rev: {{ .Values.revision }} 36 | {{- else }} 37 | # Label used by the 'default' service. For versioned deployments we match with app and version. 38 | # This avoids default deployment picking the canary 39 | istio: pilot 40 | {{- end }} 41 | --- 42 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | {{- if .Values.global.imagePullSecrets }} 4 | imagePullSecrets: 5 | {{- range .Values.global.imagePullSecrets }} 6 | - name: {{ . }} 7 | {{- end }} 8 | {{- end }} 9 | metadata: 10 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 11 | namespace: {{ .Values.global.istioNamespace }} 12 | labels: 13 | app: istiod 14 | release: {{ .Release.Name }} 15 | --- 16 | -------------------------------------------------------------------------------- /manifests/charts/istio-discovery/templates/validatingwebhookconfiguration.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.configValidation }} 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | name: istio-validator{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Values.global.istioNamespace }} 6 | labels: 7 | app: istiod 8 | release: {{ .Release.Name }} 9 | istio: istiod 10 | istio.io/rev: {{ .Values.revision | default "default" }} 11 | webhooks: 12 | # Webhook handling per-revision validation. Mostly here so we can determine whether webhooks 13 | # are rejecting invalid configs on a per-revision basis. 14 | - name: rev.validation.istio.io 15 | clientConfig: 16 | # Should change from base but cannot for API compat 17 | {{- if .Values.base.validationURL }} 18 | url: {{ .Values.base.validationURL }} 19 | {{- else }} 20 | service: 21 | name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} 22 | namespace: {{ .Values.global.istioNamespace }} 23 | path: "/validate" 24 | {{- end }} 25 | caBundle: "" # patched at runtime when the webhook is ready. 26 | rules: 27 | - operations: 28 | - CREATE 29 | - UPDATE 30 | apiGroups: 31 | - security.istio.io 32 | - networking.istio.io 33 | - telemetry.istio.io 34 | - extensions.istio.io 35 | apiVersions: 36 | - "*" 37 | resources: 38 | - "*" 39 | # Fail open until the validation webhook is ready. The webhook controller 40 | # will update this to `Fail` and patch in the `caBundle` when the webhook 41 | # endpoint is ready. 42 | failurePolicy: Ignore 43 | sideEffects: None 44 | admissionReviewVersions: ["v1beta1", "v1"] 45 | objectSelector: 46 | matchExpressions: 47 | - key: istio.io/rev 48 | operator: In 49 | values: 50 | {{- if (eq .Values.revision "") }} 51 | - "default" 52 | {{- else }} 53 | - "{{ .Values.revision }}" 54 | {{- end }} 55 | --- 56 | {{- end }} 57 | -------------------------------------------------------------------------------- /pkg/controller/controller.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package controller 16 | 17 | import ( 18 | "cannalcontroller/pkg/coredns" 19 | "cannalcontroller/pkg/tools" 20 | "context" 21 | "fmt" 22 | "github.com/golang/glog" 23 | "istio.io/client-go/pkg/apis/networking/v1alpha3" 24 | versionedclient "istio.io/client-go/pkg/clientset/versioned" 25 | netinformer "istio.io/client-go/pkg/informers/externalversions/networking/v1alpha3" 26 | lister "istio.io/client-go/pkg/listers/networking/v1alpha3" 27 | "k8s.io/apimachinery/pkg/api/errors" 28 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | "k8s.io/apimachinery/pkg/labels" 30 | "k8s.io/apimachinery/pkg/util/runtime" 31 | "k8s.io/apimachinery/pkg/util/wait" 32 | "k8s.io/client-go/kubernetes" 33 | "k8s.io/client-go/tools/cache" 34 | "k8s.io/client-go/util/workqueue" 35 | "time" 36 | ) 37 | 38 | var ( 39 | rewritePrefix = "rewrite name " 40 | rewriteSuffix = ".svc.cluster.local" 41 | ) 42 | 43 | type Controller struct { 44 | kubeclientset kubernetes.Interface 45 | vsclientset versionedclient.Interface 46 | workqueue workqueue.RateLimitingInterface 47 | virtualserviceLister lister.VirtualServiceLister 48 | virtualserviceSynced cache.InformerSynced 49 | gatewayLister lister.GatewayLister 50 | gatewaySynced cache.InformerSynced 51 | canalServiceName string 52 | canalNamespace string 53 | gatewayName string 54 | } 55 | 56 | type OperationType uint8 57 | 58 | const ( 59 | Update OperationType = 0 60 | Add OperationType = 1 61 | Delete OperationType = 2 62 | ) 63 | 64 | type ItemValue struct { 65 | key string 66 | operationType OperationType 67 | value *v1alpha3.VirtualService 68 | oldValue *v1alpha3.VirtualService 69 | } 70 | 71 | func (c *Controller) enqueueVSForDelete(obj interface{}) { 72 | deleteObj := obj.(*v1alpha3.VirtualService) 73 | glog.Info(deleteObj) 74 | var key string 75 | var err error 76 | key, err = cache.DeletionHandlingMetaNamespaceKeyFunc(obj) 77 | if err != nil { 78 | runtime.HandleError(err) 79 | return 80 | } 81 | c.workqueue.AddRateLimited(ItemValue{key: key, value: deleteObj, operationType: Delete}) 82 | } 83 | 84 | func (c *Controller) enqueueVSForAdd(obj interface{}) { 85 | addObj := obj.(*v1alpha3.VirtualService) 86 | var key string 87 | var err error 88 | if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil { 89 | runtime.HandleError(err) 90 | return 91 | } 92 | c.workqueue.AddRateLimited(ItemValue{key: key, value: addObj, operationType: Add}) 93 | } 94 | 95 | func (c *Controller) enqueueVSForUpdate(old interface{}, new interface{}) { 96 | oldObj := old.(*v1alpha3.VirtualService) 97 | newObj := new.(*v1alpha3.VirtualService) 98 | var key string 99 | var err error 100 | if key, err = cache.MetaNamespaceKeyFunc(newObj); err != nil { 101 | runtime.HandleError(err) 102 | return 103 | } 104 | c.workqueue.AddRateLimited(ItemValue{key: key, value: newObj, oldValue: oldObj, operationType: Update}) 105 | } 106 | 107 | func NewController(virtualServiceInformer netinformer.VirtualServiceInformer, gatewayInformer netinformer.GatewayInformer, kubeclientset kubernetes.Interface, 108 | vsclientset versionedclient.Interface) *Controller { 109 | controller := &Controller{ 110 | kubeclientset: kubeclientset, 111 | vsclientset: vsclientset, 112 | virtualserviceLister: virtualServiceInformer.Lister(), 113 | workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Networks"), 114 | virtualserviceSynced: virtualServiceInformer.Informer().HasSynced, 115 | gatewayLister: gatewayInformer.Lister(), 116 | gatewaySynced: gatewayInformer.Informer().HasSynced, 117 | canalNamespace: "istio-system", 118 | canalServiceName: "canal", 119 | } 120 | 121 | glog.Info("Setting up event handlers") 122 | virtualServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ 123 | AddFunc: controller.enqueueVSForAdd, 124 | UpdateFunc: func(old, new interface{}) { 125 | oldVS := old.(*v1alpha3.VirtualService) 126 | newVS := new.(*v1alpha3.VirtualService) 127 | if oldVS.ResourceVersion == newVS.ResourceVersion { 128 | return 129 | } 130 | controller.enqueueVSForUpdate(old, new) 131 | }, 132 | DeleteFunc: controller.enqueueVSForDelete, 133 | }) 134 | return controller 135 | } 136 | 137 | func (c *Controller) processNextWorkItem() bool { 138 | obj, shutdown := c.workqueue.Get() 139 | 140 | if shutdown { 141 | return false 142 | } 143 | err := func(obj interface{}) error { 144 | defer c.workqueue.Done(obj) 145 | var item ItemValue 146 | var ok bool 147 | if item, ok = obj.(ItemValue); !ok { 148 | // As the item in the workqueue is actually invalid, we call 149 | // Forget here else we'd go into a loop of attempting to 150 | // process a work item that is invalid. 151 | c.workqueue.Forget(obj) 152 | runtime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj)) 153 | return nil 154 | } 155 | if err := c.syncHandler(item); err != nil { 156 | return fmt.Errorf("error syncing '%s': %s", item.key, err.Error()) 157 | } 158 | c.workqueue.Forget(obj) 159 | glog.Infof("Successfully synced '%s'", item.key) 160 | return nil 161 | }(obj) 162 | 163 | if err != nil { 164 | runtime.HandleError(err) 165 | return true 166 | } 167 | 168 | return true 169 | } 170 | 171 | func (c *Controller) runWorker() { 172 | for c.processNextWorkItem() { 173 | } 174 | } 175 | 176 | func (c *Controller) findCanalGateWay() string { 177 | glog.Info("start find and verify gateway") 178 | gateways, err := c.gatewayLister.List(labels.NewSelector()) 179 | if err != nil { 180 | panic(err.Error()) 181 | } 182 | glog.Infof("V1alpha3 gateways num is %d", len(gateways)) 183 | if len(gateways) > 1 { 184 | panic("gateways num is not 1") 185 | } 186 | 187 | if gateways[0].Spec.Selector["app"] != "canal-gateway" || gateways[0].Namespace != "istio-system" { 188 | panic("gateways not belong to Canal") 189 | } 190 | glog.Info("gatewayName is ", gateways[0].Name) 191 | return gateways[0].Name 192 | } 193 | 194 | func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { 195 | defer runtime.HandleCrash() 196 | defer c.workqueue.ShutDown() 197 | 198 | // Start the informer factories to begin populating the informer caches 199 | glog.Info("Starting Canal control loop") 200 | 201 | // Wait for the caches to be synced before starting workers 202 | glog.Info("Waiting for informer caches to sync") 203 | if ok := cache.WaitForCacheSync(stopCh, c.virtualserviceSynced, c.gatewaySynced); !ok { 204 | return fmt.Errorf("failed to wait for caches to sync") 205 | } 206 | 207 | c.gatewayName = c.findCanalGateWay() 208 | 209 | glog.Infof("CanalServiceName: %s, CanalNamespace: %s, GatewayName: %s", c.canalServiceName, c.canalNamespace, c.gatewayName) 210 | 211 | glog.Info("Starting workers") 212 | // Launch two workers to process Network resources 213 | for i := 0; i < threadiness; i++ { 214 | go wait.Until(c.runWorker, time.Second, stopCh) 215 | } 216 | 217 | glog.Info("Started workers") 218 | <-stopCh 219 | glog.Info("Shutting down workers") 220 | 221 | return nil 222 | } 223 | 224 | func (c *Controller) syncHandler(item ItemValue) error { 225 | namespace, name, err := cache.SplitMetaNamespaceKey(item.key) 226 | if err != nil { 227 | runtime.HandleError(fmt.Errorf("invalid resource key: %s", item.key)) 228 | return nil 229 | } 230 | vs, err := c.virtualserviceLister.VirtualServices(namespace).Get(name) 231 | switch item.operationType { 232 | case Add: 233 | glog.Infof("[CoreDnsMap] Try to add VirtualService: %#v ...", vs) 234 | if err != nil { 235 | glog.Errorf("%s is err", err) 236 | return nil 237 | } 238 | c.addVirtualService(vs) 239 | case Update: 240 | glog.Infof("[CoreDnsMap] Try to update VirtualService: %#v ...", vs) 241 | if err != nil { 242 | glog.Errorf("%s is err", err) 243 | return nil 244 | } 245 | if item.oldValue == nil || item.value == nil { 246 | glog.Errorf("update %s is nil", item.key) 247 | return nil 248 | } 249 | glog.Info("first delete old vs") 250 | c.deleteVirtualService(item.oldValue) 251 | glog.Info("second add new vs") 252 | c.addVirtualService(item.value) 253 | case Delete: 254 | glog.Infof("[CoreDnsMap] Try to delete VirtualService: %#v ...", vs) 255 | if err != nil { 256 | if errors.IsNotFound(err) { 257 | glog.Warningf("VirtualService: %s/%s does not exist in local cache, will delete it from CoreDnsMap ...", 258 | namespace, name) 259 | if item.value == nil { 260 | glog.Fatalf("VirtualService: %s is not exist value", item.key) 261 | runtime.HandleError(fmt.Errorf("%s %s is not exist value", namespace, name)) 262 | } 263 | glog.Infof("[CoreDnsMap] Deleting VirtualService: %s/%s ...", namespace, name) 264 | c.deleteVirtualService(item.value) 265 | return nil 266 | } 267 | runtime.HandleError(fmt.Errorf("failed to list virtualservice by: %s/%s", namespace, name)) 268 | return err 269 | } 270 | default: 271 | return nil 272 | } 273 | return nil 274 | } 275 | 276 | func (c *Controller) buildCanalDnsName() (canalDnsName string) { 277 | return c.canalServiceName + "." + c.canalNamespace + rewriteSuffix 278 | } 279 | 280 | func (c *Controller) deleteVirtualService(vs *v1alpha3.VirtualService) { 281 | glog.Info("delete event") 282 | var needDeleteBlock []string 283 | relateServices := make(map[string][]string) 284 | canalNameFull := c.buildCanalDnsName() 285 | if tools.FilterVirtualService(vs, c.canalNamespace, c.gatewayName) { 286 | for _, http := range vs.Spec.GetHttp() { 287 | for _, ds := range http.Route { 288 | relateServices[vs.Namespace] = append(relateServices[vs.Namespace], ds.Destination.Host) 289 | } 290 | } 291 | } 292 | for k, v := range relateServices { 293 | var serviceFullName string 294 | var deleteLine string 295 | for _, service := range v { 296 | if !tools.IsDnsFullName(service) { 297 | serviceFullName = service + "." + k + rewriteSuffix 298 | } else { 299 | serviceFullName = service 300 | } 301 | num := coredns.Del(serviceFullName) 302 | if num == 0 { 303 | deleteLine = rewritePrefix + serviceFullName + " " + canalNameFull 304 | if !tools.HaveString(deleteLine, needDeleteBlock) { 305 | needDeleteBlock = append(needDeleteBlock, deleteLine) 306 | } 307 | } 308 | } 309 | } 310 | configMaps, err := c.kubeclientset.CoreV1().ConfigMaps("kube-system").List(context.TODO(), metav1.ListOptions{}) 311 | if err != nil { 312 | panic(err) 313 | } 314 | for _, configmap := range configMaps.Items { 315 | if configmap.Name == "coredns" { 316 | newConfigMap, err := coredns.BuildNewConfigMapForDelete(configmap, needDeleteBlock) 317 | if err != nil { 318 | //coredns.RollBackConfigMapData(clientSet, configmap) 319 | glog.Fatalf("Error content is empty after build: %s", err) 320 | } else { 321 | coredns.UpdateConfigMap(c.kubeclientset, newConfigMap, configmap) 322 | } 323 | } 324 | } 325 | } 326 | 327 | func (c *Controller) addVirtualService(vs *v1alpha3.VirtualService) { 328 | glog.Info("add event") 329 | var needAddBlock []string 330 | relateServices := make(map[string][]string) 331 | canalNameFull := c.buildCanalDnsName() 332 | if tools.FilterVirtualService(vs, c.canalNamespace, c.gatewayName) { 333 | for _, http := range vs.Spec.GetHttp() { 334 | for _, ds := range http.Route { 335 | relateServices[vs.Namespace] = append(relateServices[vs.Namespace], ds.Destination.Host) 336 | } 337 | } 338 | } 339 | for k, v := range relateServices { 340 | var serviceFullName string 341 | var rewriteLine string 342 | for _, service := range v { 343 | if !tools.IsDnsFullName(service) { 344 | serviceFullName = service + "." + k + rewriteSuffix 345 | } else { 346 | serviceFullName = service 347 | } 348 | num := coredns.Put(serviceFullName) 349 | if num == 1 { 350 | rewriteLine = rewritePrefix + serviceFullName + " " + canalNameFull 351 | if !tools.HaveString(rewriteLine, needAddBlock) { 352 | needAddBlock = append(needAddBlock, rewriteLine) 353 | } 354 | } 355 | } 356 | } 357 | glog.Infof("addBlock is : %v", needAddBlock) 358 | configMaps, err := c.kubeclientset.CoreV1().ConfigMaps("kube-system").List(context.TODO(), metav1.ListOptions{}) 359 | if err != nil { 360 | panic(err) 361 | } 362 | for _, configmap := range configMaps.Items { 363 | if configmap.Name == "coredns" { 364 | newConfigMap, err := coredns.BuildNewConfigMapForAdd(configmap, needAddBlock) 365 | if err != nil { 366 | //coredns.RollBackConfigMapData(clientSet, configmap) 367 | glog.Fatalf("Error content is empty after build: %s", err) 368 | } else { 369 | coredns.UpdateConfigMap(c.kubeclientset, newConfigMap, configmap) 370 | } 371 | } 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /pkg/coredns/coredns_process.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coredns 16 | 17 | import ( 18 | "cannalcontroller/pkg/tools" 19 | "context" 20 | "errors" 21 | "github.com/golang/glog" 22 | "k8s.io/api/core/v1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/client-go/kubernetes" 25 | "strings" 26 | ) 27 | 28 | var ( 29 | content string 30 | deepNum int 31 | ) 32 | 33 | func insertBlock(block []string) { 34 | for _, line := range block { 35 | content += " " + line + "\n" 36 | } 37 | } 38 | 39 | func processLineForAdd(line string, block []string) { 40 | content += line + "\n" 41 | var haveFlag = false 42 | if strings.Contains(line, "{") { 43 | deepNum++ 44 | haveFlag = true 45 | } 46 | if strings.Contains(line, "}") { 47 | deepNum-- 48 | } 49 | if deepNum == 1 && haveFlag { 50 | insertBlock(block) 51 | } 52 | if deepNum < 0 { 53 | glog.Fatalf("Error deepNum is %d : %s\n", deepNum, line) 54 | return 55 | } 56 | } 57 | 58 | func processLineForDelete(line string, deleteBlock []string) { 59 | if !tools.HaveString(tools.CleanString(line), deleteBlock) { 60 | content += line + "\n" 61 | return 62 | } 63 | } 64 | 65 | func BuildNewConfigMapForAdd(oldConfigMap v1.ConfigMap, insertBlock []string) (newConfigMap v1.ConfigMap, err error) { 66 | if len(insertBlock) == 0 { 67 | glog.Warning("insertBlock is empty") 68 | return 69 | } 70 | oldConfigMap.DeepCopyInto(&newConfigMap) 71 | for k, v := range oldConfigMap.Data { 72 | if k == "Corefile" { 73 | lines := strings.Split(v, "\n") 74 | for i := 0; i < len(lines); i++ { 75 | processLineForAdd(lines[i], insertBlock) 76 | } 77 | } 78 | } 79 | 80 | if content == "" { 81 | glog.Fatalf("Error content is empty after build: %s", content) 82 | return newConfigMap, errors.New("content is empty") 83 | } 84 | newConfigMap.Data["Corefile"] = content 85 | content = "" 86 | return newConfigMap, nil 87 | } 88 | 89 | func BuildNewConfigMapForDelete(oldConfigMap v1.ConfigMap, deleteBlock []string) (newConfigMap v1.ConfigMap, err error) { 90 | if len(deleteBlock) == 0 { 91 | glog.Warning("deleteBlock is empty") 92 | return 93 | } 94 | oldConfigMap.DeepCopyInto(&newConfigMap) 95 | if len(deleteBlock) != 0 { 96 | for k, v := range oldConfigMap.Data { 97 | if k == "Corefile" { 98 | lines := strings.Split(v, "\n") 99 | for i := 0; i < len(lines); i++ { 100 | processLineForDelete(lines[i], deleteBlock) 101 | } 102 | } 103 | } 104 | } 105 | if content == "" { 106 | glog.Fatalf("Error content is empty after build: %s", content) 107 | return newConfigMap, errors.New("content is empty") 108 | } 109 | newConfigMap.Data["Corefile"] = content 110 | content = "" 111 | return newConfigMap, nil 112 | } 113 | 114 | func rollBackConfigMapData(clientSet kubernetes.Interface, oldConfigMap v1.ConfigMap) { 115 | return 116 | } 117 | 118 | func UpdateConfigMap(clientSet kubernetes.Interface, newConfigMap v1.ConfigMap, oldConfigMap v1.ConfigMap) { 119 | _, err := clientSet.CoreV1().ConfigMaps("kube-system").Update(context.TODO(), &newConfigMap, metav1.UpdateOptions{}) 120 | if err != nil { 121 | rollBackConfigMapData(clientSet, oldConfigMap) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /pkg/coredns/debug_info.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coredns 16 | 17 | import ( 18 | "fmt" 19 | "github.com/golang/glog" 20 | "net/http" 21 | "strconv" 22 | ) 23 | 24 | func printMap(w http.ResponseWriter, r *http.Request) { 25 | mapInfo := Get() 26 | for k, v := range mapInfo { 27 | lineSvc := k + "->" + strconv.Itoa(int(v)) + "\n" 28 | _, err := fmt.Fprintf(w, lineSvc) 29 | if err != nil { 30 | return 31 | } 32 | } 33 | } 34 | 35 | func run() error { 36 | http.HandleFunc("/configMap", printMap) 37 | err := http.ListenAndServe(":2323", nil) 38 | if err != nil { 39 | glog.Fatal("ListenAndServe: ", err) 40 | } 41 | return err 42 | } 43 | 44 | func StartDebugServer() { 45 | glog.Info("Start debug server") 46 | go func() { 47 | err := run() 48 | if err != nil { 49 | panic(err) 50 | } 51 | }() 52 | } 53 | -------------------------------------------------------------------------------- /pkg/coredns/service_map.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coredns 16 | 17 | import ( 18 | "cannalcontroller/pkg/tools" 19 | "fmt" 20 | "github.com/golang/glog" 21 | "k8s.io/apimachinery/pkg/util/runtime" 22 | ) 23 | 24 | var ( 25 | serviceMap = make(map[string]uint32) 26 | ) 27 | 28 | func Put(service string) uint32 { 29 | if !tools.IsDnsFullName(service) { 30 | glog.Errorf("Put %s is not full dns name", service) 31 | runtime.HandleError(fmt.Errorf("put %s is not correct fmt", service)) 32 | } 33 | serviceMap[service] = serviceMap[service] + 1 34 | return serviceMap[service] 35 | } 36 | 37 | func Del(service string) uint32 { 38 | if !tools.IsDnsFullName(service) { 39 | glog.Errorf("Del %s is not full dns name", service) 40 | runtime.HandleError(fmt.Errorf("del %s is not correct fmt", service)) 41 | } 42 | serviceMap[service] = serviceMap[service] - 1 43 | if serviceMap[service] == 0 { 44 | delete(serviceMap, service) 45 | return 0 46 | } 47 | return serviceMap[service] 48 | } 49 | 50 | func Get() map[string]uint32 { 51 | return tools.DeepCopy(serviceMap).(map[string]uint32) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/signal/signal.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package signal 16 | 17 | import ( 18 | "os" 19 | "os/signal" 20 | ) 21 | 22 | var onlyOneSignalHandler = make(chan struct{}) 23 | 24 | func SetupSignalHandler() (stopCh <-chan struct{}) { 25 | close(onlyOneSignalHandler) // panics when called twice 26 | 27 | stop := make(chan struct{}) 28 | c := make(chan os.Signal, 2) 29 | signal.Notify(c, shutdownSignals...) 30 | go func() { 31 | <-c 32 | close(stop) 33 | <-c 34 | os.Exit(1) // second signal. Exit directly. 35 | }() 36 | 37 | return stop 38 | } 39 | -------------------------------------------------------------------------------- /pkg/signal/signal_posix.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build !windows 16 | 17 | package signal 18 | 19 | import ( 20 | "os" 21 | "syscall" 22 | ) 23 | 24 | var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} 25 | -------------------------------------------------------------------------------- /pkg/signal/signal_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package signal 16 | 17 | import ( 18 | "os" 19 | ) 20 | 21 | var shutdownSignals = []os.Signal{os.Interrupt} 22 | -------------------------------------------------------------------------------- /pkg/tools/tool.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Alibaba Group。 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tools 16 | 17 | import ( 18 | "gopkg.in/mgo.v2/bson" 19 | "istio.io/client-go/pkg/apis/networking/v1alpha3" 20 | "strings" 21 | ) 22 | 23 | func HaveString(target string, list []string) bool { 24 | for _, ele := range list { 25 | if ele == target { 26 | //glog.Infof("ele: %s, target: %s", ele, target) 27 | return true 28 | } 29 | } 30 | return false 31 | } 32 | 33 | func CleanString(target string) (ret string) { 34 | ret = strings.TrimLeft(target, " ") 35 | ret = strings.TrimLeft(ret, "\n") 36 | ret = strings.TrimLeft(ret, "\t") 37 | 38 | ret = strings.TrimRight(ret, " ") 39 | ret = strings.TrimRight(ret, "\n") 40 | ret = strings.TrimRight(ret, "\t") 41 | return ret 42 | } 43 | 44 | func IsDnsFullName(service string) bool { 45 | return strings.Contains(service, ".svc.cluster.local") 46 | } 47 | 48 | func DeepCopy(value interface{}) interface{} { 49 | if valueMap, ok := value.(map[string]interface{}); ok { 50 | newMap := make(map[string]interface{}) 51 | for k, v := range valueMap { 52 | newMap[k] = DeepCopy(v) 53 | } 54 | 55 | return newMap 56 | } else if valueSlice, ok := value.([]interface{}); ok { 57 | newSlice := make([]interface{}, len(valueSlice)) 58 | for k, v := range valueSlice { 59 | newSlice[k] = DeepCopy(v) 60 | } 61 | 62 | return newSlice 63 | } else if valueMap, ok := value.(bson.M); ok { 64 | newMap := make(bson.M) 65 | for k, v := range valueMap { 66 | newMap[k] = DeepCopy(v) 67 | } 68 | } 69 | return value 70 | } 71 | 72 | func FilterVirtualService(virtualService *v1alpha3.VirtualService, ns string, name string) bool { 73 | if virtualService.Namespace != ns { 74 | return false 75 | } 76 | for i := 0; i < len(virtualService.Spec.Gateways); i++ { 77 | if virtualService.Spec.Gateways[i] == name { 78 | return true 79 | } 80 | } 81 | return false 82 | } 83 | -------------------------------------------------------------------------------- /samples/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # Helloworld service 2 | 3 | This sample includes two versions of a simple helloworld service that returns its version 4 | and instance (hostname) when called. 5 | It can be used as a test service when experimenting with version routing. 6 | 7 | This service is also used to demonstrate canary deployments working in conjunction with autoscaling. 8 | See [Canary deployments using Istio](https://istio.io/blog/2017/0.1-canary). 9 | 10 | ## Start the helloworld service 11 | 12 | The following commands assume you have 13 | [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) 14 | enabled in your cluster. 15 | If not, you'll need to modify them to include 16 | [manual sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#manual-sidecar-injection). 17 | 18 | To run both versions of the helloworld service, use the following command: 19 | 20 | ```bash 21 | kubectl apply -f helloworld.yaml 22 | ``` 23 | 24 | Alternatively, you can run just one version at a time by first defining the service: 25 | 26 | ```bash 27 | kubectl apply -f helloworld.yaml -l service=helloworld 28 | ``` 29 | 30 | and then deploying version v1, v2, or both: 31 | 32 | ```bash 33 | kubectl apply -f helloworld.yaml -l version=v1 34 | kubectl apply -f helloworld.yaml -l version=v2 35 | ``` 36 | 37 | For even more flexibility, there is also a script, `gen-helloworld.sh`, that will 38 | generate YAML for the helloworld service. This script takes the following 39 | arguments: 40 | 41 | Argument | Default | Description 42 | -------- | ------- | ----------- 43 | `--version` | `v1` | Specifies the version that will be returned by the helloworld service. 44 | `--includeService` | `true` | If `true` the service will be included in the YAML. 45 | `--includeDeployment` | `true` | If `true` the deployment will be included in the YAML. 46 | 47 | You can use this script to deploy a custom version: 48 | 49 | ```bash 50 | ./gen-helloworld.sh --version customversion | \ 51 | kubectl apply -f - 52 | ``` 53 | 54 | ## Configure the helloworld gateway 55 | 56 | Apply the helloworld gateway configuration: 57 | 58 | ```bash 59 | kubectl apply -f helloworld-gateway.yaml 60 | ``` 61 | 62 | Follow [these instructions](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports) 63 | to set the INGRESS_HOST and INGRESS_PORT variables and then confirm the sample is running using curl: 64 | 65 | ```bash 66 | export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT 67 | curl http://$GATEWAY_URL/hello 68 | ``` 69 | 70 | ## Autoscale the services 71 | 72 | Note that a Kubernetes [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) 73 | only works if all containers in the pods request cpu. In this sample the deployment 74 | containers in `helloworld.yaml` are configured with the request. 75 | The injected istio-proxy containers also include cpu requests, 76 | making the helloworld service ready for autoscaling. 77 | 78 | Enable autoscaling on both versions of the service: 79 | 80 | ```bash 81 | kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10 82 | kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10 83 | kubectl get hpa 84 | ``` 85 | 86 | ## Generate load 87 | 88 | ```bash 89 | ./loadgen.sh & 90 | ./loadgen.sh & # run it twice to generate lots of load 91 | ``` 92 | 93 | Wait for about 2 minutes and then check the number of replicas: 94 | 95 | ```bash 96 | kubectl get hpa 97 | ``` 98 | 99 | If the autoscaler is functioning correctly, the `REPLICAS` column should have a value > 1. 100 | 101 | ## Cleanup 102 | 103 | ```bash 104 | kubectl delete -f helloworld.yaml 105 | kubectl delete -f helloworld-gateway.yaml 106 | kubectl delete hpa helloworld-v1 helloworld-v2 107 | ``` 108 | -------------------------------------------------------------------------------- /samples/helloworld/gen-helloworld.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright Istio Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | INCLUDE_SERVICE=${INCLUDE_SERVICE:-"true"} 20 | INCLUDE_DEPLOYMENT=${INCLUDE_DEPLOYMENT:-"true"} 21 | SERVICE_VERSION=${SERVICE_VERSION:-"v1"} 22 | while (( "$#" )); do 23 | case "$1" in 24 | --version) 25 | SERVICE_VERSION=$2 26 | shift 2 27 | ;; 28 | 29 | --includeService) 30 | INCLUDE_SERVICE=$2 31 | shift 2 32 | ;; 33 | 34 | --includeDeployment) 35 | INCLUDE_DEPLOYMENT=$2 36 | shift 2 37 | ;; 38 | 39 | *) 40 | echo "Error: Unsupported flag $1" >&2 41 | exit 1 42 | ;; 43 | esac 44 | done 45 | 46 | SERVICE_YAML=$(cat <