There are a few concepts to keep in mind
- A builder. A builder consists of a stack and one or more groups of buildpacks.
- A stack is a base build and run image.
- A buildpack is an OCI image with at least two binaries,
detect
and build
.
- The lifecycle. The lifecycle responsible for running all of the builders.
With that in mind, at a high level this is what happens
When you run pack build
. The cli takes all your information and uses that to perform the build. To do a build, it will set up a container. The container uses the build image from your stack, which includes the groups of buildpacks from the builder, and usually some development libraries exclusive to that image to make building your app easier. It then passes off the settings you input via the cli and runs the lifecycle inside that container.
First, the lifecycle will run the detect
script from each buildpack. The output of detect
is a build plan, which the lifecycle uses to assemble the list of buildpacks that will participate in the build. This is how the pack
cli and ultimately the lifecycle can build a Java app, a Node.js app or anything else supported by buildpacks. The build plan provides specific instructions on which buildpacks are required to do that.
Second, the lifecycle will take the buildpacks that are participating in the build, again which is determined by detect
and the selected buildplan, and run them in order. Each buildpack then runs and performs the actions that are required to build your application. Exactly what happens, depends on your buildpack, but a buildpack can do virtually anything. The net result of a buildpack running is a set of layers that are populated with information & files.
The lifecycle then takes the run image from the builder and all the layers generated by the buildpacks that ran and marked as destined for the launch image and combines them into the output or launch image.
The lifecycle also handles storing build and cached layers such that subsequent builds will be able to take advantage and run much faster.
Dockerfiles or Buildpacks?
The answer is that it's not one or the other. Each tool is good for certain things and you should use the best tool for the job.
Buildpacks are targeting developers that have source code and wish to turn that into OCI images. Buildpacks eliminate the need to curate handcrafted, artisanal Dockerfiles for this task, freeing developers up to write more code and add value to their apps.
The buildpacks accomplish this by wrapping up the patterns and best practices for creating OCI images for each programming language into an encapsulated, well-tested, and easy-to-use to use tool.
Dockerfiles tend to be better suited for other tasks (i.e. not packaging up your application) such as making generic OS images or packing up servers like databases or message queues. In fact, Buildpacks use Dockerfiles to create the base build and run images that are part of the builder.