Technology6 min read

Use Paicku to containerize and test any app with buildpacks and Node.js

By · Published by Everything Blog

In short

Paicku simplifies this process by integrating with Cloud Native Buildpacks, making it easier to containerize Node.js applications with Node.js. Paicku acts as a wrapper around the Pack command, allowing you to run Pack directly from Node.js, enhancing your workflow. ### Using Paicku #### Prerequisites Node.js 20 or greater** Podman or Docker** A Node.js application** #### Installation and Usage To install Paicku globally: ```sh npm install -g paicku ``` For local development: ```sh npm install -D pa…

Key points

  • Paicku is essential for containerizing Node.js applications with Node.js.: Paicku is essential for containerizing Node.js applications with Node.js.
  • It simplifies the process of building and running container images.: It simplifies the process of building and running container images.
  • Paicku ensures consistency and portability across different environments.: Paicku ensures consistency and portability across different environments.

Containerizing applications is an important step in modern software development. It helps with consistency, portability, and reliability across different environments. The Paicku project helps you streamline the process of containerization and testing so you can be sure that your application works as expected during development and once it's been released.

Paicku is a command-line tool, as well as a Node.js library, that lets you containerize applications with Cloud Native Buildpacks. You can run Paicku from the command-line or from Node.js.

Paicku is a wrapper around the pack

command (the official interface for building container images with buildpacks).

Why use Paicku?

The name Paicku is a portmanteau of "pack" and "haiku", and it was chosen to reflect the simplicity of its results. Paicku exists to reduce setup, and to fit buildpacks into your Node.js workflow. Specifically, Paicku:

- Downloads the Pack CLI for your operating system (OS) and configures it

- Allows you to call Pack from Node.js, so you can write integration tests and run them in continuous integration and continuous delivery (CI/CD)

- Offers convenience with some additional features during build (for example, switching container-runtime)

Using Paicku

Paicku supports 2 interfaces:

- A command-line application

- A Node.js library, for JavaScript code that calls Paicku

To install and use Paicku, you must have:

- Node.js 20 or greater

- Podman or Docker

- A Node.js application (you can use the Paketo Buildpacks samples repository for testing)

Using the paicku command

You can install paicku

globally using npm

:

npm install -g paicku

If you're just testing it out, then you don't need to install Paicku globally because npx

downloads it and runs it for you.

Whether you've installed paicku

or you've decided to use npx paicku

, clone the samples repository to follow along with this article's example:

git clone https://github.com/paketo-buildpacks/samples

