Skip to content

Instantly share code, notes, and snippets.

@pauldougan
Last active June 23, 2022 12:02
Show Gist options
  • Save pauldougan/286dcc9fb019646de40449005555e2ae to your computer and use it in GitHub Desktop.
Save pauldougan/286dcc9fb019646de40449005555e2ae to your computer and use it in GitHub Desktop.
cnb and cf

Cloud Native buildpacks and Cloud Foundry

Introduction

Cloud Foundry supports two models for running applications in containers:

  1. Cloud Foundry Buildpacks
  2. Cloud Foundry Docker support

Some tenants prefer one of the other and others mix and match.

The CFF have a vision of replatforming Cloud Foundry onto a kubernetes stack.

The project for this work is called Korifi, it is in early development ([v0.1.0]) and is overseen by the [CFF cf on k8s working group].

The traditional container build components of Cloud Foundry are being replaced with kubernetes components, namely:

Paketo buildpacks are a new modular approach to the buildpack concept and is an evolution of the work done in the CLoud Foundry and Heroku communities.

Originally created by Heroku (part of Salesforce) the concept forked into a couple of dialects. CNCF buildpacks is standardising the approach and unbundling it from the PaaS platforms where it traditionally lived. More platforms are appearing that support cloud native buildpacks.

CNCF Buildpacks schematic

Korifi will only support the new cloud native buildpack model and will not be backwardly compatible with the traditional buildpacks.

In addition there will be no native support for cloud native buildpacks in the traditional Cloud Foundry stack (based on BOSH)

This means that a tenant cannot specify a new cloud native buildpack as part of a cf push command to the current version of Cloud Foundry.

There will be replacements for the familiar buildpacks however there may be some differences. (note it needs a couple of environment variables)

CF on BOSH CF on k8s
Classic buildpacks yes no
Cloud Native buildpacks no yes

How to use cloud native buildpacks with GOV.UK PaaS

Since the pack tool can create container images from source locally without any dependencies on Cloud Foundry it is possible to do the following:

  • create a container image using the pack command
  • upload the container image to a container registry (Dockerhub, GitHub Container Registry or any other registry that you want. ECR, GCP, harbor, quay.io)
  • deploy the container image to a Cloud Foundry using the Docker support in cf push -o

This will work with both:

  • GOV.UK PaaS
  • a Korifi Cloud Foundry on Kubernetes cluster running locally

For this example we will use the GOV.UK Prototype kit from alphagov/govuk-prototype-kit as our sample app. You can git clone https://github.com/alphagov/govuk-prototype-kit

You can also install the pack command with

brew install buildpacks/tap/pack

Containerise the GOV.UK Prototype kit with cloud native buildpacks

pack build govuk-prototype-kit

full: Pulling from paketobuildpacks/builder
Digest: sha256:a1b349cb32d9cfb7c634b35aacdcaa42892275ced21f01f2238592573a8f838a
Status: Image is up to date for paketobuildpacks/builder:full
full-cnb: Pulling from paketobuildpacks/run
Digest: sha256:5c8332799698b02c78ac151feed0827e6d6b1f84ed91a9ba04827d96306a7ec7
Status: Image is up to date for paketobuildpacks/run:full-cnb

Previous image with name "govuk-prototype-kit" not found
===> DETECTING
7 of 11 buildpacks participating
paketo-buildpacks/ca-certificates 3.1.0
paketo-buildpacks/node-engine     0.12.3
paketo-buildpacks/npm-install     0.9.0
paketo-buildpacks/node-module-bom 0.2.4
paketo-buildpacks/node-start      0.8.0
paketo-buildpacks/npm-start       0.9.0
paketo-buildpacks/procfile        5.1.0
===> RESTORING
Restoring metadata for "paketo-buildpacks/node-module-bom:cyclonedx-node-module" from cache
Restoring data for "paketo-buildpacks/node-module-bom:cyclonedx-node-module" from cache
Restoring data for SBOM from cache
===> BUILDING

Paketo CA Certificates Buildpack 3.1.0
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
Paketo Node Engine Buildpack 0.12.3
  Resolving Node Engine version
    Candidate version sources (in priority order):
      package.json -> ">=10.0.0 <15.0.0"
      .nvmrc       -> "14.15.1"
      <unknown>    -> ""

    Selected Node Engine version (using package.json): 14.19.1

  Executing build process
    Installing Node Engine 14.19.1
      Completed in 4.531s

  Generating SBOM for directory /layers/paketo-buildpacks_node-engine/node
      Completed in 0s

  Configuring build environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/paketo-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

  Configuring launch environment
    NODE_ENV     -> "production"
    NODE_HOME    -> "/layers/paketo-buildpacks_node-engine/node"
    NODE_VERBOSE -> "false"

    Writing exec.d/0-optimize-memory
      Calculates available memory based on container limits at launch time.
      Made available in the MEMORY_AVAILABLE environment variable.

