<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joe Kutner</title>
    <description>The latest articles on DEV Community by Joe Kutner (@jkutner).</description>
    <link>https://dev.to/jkutner</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F981469%2Fe4016b6e-6b7f-4d19-b3a0-44e72f0dc02a.jpeg</url>
      <title>DEV Community: Joe Kutner</title>
      <link>https://dev.to/jkutner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jkutner"/>
    <language>en</language>
    <item>
      <title>12 Things You Might Not Know About Buildpacks</title>
      <dc:creator>Joe Kutner</dc:creator>
      <pubDate>Thu, 01 Dec 2022 13:53:16 +0000</pubDate>
      <link>https://dev.to/jkutner/12-things-you-might-not-know-about-buildpacks-1jhg</link>
      <guid>https://dev.to/jkutner/12-things-you-might-not-know-about-buildpacks-1jhg</guid>
      <description>&lt;p&gt;For most buildpack users, the only thing you need to know is that running &lt;code&gt;pack build&lt;/code&gt; will turn your source code into a Docker image. But the power of buildpacks goes far beyond this initial experience. Buildpacks also provide powerful features that no other image building tool can match. Let's take a look at a few of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use metadata from a previous build
&lt;/h2&gt;

&lt;p&gt;A buildpack can analyze information about layers it created during a previous build. For buildpack authors, this can aid in optimizing build performance by skipping steps if a buildpack determines something hasn't changed.&lt;/p&gt;

&lt;p&gt;For example, it's common to store a checksum of a dependency in the metadata of a build layer, and then compare it to the latest version in the next build. If they match, the buildpack may skip installing that dependency and instead reuse the exact same layer from the previous build. This avoids the costly overhead of downloading large layers and moving them around unnecessarily. &lt;/p&gt;

&lt;p&gt;Effectively, this means a buildpack can construct a new image from both existing layers and new layers in any order.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frycmfna1q57znpjg0hxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frycmfna1q57znpjg0hxd.png" alt="Layer construction" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information on buildpack layer caching, see the documentation on &lt;a href="https://buildpacks.io/docs/buildpack-author-guide/caching-strategies/#layers" rel="noopener noreferrer"&gt;buildpack layer types&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Update the operating system without re-building
&lt;/h2&gt;

&lt;p&gt;Buildpacks allow you to rapidly update an image when its base image (i.e operating system) has changed. This process is called rebasing, and it avoids the need to fully rebuild the app when a new operating system or base image becomes available.&lt;/p&gt;

&lt;p&gt;Consider an image &lt;code&gt;my-app:latest&lt;/code&gt; that was originally built using the latest version of a base image, &lt;code&gt;pack/run:latest&lt;/code&gt;. Running the following will update those layers of &lt;code&gt;my-app:latest&lt;/code&gt; with the latest version of &lt;code&gt;pack/run:latest&lt;/code&gt; without rebuilding the app layers above them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pack rebase my-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoiding rebuilds is a nice performance boost for a single image, but for a fleet of hundreds (or even millions) of images, it becomes a critical operational and security tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Write Buildpacks in any language
&lt;/h2&gt;

&lt;p&gt;Not everyone needs to write a buildpack. Most people just use the Paketo, Heroku, or Google buildpacks. But for those who need to create one from scratch, they're able to choose any language they want.&lt;/p&gt;

&lt;p&gt;The buildpack API defines its entry-points only as executables. That means the executable can be a Python script, a Bash script, or a binary compiled from Golang code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97cut5dkjw9utbcsrr9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97cut5dkjw9utbcsrr9g.png" alt="Language logos" width="600" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Paketo Buildpacks are mostly written in Go, while the Heroku buildpacks are written in Bash and &lt;a href="https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-engine/src/main.rs" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;. The &lt;a href="https://github.com/buildpacks/libcnb" rel="noopener noreferrer"&gt;libcnb&lt;/a&gt; library is a Go language binding of the Cloud Native Buildpacks API. It's supported by the project, but there are also libraries outside of the project like &lt;a href="https://github.com/jkutner/libcnb.bash" rel="noopener noreferrer"&gt;libcnb.bash&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add buildpacks inline with your source code
&lt;/h2&gt;

&lt;p&gt;You can create a buildpack in your source code repo very similarly to how you might drop in a &lt;code&gt;Dockerfile&lt;/code&gt;. To do so, create a &lt;code&gt;project.toml&lt;/code&gt; file and define your buildpack commands inline.&lt;/p&gt;

&lt;p&gt;For example, if you wanted run a Bash script as part of your build, your &lt;code&gt;project.toml&lt;/code&gt; would include something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[build.buildpacks]]&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"me/setup-tasks"&lt;/span&gt;

  &lt;span class="nn"&gt;[build.buildpacks.script]&lt;/span&gt;
  &lt;span class="py"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.8"&lt;/span&gt;
  &lt;span class="py"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"bash setup.sh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information, see the &lt;a href="https://buildpacks.io/docs/app-developer-guide/using-inline-buildpacks/" rel="noopener noreferrer"&gt;inline buildpacks documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Create images from scratch
&lt;/h2&gt;

&lt;p&gt;Buildpacks can build images that have no underlying base layers, just as if you were using &lt;code&gt;FROM scratch&lt;/code&gt;. Most of the off-the-shelf buildpacks from Paketo and Heroku don't do this because they rely on the operating system they run on, but when creating your own buildpacks it is possible with a custom base image. The &lt;code&gt;Dockerfile&lt;/code&gt; for such a base image can be as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM scratch
ENV CNB_USER_ID=1000
ENV CNB_GROUP_ID=1000
LABEL io.buildpacks.stack.id="my-scratch-img"
USER ${CNB_USER_ID}:${CNB_GROUP_ID}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a more robust but still slim image, try the &lt;a href="https://github.com/paketo-buildpacks/jammy-tiny-stack" rel="noopener noreferrer"&gt;Paketo "tiny" base image&lt;/a&gt;. For more information on using custom base images see the documentation on &lt;a href="https://buildpacks.io/docs/concepts/components/stack/" rel="noopener noreferrer"&gt;stacks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Use the Pack CLI as a library
&lt;/h2&gt;