Build one of the available Node.js apps (replace npx paicku

with just paicku

if you've installed Paicku globally):

npx paicku build my-npm-app --path ./samples/nodejs/npm

You can omit the image name during paicku build

to let Paicku assign a random one. After a successful build, you get a message:

Successfully built image my-npm-app

Paicku doesn't require you to choose a builder. When no builder is defined, you get a warning in the build log telling you that paketobuildpacks/builder-ubi8-base

is being used by default:

Warning: You haven't specified a builder, using the default one: docker.io/paketobuildpacks/builder-ubi8-base

That image is based on the Red Hat Universal Base Image (UBI). For more information about UBI builders with Paketo, see Build applications with Paketo Buildpacks and Red Hat UBI container images

You can list available builders with the npx paicku builder suggest

command.

Now run the container image:

podman run -d --rm --name containerized-app -p 8080:8080 my-npm-app

Open a browser and navigate to localhost:8080

to see the Paketo logo, or send an HTTP request with curl

:

curl -i http://localhost:8080

HTTP/1.1 200 OK

[...]

<!DOCTYPE html>

<html>

<head>

<title>Powered By Paketo Buildpacks</title>

</head>

<body>

<img style="display: block; margin-left: auto; margin-right: auto; width: 50%;" src="https://paketo.io/images/paketo-logo-full-color.png"></img>

</body>

</html>

Stop and remove the container

podman stop containerized-app

As you might have noticed, Paicku detects whether Podman or Docker is available on your host, and configures Pack before each build, meaning you can skip the manual configuration instructions.

To explicitly choose a container runtime, use the --container-runtime

argument:

npx paicku build --container-runtime docker \

--path ./samples/nodejs/npm

Using paicku as a Node.js library

First, clone the sample repository:

git clone https://github.com/paketo-buildpacks/samples

Next, install the Paicku package as a development Node.js dependency:

cd samples/nodejs/npm

npm install -D paicku

Create a JavaScript file:

touch paicku-simple-example.mjs

Open the paicku-simple-example.mjs

and add this code:

import { createPaicku } from "paicku";

const paicku = createPaicku();

console.log("Containerizing the app...");

const image = await paicku.build({

path: ".",

builder: "docker.io/paketobuildpacks/builder-ubi8-base",

});

console.log("Starting container...");

const container = await image.run({ exposedPorts: 8080 });

const response = await fetch(container.getUrl());

console.log("Response status:", response.status);

console.log("Stopping and removing container...");

await container.stop();

In case you have 2 container runtimes available on your machine, use the containerRuntime

attribute on paicku.build

to specify which one you want to use. For example:

const image = await paicku.build({

path: ".",

builder: "docker.io/paketobuildpacks/builder-ubi8-base",

containerRuntime: "podman"

});

Run the file:

node ./paicku-simple-example.mjs

You receive a 200 response status, but if the build fails, a PaickuError

object prints the build failure. The script above containerizes the application with buildpacks and runs the image from Node.js.

The next section shows how to turn this into an integration test.

The power of Paicku as a Node.js library

Normally, writing integration tests for apps using buildpacks can require some extra effort. You must configure the machine, install dependencies, and provide code to handle the build process. Paicku wraps that work into an API for you.

To start writing integration tests with the Paicku API, first install the paicku

package as a project dependency and create a test file:

cd samples/nodejs/npm

npm install -D paicku

touch buildpacks-integration.test.mjs

Add the following code to the test file:

import test from "node:test";

import assert from "node:assert";

import { createPaicku } from "paicku";

const paicku = createPaicku();

test("Paicku should build and run an app", async () => {

const appPath = ".";

const appPort = 8080;

let container;

try {

const containerImage = await paicku.build({

builder: "docker.io/paketobuildpacks/builder-ubi8-base",

path: appPath,

});

container = await containerImage.run({ exposedPorts: appPort });

const url = new URL("/", container.getUrl()).toString();

const response = await fetch(url);

assert.strictEqual(

response.status,

200,

`Expected HTTP status 200, but got ${response.status}`,

);

} finally {

if (container) {

await container.stop();

}

}

});

Run the test:

node buildpacks-integration.test.mjs

In the event of a successful run, you see the following output:

✔ Paicku should build and run an app (108940.401392ms)

ℹ tests 1

ℹ suites 0

ℹ pass 1

ℹ fail 0

ℹ cancelled 0

ℹ skipped 0

ℹ todo 0

ℹ duration_ms 108943.317838

Buildpacks aren't limited to containerizing only Node.js applications. They support several languages, and so does Paicku. You can containerize a Java application, or any other app the builder supports.

To write an integration test for the samples/java/maven

application, change appPath

in buildpacks-integration.test.mjs

to point to the java/maven

project. Here's the relevant section, with the change:

test("Paicku should build and run an app", async () => {

const appPath = "../../java/maven";

const appPort = 8080;

let container;

Run the tests:

node buildpacks-integration.test.mjs

You've just containerized a Java application, and the only difference between the 2 tests is the directory they point to.

For more examples, see the Paicku examples repository.

Conclusion

In this article, I demonstrated a few of the conveniences that Paicku has to offer when it comes to configuring Pack CLI. You've also seen how the Paicku Node.js library allows you to call Paicku programmatically, and write integration tests not just for Node.js applications but for any language that a builder supports.

I hope you found this article useful, and in case you have any ideas or questions, feel free to open an issue or a PR on the Paicku project.

Until next time, happy building!

Original source: developers.redhat.com

Technology