Installing the Istio Sidecar

The following requires Istio 0.5 or greater. See https://archive.istio.io/v0.4/docs/setup/kubernetes/sidecar-injection for Istio 0.4 or prior.

In previous releases, the Kubernetes initializer feature was used for automatic proxy injection. This was an Alpha feature, subject to change/removal, and not enabled by default in Kubernetes. Starting in Kubernetes 1.9 it was replaced by a beta feature called mutating webhooks, which is now enabled by default in Kubernetes 1.9 and beyond. Starting with Istio 0.5.0 the automatic proxy injection uses mutating webhooks, and support for injection by initializer has been removed. Users who cannot upgrade to Kubernetes 1.9 should use manual injection.

Pod spec requirements

In order to be a part of the service mesh, each pod in the Kubernetes cluster must satisfy the following requirements:

  1. Service association: The pod must belong to a single Kubernetes Service (pods that belong to multiple services are not supported as of now).

  2. Named ports: Service ports must be named. The port names must be of the form <protocol>[-<suffix>] with http, http2, grpc, mongo, or redis as the <protocol> in order to take advantage of Istio's routing features. For example, name: http2-foo or name: http are valid port names, but name: http2foo is not. If the port name does not begin with a recognized prefix or if the port is unnamed, traffic on the port will be treated as plain TCP traffic (unless the port explicitly uses Protocol: UDP to signify a UDP port).

  3. Deployments with app label: It is recommended that Pods deployed using the Kubernetes Deployment have an explicit app label in the Deployment specification. Each deployment specification should have a distinct app label with a value indicating something meaningful. The app label is used to add contextual information in distributed tracing.

  4. Sidecar in every pod in mesh: Finally, each pod in the mesh must be running an Istio compatible sidecar. The following sections describe two ways of injecting the Istio sidecar into a pod: manually using istioctl CLI tool or automatically using the Istio Initializer. Note that the sidecar is not involved in traffic between containers in the same pod.

Injection

Manual injection modifies the controller configuration, e.g. deployment. It does this by modifying the pod template spec such that all pods for that deployment are created with the injected sidecar. Adding/Updating/Removing the sidecar requires modifying the entire deployment.

Automatic injection injects at pod creation time. The controller resource is unmodified. Sidecars can be updated selectively by manually deleting a pods or systematically with a deployment rolling update.

Manual and automatic injection use the same templated configuration. Automatic injection loads the configuration from the istio-sidecar-injector ConfigMap in the istio-system namespace. Manual injection can load from a local file or from the ConfigMap.

Manual sidecar injection

Use the built-in defaults template and dynamically fetch the mesh configuration from the istio ConfigMap. Additional parameter overrides are available via flags (see istioctl kube-inject --help).

$ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)

kube-inject can also be run without access to a running Kubernetes cluster. Create local copies of the injection and mesh configmap.

The istioctl kube-inject operation may not be repeated on the output from a previous kube-inject. The kube-inject operation is not idempotent. For upgrade purposes, if using manual injection, it is recommended to keep the original non-injected yaml file so that the dataplane sidecars may be updated.

$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml
$ kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml

Run kube-inject over the input file.

$ istioctl kube-inject \
    --injectConfigFile inject-config.yaml \
    --meshConfigFile mesh-config.yaml \
    --filename @samples/sleep/sleep.yaml@ \
    --output sleep-injected.yaml

Deploy the injected YAML file.

$ kubectl apply -f sleep-injected.yaml

Verify that the sidecar has been injected into the deployment.

$ kubectl get deployment sleep -o wide
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS          IMAGES                             SELECTOR
sleep     1         1         1            1           2h        sleep,istio-proxy   tutum/curl,unknown/proxy:unknown   app=sleep

Automatic sidecar injection

Sidecars can be automatically added to applicable Kubernetes pods using a mutating webhook admission controller. This feature requires Kubernetes 1.9 or later. Verify that the kube-apiserver process has the admission-control flag set with the MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controllers added and listed in the correct order and the admissionregistration API is enabled.

$ kubectl api-versions | grep admissionregistration
admissionregistration.k8s.io/v1alpha1
admissionregistration.k8s.io/v1beta1

See the Kubernetes quick start guide for instructions on installing Kubernetes version >= 1.9.

Note that unlike manual injection, automatic injection occurs at the pod-level. You won't see any change to the deployment itself. Instead you'll want to check individual pods (via kubectl describe) to see the injected proxy.

Disabling or updating the webhook

The sidecar injecting webhook is enabled by default. If you wish to disable the webhook, you can use Helm to generate an updated istio.yaml with the option sidecarInjectorWebhook.enabled set to false. E.g.

$ helm template --namespace=istio-system --set sidecarInjectorWebhook.enabled=false @install/kubernetes/helm/istio@ > istio.yaml
$ kubectl create ns istio-system
$ kubectl apply -n istio-system -f istio.yaml

In addition, there are some other configuration parameters defined for the sidecar injector webhook service in values.yaml. You can override the default values to customize the installation.

Deploying an app

Deploy sleep app. Verify both deployment and pod have a single container.

