Software Engineering

Dear manifest.yml file, can’t you just do this for me!?

When you’re working with Cloud Foundry (CF) you find yourself using the Command Line Interface (CLI) a lot. Which is fine for most of the time. Especially since the Cloud Foundry Command Line Interface (cf CLI) is – in my opinion – very well designed. But at some point, when I was building and deploying apps again and again, I started to use manifest files more often. This blogpost will give you some ideas of how to use them.

Why manifests?

When deploying an application to an environment, manifest files help you to configure the deployment itself and to set up the environment. At some point of the development of an application you already know your future environment will need some pre-configuration in order to run your app. Instead of doing all this configuration manually step by step before deployment, you’re able to store it in a manifest file just at the time of development. The manifest will be picked up when deploying the app and the environment will be configured as defined.

In general, you don’t get any extra features by using manifests. All you do is overriding default values of the cf CLI which you can do from the command line as well. But what you get is consistency, reproducibility and automation with very little effort. You’re able to make sure that you will not forget to set any specific flag or variable you need in order to avoid unnecessary failures. Manifests for CF have to be written in YAML – so let’s start with some code of a manifest.yml file.

Our first manifest

We want to push two Java apps to CF by defining their names and paths to their JAR files. Without a manifest, we would have to run the two following cf push commands:

cf push first-app -p first-app/build/libs/first-app.jar --random-route
cf push second-app -p second-app/build/libs/second-app.jar --random-route

With the usage of a manifest we’re able to reduce it to nothing more than just:

cf push

So, in this case we will set the name of our apps, the specific path to their JAR files and set the route to a random-route which will be picked up for us by CF. The manifest.yml file could look like this:

applications:
- name: first-app
  path: first-app
/build/libs/first-app.jar
  random-route: true
- name: second-app
  path: second-app/build/libs/first-app.jar
  random-route: true

As you can see, the manifest starts with the applications block by ending with a colon. The name of the app is preceded by a single dash and one space. Every line underneath has to align with name in order to specify the values of this specific app, called first-app. In order to set values for another app, start a new line with a dash, a space and name followed by a colon. In general, I always try to remind myself: never forget spaces after dashes or colons (unless they are part of a value, of course) and never forget to align things belonging together.

Since we’re working with relative paths here, it matters where to locate our manifest file. The following project structure shows where to put the sources and the manifest.yml file.

└─ apps
            ├─ first-app
            │         └─ src/main/java
            ├─ second-app
            │         └─ src/main/java
            └─ manifest.yml

To pick up all the configuration of the upper manifest when deploying the two apps, just run cf push from the apps directory.

Some things to emphasize

There are several important things to notice at this point:

  • By just running cf push in the apps directory, it will always deploy and start both apps. In order to start just the first app but with the defined values of the manifest, run cf push first-app.
  • If you set the -p flag in the command line with a path to another JAR file, it will override your configuration of the manifest.yml file. Which is the case for any value written in the manifest file. Which will give you even more freedom in my opinion, because you’re still able to adjust single values for a specific use case without changing it in your manifest.
  • By default, the file will be picked up because it’s called manifest.yml and is located in the top of your directory containing these apps. If you put it somewhere else, name it differently or have multiple manifests for different use-cases, you have to set the -f flag with the path to your manifest when running cf push.

What about environment variables?

Manifests are quite powerful and there are many cases where they can come into action. For example, setting the environment variables of CF via manifest files speeds up deployment a lot.

Let’s say we want to have three kinds of environment variables: a String telling which environment configuration was picked up, another String which is the endpoint of another app being different in a local- and a cloud-environment and a specific value telling our cloud environment which JDK version to use. Moreover, the route to our app called cloud-app should no longer be a random one picked up by CF but it two specific routes defined by us.

Again, instead of typing several cf push or even cf create-route and cf map-route followed by some cf set-env commands we just want run cf push. It’s not just about the actual time of typing these commands which can be tiring. But the risk of typos or to forget some configuration is quite high and the effort of finding and fixing the subsequent failures is even higher. An appropriate manifest.yml file could look like this:

applications:
- name: cloud-app
  path: build/libs/cloud-app.jar
  routes:
  - route: cloud-app-for-you.esentri.com
  - route: cloud-app-for-me.esentri.com
  env:
    ENVIRONMENT_MESSAGE: Hello from the Cloud Environment
    ENDPOINT_OF_ANOTHER_APP: https://my-other-cloud-app.esentri.com
    JBP_CONFIG_OPEN_JDK_JRE: '{ jre: { version: 12.+ } }'

Now, as you can see from the upper relative path, our manifest has to be located at the top-level of the cloud-app directory.

Don’t just remove but unset environment variables!

One last remarkable thing: if you change the value of an environment variable in the manifest.yml it will be changed by the next push as expected. But if you just remove an environment variable from the manifest it will still be set in the environment even if you push it again. Make sure to use the explicit cf unset-env command if you want to unset environment variables.

If you want to test some of the things we just went through, you can do so by building a simple Spring Boot Application running in the cloud and using environment variables. My blogpost Hello World from Pivotal Cloud Foundry is providing a handy guide. When you finished, try to use a manifest.yml file which will set the path, define a route and set the needed environment variable. Enjoy!

References