Rolling out with Shipper

Note

This documentation assumes that you have set up Shipper in two clusters. kind-mgmt is the name of the context that points to the management cluster, and kind-app is the name of the context that points to the application cluster.

Rollouts with Shipper are all about transitioning from an old Release, the incumbent, to a new Release, the contender. If you’re rolling out an Application for the very first time, then there is no incumbent, only a contender.

In general Shipper tries to present a familiar interface for people accustomed to Deployment objects.

Application object

Here’s the Application object we’ll use:

apiVersion: shipper.booking.com/v1alpha1
kind: Application
metadata:
  name: super-server
spec:
  revisionHistoryLimit: 3
  template:
    chart:
      name: nginx
      repoUrl: https://raw.githubusercontent.com/bookingcom/shipper/master/test/e2e/testdata
      version: 0.0.1
    clusterRequirements:
      regions:
      - name: local
    strategy:
      steps:
      - capacity:
          contender: 1
          incumbent: 100
        name: staging
        traffic:
          contender: 0
          incumbent: 100
      - capacity:
          contender: 100
          incumbent: 0
        name: full on
        traffic:
          contender: 100
          incumbent: 0
    values:
      replicaCount: 3

Copy this to a file called app.yaml and apply it to your Kubernetes management cluster:

$ kubectl --context kind-mgmt apply -f app.yaml

This will create an Application and Release object. Shortly thereafter, you should also see the set of Chart objects: a Deployment, a Service, and a Pod.

Checking progress

There are a few different ways to figure out how your rollout is going.

We can check in on the Release to see the progress we’re making:

.status.achievedStep

This field is the definitive answer for whether Shipper considers a given step in a rollout strategy complete.

$ kubectl --context kind-mgmt get rel super-server-83e4eedd-0 -o json | jq .status.achievedStep
null
$ # "null" means Shipper has not written the achievedStep key, because it hasn't finished the first step
$ kubectl get rel -o json | jq .items[0].status.achievedStep
{
  "name": "staging",
  "step": 0
}

If everything is working, you should see one Pod active/ready.

.status.conditions

Just like any other object, the status field of a Release object contains information on anything that is going wrong, and anything that is going right:

This set of conditions shows that the strategy hasn’t been executed because Shipper can not contact the application cluster called kind-app.

.status.strategy.conditions

For a more detailed view of what’s happening while things are in between states, you can use the Strategy conditions.

$ kubectl --context kind-mgmt get rel super-server-83e4eedd-0 -o json | jq .status.strategy.conditions
[
  {
    "lastTransitionTime": "2018-12-09T10:00:55Z",
    "message": "clusters pending capacity adjustments: [microk8s]",
    "reason": "ClustersNotReady",
    "status": "False",
    "type": "ContenderAchievedCapacity"
  },
  {
    "lastTransitionTime": "2018-12-09T10:00:55Z",
    "status": "True",
    "type": "ContenderAchievedInstallation"
  }
]

These will tell you which part of the step Shipper is currently working on. In this example, Shipper is waiting for the desired capacity in the microk8s cluster. This means that Pods aren’t ready yet.

.status.strategy.state

Finally, because the Strategy conditions can be kind of a lot to parse, they are summarized into estatus.strategy.state.

$ kubectl get rel super-server-83e4eedd-0 -o json | jq .status.strategy.state
{
  "waitingForCapacity": "True",
  "waitingForCommand": "False",
  "waitingForInstallation": "False",
  "waitingForTraffic": "False"
}

The troubleshooting guide has more information on how to dig deep into what’s going on with any given Release.

Advancing the rollout

So now that we’ve checked on our Release and seen that Shipper considers step 0 achieved, let’s advance the rollout:

$ kubectl --context kind-mgmt patch rel super-server-83e4eedd-0 --type=merge -p '{"spec":{"targetStep":1}}'

I’m using patch here to keep things concise, but any means of modifying objects will work just fine.

Now, if you’ve got your kind-app context set to the same namespace as your Application object in the management cluster, you should be able to see 2 more pods spin up:

$ kubectl --context kind-app get po
NAME                                             READY STATUS  RESTARTS AGE
super-server-83e4eedd-0-nginx-5775885bf6-76l6g   1/1   Running 0        7s
super-server-83e4eedd-0-nginx-5775885bf6-9hdn5   1/1   Running 0        7s
super-server-83e4eedd-0-nginx-5775885bf6-dkqbh   1/1   Running 0        3m55s

And confirm that Shipper believes this rollout to be done:

$ kubectl --context kind-mgmt get rel -o json | jq .items[0].status.achievedStep
{
  "name": "full on",
  "step": 1
}

That’s it! Doing another rollout is as simple as editing the Application object, just like you would with a Deployment. The main principle is patching the Release object to move from step to step.