Skip to content

tiff-ritz/buildpacks-deb-packages

 
 

Repository files navigation

Heroku's .deb Packages Buildpack

CI Registry

heroku/deb-packages is a Heroku Cloud Native Buildpack that adds support for installing Debian packages required by an application that are not available in the build or run image used.

System dependencies on Debian distributions like Ubuntu are described by <package-name>.deb files. These are typically installed using CLI tools such as apt or dpkg. This buildpack implements logic to install packages from .deb files in a CNB-friendly manner that does not require root permissions or modifications to system files that could invalidate how CNB rebasing functionality works.

Important

This is a Cloud Native Buildpack, and is a component of the Heroku Cloud Native Buildpacks project, which is in preview. If you are instead looking for the Heroku Apt Buildpack (for use on the Heroku platform), you may find it here.

This buildpack is compatible with the following environments:

OS Arch Distro Name Distro Version
linux amd64 Ubuntu 24.04
linux arm64 Ubuntu 24.04
linux amd64 Ubuntu 22.04

Usage

Note

Before getting started, ensure you have the pack CLI installed. Installation instructions are available here.

To include this buildpack in your application:

pack build my-app --builder heroku/builder:24 --buildpack heroku/deb-packages

And then run the image:

docker run --rm -it my-app

Configuration

project.toml

The configuration for this buildpack must be added to the project descriptor file (project.toml) at the root of your project using the com.heroku.buildpacks.deb-packages table. The list of packages to install must be specified there. See below for the configuration schema and an example.

Configuring Environment Variables

You can configure environment variables for the packages installed by this buildpack by defining them in the project.toml file. The environment variables are specified under the env key for each package. There can be more than one environment variable defined for each package.

During the build process, the buildpack will read the project.toml file and apply the specified environment variables. The {install_dir} placeholder will be replaced with the actual paths so the variables are available at both build and launch phases using layer environment variables.

Default Package Environment Variables

The buildpack includes a set of default environment variables for each package, known as PACKAGE_ENV_VARS. These default environment variables are applied during the build process. However, you can override these default values by specifying environment variables in the project.toml file.

If a package is listed in the project.toml file with environment variables under the env key, those variables will take precedence over the default PACKAGE_ENV_VARS.

Executing Commands After Package Installation

You can specify commands to be executed after the installation of each package by defining them in the project.toml file under the commands key for each package. These commands will be executed in the order they are listed.

Environment Variables and Post-Install Commands for Skipped Packages

Even if a package is skipped, the environment variables and post-install commands defined for that package will still be applied and executed. This ensures that any necessary configuration or setup steps are performed, even if the package itself is not installed.

Example

# _.schema-version is required for the project descriptor
[_]
schema-version = "0.2"

# buildpack configuration goes here
[com.heroku.buildpacks.deb-packages]
install = [
  # basic package with some dependencies
  "libgwenhywfar79",
  # child package of "libgwenhywfar79" so we should get a warning that it was already installed by the previous entry
  "libgwenhywfar-data",
  # package with child dependencies skipped so no "libxmlsec1" or "libxmlsec1-openssl" will be installed
  { name = "xmlsec1", skip_dependencies = true },
  # a package already installed on the system
  "wget",
  # libvips is a virtual package which is only provided by libvips42 so no need to halt and ask the user which implementing package to install
  "libvips",
  # curl is already on the system so we're going to force it to be installed
  { name = "curl", force = true },
  # git needs to have environment variables set and post installation commands run
  { name = "git", env = {"GIT_EXEC_PATH" = "{install_dir}/usr/lib/git-core", "GIT_TEMPLATE_DIR" = "{install_dir}/usr/share/git-core/templates"}, commands = ["echo 'Git installed successfully'", "git --version"]},
]

Schema

  • com.heroku.buildpacks.deb-packages (table, optional)

    The root configuration for this buildpack.

    • install (array, optional)

      A list of one or more packages to install. Each package can be specified in either of the following formats:

      • (string)

        The name of the package to install.

          OR

      • (inline-table)
        • name (string, required)

          The name of the package to install.

        • skip_dependencies (boolean, optional, default = false)

          If set to true, no attempt will be made to install any dependencies of the given package.

        • force (boolean, optional, default = false)

          If set to true, the package will be installed even if it's already installed on the system.

        • env (inline-table, optional, default={})

          A table of environment variables to set for the package. The keys are the variable names and the values are the variable values. The {build_dir} placeholder can be used in the values and will be replaced with the actual build directory path.

        • commands (array, optional, default=[])

          A list of commands to execute after the package is installed. The commands will be executed in the order they are listed.

