Jenkins X: Preview Environment

Jenkins X lets you spin up Preview Environments for your Pull Requests so you can get fast feedback before changes are merged to master.

Jenkins X

Jenkins X is an opinionated platform for providing CI / CD on top of Kubernetes. It gives you infrastructure (Kubernetes cluster), automatic builds and promotions (pipelines in Jenkins), immutable images, GitOps.

If you haven’t heart about Jenkins X yet, watch the following video.

But this article is about Preview environment …


Preview environment

Environment is a place where applications get deployed. Jenkins X by default creates Staging and Production environments. They are sometimes referred as permanent environments.

However a Jenkins X Preview environment is an ephemeral (ad hoc) environment meant for testing an application change in a Git branch before merging it into master.

Preview environment is automatically created on a pull request creation and is subsequently updated with every commit to the branch in question.

Continuous delivery by Jenkins X. Source: https://jenkins-x.io.

Creating Preview environment

When a new pull request is created on a branch or a change is committed into the branch pull request build pipeline:

  • builds the application
  • packages it into a Helm chart
  • creates a unique Kubernetes namespace -only on first build
  • deploys the application into the namespace
  • adds a pull request comment with preview environment URL
Pull request comment with preview environment URL

To see all preview environments use jx get previews

$ jx get previews

Application in the preview environment is isolated from the rest of the world due to being deployed into own Kubernetes namespace.

If the application is very simple it can been tested now and potentially merged into the master branch. However most applications require additional applications, e.g.: API, database, authentication server or a front-end to be meaningfully tested.

Here are few steps on how to add dependencies into the preview environment.


Dependencies of Preview environment

In Kubernetes lingo: It is adding resources into the preview environment namespace.

Dependencies can be added in two ways:

  • link Kubernetes service from other environment /namespace
  • create an instance of a dependency in the preview environment through Helm chart.
Preview environment is actually a Helm chart at `charts/preview/Chart.yaml`

Service Linking

This is the easiest way to add a dependency in a preview environment. Just create a Kubernetes service yaml in `charts/preview/templates` directory.

Link service to MySQL in staging environment.

Commit, push and after the pull request built, mysql service appears in the preview environment namespace:

$ kubectl get svc -n <preview environment namespace>

mysqlpoints to a MySQL instance in staging environment. mysql.jx-staging.svc.cluster.localis the staging MySQL instance URL.

Creating a dependency instance

On the other hand, different approach is to create an instance of an application dependency, say database, in the preview environment. This way preview does not share data with other users of the system.

As I said before “Preview environment is a Helm chart” and its dependencies are actually Helm charts. In Helm lingo they are called Chart Dependencies and are stored in charts/preview/requirements.yaml.

To find a chart search helm repositories by

$ helm search mysql
$ helm search mysql

Let’s use my favorite example, MySQL:

charts/preview/requirements.yaml

After commit, push, pull request built:

$ kubectl get svc,pod,pv -n <preview-env-NS>

Here is couple of things to notice:

  1. MySQL service is called <preview-env-NS>-mysql, in my case it is jx-michalfoksa-bellonda-pr-11-mysql.
  2. new, 8GB, persisted volume was claimed
  3. my-app1 cannot start. It is in ChrashLoopBackOff status and has already been restarted 6 times and counting.

4. It is not visible above, but database and database user are not created

Reasons:

  • service name is due to how Helm 2.x creates service names. More on it in The problem with Tiller
  • by default, MySQL chart claims 8GB persistent volume
  • my-app1 expects database to be available under `mysql` domain name. See data source URL: spring.datasource.url: jdbc:mysql://mysql:3306/db_example

Let’s fix it by overriding MySQL chart defaults in charts/preview/values.yaml.

charts/preview/values.yaml

After commit, push, pull request built:

$ kubectl get svc,pod,pv -n <preview-env-NS>

Now the actual software change can be live reviewed and potentially merged into the master branch.


Cleanup

Automatically

Every 3 hours Jenkins X runs a Kubernetes a cron job to clean up preview environments associated with closed or merged pull request.

The cron job essentially executes:

$ jx garbage collect previews

Bear in mind that it takes few minutes before a preview environment gets eligible for garbage collection after a pull request is merged or closed if you are going to test it.

Manually

Run jx delete preview and choose a preview environment to delete.

To see all preview environments execute jx get previews.

My environment

Jenkins X is rapidly evolving. For the reference here is a environment used in writing this article:

Cloud provider:      GKE
$ jx version
NAME VERSION
jx 1.3.701
jenkins x platform 0.0.3125
Kubernetes cluster v1.10.9-gke.5
kubectl v1.10.7
helm client v2.12.1+g02a47c7
helm server v2.12.0+gd325d2a
git git version 2.11.0
Operating System Debian GNU/Linux 9.6 (stretch)