How to Set Up Liquibase in Spinnaker hero graphic

How to Set Up Liquibase in Spinnaker

Nov 21, 2020 by Ryan Cartwright

Note: We are delighted to host this guest post by Robert Reeves, Co-Founder & CTO of Liquibase. The post can also be found on the Liquibase Blog.

Liquibase simplifies and automates database deployment and configuration for applications.

We’ve been having a lot of fun with CICD integrations at Liquibase. We’ve recently released our official GitHub Action and an example for Travis CI. It’s past time to do the same for Spinnaker!

For the uninitiated, Spinnaker is an open source, multi-cloud continuous delivery platform built by Netflix for releasing software changes with high velocity and confidence. Fun fact: Spinnaker uses Liquibase to manage the internal database that holds configuration information. A lot of amazing companies use Spinnaker: Netflix, Google, Microsoft, Veritas, Target, Kenzan, Schibsted, and many others.

If Liquibase is good enough for Spinnaker, imagine what it can do for your CI/CD workflow.

Using Liquibase in Spinnaker

You can execute Liquibase within Spinnaker using the Run Job (Manifest) stage. This stage uses the Liquibase Docker image to execute Liquibase commands. This is the same underlying workflow that we have used for GitHub Action and Travis CI.

High-Level Architecture

Docker, Liquibase and Spinnaker high-level architecture

Spinnaker Setup

In Spinnaker, configure a Run Job (Manifest) stage and use the following manifest source text (YML):

apiVersion: batch/v1
kind: Job
metadata:
 name: liquibase-runner
spec:
 backoffLimit: 0
 template:
   spec:
     containers:
       - args:
           - '--classpath=/workspace/example/changelogs'
           - '--changeLogFile=samplechangelog.h2.sql'
           - '--username=liqubase'
           - '--password=password'
           - '--url=jdbc:sqlserver://<IP OR HOSTNAME>:1433;database=<database name>'
           - update
         image: 'index.docker.io/liquibase/liquibase:4.1'
         name: liquibase
         volumeMounts:
           - mountPath: /workspace
             name: workspace
     initContainers:
       - command:
           - git
           - clone
           - '--single-branch'
           - '--branch'
           - $(BRANCH)
           - $(REPO)
           - /workspace
         env:
           - name: BRANCH
             value: main
           - name: REPO
             value: 'https://github.com/liquibase/liquibase-github-action-example'
         image: alpine/git
         name: git
         volumeMounts:
           - mountPath: /workspace
             name: workspace
     restartPolicy: Never
     volumes:
       - emptyDir: {}
         name: workspace

Notice that in the code above, the following parameters are hard-coded for reference:

Once you have create the job, you should see the following in Spinnaker:

And when executed, you will see a happy Liquibase update.

Author’s note: I wanted to give a big thanks to our good friends at Armory. If you are interested in using Spinnaker in an Enterprise setting, we can think of no better partner than Armory. They are super helpful and just great people to work with!

Author’s second note: Of course, all Spinnaker jobs are JSON under the hood. So, here’s the underlying JSON for the job listed above if you prefer to manage your Spinnaker pipeline as code:

{
 "keepWaitingPipelines": false,
 "lastModifiedBy": "admin",
 "limitConcurrent": true,
 "spelEvaluator": "v4",
 "stages": [
   {
     "account": "spinnaker",
     "alias": "runJob",
     "application": "liquibasejenkins",
     "cloudProvider": "kubernetes",
     "credentials": "spinnaker",
     "manifest": {
       "apiVersion": "batch/v1",
       "kind": "Job",
       "metadata": {
         "name": "liquibase-runner"
       },
       "spec": {
         "backoffLimit": 0,
         "template": {
           "spec": {
             "containers": [
               {
                 "args": [
                   "--classpath=/workspace/example/changelogs",
                   "--changeLogFile=samplechangelog.h2.sql",
                   "--username=liqubase",
                   "--password=password",
                   "--url=jdbc:h2:file:./H2_project/h2tutorial",
                   "update"
                 ],
                 "image": "index.docker.io/liquibase/liquibase:4.1",
                 "name": "liquibase",
                 "volumeMounts": [
                   {
                     "mountPath": "/workspace",
                     "name": "workspace"
                   }
                 ]
               }
             ],
             "initContainers": [
               {
                 "command": [
                   "git",
                   "clone",
                   "--single-branch",
                   "--branch",
                   "$(BRANCH)",
                   "$(REPO)",
                   "/workspace"
                 ],
                 "env": [
                   {
                     "name": "BRANCH",
                     "value": "main"
                   },
                   {
                     "name": "REPO",
                     "value": "https://github.com/liquibase/liquibase-github-action-example"
                   }
                 ],
                 "image": "alpine/git",
                 "name": "git",
                 "volumeMounts": [
                   {
                     "mountPath": "/workspace",
                     "name": "workspace"
                   }
                 ]
               }
             ],
             "restartPolicy": "Never",
             "volumes": [
               {
                 "emptyDir": {},
                 "name": "workspace"
               }
             ]
           }
         }
       }
     },
     "name": "Run Job (Manifest)",
     "refId": "1",
     "requisiteStageRefIds": [],
     "source": "text",
     "type": "runJobManifest"
   }
 ],
 "triggers": [],
 "updateTs": "1603738482000"
}

Reference: Extending Spinnaker with Kubernetes and Containers

Recently Published Posts

A Faster Way to Evaluate Self-Hosted Continuous Deployment from Armory

Sep 30, 2022

Introducing Quick Spin One of the most common challenges that organizations face when implementing a continuous deployment strategy is the time and focus that it takes to set up the tools and processes. But a secure, flexible, resilient and scalable solution is available right now. Want to see if it’s the right tool for your […]

Read more

3 Common Spinnaker Challenges (and Easy Ways to Solve Them)

Sep 27, 2022

Spinnaker is the most powerful continuous delivery tool on the market.  DevOps engineers and developers recognize this power and are looking to use Spinnaker as a foundational tool in their Continuous Integration and Continuous Delivery (CI/CD) process for hybrid and multi-cloud deployments. Such a powerful, expansive open source tool needs expertise within your organization to […]

Read more

Streamline Advanced Kubernetes Deployments from GitHub Actions with New Armory Service

Sep 23, 2022

Today, Armory is excited to announce the availability of the GitHub Action for Armory Continuous Deployment-as-a-Service. GitHub is where developers shape the future of software. After a developer writes and tests their code in GitHub, it must be deployed. Armory’s GitHub Action for Continuous Deployment-as-a-Service extends the best-in-class deployment capabilities to Kubernetes. CD-as-a-Service enables declarative […]

Read more