$ kubectl apply -f @samples/sleep/sleep.yaml@
$ kubectl get deployment -o wide
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS   IMAGES       SELECTOR
sleep     1         1         1            1           12m       sleep        tutum/curl   app=sleep
$ kubectl get pod
NAME                     READY     STATUS        RESTARTS   AGE
sleep-776b7bcdcd-7hpnk   1/1       Running       0          4

Label the default namespace with istio-injection=enabled

$ kubectl label namespace default istio-injection=enabled
$ kubectl get namespace -L istio-injection
NAME           STATUS    AGE       ISTIO-INJECTION
default        Active    1h        enabled
istio-system   Active    1h
kube-public    Active    1h
kube-system    Active    1h

Injection occurs at pod creation time. Kill the running pod and verify a new pod is created with the injected sidecar. The original pod has 1/1 READY containers and the pod with injected sidecar has 2/2 READY containers.

$ kubectl delete pod sleep-776b7bcdcd-7hpnk
$ kubectl get pod
NAME                     READY     STATUS        RESTARTS   AGE
sleep-776b7bcdcd-7hpnk   1/1       Terminating   0          1m
sleep-776b7bcdcd-bhn9m   2/2       Running       0          7s

View detailed state of the injected pod. You should see the injected istio-proxy container and corresponding volumes. Be sure to substitute the correct name for the Running pod below.

$ kubectl describe pod sleep-776b7bcdcd-bhn9m

Disable injection for the default namespace and verify new pods are created without the sidecar.

$ kubectl label namespace default istio-injection-
$ kubectl delete pod sleep-776b7bcdcd-bhn9m
$ kubectl get pod
NAME                     READY     STATUS        RESTARTS   AGE
sleep-776b7bcdcd-bhn9m   2/2       Terminating   0          2m
sleep-776b7bcdcd-gmvnr   1/1       Running       0          2s

Understanding what happened

admissionregistration.k8s.io/v1beta1#MutatingWebhookConfiguration configures when the webhook is invoked by Kubernetes. The default supplied with Istio selects pods in namespaces with label istio-injection=enabled. This can be changed by modifying the MutatingWebhookConfiguration in install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml.

The istio-sidecar-injector ConfigMap in the istio-system namespace has the default injection policy and sidecar injection template.

policy

disabled - The sidecar injector will not inject the sidecar into pods by default. Add the sidecar.istio.io/inject annotation with value true to the pod template spec to enable injection.

enabled - The sidecar injector will inject the sidecar into pods by default. Add the sidecar.istio.io/inject annotation with value false to the pod template spec to disable injection.

The following example uses the sidecar.istio.io/inject annotation to disable sidecar injection.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: ignored
spec:
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"
    spec:
      containers:
      - name: ignored
        image: tutum/curl
        command: ["/bin/sleep","infinity"]
template

The sidecar injection template uses https://golang.org/pkg/text/template which, when parsed and executed, is decoded to the following struct containing the list of containers and volumes to inject into the pod.

type SidecarInjectionSpec struct {
      InitContainers []v1.Container `yaml:"initContainers"`
      Containers     []v1.Container `yaml:"containers"`
      Volumes        []v1.Volume    `yaml:"volumes"`
}

The template is applied to the following data structure at runtime.

type SidecarTemplateData struct {
    ObjectMeta  *metav1.ObjectMeta
    Spec        *v1.PodSpec
    ProxyConfig *meshconfig.ProxyConfig  // Defined by https://istio.io/docs/reference/config/service-mesh.html#proxyconfig
    MeshConfig  *meshconfig.MeshConfig   // Defined by https://istio.io/docs/reference/config/service-mesh.html#meshconfig
}

ObjectMeta and Spec are from the pod. ProxyConfig and MeshConfig are from the istio ConfigMap in the istio-system namespace. Templates can conditional define injected containers and volumes with this data.

For example, the following template snippet from install/kubernetes/istio-sidecar-injector-configmap-release.yaml

containers:
- name: istio-proxy
  image: istio.io/proxy:0.5.0
  args:
  - proxy
  - sidecar
  - --configPath
  - {{ .ProxyConfig.ConfigPath }}
  - --binaryPath
  - {{ .ProxyConfig.BinaryPath }}
  - --serviceCluster
  {{ if ne "" (index .ObjectMeta.Labels "app") -}}
  - {{ index .ObjectMeta.Labels "app" }}
  {{ else -}}
  - "istio-proxy"
  {{ end -}}

expands to

containers:
- name: istio-proxy
  image: istio.io/proxy:0.5.0
  args:
  - proxy
  - sidecar
  - --configPath
  - /etc/istio/proxy
  - --binaryPath
  - /usr/local/bin/envoy
  - --serviceCluster
  - sleep

when applied over a pod defined by the pod template spec in samples/sleep/sleep.yaml.

Uninstalling the webhook

$ kubectl delete -f @install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml@

The above command will not remove the injected sidecars from Pods. A rolling update or simply deleting the pods and forcing the deployment to create them is required.

Optionally, if may be also be desirable to clean-up other resources that were created in this task. This includes the secret holding the cert/key and CSR used to sign them, as well as any namespace that was labeled for injection.

$ kubectl -n istio-system delete secret sidecar-injector-certs
$ kubectl delete csr istio-sidecar-injector.istio-system
$ kubectl label namespace default istio-injection-