@arvindkgsArvind Kumar GS
Passionate software developer, Linux enthusiast, clean code crusader, DIY advocate, Tech Evangelist
Docker is a containerization technology that allows an application to run in an isolated environment while being bundled with all the dependencies it needs to run. So it provides a standard way to run applications in a server agnostic manner.
It also provides an easy way to build, distribute and maintain your application artifacts.
The basic flow is:
- Create your application on local/dev environment. Run and test.
- Compose a docker file, that contains instructions to build images.
a. This contains a list of instructions that defines a base image and copying and extracting the executables of the app and setting environment variables and running the specific executable programming
- Push images to docker registry.
a. This can be a private registry or dockerhub
- Pull images and deploy on a container runtime.
a. Pulling images and running can be done manually, or can be managed by an orchestrator like Kubernetes
If you see above steps, step 2, which is creating a docker file is not standardized, as developers can create images with arbitrary base image and without proper versioning. Also docker file cannot be shared across organization as reusable modules.
But there are higher order tools that address these drawbacks, namely Buildpacks.
Buildpacks is tool that provide a modular way of adding arbitrary content and behavior into an image, while ensuring its manageable, auditable, repeatable and reliable.
Buildpacks build docker images without needing to compose a docker file. It utilizes a builder which uses the best practices to build the image, (the builders are maintained by third party providers like Packeto which is built by Heroku and Cloud Foundry). Buildpacks allows developers to not worry about setting up the runtime environment. It also provides features like inspecting of built images and patching only certain layers of built images with ability to permeate through out the images in an organization. This is useful for security fixes.
While Docker files are used by a lot of companies to create docker images and is the de-facto, there are higher level tools like Buildpack which address the limitations of Docker files namely sharing best practices of building docker images as modules across organizations, meaning no standard way to build images.
Buildpacks have 4 parts:
- Tool: pack, is the cli that is used to interact with Buildpack ecosystem.
- Buildpacks – Generally packaged into a builder. The builder will include image for build environment and image for run environment, include logic that you generally write in Docker file to correctly unpack and setup the runtime environment for your application on the container.
It has templates for setting up the runtime environment for applications written in Java, GoLang, NodeJS, DotNet etc. It provides a standard way to version your dependencies. It hides the setup part of the container from the developer, so they can focus on business logic. This is similar in comparison to Paas vs Iaas. Paas is provided by buildpacks vs Iaas is what is provided by plain Docker file. You will need to setup your runtime environment on Iaas.
- Lifecycle: It does the job of the docker daemon. It builds the required docker image utilizing the buildpacks. It also has features like caching, it also detects the underlying application for which the image is being created and pulls specific buildpacks.
- Builder: Repository from which buildpacks are pulled, similar to Maven Central.
To create a docker image:
pack build $IMG_NS/$APPLICATION_NAME:$TAG [options]
$IMG_NS – Image namespace on your docker registry/dockerhub
$APPLICATION_NAME – name of docker image
$TAG – Version of image
--no-pull - If you already have pulled the builder earlier --publish - do docker push
If you use Spring Boot >= 2.3, you can use the maven/gradle plugin to call buildpacks directly, to build docker image containing Spring Boot app. It is as simple.
In Maven :
$ ./mvnw spring-boot:build-image
OR in Gradle :
$ ./gradlew bootBuildImage