Paketo NPM Install Buildpack 0.9.0
  Resolving installation process
    Process inputs:
      node_modules      -> "Found"
      npm-cache         -> "Not found"
      package-lock.json -> "Not found"

    Selected NPM build process: 'npm rebuild'

  Executing launch environment install process
    Running 'npm run-script preinstall --if-present'
    Running 'npm rebuild --nodedir=/layers/paketo-buildpacks_node-engine/node'
    Running 'npm run-script postinstall --if-present'
      Completed in 26.375s

  Configuring launch environment
    NPM_CONFIG_LOGLEVEL -> "error"
    PATH                -> "$PATH:/layers/paketo-buildpacks_npm-install/launch-modules/node_modules/.bin"

  Generating SBOM for directory /layers/paketo-buildpacks_npm-install/launch-modules
      Completed in 29.383s


Paketo Node Module Bill of Materials Generator Buildpack 0.2.4
  Resolving CycloneDX Node.js Module version
    Selected CycloneDX Node.js Module version: 3.0.7

  Reusing cached layer /layers/paketo-buildpacks_node-module-bom/cyclonedx-node-module

  Configuring environment
    Appending CycloneDX Node.js Module onto PATH

  Running CycloneDX Node.js Module
    Running 'cyclonedx-bom -o bom.json'
      Completed in 6.727s

Paketo Node Start Buildpack 0.8.0
  Assigning launch processes:
    web (default): node server.js

Paketo NPM Start Buildpack 0.9.0
  Assigning launch processes:
    web (default): bash -c node start.js


Paketo Procfile Buildpack 5.1.0
  https://github.com/paketo-buildpacks/procfile
  Process types:
    web: node ./node_modules/gulp/bin/gulp generate-assets && node listen-on-port.js
===> EXPORTING
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/node-engine:node'
Adding layer 'paketo-buildpacks/npm-install:launch-modules'
Adding layer 'launch.sbom'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving govuk-prototype-kit...
*** Images (676f0d0101e4):
      govuk-prototype-kit
Reusing cache layer 'paketo-buildpacks/node-engine:node'
Reusing cache layer 'paketo-buildpacks/node-module-bom:cyclonedx-node-module'
Adding cache layer 'cache.sbom'
Successfully built image govuk-prototype-kit

pack inspect govuk-prototype-kit

Inspecting image: govuk-prototype-kit

REMOTE:
(not present)

LOCAL:

Stack: io.buildpacks.stacks.bionic

Base Image:
  Reference: a193a611aa391847f2c8fcdc0e6dd39fb6f6ec4dddba92924ab26e59ed6325d9
  Top Layer: sha256:595a12e83a3e7f8d46663adf8b7af56e69098a994bf6e718134d0e8827071054

Run Images:
  index.docker.io/paketobuildpacks/run:full-cnb
  gcr.io/paketo-buildpacks/run:full-cnb

Buildpacks:
  ID                                       VERSION        HOMEPAGE
  paketo-buildpacks/ca-certificates        3.1.0          https://github.com/paketo-buildpacks/ca-certificates
  gcr.io/paketo-buildpacks/run:full-cnb

Buildpacks:
  ID                                       VERSION        HOMEPAGE
  paketo-buildpacks/ca-certificates        3.1.0          https://github.com/paketo-buildpacks/ca-certificates
  paketo-buildpacks/node-engine            0.12.3         https://github.com/paketo-buildpacks/node-engine
  paketo-buildpacks/npm-install            0.9.0          https://github.com/paketo-buildpacks/npm-install
  paketo-buildpacks/node-module-bom        0.2.4          https://github.com/paketo-buildpacks/node-module-bom
  paketo-buildpacks/node-start             0.8.0          https://github.com/paketo-buildpacks/node-start
  paketo-buildpacks/npm-start              0.9.0          https://github.com/paketo-buildpacks/npm-start
  paketo-buildpacks/procfile               5.1.0          https://github.com/paketo-buildpacks/procfile