&lt;p&gt;The Pack CLI (i.e. &lt;code&gt;pack&lt;/code&gt;) is a great tool for using buildpacks. But many end users want to bake these capabilities directly into some other tooling. Fortunately, &lt;code&gt;pack&lt;/code&gt; is also a Golang library. You can include it in other Go based projects by simply running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/buildpacks/pack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry, this is a completely supported pattern. In fact, many of the organizations contributing to the project, including Salesforce, do this very thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Compose buildpacks with other buildpacks
&lt;/h2&gt;

&lt;p&gt;Most advanced buildpacks aren't actually a single buildpack, but instead a composite of several buildpacks that each do smaller jobs. For example, the &lt;a href="https://github.com/heroku/buildpacks-nodejs/blob/main/meta-buildpacks/nodejs/buildpack.toml" rel="noopener noreferrer"&gt;Heroku Node.js buildpack&lt;/a&gt; is actually a collection of several NPM and Node engine buildpacks. Here's an excerpt from its &lt;code&gt;buildpack.toml&lt;/code&gt; descriptor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[order.group]]&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"heroku/nodejs-engine"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.8.12"&lt;/span&gt;

&lt;span class="nn"&gt;[[order.group]]&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"heroku/nodejs-npm"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.5.2"&lt;/span&gt;

&lt;span class="nn"&gt;[[order.group]]&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"heroku/procfile"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2.0.0"&lt;/span&gt;
&lt;span class="py"&gt;optional&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This composability makes it much easier for buildpack authors to reuse buildpacks, and allows end users to leverage them in unexpected ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Create a standardized SBOM
&lt;/h2&gt;

&lt;p&gt;A Software-Bill-of-Materials (SBOM) lists all the software components included in an image. Buildpacks support SBOMs in &lt;a href="https://cyclonedx.org/" rel="noopener noreferrer"&gt;CycloneDX&lt;/a&gt;, &lt;a href="https://github.com/anchore/syft" rel="noopener noreferrer"&gt;Syft&lt;/a&gt; and &lt;a href="https://spdx.dev/" rel="noopener noreferrer"&gt;SPDX&lt;/a&gt; formats.&lt;/p&gt;

&lt;p&gt;Each buildpack can populate the SBOM with the information about the dependencies they have provided. And end users can view that metadata with the Pack CLI by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pack sbom download your-image-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information see the &lt;a href="https://buildpacks.io/docs/features/bill-of-materials/" rel="noopener noreferrer"&gt;buildpacks documentation on SBOM&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Use buildpacks without Docker installed
&lt;/h2&gt;

&lt;p&gt;Pack uses the Docker API to run containerized builds and create runnable OCI images, which means it works equally well with a &lt;a href="https://docs.docker.com/engine/security/protect-access/" rel="noopener noreferrer"&gt;secure remote daemon&lt;/a&gt; as it does with a local daemon. Using a remote daemon looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tcp://daemon-hostname:2376
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_CERT_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.docker/
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_TLS_VERIFY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

pack build my-app &lt;span class="nt"&gt;--path&lt;/span&gt; ./my-source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information on how to do this, see our past blog post &lt;a href="https://medium.com/buildpacks/pack-with-a-remote-docker-daemon-41aab804b839" rel="noopener noreferrer"&gt;using Pack with a remote Docker daemon&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Create reproducible builds
&lt;/h2&gt;

&lt;p&gt;Given a set of inputs (source code, dependencies, etc) a buildpack can produce an image with the exact same digest (i.e. the same checksum of everything it contains) as an image from a previous build.&lt;/p&gt;

&lt;p&gt;Reproducible builds aren't something that happens by default; each buildpack needs to be smart enough to compare the layers it creates to the metadata from previous builds. But the buildpacks API makes it possible for discerning users.&lt;/p&gt;

&lt;p&gt;With something like Dockerfile, reproducible builds are effectively impossible because even a change to the timestamp of a file will give you a new image digest. This is why buildpacks produce images that appear to be created &lt;a href="https://medium.com/buildpacks/time-travel-with-pack-e0efd8bf05db" rel="noopener noreferrer"&gt;40 years ago&lt;/a&gt; (you can use the &lt;code&gt;--creation-time&lt;/code&gt; flag if you don't want this feature).&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Run buildpacks with Github Actions
&lt;/h2&gt;

&lt;p&gt;The Buildpacks project maintains a set of &lt;a href="https://github.com/buildpacks/github-actions" rel="noopener noreferrer"&gt;github-actions&lt;/a&gt; that can be used for various buildpack related tasks. Among these is the ability to set up a job that is ready with the pack CLI. It's as simple as using this action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;buildpacks/github-actions/setup-pack@v4.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here, you can run pack to build images, create builders, inspect SBOM metadata, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Use buildpacks with a Dockerfile
&lt;/h2&gt;

&lt;p&gt;Ok, I'm cheating here because this might not be ready when I publish this blog post. Very soon, you'll be able to provide a &lt;code&gt;Dockerfile&lt;/code&gt; in your buildpack build in order to customize the build process.&lt;/p&gt;

&lt;p&gt;For more information, see the finalized RFC on &lt;a href="https://github.com/buildpacks/rfcs/blob/main/text/0105-dockerfiles.md" rel="noopener noreferrer"&gt;supporting Dockerfiles&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