Tip

Users of the heroku-community/apt can migrate their Aptfile to the above configuration by adding a project.toml file with:

[_]
schema-version = "0.2"

[com.heroku.buildpacks.deb-packages]
install = [
  # copy the contents of your Aptfile here, e.g.;
  # "package-a",
  # "package-b",
  # "package-c"
]

If your Aptfile contains a package name that uses wildcards (e.g.; mysql-*) this must be replaced with the full list of matching package names.

Environment Variables

The following environment variables can be passed to the buildpack:

Name Value Default Description
BP_LOG_LEVEL INFO,
DEBUG
INFO Configures the verbosity of buildpack output. The DEBUG level is a superset of the INFO level.

How it works

Detection

This buildpack will pass detection if:

  • A project.toml file is found at the root of the application source directory

Build

Step 1: Build the package index

Each supported distro is configured to download from the following Ubuntu repositories:

  • main - Canonical-supported free and open-source software.
  • universe - Community-maintained free and open-source software.

These repositories comply with the Debian Repository Format so building the list of packages involves:

  • Downloading the Release file, validating its OpenPGP signature, and caching this in a layer available at build.
  • Finding and downloading the Package Index entry from the Release for the target architecture and caching this in a layer available at build.
  • Building an index of Package Name → (Repository URI, Binary Package) entries that can be used to lookup information about any packages requested for install.

Step 2: Determine the packages to install

For each package requested for install declared in the buildpack configuration:

  • Lookup the Binary Package in the Package Index.
  • Check if the requested package is already installed on the system
    • If it is already installed and the requested package is configured with force = false
      • Skip the package
  • If the requested package is configured with skip_dependencies = false:
    • Add the latest version of the requested package.
    • Read the dependencies listed in the Depends and Pre-Depends from the Binary Package.
    • For each dependency:
      • Recursively lookup the dependent package and follow the same steps outlined above until all transitive dependencies are added.
  • If the requested package is configured with skip_dependencies = true:
    • Add the latest version of the requested package.

Note

This buildpack is not meant to be a replacement for a fully-featured dependency manager like Apt. The simplistic dependency resolution strategy described above is for convenience, not accuracy. Any extra dependencies added are reported to the user during the build process so, if they aren't correct, you should disable the dependency resolution on a per-package basis with configuration and explicitly list out each package you need installed.

Step 3: Install packages

For each package added after determining the packages to install:

Environment Variable Appended Values Contents
PATH /<layer_dir>/bin
/<layer_dir>/usr/bin
/<layer_dir>/usr/sbin
binaries
LD_LIBRARY_PATH /<layer_dir>/usr/lib/<arch>
/<layer_dir>/usr/lib
/<layer_dir>/lib/<arch>
/<layer_dir>/lib
shared libraries
LIBRARY_PATH Same as LD_LIBRARY_PATH static libraries
INCLUDE_PATH /<layer_dir>/usr/include/<arch>
/<layer_dir>/usr/include
header files
CPATH Same as INCLUDE_PATH header files
CPPPATH Same as INCLUDE_PATH header files
PKG_CONFIG_PATH /<layer_dir>/usr/lib/<arch>/pkgconfig
/<layer_dir>/usr/lib/pkgconfig
pc files
GIT_EXEC_PATH /<layer_dir>/app/.apt/usr/lib/git-core git files

Contributing

Issues and pull requests are welcome. See our contributing guidelines if you would like to help.

Testing Locally

To test the project locally, follow these steps:

Prerequisites

Ensure you have the following installed:

  • Rust and Cargo: Installation Guide
  • Docker (if applicable for your tests)
  • cargo install libcnb-cargo

Building the Project

cargo build to build the project cargo test to run the automated tests cargo test --test integration_test to run integration tests cargo libcnb package builds an image of the buildpack that can be used with an application. The output of this command shows usage of the generated image.

About

Heroku's `.deb` Packages Cloud Native Buildpack.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Rust 98.1%
  • Shell 1.9%