Processes:
  TYPE                 SHELL        COMMAND                                                                            ARGS        WORK DIR
  web (default)        bash         node ./node_modules/gulp/bin/gulp generate-assets && node listen-on-port.js                    /workspace

docker images | grep govuk-prototype-kit

govuk-prototype-kit                      latest                                 676f0d0101e4   42 years ago   957M

docker tag 676f0d0101e4 ghcr.io/pauldougan/govuk-prototype-kit

Assumes you are set up to push to GitHub container registery, see configuration instructions

docker push

docker push ghcr.io/pauldougan/govuk-prototype-kit
Using default tag: latest
The push refers to repository [ghcr.io/pauldougan/govuk-prototype-kit]
83d85471d9f8: Mounted from pauldougan/python-flask
4769a67a4c53: Pushed
9497805c7bd5: Mounted from pauldougan/python-flask
95a4eb25570c: Pushed
5da05bec2e97: Pushed
28d1a8f81e24: Pushing [==================================================>]  153.3MB
09a8b1e6c657: Pushing [===================================>               ]  76.86MB/106.9MB
7a5c55250641: Pushed
595a12e83a3e: Pushed
ed561ffcdffe: Pushing [==========>                                        ]    131MB/627.1MB
cfb1c0cbebeb: Pushed

open https://ghcr.io/pauldougan/govuk-prototype-kit

or go to https://ghcr.io/pauldougan/govuk-prototype-kit

Deploying the cloud native container image to GOV.UK PaaS

cf api

API endpoint:   https://api.london.cloud.service.gov.uk
API version:    3.116.0

cf login --sso

API endpoint: https://api.london.cloud.service.gov.uk

