Paicku is a Node.js library and command-line application for containerizing applications with buildpacks. It is a wrapper around Cloud Native Buildpacks' pack CLI.
- Zero setup. Automatically downloads the official
packbinary on the first run. - Zero configuration. Automatically detects your running container daemon (Docker or Podman) based on the OS and configures it.
- End-to-End Testing. Allows you to build and run containers with Node.js, to write robust integration tests.
- TypeScript Ready. First-class TypeScript support with native type definitions included out of the box.
- Choose runtime. Allows you to specify which container runtime would like to use, just by specifying the corresponding argument.
You can install Paicku globally through npm, yarn, or pnpm. Alternatively, drop the global flag (global/-g) to use it in your Node.js project.
# npm
npm install -g paicku
# yarn
yarn global add paicku
# pnpm
pnpm add -g paickuWe officially support two interfaces for Paicku:
- Command-line application
- Node.js library - For general use in Node.js.
Containerizing an application
paicku build --path ./app
To use Paicku, ensure you've installed the dependency, then import the createPaicku function.
Here's a minimal example
import {createPaicku} from 'paicku'
const paicku = createPaicku()
console.log('Containerizing app...')
const image = await paicku.build({path: './app'})
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()Note: See paicku examples for complete scripts.
The CLI and Node.js library support the following topics
paicku build- Build an imagepaicku builder- Display suggested builders for the given applicationpaicku help- Display help for paicku.paicku inspect- Show information about a built app imagepaicku sbom- Interact with SBoM
import {expect} from 'chai'
import {after, before, describe, it} from 'mocha'
import {createPaicku} from 'paicku'
const appPath = './app'
const appPort = 8080
describe('Mocha, Chai and Paicku', function () {
this.timeout(600_000) // Give some time for the build to complete
const paicku = createPaicku()
let containerImage
let container
before(async () => {
containerImage = await paicku.build({
builder: 'docker.io/paketobuildpacks/builder-ubi8-base',
path: appPath,
})
})
after(async () => {
if (container) {
await container.stop()
}
})
it('should successfully build and run an app', async () => {
container = await containerImage.run({exposedPorts: appPort})
const response = await fetch(container.getUrl())
expect(response.status).to.equal(200)
})
})Important: Always pass exposedPorts when you need a URL, as there is no default port mapping.
You can optionally define a custom working directory or provide a local path to the pack executable if you prefer not to download the default one.
const paicku = createPaicku({
cwd: process.cwd(), // Optional: working directory for Paicku
executablePath: '/path/to/pack', // Optional: skips automatic download
})You can choose which container runtime you prefer [podman or docker]:
CLI:
paicku build my-app --container-runtime dockerNode.js:
const paicku = createPaicku()
const result = await paicku.build({
imageName: 'my-app',
path: './app',
'container-runtime': 'docker',
})CLI:
paicku build nodejs-noble-container-image \
--builder docker.io/paketobuildpacks/ubuntu-noble-builder \
--run-image docker.io/paketobuildpacks/ubuntu-noble-run-tiny \
--env BP_LAUNCH_WITH_TINI=trueNode.js:
const paicku = createPaicku()
const result = await paicku.build({
imageName: 'nodejs-noble-container-image',
builder: 'docker.io/paketobuildpacks/ubuntu-noble-builder',
'run-image': 'docker.io/paketobuildpacks/ubuntu-noble-run-tiny',
env: ['BP_LAUNCH_WITH_TINI=true'],
path: './app',
})Note: The builder must include a registry prefix (docker.io/, ghcr.io/, …).
Append :<subdirectory> to the Git URL when the app is not at the repository root.
CLI:
paicku build backend-image --path https://github.com/nodeshift/mern-workshop:backendNode.js:
const paicku = createPaicku()
const result = await paicku.build({
imageName: 'backend-image',
path: 'https://github.com/nodeshift/mern-workshop:backend',
})Inspect your application by using the inspect command
CLI:
paicku inspect my-containerized-app:latest --output jsonNode.js:
const paicku = createPaicku()
const result = await paicku.inspect('my-containerized-app:latest', {
output: 'json',
})
console.log(result.parsedStdout)CLI:
paicku builder suggestNode.js:
const paicku = createPaicku()
const result = await paicku.builder.suggest()
console.log(result.stdout)CLI:
paicku sbom download my-containerized-app:latest --output-dir ./sbomNode.js:
const paicku = createPaicku()
await paicku.sbom.download('my-containerized-app:latest', {
'output-dir': './sbom',
})Contributions are welcome, feel free to open an issue or a pull request.
npm installRun the CLI against source:
./bin/dev.js build test/integration/testdata/nodejs_simple_app --container-runtime podmanProduction mode needs a build first:
npm run build
./bin/run.jsRebuild after changing source.
npm run testIntegration tests (require Docker or Podman):
npm run integration:test:podman
npm run integration:test:dockerDebug unit tests (--timeout 0, useful with .only):
npm run unit:test:debugCoverage:
npm run test:report