Beyond the basics with Cloud Foundry

Introduction

The advent of Docker changed the way we develop applications. Once you write a Dockerfile and build the image, your application will run (almost) anywhere, regardless of the underlying operating system. Best of all, it just works. You can then expose ports, map volumes to persist data, and deploy your image in Docker Swarm or Kubernetes (K8s). With great flexibility, however, comes greater costs, whether they are higher developer skill set requirements, increased time spent on writing multiple K8s YAML configuration files, or pricier services on your favorite cloud provider.

This article presents the usage of different tools and interesting tidbits to ease development with Cloud Foundry, similar to the likes of Docker. These include:

  • Developing locally with the CF Local plugin.
  • Running Docker images inside a Cloud Foundry container.
  • Sequencing the startup of multiple Cloud Foundry applications.
  • Configuring container-to-container networking.

For the remainder of this article, I will use toddler-auth as the example.

Prerequisites

This article assumes you have a basic understanding of Cloud Foundry, how to use it and how to deploy your application onto IBM Cloud with the IBM Cloud CLI. If any of these topics are unfamiliar to you, have a look at the related links section to learn more about each technology.

If you are using the stand-alone IBM Cloud CLI, it bundles into the Cloud Foundry CLI. Effectively, ibmcloud cf is equivalent to using cf. Personally, I use ibmcloud cf as it provides login mechanisms to access my internal IBM Cloud account and to use other services. I created an alias to ibmcloud cf with alias cf='ibmcloud cf'. Henceforth, any mention of cf means ibmcloud cf is invoked.

Estimated time

10 minutes

Developing locally with the CF Local plugin

CF Local lets you develop locally and requires Docker to be installed. To install CF Local, invoke cf install-plugin cflocal. CF Local only uses a local.yml instead of manifest.yml. You can place multiple applications and specify environment variables just like any Cloud Foundry application.

As an example, below is my toddler-auth local.yml file. The route is super helpful to enable applications to talk to each other.

---
applications:
- name: toddler-auth
  routes:
    - route: toddler-auth.apps.internal
  memory: 128M
  disk_quota: 128M
  env:
    TODDLER_USERNAME: <username>
    TODDLER_PASSWORD: <password>
    TODDLER_WORLD_ID: <worldId>

Once you navigate to the application folder, stage the application by invoking:

cf local stage toddler-auth

Staging an application

Then, you run the application by invoking:

cf local run toddler-auth

Running an application

The first staging period can take some time to download buildpacks and set things up. Once it completes, CF Local creates .cache files inside the application’s directory. Subsequent runs are faster.

Deploying Docker images into Cloud Foundry containers

Sometime in 2015, Cloud Foundry started to support Docker images by adopting the Open Containers Initiative (OCI) container execution interface. For more information on deploying a Docker image, have a look at the full documentation. Two of the most important tidbits are:

  • Only one exposed port per image is supported.
  • The exposed port is controlled by the EXPOSE directive in the Dockerfile.

While you can control the exposed port by other means outlined in the documentation, using the default exposed port is the easiest way to go. An example of using a Docker image is provided in toddler-auth’s manifest.yml:

---
applications:
- name: toddler-nats
  memory: 128M
  disk_quota: 256M
  docker:
    image: bitnami/nats:latest
  routes:
    - route: toddler-nats.apps.internal

In the above example, I am running an application named toddler-nats. It uses Bitnami’s nats.io image from Docker Hub and maps an internal route of:

toddler-nats.apps.internal

Sequencing applications startup

In the world of Docker Compose, Swarm, and Kubernetes, applications are started in parallel. The applications startup sequence is not controlled by the orchestrator. This can be annoying as you need to write extra Bash files and build in service availability detection.

On the contrary, in Cloud Foundry, if your manifest.yml contains multiple applications, Cloud Foundry applications are deployed in sequence during deployment from top to bottom. If any application in the chain fails, the entire deployment halts. This is great if you need to sequence the startup of multiple applications.

Configuring container-to-container networking

Before talking about container-to-container (C2C) networking, I just want to touch on why this was significant for my project.

I need TCP routing

My toddler application relies on a messaging service such as NATS as a communication transport between different microservices. NATS is a great alternative to HTTP. It has all of the nice features of a message queue like publish/subscribe, topic routing, very high throughput, and well-developed client libraries.

In mid-2016, Cloud Foundry rolled out support for TCP routing. According to the Cloud Foundry list routes documentation, if tcp is shown under type for any route, that route can be configured as a TCP route. Not all cloud providers, however, support this feature. For example, IBM Cloud does not.

Cloud Foundry domains

However, searching around reveals that you can set up a custom TCP port with C2C networking.

Setting up container-to-container networking

Setting up C2C networking is straightforward and disabled by default. To enable C2C between two applications, you first need both applications deployed. Then invoke:

cf add-network-policy $SOURCE_APP_NAME --destination-app $DEST_APP_NAME --port $PORT --protocol tcp

For my project, I needed to enable port 4222 from toddler-auth to toddler-nats. On my terminal, this was set up with:

cf add-network-policy toddler-auth --destination-app toddler-nats --port 4222 --protocol tcp

For toddler-auth talk to toddler-nats, I mapped an internal route on toddler-nats to be toddler-nats.apps.internal. Note that I did not have to add a network policy into CF Local when deploying the application locally.

Summary

To summarize, this article demonstrated some tools that can help you with:

  • Developing and testing locally with CF Local maps to build an image and test a deployment with docker-compose.
  • Configuring container-to-container networking maps to call services within a docker-compose file.
  • Running a Docker image inside a Cloud Foundry container.
  • Sequencing application startup.
Cong Nguyen