Using JX for a GitOps Managed Jenkins X Installation with CloudBees CodeShip and Terraform on GKE

Codeship BasicDevelopment

Reading Time: 6 minutes

Jenkins X is a reimagined CI/CD implementation for the cloud which is heavily influenced by the State of DevOps reports, and more recently the book, Accelerate: The Science of Lean Software and DevOps by Nicole Forsgren, Jez Humble and Gene Kim, summarised in this blog post.

This post will show you how to use Jenkins X to create a GitOps managed install of Jenkins X using CloudBees CodeShip and HashiCorp’s Terraform on Google Kubernetes Engine (GKE) with a single command, and, make changes to that environment via GitOps.


GitOps is a great way of managing cloud environments. By ensuring all changes originate from a Git commit, we have a full audit trail into all changes made to an environment. This approach also gives us the added benefit of being able to reconstruct an environment from its git history, reducing MTTR. For more information on using GitOps as a method of delivery, see the Weave Works Blog.

Before you start Some of the commands that are shown here are recent additions to the Jenkins-X CLI. To make use of these you’ll need to be on a fairly recent version of jx. I’m using:

jx --version

If you need to upgrade the version of jx, you can use jx upgrade cli, or for a new installation follow the guide.

You’ll also need a Google Cloud Account, you can sign up for a free account which entitles you to $300 of spend over a 12 month period. The default quotas for the trial account are just enough to create a very minimal GKE cluster.

The magic command…

jx create codeship

Whilst you can run this without any parameters, we’re going to supply an organisation name rather than allowing jx to generate one for us.

jx create codeship -o codeship

jx create codeship

This will perform three things:

1. Create a GCP service account

Firstly, in order to administer the cluster, jx will create a Service Account on GCP. We want to do this to ensure that the administration of the cluster is done with the minimum privilege possible. You can do this via the GCP console or via the gcloud cli tool, or you could use the jx create gke-service-account helper command.

jx will:

  1. Validate you have enough permissions to create a new service account
  2. If the account doesn’t already exist, create a service account called codeship
  3. Assign the appropriate permissions
  4. Create a service account key
  5. Download the key to your home directory to a file called codeship.key.json

2. Create the organisation repository and Terraform scripts

The second step that jx performs is to create the organisation repository (we’ll use GitHub for this) that contains all of the Terraform configuration for the environment. In your home directory, a .jx folder will be created if it doesn’t already exist and within that, you’ll see the organisations directory with the newly created organisation-codeship repo and its Terraform configuration.

A terraform.tfvars will be created and populated with the values supplied during the install such as ‘Minimum Number of Nodes’, ‘Cluster Name’ etc.

✔ ~/.jx
$ tree organisations/organisation-codeship/
├──                             <- build/deploy script that codeship calls
└── clusters
    └── dev                              <- cluster definition
        └── terraform
            ├──                  <- main terraform cluster config file
            ├── terraform.tfvars         <- terraform variable file for customisation
3 directories, 8 files
✔ ~/.jx

The configuration files listed above can all be modified to tailor your cluster configuration to your needs.

3. Create the CloudBees CodeShip build and trigger the deployment

Once the Terraform scripts have been created and pushed back up to the remote organisation-codeship repo, a CloudBees CodeShip project & build will be created to trigger from any changes to this repository. jx will prompt you for your CloudBees CodeShip login details. These details will not be stored anywhere and are only used to login to the CloudBees CodeShip v2 API behind the scenes. This post assumes you already have a CloudBees CodeShip account setup. If you don’t have a CloudBees CodeShip account, you can setup a free one here.

If you login to the CloudBees CodeShip user interface, you will see the newly created project:

enter image description here

By clicking on that, you will see the build is in progress. To create a fresh cluster and install jx normally takes around 10-15 minutes the first time it is run. When it’s complete, it should look something like the screenshot below:

enter image description here

You now have a working environment deployed by Terraform and CloudBees CodeShip. By expanding the ./ section of the build, you will be able to see the generated admin password and URLs needed to login to the environment.

Making a ‘safe’ change

Now that we have a cluster deployed with Jenkins X installed and running, we can use GitOps to manage changes to the cluster.

To start off we going to make a “safe change” to the cluster. A safe change is one that does not result in any destructive behavior when being applied by Terraform. In this example, we are going to change the auto scaling parameters for a default node pool.

  • Clone the organisation repository locally
  • Create a local branch to work on git branch -b autoscaling
  • Edit clusters/dev/terraform.tfvars, change max_node_count to a new value
  • Commit the change and push to the autoscaling branch with git push origin autoscaling
  • Create a pull-request with hub pull-request

Although CloudBees CodeShip does not (currently) build pull requests on forked repositories, it will notice the new commit on the branch and attempt to validate the change is non destructive. Feedback will be posted to the PR in GitHub stating whether it can be safely merged.

When the PR is merged, CloudBees CodeShip will trigger the deployment and apply the required changes to the cluster.

Making a ‘destructive’ change

Lets try the same again, except this time we will change something that will force the creation of a new resource, such as renaming the cluster. For a full list of available options see the Terraform documentation.

  1. Create a new local branch to work on git branch -b rename-cluster
  2. Edit clusters/dev/terraform.tfvars, change cluster_name to a new value
  3. Commit the change and push to the rename-cluster branch with git push origin rename-cluster
  4. Create a pull-request with hub pull-request

CloudBees CodeShip will attempt to validate that the PR does not contain any destructive Terraform plans, in this instance it should fail and post feedback, stopping a merge, to the the PR on GitHub.

Fancy a closer look?

James Rawlings, James Strachan and Rob Davies are going to be presenting and running workshops at DevOps World | Jenkins World. They’ll also be hanging out at the Jenkins X demo area so come and say hello and see what’s the latest cool and exiting things to come out of Jenkins X. Use JWFOSS for 30% discount off the registration

Want to get involved?

Jenkins X is open source, the community mainly hangs out in the Jenkins X Kubernetes Slack channels and for tips on being more involved with Jenkins X take a look at our contributing docs. We’ve been helping lots of folks get into open source, learn new technologies and languages like golang. Why not get involved?

Editor’s Note: This blog post was first published on CloudBees, Inc. and reprinted with permission from the author.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.

We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.

  • Julian Fortes

    Great article, thanks for sharing! My team would learn a lot just by reading this. If you are looking for DevOps system solution, you can give this a try.