Temporary Authentication Code ( Get one at https://login.london.cloud.service.gov.uk/passcode ):
Authenticating...
OK


Select an org:
There are too many options to display; please type in the name.

Org (enter to skip): gds-techarchs
Targeted org gds-techarchs.

Select a space:

1. sandbox
2. paul

Space (enter to skip): 1
Targeted space sandbox.

API endpoint:   https://api.london.cloud.service.gov.uk
API version:    3.116.0
user:           104206899246339571570
org:            gds-techarchs
space:          sandbox

cf push -o ghcr.io/pauldougan/govuk-prototype-kit -m 128M -k 1G --no-manifest --no-start govuk-prototype-kit-paketo

name:              govuk-prototype-kit-paketo
requested state:   stopped
routes:            govuk-prototype-kit-paketo.london.cloudapps.digital
last uploaded:
stack:
docker image:

type:           web
sidecars:
instances:      0/1
memory usage:   128M
     state   since                  cpu    memory   disk     details
#0   down    2022-06-23T11:01:37Z   0.0%   0 of 0   0 of 0

cf set-env govuk-prototype-kit-paketo USERNAME user

cf set-env govuk-prototype-kit-paketo USERNAME user
Setting env variable USERNAME for app govuk-prototype-kit-paketo in org gds-techarchs / space sandbox as 104206899246339571570...
OK

TIP: Use 'cf restage govuk-prototype-kit-paketo' to ensure your env variable changes take effect.
GDS11172:govuk-prototype-kit

cf set-env govuk-prototype-kit-paketo PASSWORD password
Setting env variable PASSWORD for app govuk-prototype-kit-paketo in org gds-techarchs / space sandbox as 104206899246339571570...
OK

TIP: Use 'cf restage govuk-prototype-kit-paketo' to ensure your env variable changes take effect.

cf env govuk-prototype-kit-paketo

Getting env variables for app govuk-prototype-kit-paketo in org gds-techarchs / space sandbox as 104206899246339571570...
System-Provided:
VCAP_SERVICES: {}


VCAP_APPLICATION: {
  "application_id": "d7cb4d80-6746-4a7d-b5b0-4f3ca14181c4",
  "application_name": "govuk-prototype-kit-paketo",
  "application_uris": [
    "govuk-prototype-kit-paketo.london.cloudapps.digital"
  ],
  "cf_api": "https://api.london.cloud.service.gov.uk",
  "limits": {
    "fds": 16384
  },
  "name": "govuk-prototype-kit-paketo",
  "organization_id": "7d8b1665-815a-4500-a8d7-f1ac0a61150f",
  "organization_name": "gds-techarchs",
  "space_id": "0b52392e-e1c3-43e1-84bc-7024bf61715f",
  "space_name": "sandbox",
  "uris": [
    "govuk-prototype-kit-paketo.london.cloudapps.digital"
  ],
  "users": null
}


User-Provided:
PASSWORD: password
USERNAME: user

No running env variables have been set

No staging env variables have been set

cf start

Starting app govuk-prototype-kit-paketo in org gds-techarchs / space sandbox as 104206899246339571570...

Staging app and tracing logs...
   Cell 6617ab70-812f-454b-bff1-71a21515d135 creating container for instance ab96e02b-17e2-4a18-874d-d5cb17be255a
   Cell 6617ab70-812f-454b-bff1-71a21515d135 successfully created container for instance ab96e02b-17e2-4a18-874d-d5cb17be255a

Starting app govuk-prototype-kit-paketo in org gds-techarchs / space sandbox as 104206899246339571570...

Waiting for app to start...

Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...
Instances starting...

name:              govuk-prototype-kit-paketo
requested state:   started
routes:            govuk-prototype-kit-paketo.london.cloudapps.digital
last uploaded:     Thu 23 Jun 12:03:57 BST 2022
stack:
docker image:      ghcr.io/pauldougan/govuk-prototype-kit:latest

type:           web
sidecars:
instances:      1/1
memory usage:   128M
     state     since                  cpu    memory          disk           details
#0   running   2022-06-23T11:04:36Z   0.0%   30.4M of 128M   916.8M of 1G

cf ssh

cf ssh govuk-prototype-kit-paketo
cnb@b4bc4b08-56bf-47aa-62eb-abc2:~$
top
KiB Swap: 32407548 total, 31376380 free,  1031168 used. 23655736 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
      1 root      20   0    1044      4      0 S   0.0  0.0   0:00.02 garden-init
      7 cnb       20   0  716108  10616   8516 S   0.0  0.0   0:00.14 diego-sshd
      8 cnb       20   0  642128  57748  33164 S   0.0  0.2   0:01.10 node
     44 root      20   0    4632    856    792 S   0.0  0.0   0:00.03 sh
     90 root      20   0 2300508  50700  35892 S   0.0  0.2   0:00.86 envoy
    143 root      20   0  706000   3424   2804 S   0.0  0.0   0:00.04 healthcheck
    178 cnb       20   0   20184   3816   3476 S   0.0  0.0   0:00.00 bash
    188 cnb       20   0   40368   3700   3212 R   0.0  0.0   0:00.00 top


open https://govuk-prototype-kit-paketo.london.cloudapps.digital

or visit https://govuk-prototype-kit-paketo.london.cloudapps.digital/

using user and password when prompted

Deploying a cloud native container image to a local korifi cluster

assumes you have a local cluster installed, see pauls notes on korifi for some help getting it installed.

TLDR; assuming you have cf, docker, kind and kubectl

./scripts/deploy-on-kind.sh -d -l cf wait 7 minutes

`cf api``

API endpoint:   https://localhost
API version:    3.117.0+cf-k8s

cf login -o demo-org -s sandbox

API endpoint: https://localhost

1. cf-admin
2. kind-cf

Choose your Kubernetes authentication info (enter to skip): 1

Authenticating...
OK

Targeted org demo-org.

Targeted space sandbox.

API endpoint:   https://localhost
API version:    3.117.0+cf-k8s
user:           cf-admin
org:            demo-org
space:          sandbox

not the -o is not currently supported so we will use the inbuilt paketo-buildpacks

cf push --no-start --random-route -m 128M -k 1G --no-manifest govuk-prototype-kit-paketo

cf set-env govuk-prototype-kit-paketo USERNAME user

Setting env variable USERNAME for app govuk-prototype-kit-paketo in org demo-org / space sandbox as cf-admin...
OK

TIP: Use 'cf restage govuk-prototype-kit-paketo' to ensure your env variable changes take effect.
GDS11172:govuk-prototype-kit pauldougan$ cf set-env govuk-prototype-kit-paketo PASSWORD password
Setting env variable PASSWORD for app govuk-prototype-kit-paketo in org demo-org / space sandbox as cf-admin...
OK

TIP: Use 'cf restage govuk-prototype-kit-paketo' to ensure your env variable changes take effect.

cf start govuk-prototype-kit-paketo

cf apps

curl

kubectl get cfapps -A

Closing comments

This demonstrates that tenants could start using Cloud Native Buildpacks now and help future proof their applicaions. Targetting CNB would prepare for:

  • a migration to a CF on k8s enviroment based on Korifi and ensure that the apps are compatible
  • a migration to another container hosting platform that supports OCI compatible images which may or may not be k8s based
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment