To package this image, we usually use Docker and write a Dockerfile describing what we need to install, the Runtime we want the code to run on, the dependencies, etc. Writing this Dockerfile can be fairly tedious for some devs, or maybe they're just lazy to learn how to write one. So today I'll introduce another tool that replaces Dockerfile: BUILDPACK
What is Buildpack?
BuildPack is a tool that helps us package an application from source code into a container Image, so the application can run on many different platforms: VM, Cloud, K8s, etc. — as long as they support running containers.
This tool eliminates having to write procedural files like a Dockerfile to build an image for each application. For applications with a similar, uncomplicated structure, buildpack can be easily applied across all of them.
Concepts in BuildPack
Let's go through the concepts used in buildpack — these concepts correspond to the components present in an image when they get built. For example, imagine the built image as a hamburger like in the image.
BuildPacks (the filling)
Buildpacks are the component that detects the language, libraries, and Runtime needed for your application to run.
A built image can be based on many different buildpacks, just like the layers in a hamburger (Layers).
Example:
When you want to build an image for a python application, buildpacks get added like:
- pip
- Procfile
- Cpython
- ...
Buildpacks analyze your source code — for example, if the code contains a Procfile file => matches a buildpack's condition => installs the Procfile Buildpack that supports running the application.
Similarly, when it detects a requirements.txt file => installs the pip buildpack to install dependencies
Buildpack consists of 2 processes: Detect and Build
- As explained above, Detect is like figuring out what you want in your hamburger (more meat less veggies, or more veggies less meat) to add accordingly
- The Build process is the process of actually making the burger from what was determined in the Detect process above. In practice this is the process of installing dependencies like pip install -r requirements.txt.
We'll see this process more clearly later, when we go through the process of building from source to image Learn more: buildpacks.io
Stack (the bun)
If buildpacks are like the filling, Stack is the bun that wraps around it. A Stack has 2 main components: Build Image and Run Image.
Exactly as the name suggests:
- Build image is the environment used to build the application image
- Run Image is the environment we'll run that application in
Just like choosing a bun, we can choose a thick bun (image full of libraries) or a thin bun (image with minimal libraries) to reduce the image size.
Learn more: buildpacks.io
Builders (the whole burger)
Finally, a builder is nothing but the whole burger, including both Stack and Buildpacks. Builder is the final packaged component you can use to run your source code on.
A Builder consists of:
- A list of BuildPacks
- A Stack
- CNB Lifecycle
A Builder is like a burger too — small, medium, large, to fit each person's needs.
Docs for building your own burger: buildpacks.io
Trying it out
Tools needed:
We'll use a ready-made builder from paketo.io to build an image for a Python application — here I'll choose the builder with the base tag, a medium-size version; there are also 2 other versions, tiny and full. Once you've installed the 2 tools above, go into the folder containing the source code and run the following command to build the image.
Source code repo: github.com/MMA17/Up-Download-Files-Auth-with-JWT-Token
pack build python-app --builder paketobuildpacks/builder:base
base: Pulling from paketobuildpacks/builder
Digest: sha256:13e72e425779b45c126941e0c5a9bc9edfd5d5c6ded064d3a00ef1706d7d7259
Status: Image is up to date for paketobuildpacks/builder:base
base-cnb: Pulling from paketobuildpacks/run
Digest: sha256:ef018536d42417d74d9e8532058d755492922e251949a918e7be371c9f4a5191
Status: Image is up to date for paketobuildpacks/run:base-cnb
Restoring data for SBOM from previous image
===> DETECTING
6 of 9 buildpacks participating
paketo-buildpacks/ca-certificates 3.2.4
paketo-buildpacks/cpython 1.0.1
paketo-buildpacks/pip 0.11.1
paketo-buildpacks/pip-install 0.4.2
paketo-buildpacks/python-start 0.10.0
paketo-buildpacks/procfile 5.1.2
===> RESTORING
Restoring metadata for "paketo-buildpacks/ca-certificates:helper" from app image
Restoring metadata for "paketo-buildpacks/cpython:cpython" from app image
Restoring metadata for "paketo-buildpacks/pip:pip" from cache
Restoring metadata for "paketo-buildpacks/pip-install:packages" from app image
Restoring metadata for "paketo-buildpacks/pip-install:cache" from cache
Restoring data for "paketo-buildpacks/cpython:cpython" from cache
Restoring data for "paketo-buildpacks/pip:pip" from cache
Restoring data for "paketo-buildpacks/pip-install:cache" from cache
Restoring data for "paketo-buildpacks/pip-install:packages" from cache
Restoring data for SBOM from cache
===> BUILDING
Paketo CA Certificates Buildpack 3.2.4
https://github.com/paketo-buildpacks/ca-certificates
Launch Helper: Reusing cached layer
Paketo CPython Buildpack 1.0.1
Resolving CPython version
Candidate version sources (in priority order):
-> ""
-> ""
Selected CPython version (using ): 3.9.13
Reusing cached layer /layers/paketo-buildpacks_cpython/cpython
Paketo Pip Buildpack 0.11.1
Resolving Pip version
Candidate version sources (in priority order):
-> ""
Selected Pip version (using ): 22.1.2
Reusing cached layer /layers/paketo-buildpacks_pip/pip
Paketo Pip Install Buildpack 0.4.2
Executing build process
Running 'pip install --requirement requirements.txt --exists-action=w --cache-dir=/layers/paketo-buildpacks_pip-install/cache --compile --user --disable-pip-version-check'
Completed in 2.624s
Generating SBOM for /layers/paketo-buildpacks_pip-install/packages
Completed in 41ms
Configuring build environment
PYTHONPATH -> "/layers/paketo-buildpacks_pip-install/packages/lib/python3.9/site-packages:$PYTHONPATH"
Configuring launch environment
PYTHONPATH -> "/layers/paketo-buildpacks_pip-install/packages/lib/python3.9/site-packages:$PYTHONPATH"
Paketo Python Start Buildpack 0.10.0
Assigning launch processes:
web (default): python
Paketo Procfile Buildpack 5.1.2
https://github.com/paketo-buildpacks/procfile
Process types:
web: python main.py
===> EXPORTING
Reusing layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/cpython:cpython'
Reusing layer 'paketo-buildpacks/pip-install:packages'
Adding layer 'launch.sbom'
Reusing 1/1 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Reusing 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 python-app...
*** Images (ddab9631519a):
python-app
Adding cache layer 'paketo-buildpacks/cpython:cpython'
Adding cache layer 'paketo-buildpacks/pip:pip'
Reusing cache layer 'paketo-buildpacks_pip-install/cache'
Reusing cache layer 'paketo-buildpacks/pip-install:packages'
Adding cache layer 'cache.sbom'
Successfully built image python-app
We can see the buildpacks installed are:
- paketo-buildpacks/ca-certificates 3.2.4
- paketo-buildpacks/cpython 1.0.1
- paketo-buildpacks/pip 0.11.1
- paketo-buildpacks/pip-install 0.4.2
- paketo-buildpacks/python-start 0.10.0
- paketo-buildpacks/procfile 5.1.2
These buildpacks got installed because our source code matched these buildpacks' conditions. To add another buildpack from outside, we can add --buildpack when running
pack build my-app --buildpack paketo-buildpacks/python \
--builder paketobuildpacks/builder:base
Typing docker images we'll see the python-app image — using docker run to launch the application on port 5000, we'll see it runs successfully.
Pros and cons
Pros:
- Quick to use
- Easy to apply for applications with a standard structure
- ...
Cons:
- Only works with applications using 1 language
- Requires defining certain specific files depending on the language
- The built image size is much larger compared to Dockerfile
- ...
Wrapping up
Maybe the reason BuildPack hasn't become widely used is that it isn't really flexible for cases with complex requirements, and the image size is fairly heavy compared to Dockerfile. Hope this post gives you another approach to solving a problem at work.
If you're running into technical challenges or need help with systems, DevOps tools, I'm confident I can help. Get in touch at hoangviet.io.vn
Thank you all! Have a nice day!