{"id":61662,"date":"2021-05-21T17:15:33","date_gmt":"2021-05-21T14:15:33","guid":{"rendered":"https:\/\/www.altoros.com\/blog\/?p=61662"},"modified":"2021-06-09T15:40:41","modified_gmt":"2021-06-09T12:40:41","slug":"cloud-native-buildpacks-creating-custom-components","status":"publish","type":"post","link":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/","title":{"rendered":"Cloud Native Buildpacks: Creating a Stack for Custom Components"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-transparent ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#Why_create_custom_buildpack_components\" >Why create custom buildpack components?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#The_toolchain\" >The toolchain<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#The_stack\" >The stack<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#The_base_image\" >The base image<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#The_build_image\" >The build image<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#The_run_image\" >The run image<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#Building_the_images\" >Building the images<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#More_in_this_series\" >More in this series<\/a><\/li><\/ul><\/nav><\/div>\n<h3><span class=\"ez-toc-section\" id=\"Why_create_custom_buildpack_components\"><\/span>Why create custom buildpack components?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><a href=\"https:\/\/buildpacks.io\/docs\/\" rel=\"noopener noreferrer\" target=\"_blank\">Cloud Native Buildpacks<\/a> (CNB) provide a strong value proposition in terms of both industry trends and process advantages. In <a href=\"https:\/\/www.altoros.com\/blog\/streamlining-the-creation-of-docker-images-with-cloud-native-buildpacks\/\">the previous post<\/a>, we wrote how buildpacks help to streamline the creation of Docker images.<\/p>\n<p>While the community-provided framework <a href=\"https:\/\/github.com\/buildpacks\/samples\/\" rel=\"noopener noreferrer\" target=\"_blank\">components<\/a> are excellent, it\u2019s not always feasible or wise to rely entirely on third-party tools for builds. Third-party tools can change, vanish, or end support without warning. Security requirements may preclude pulling arbitrary images from the Internet or mandate everything be developed in-house.<\/p>\n<p>In addition to preventing potential problems, building your own components offers a number of advantages. Need to ensure every application image runs on the same base operating system with the same set of packages installed, or that your internal SSL certificates are present? Custom CNB components are a tidy way to accomplish that.<\/p>\n<p><center><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-components.png\"><img decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-components.png\" alt=\"\" width=\"580\" class=\"aligncenter size-full wp-image-61692\" \/><\/a><small>The stack&#8217;s place in the CNB process<\/small><\/center><\/p>\n<p>There are three major pieces to the CNB process. <b>Stacks<\/b> define the images for building and running the app. <b>Buildpacks<\/b> are tech stack\u2013specific and perform the application build. <b>Builders<\/b> combine stacks and buildpacks to create the fundamental CNB unit of work. In this tutorial, we get familiar with the CNB toolchain and create a stack. The upcoming two parts of this series will consume the stack during creation of a buildpack and builder. All of the code referenced here is available in <a href=\"https:\/\/github.com\/Altoros\/cn-buildpacks-example\/tree\/master\/cnb-components\" rel=\"noopener noreferrer\" target=\"_blank\">our GitHub repo<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_toolchain\"><\/span>The toolchain<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The Cloud Native Buildpack framework is very lightweight. It has only three requirements for use:<\/p>\n<ul>\n<li style=\"margin-bottom: 6px;\"><a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" rel=\"noopener noreferrer\" target=\"_blank\">The Docker runtime<\/a>.<\/li>\n<li style=\"margin-bottom: 6px;\"><a href=\"https:\/\/buildpacks.io\/docs\/tools\/pack\/\" rel=\"noopener noreferrer\" target=\"_blank\">The pack CLI tool<\/a> (or <a href=\"https:\/\/buildpacks.io\/docs\/tools\/kpack\/\" rel=\"noopener noreferrer\" target=\"_blank\">kpack<\/a> if the image building is done within a Kubernetes environment; the commands and features are the same).<\/li>\n<li style=\"margin-bottom: 6px;\">Components must adhere to the <a href=\"https:\/\/github.com\/buildpacks\/spec\" rel=\"noopener noreferrer\" target=\"_blank\">the CNB specification<\/a> (don\u2019t worry, it does not require reading).<\/li>\n<\/ul>\n<p>Both prerequisite tools are multiplatform, and the CNB outputs are Docker images at each step, making everything highly portable and cloud provider\u2013agnostic. Simply install Docker and pack, and you\u2019ll be ready to go!<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_stack\"><\/span>The stack<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A stack is simply a set of Docker images that get consumed by the CNB framework when building app images. The stack controls the environment for both running the app and the CNB build process. A stack has three parts: a <b>base<\/b> image, a <b>build<\/b> image, and a <b>run<\/b> image. The build and run images extend the base image. This is in line with the best practice principles of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Don%27t_repeat_yourself#:~:text=The%20DRY%20principle%20is%20stated,authoritative%20representation%20within%20a%20system%22.&#038;text=When%20the%20DRY%20principle%20is,in%20other%20logically%20unrelated%20elements.\" rel=\"noopener noreferrer\" target=\"_blank\">DRY<\/a>, as well as <a href=\"https:\/\/12factor.net\/\" rel=\"noopener noreferrer\" target=\"_blank\">twelve-factor<\/a> number five: separating the building and running of an app. The CNB build process happens within the build image, and the run image is used as the base for the final app image.<\/p>\n<p><center><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/creating-custom-components-for-cloud-native-buildpacks-the-stack.png\"><img decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/creating-custom-components-for-cloud-native-buildpacks-the-stack.png\" width=\"640\" class=\"aligncenter size-full wp-image-61694\" \/><\/a><small>The structure and use of the CNB stack<\/small><\/center><\/p>\n<p>Since all three pieces of the stack are related Docker images, this is an excellent scenario for <a href=\"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/\" rel=\"noopener noreferrer\" target=\"_blank\">Docker multistage builds<\/a>, allowing all three images to be cleanly defined in a single Dockerfile. All of the code comes from <a href=\"https:\/\/github.com\/Altoros\/cn-buildpacks-example\/blob\/master\/cnb-components\/stacks\/Dockerfile\" rel=\"noopener noreferrer\" target=\"_blank\">our example stack<\/a>. We\u2019ll go through it sequentially.<\/p>\n<p><center><a href=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-example.png\"><img decoding=\"async\" src=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-example.png\" width=\"300\" class=\"aligncenter size-full wp-image-61709\" \/><\/a><small>Stack-related files in the example repository<\/small><\/center><\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_base_image\"><\/span>The base image<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Exactly as you would expect from the name, a base image contains the underlying basic infrastructure and defines the layers common to both the build and run environments.<\/p>\n<p>The first line is straightforward for anyone familiar with Dockerfiles: <code style=\"color: black; background-color: #e6e6e6;\">FROM ubuntu:bionic as base<\/code>. This declares the definition of an image named <code style=\"color: black; background-color: #e6e6e6;\">base<\/code>, which runs Ubuntu\u2019s Bionic Beaver edition.<\/p>\n<p>Each stack needs an identifier. This is used by the CNB framework to determine compatibility among components, for example, matching the build and run images of a stack, or stack eligibility to use with a particular buildpack.<\/p>\n<pre style=\"padding-left: 20px;\">ENV CNB_STACK_ID=\"com.altoros.demo.cnb.stacks.ubuntu\"\r\nLABEL io.buildpacks.stack.id=\"com.altoros.demo.cnb.stacks.ubuntu\"<\/pre>\n<p>Defining both the environment variable and label is required. The CNB framework is configured by both environment variables and image labels. It uses the variables within executing containers and image labels in the host build environment. It\u2019s also important to make sure these have the same value. While the demo is hardcoded for simplicity, a good process improvement in a CI environment would be passing this value in as an <code style=\"color: black; background-color: #e6e6e6;\">ARG<\/code>.<\/p>\n<p>The CNB framework executes commands during image building as a specified user rather than the Docker default of root. In fact, it is expressly forbidden to use any root level user for CNB purposes. This improves the security and helps prevent permissions problems within the final application image.<\/p>\n<pre style=\"padding-left: 20px;\">ENV CNB_USER_ID=1000\r\nENV CNB_GROUP_ID=1000\r\nRUN groupadd cnb --gid ${CNB_GROUP_ID} && \\\r\n useradd --uid ${CNB_USER_ID} --gid ${CNB_GROUP_ID} -m -s \/bin\/bash cnb<\/pre>\n<p>The ID values themselves are not important, as long as they don\u2019t collide with any others.<\/p>\n<p>All the previous steps were required, but this one is optional: install any packages, files, or dependencies that should be available during both image building and app execution.<\/p>\n<pre style=\"padding-left: 20px;\">RUN apt-get update && \\\r\n  apt-get install -y xz-utils ca-certificates && \\\r\n  rm -rf \/var\/lib\/apt\/lists\/*<\/pre>\n<p>Here, we install the latest version of two core utility packages, then wipe the package manager\u2019s cache. Chaining these three commands together creates a single layer in the Docker image. Capturing the package manager output and leaving its cache in the final image is wasteful and unnecessary.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_build_image\"><\/span>The build image<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>So far, so good. Now, it\u2019s time to consume the base image just defined to produce the build image. This specifies the environment that the CNB build process executes in. To put it another way, the final app images will be built inside of a container running this build image. Docker-in-Docker sounds complex, but the CNB framework abstracts all of this away, so creating a build image is actually quite easy.<\/p>\n<p>Just as before, we start with defining a new image that extends another, base as previously defined in this case.<\/p>\n<pre style=\"padding-left: 20px;\">FROM base as build<\/pre>\n<p>Similarly, we also want to install packages that should be available during the CNB build process.<\/p>\n<pre style=\"padding-left: 20px;\">RUN apt-get update && \\\r\n  apt-get install -y git wget jq && \\\r\n  rm -rf \/var\/lib\/apt\/lists\/* && \\\r\n  wget https:\/\/github.com\/sclevine\/yj\/releases\/download\/v5.0.0\/yj-linux -O \/usr\/local\/bin\/yj && \\\r\n  chmod +x \/usr\/local\/bin\/yj<\/pre>\n<p>We will be using these packages later when creating a buildpack.<\/p>\n<p>Something that is optional is declaring the <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">mixin<\/code> packages, which the image provides. These are preinstalled operating system dependencies that the image guarantees as available. The CNB components have the ability to declare and check dependencies to ensure compatibility.<\/p>\n<pre style=\"padding-left: 20px;\">LABEL io.buildpacks.stack.mixins=\"[\\\"build:wget\\\", \\\"build:jq\\\", \\\"build:yj\\\"]\"<\/pre>\n<p>The value of this setting is a JSON list specifying the provided <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">mixin<\/code> package names. Prefixing the package with <code style=\"color: black; background-color: #e6e6e6;\">build:<\/code> or <code style=\"color: black; background-color: #e6e6e6;\">run:<\/code> specifies that the dependency is only available during that stage. No prefix means it is available at both build and run time. Here, we mark the three packages we&#8217;ve just installed as available at build time.<\/p>\n<p>Finally, we set the active user for the image employing the environment variables declared in the base image.<\/p>\n<pre style=\"padding-left: 20px;\">USER ${CNB_USER_ID}:${CNB_GROUP_ID}<\/pre>\n<p>It\u2019s important to do this after installing the additional packages to ensure the install succeeds.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The_run_image\"><\/span>The run image<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The counterpart to the build image, the run image is consumed by the CNB build process to host the built app. This is the base image that will end up being deployed to production.<\/p>\n<pre style=\"padding-left: 20px;\">FROM base as run\r\nUSER ${CNB_USER_ID}:${CNB_GROUP_ID}<\/pre>\n<p>In this case, our run image is exceedingly simple. We have no additional dependencies to add or <code style=\"color: #222222; background-color: #e6e6e6; padding: 1px 2px;\">mixins<\/code> to declare, so all that remains is to set an active user. Remember, we could not do so in the base image, because the build image needed to install additional dependencies, so this image definition is not superfluous.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Building_the_images\"><\/span>Building the images<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Now that we have defined the images comprising the stack, it\u2019s time to build them. From the same directory as the Dockerfile, run the command below.<\/p>\n<pre style=\"padding-left: 20px;\">docker build . -t altoros\/build-image:ubuntu --target build\r\ndocker build . -t altoros\/run-image:ubuntu --target run<\/pre>\n<p>This creates and tags both images using the <code style=\"color: black; background-color: #e6e6e6;\">--target<\/code> option to choose the appropriate stage. For convenience, the demo repository has a <a href=\"https:\/\/github.com\/Altoros\/cn-buildpacks-example\/blob\/master\/cnb-components\/create-images.sh\" rel=\"noopener noreferrer\" target=\"_blank\">script<\/a> that will build all the images at once.<\/p>\n<p>In a robust CI environment, these images should be published to the appropriate image repo, then pulled down as needed. However, for our purposes, the stack is finished and ready to be consumed by other CNB components.<\/p>\n<p>For full code samples, check out <a href=\"https:\/\/github.com\/Altoros\/cn-buildpacks-example\/tree\/master\/cnb-components\" rel=\"noopener noreferrer\" target=\"_blank\">this GitHub repository<\/a>.<\/p>\n<p>Creating a stack is very straightforward, and already we can see opportunities for improving the process and standardization when building application images. In the next blog post in this series, we\u2019ll create a buildpack based on this stack.<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"More_in_this_series\"><\/span>More in this series<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/streamlining-the-creation-of-docker-images-with-cloud-native-buildpacks\/\">Cloud Native Buildpacks: Streamlining the Creation of Docker Images<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-how-to-create-a-custom-buildpack\/\">Cloud Native Buildpacks: How to Create a Custom Buildpack<\/a><\/li>\n<li><a href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-how-to-create-a-custom-builder\/\">Cloud Native Buildpacks: How to Create a Custom Builder<\/a><\/li>\n<\/ul>\n<hr \/>\n<p><center><small>This post is written by <a href=\"https:\/\/github.com\/mikebeaverson\" rel=\"noopener noreferrer\" target=\"_blank\">Michael Beaverson<\/a>, edited by <a href=\"https:\/\/www.altoros.com\/blog\/author\/sophie.turol\/\">Sophia Turol<\/a> and <a href=\"https:\/\/www.altoros.com\/blog\/author\/alex\/\">Alex Khizhniak<\/a>.<\/small><\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why create custom buildpack components?<\/p>\n<p>Cloud Native Buildpacks (CNB) provide a strong value proposition in terms of both industry trends and process advantages. In the previous post, we wrote how buildpacks help to streamline the creation of Docker images.<\/p>\n<p>While the community-provided framework components are excellent, it\u2019s not always feasible or wise [&#8230;]<\/p>\n","protected":false},"author":194,"featured_media":61704,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[214],"tags":[873,912],"class_list":["post-61662","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-cloud-native","tag-kubernetes"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros<\/title>\n<meta name=\"description\" content=\"With code samples, this tutorial demonstrates how to create a CNB stack including the base, build, and run images.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros\" \/>\n<meta property=\"og:description\" content=\"Why create custom buildpack components? Cloud Native Buildpacks (CNB) provide a strong value proposition in terms of both industry trends and process advantages. In the previous post, we wrote how buildpacks help to streamline the creation of Docker images. While the community-provided framework components are excellent, it\u2019s not always feasible or wise [...]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/\" \/>\n<meta property=\"og:site_name\" content=\"Altoros\" \/>\n<meta property=\"article:published_time\" content=\"2021-05-21T14:15:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-06-09T12:40:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"554\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/gif\" \/>\n<meta name=\"author\" content=\"Michael Beaverson\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michael Beaverson\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/\",\"name\":\"Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros\",\"isPartOf\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif\",\"datePublished\":\"2021-05-21T14:15:33+00:00\",\"dateModified\":\"2021-06-09T12:40:41+00:00\",\"author\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/b11121ca2e84b84615c416bbef10f7cc\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif\",\"width\":1024,\"height\":554},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.altoros.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cloud Native Buildpacks: Creating a Stack for Custom Components\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#website\",\"url\":\"https:\/\/www.altoros.com\/blog\/\",\"name\":\"Altoros\",\"description\":\"Insight\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.altoros.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/b11121ca2e84b84615c416bbef10f7cc\",\"name\":\"Michael Beaverson\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/06\/Michael-Beaverson-96x96.jpg\",\"contentUrl\":\"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/06\/Michael-Beaverson-96x96.jpg\",\"caption\":\"Michael Beaverson\"},\"description\":\"Michael Beaverson is Cloud Architect at Altoros. He has a proven track record in working with teams, both as a member and as a technical lead, across end-to-end development of full-stack applications. Mike is an active contributor on Stack Overflow and other Stack Exchange sites, where he reads, reviews, and answers questions, keeping him up-to-date on current technologies.\",\"url\":\"https:\/\/www.altoros.com\/blog\/author\/m-beaverson\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros","description":"With code samples, this tutorial demonstrates how to create a CNB stack including the base, build, and run images.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/","og_locale":"en_US","og_type":"article","og_title":"Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros","og_description":"Why create custom buildpack components? Cloud Native Buildpacks (CNB) provide a strong value proposition in terms of both industry trends and process advantages. In the previous post, we wrote how buildpacks help to streamline the creation of Docker images. While the community-provided framework components are excellent, it\u2019s not always feasible or wise [...]","og_url":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/","og_site_name":"Altoros","article_published_time":"2021-05-21T14:15:33+00:00","article_modified_time":"2021-06-09T12:40:41+00:00","og_image":[{"width":1024,"height":554,"url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif","type":"image\/gif"}],"author":"Michael Beaverson","twitter_misc":{"Written by":"Michael Beaverson","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/","url":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/","name":"Cloud Native Buildpacks: Creating a Stack for Custom Components | Altoros","isPartOf":{"@id":"https:\/\/www.altoros.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage"},"image":{"@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage"},"thumbnailUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif","datePublished":"2021-05-21T14:15:33+00:00","dateModified":"2021-06-09T12:40:41+00:00","author":{"@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/b11121ca2e84b84615c416bbef10f7cc"},"breadcrumb":{"@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#primaryimage","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/05\/cloud-native-buildpacks-part-1-creating-custom-components.gif","width":1024,"height":554},{"@type":"BreadcrumbList","@id":"https:\/\/www.altoros.com\/blog\/cloud-native-buildpacks-creating-custom-components\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.altoros.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Cloud Native Buildpacks: Creating a Stack for Custom Components"}]},{"@type":"WebSite","@id":"https:\/\/www.altoros.com\/blog\/#website","url":"https:\/\/www.altoros.com\/blog\/","name":"Altoros","description":"Insight","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.altoros.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/b11121ca2e84b84615c416bbef10f7cc","name":"Michael Beaverson","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.altoros.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/06\/Michael-Beaverson-96x96.jpg","contentUrl":"https:\/\/www.altoros.com\/blog\/wp-content\/uploads\/2021\/06\/Michael-Beaverson-96x96.jpg","caption":"Michael Beaverson"},"description":"Michael Beaverson is Cloud Architect at Altoros. He has a proven track record in working with teams, both as a member and as a technical lead, across end-to-end development of full-stack applications. Mike is an active contributor on Stack Overflow and other Stack Exchange sites, where he reads, reviews, and answers questions, keeping him up-to-date on current technologies.","url":"https:\/\/www.altoros.com\/blog\/author\/m-beaverson\/"}]}},"_links":{"self":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/61662","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/users\/194"}],"replies":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/comments?post=61662"}],"version-history":[{"count":50,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/61662\/revisions"}],"predecessor-version":[{"id":62020,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/posts\/61662\/revisions\/62020"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media\/61704"}],"wp:attachment":[{"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/media?parent=61662"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/categories?post=61662"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.altoros.com\/blog\/wp-json\/wp\/v2\/tags?post=61662"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}