Thumbnail image

Hello Buildpacks, goodbye Dockerfiles

I might be late to the party, but recently I learned about Buildpacks.io and what they can do vs Dockerfiles, and I just had to try it out.

If you never heard about Buildpacks, then it’s a way to package your application into a container, without using Dockerfiles.

The benefits can be

  • More secure images.
  • Faster upgrades of your applications
  • Easier to maintain images

And many more.

But it requires your application, to be fit for it. You can read more about this on Buildpacks.io, and it’s too big a topic, for me to cover it here.

Instead I will show how I created my first Buildpack app, and how I integrated it with Github Actions, for auto builds, because you have to automate it - Right ?

The Github Repo with all the code I mention, can be found here : https://github.com/rhjensen79/buildpacks-first-app

Feel free to use it as reference, if you want to try it out yourself.

All you need to create your container, if you are running Python, is the following files :

  • app.py
  • requirements.txt
  • Procfile

app.py consists of a few lines of code, that basicly imports Streamlit, and creates a Headline and a table. It’s not pretty, but it works for my purpose.

import streamlit as st
import pandas as pd

st.title('My first app')

st.write("Here's our first attempt at using data to create a table:")
st.write(pd.DataFrame({
    'first column': [1, 2, 3, 4],
    'second column': [10, 20, 30, 40]
}))

requirements.txt tells Buildpacks what to install, for the app to work (Note this is not the full file, listed below)

altair==4.1.0
appnope==0.1.2
argon2-cffi==21.1.0
astor==0.8.1
attrs==21.2.0
backcall==0.2.0
...

Procfile tells that it’s a Web app, and what process to start at runtime.

In this case, it runs the setup.sh and Streamlit.

web: sh setup.sh && streamlit run app.py

The purpose of the setup.sh file, is just to setup some Streamlit configurations in the container. So it only specific to my app, and not Buildpacks in general.

Now all there is left, is to build the container. I wanted to use github Actions for this, so I created a .github/workflows/master.yml file containing all the steps.

name: Deploy

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a set of commands using the runners shell
      - name: Pre requisites
        run: |
          echo add buildpack repo and install
          sudo add-apt-repository ppa:cncf-buildpacks/pack-cli
          sudo apt-get update
          sudo apt-get install pack-cli -y
          echo set pack builder
          pack config default-builder heroku/buildpacks:20
          echo Docker Registry login
          docker login -u ${{ secrets.DOCKER_HUB_USER }} -p ${{ secrets.DOCKER_HUB_PASSWORD }} ${{ secrets.REGISTRY }}

      # Runs a set of commands using the runners shell
      - name: Build
        run: |
          echo Build container
          pack build ${{ secrets.REGISTRY }}/cmplab/first-app:${{ github.run_id }}
          echo Push container to registry
          docker push ${{ secrets.REGISTRY }}/cmplab/first-app:${{ github.run_id }}

It requires 3 secrets in your repo :

  • DOCKER_HUB_USER
  • DOCKER_HUB_PASSWORD
  • REGISTRY

to be able to login and push your container after build. But once you get this, then it auto builds, on every push. actions In my setup, it takes less than 3 minutes, to execute.

The echo part of the script, should explain what every part of the job does, so I won’t cover it in details here.

The versioning is based on the run_id variable. There might be better ways of doing this, but it works fine in my usecase.

After it’s build, and pushed, my Harbor registry, does security scans on it. So this is something to consider, for extra security.

Harbor

To test the image, simply run

docker run -p 80:80 registry.cmplab.dk:443/cmplab/first-app@sha256:4873acdd3b3c00f7735eead784f9b531f1501d990e38abf53e389bc0ca0cf9c5

And open http://localhost:80 to see the app Harbor

Note that the version, needs to be correct, as well as your registry url, for this to work. The above example, only works for the specific version, that might not be available, when you read this.

This concludes my quick getting started guide. Thanks for reading this far.

Photo by Kelly Sikkema on Unsplash