2. Opinionated implementation
Prev |  | Next

# 2. Opinionated implementation

For the demo purposes we’re providing Docker Compose setup with Artifactory and Concourse / Jenkins tools. Regardless of the picked CD application for the pipeline to pass one needs either

- a Cloud Foundry instance (for example Pivotal Web Services or PCF Dev)
- a Kubernetes cluster (for example Minikube)
- the infrastructure applications deployed to the JAR hosting application (for the demo we’re providing Artifactory).
- `Eureka` for Service Discovery
- `Stub Runner Boot` for running Spring Cloud Contract stubs.

| Tip
In the demos we’re showing you how to first build the `github-webhook` project. That’s because the `github-analytics` needs the stubs of `github-webhook` to pass the tests. Below you’ll find references to `github-analytics` project since it contains more interesting pieces as far as testing is concerned.

## 2.1 Build

Figure 2.1. Build and upload artifacts

In this step we’re generating a version of the pipeline, next we’re running unit, integration and contract tests. Finally we’re:

- publishing a fat jar of the application
- publishing a Spring Cloud Contract jar containing stubs of the application
- for Kubernetes - uploading a Docker image of the application

During this phase we’re executing a `Maven` build using Maven Wrapper or a `Gradle` build using Gradle Wrapper , with unit and integration tests. We’re also tagging the repository with `dev/${version}` format. That way in each subsequent step of the pipeline we’re able to retrieve the tagged version. Also we know exactly which version of the pipeline corresponds to which Git hash.

Once the artifact got built we’re running API compatibility check.

- we’re searching for the latest production deployment
- we’re retrieving the contracts that were used by that deployment
- from the contracts we’re generating API tests to see if the current implementation is fulfilling the HTTP / messaging contracts that the current production deployment has defined (we’re checking backward compatibility of the API)

## 2.2 Test

Figure 2.2. Smoke test and rollback test on test environment

Here we’re

- starting a RabbitMQ service in PaaS
- deploying `Eureka` infrastructure application to PaaS
- downloading the fat jar from Nexus and we’re uploading it to PaaS. We want the application to run in isolation (be surrounded by stubs).

| Tip
Currently due to port constraints in Cloud Foundry we cannot run multiple stubbed HTTP services in the cloud so to fix this issue we’re running the application with `smoke` Spring profile on which you can stub out all HTTP calls to return a mocked response

- if the application is using a database then it gets upgraded at this point via Flyway, Liquibase or any other tool once the application gets started
- from the project’s Maven or Gradle build we’re extracting `stubrunner.ids` property that contains all the `groupId:artifactId:version:classifier` notation of dependant projects for which the stubs should be downloaded.
- then we’re uploading `Stub Runner Boot` and pass the extracted `stubrunner.ids` to it. That way we’ll have a running application in Cloud Foundry that will download all the necessary stubs of our application
- from the checked out code we’re running the tests available under the `smoke` profile. In the case of `GitHub Analytics` application we’re triggering a message from the `GitHub Webhook` application’s stub, that is sent via RabbitMQ to GitHub Analytics. Then we’re checking if message count has increased.
- once the tests pass we’re searching for the last production release. Once the application is deployed to production we’re tagging it with `prod/${version}` tag. If there is no such tag (there was no production release) there will be no rollback tests executed. If there was a production release the tests will get executed.
- assuming that there was a production release we’re checking out the code corresponding to that release (we’re checking out the tag), we’re downloading the appropriate artifact (either JAR for Cloud Foundry or Docker image for Kubernetes) and we’re uploading it to PaaS. IMPORTANT the old artifact is running against the NEW version of the database.
- we’re running the old `smoke` tests against the freshly deployed application surrounded by stubs. If those tests pass then we have a high probability that the application is backwards compatible
- the default behaviour is that after all of those steps the user can manually click to deploy the application to a stage environment

## 2.3 Stage

Figure 2.3. End to end tests on stage environment

Here we’re

- starting a RabbitMQ service in PaaS
- deploying `Eureka` infrastructure application to PaaS
- downloading the artifact (either JAR for Cloud Foundry or Docker image for Kubernetes) from and we’re uploading it to PaaS.

Next we have a manual step in which:

- from the checked out code we’re running the tests available under the `e2e` profile. In the case of `GitHub Analytics` application we’re sending a HTTP message to GitHub Analytic’s endpoint. Then we’re checking if the received message count has increased.

The step is manual by default due to the fact that stage environment is often shared between teams and some preparations on databases / infrastructure have to take place before running the tests. Ideally these step should be fully automatic.

## 2.4 Prod

Figure 2.4. Deployment to production

The step to deploy to production is manual but ideally it should be automatic.

| Important
This step does deployment to production. On production you would assume that you have the infrastructure running. That’s why before you run this step you must execute a script that will provision the services on the production environment. For `Cloud Foundry` just call `tools/cf-helper.sh setup-prod-infra` and for Kubernetes `tools/k8s-helper.sh setup-prod-infra`

Here we’re

- tagging the Git repo with `prod/${version}` tag
- downloading the application artifact (either JAR for Cloud Foundry or Docker image for Kubernetes)
- we’re doing Blue Green deployment:

- for Cloud Foundry

  - we’re renaming the current instance of the app e.g. `fooService` to `fooService-venerable`
  - we’re deploying the new instance of the app under the `fooService` name
  - now two instances of the same application are running on production

- for Kubernetes

  - we’re deploying a service with the name of the app e.g. `fooService`
  - we’re doing a deployment with the name of the app with version suffix (with the name escaped to fulfill the DNS name requirements) e.g. `fooService-1-0-0-M1-123-456-VERSION`
  - all deployments of the same application have the same label `name` equal to app name e.g. `fooService`
  - the service is routing the traffic basing on the `name` label selector
  - now two instances of the same application are running on production

- in the `Complete switch over` which is a manual step

  - we’re stopping the old instance
  - remember to run this step only after you have confirmed that both instances are working fine!

- in the `Rollback` which is a manual step

  - we’re routing all the traffic to the old instance

    - in CF we do that by ensuring that blue is running and removing green
    - in K8S we do that by scaling the number of instances of green to 0
  - we’re removing the latest prod git tag

Prev |  | Next
1. Introduction | Home | 3. Project opinions