How to Upgrade Istio the Git-Ops Way


Istio 1.17 has been running really well in my Garage Kubernetes lab, but I thought it’s time to give it an upgrade. It was installed and configured using istioctl utility last time when I bootstrapped the cluster. Since I’ve automated a lot of Kubernetes resources using ArgoCD I would like to upgrade Istio the git-ops way too.

First I configured istio-operator as an ArgoCD application, so it will be installed using its upstream Helm templates. The ArgoCD application looks like this:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-operator
  namespace: argocd
spec:
  destination:
    namespace: istio-operator
    server: https://kubernetes.default.svc
  project: default
  source:
    # the Helm chart is at https://github.com/istio/istio/blob/master/manifests/charts/istio-operator/Chart.yaml
    path: manifests/charts/istio-operator
    repoURL: https://github.com/istio/istio
    targetRevision: master
    helm:
      values: |
        # ref. https://github.com/istio/istio/blob/master/manifests/charts/istio-operator/values.yaml
        # by default it will use latest which is 1.23 alpha ATM
        # also I chose 2 minor versions above my existing one(1.17). This is not officially recommended.
        tag: 1.19.0-releasebuilder.c356675
        deploymentHistory: 3
  syncPolicy:
    automated:
      prune: true
    syncOptions:
      - CreateNamespace=true
    

Once the application has been sync’ed I can verify it in ArgoCD:

I can see there’s an istiooperators.install.istio.io Custom Resource(CR) called installed-state and it coincidentally matches the configuration of my existing Istio 1.17 installation. I don’t know if it’s really there for 306 days – maybe it was created by the istioctl command last time.

$ k get istiooperators.install.istio.io 
NAME                 REVISION   STATUS    AGE
installed-state                           306d

But anyways there’s no blocker so far. Following the official instructions for upgrading using the operator, I need to create 2 new CRs like these:

# istio-control-plane.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: control-plane-1-19
  namespace: istio-system
spec:
  # as the name suggests, minimal profile only has the control plane
  profile: minimal
  revision: 1-19

---
# istio-gateways.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: gateways
  namespace: istio-system
spec:
  profile: empty
  revision: 1-19
  components:
    ingressGateways:
      - name: istio-ingressgateway
        enabled: true

After the above yaml sync’ed, I verified that 2 new CRs have been created:

$ k get istiooperators.install.istio.io 
NAME                 REVISION   STATUS    AGE
control-plane-1-19   1-19       HEALTHY   153m
gateways             1-19       HEALTHY   152m
installed-state                           306d

I didn’t pay much attention because it’s my garage Kubernetes cluster and nobody would really care if I break it. But as a nice surprise, the ingress gateway was upgraded in-place so there is hardly any downtime caused to my stuff including this blog.

The next step is to migrate all workloads to use the new Istio revision, which is 1-19 stated above. This can be done by replacing all old sidecar.istio.io/inject: true labels with istio.io/rev: 1-19. These are pod labels just in case because I prefer to do it at pod level to reduce the number of Istio sidecar containers.

After all labels were done, I verified this with istioctl:

$ istioctl proxy-status
NAME                                                   CLUSTER        CDS        LDS        EDS        RDS        ECDS         ISTIOD                           VERSION
argocd-server-7c98587c9c-5rr96.argocd                  Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-19-7987854944-v5hd5     
...

When all the entries above go through the new 1-19 revision, the old Istio revision can be safely deleted.

🙂