devpack-for-spring has an option to automatically add the Rockcraft plugin to your application. You can read more about the plugin in the repository’s README. The plugin enables building different rocks (OCI compatible container images) for your project. Beyond packaging your project as a rock, you can also build more complex and interesting rocks. For example, a rock that encapsulates the entire build environment so it remains immutable and can be easily shared across your organisation.
We use multipass to manage our playground. You can also use Canonical workshop to create a playground or if you are feeling adventurous and have docker installed do it on your host. First, install multipass:
$ snap install multipass
Create a VM with enough resources:
$ multipass launch --memory 4G --disk 32G --cpus 2 --name devpack
Finally, enter the VM environment. Execute all subsequent commands inside this VM to keep your host environment unaltered:
$ multipass shell devpack
We need to install devpack-for-spring first. This guide requires at least version 1.4.4 which is at the time of writing available from the edge channel and will be promoted to stable soon, please check snap info output first:
$ snap info devpack-for-spring
name: devpack-for-spring
summary: Development tools for Spring® projects
publisher: Canonical✓
store-url: https://snapcraft.io/devpack-for-spring
license: Apache-2.0
description: |
Command line tool for developing and packaging Spring(R) projects.
Automates environment setup, build plugins configuration and offline
library management. Type devpack-for-spring help after installation to
start.
Snap documentation:
https://github.com/canonical/devpack-for-spring/blob/main/devpack-for-sprin
g/README.md
Spring is a trademark of Broadcom Inc. and/or its subsidiaries.
snap-id: osRAKvOvEInhp5g4UEEe9ZBszyVyO6DT
channels:
latest/stable: 1.3.3 2026-04-22 (233) 215MB classic
latest/candidate: ↑
latest/beta: ↑
latest/edge: 1.4.4 2026-08-20 (275) 219MB classic
Let’s install the packages using the following command:
$ sudo snap install devpack-for-spring --channel latest/edge --classic
Naturally, in order to use the Rockcraft plugin you need to have the Rockcraft tool installed. Since it’s a part of the pre-defined environment known to devpack-for-spring, we can use the tool itself to install required packages. Some configuration changes are required before we proceed with the installation, though.
WARNING: There is a known connectivity issue with LXD and Docker. To avoid this issue, enable IPv4 forwarding before installing Docker:
$ echo "net.ipv4.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.d/99-forwarding.conf $ sudo systemctl restart systemd-sysctl
By default, Docker requires root privileges. Grant your regular user account access to run Docker commands so devpack can push images to the local registry:
$ sudo addgroup --system docker
$ sudo adduser $USER docker
$ newgrp docker
Now we are ready to install the required tools with a single command:
$ devpack-for-spring setup --add rockcraft,docker,git
WARNING:
devpackwill pull the LXD automatically, but it is necessary to initialise LXD after installation. Otherwise the rock build process will fail unable to spawn a build environment:$ lxd init --auto
See Rockcraft tutorial: Setup your environment section for additional information about setting up the rockcraft tool and its dependencies.
Of course, we will also need OpenJDK 25, install it using apt for now (soon to be integrated properly):
$ sudo apt install openjdk-25-jdk -y
Finally, we need a Java project to experiment with. We will use the devpack-for-spring itself:
$ git clone --depth=1 https://github.com/canonical/devpack-for-spring-cli.git
$ cd devpack-for-spring-cli
If you want to keep working on the project you may want to omit --depth=1. We are experimenting in a throw away environment and it does not make much sense to pull the entire project history right now.
For an arbitrary project you can use devpack-for-spring init-plugin to create the local configuration. `devpack-for-spring` already comes with a plugin configuration, but the tool will detect its presence and do nothing. Actually, you do not need to do so unless you want to override something, but we are going to explore the internals. init-plugin creates “.devpack-for-spring/plugin-configuration.yaml”. You can move the YAML file anywhere and load that copy using SPRING_CLI_BUILD_COMMANDS_PLUGIN_CONFIGURATION environment variable when calling devpack-for-spring run. Peeking inside we can see that build-rock is the default task for both gradle and maven:
rockcraft:
gradle:
id: io.github.rockcrafters.rockcraft
[ ... ]
default-task: build-rock
[ ... ]
Let’s start with a smaller task creating rockcraft.yaml first. build-* will do it automatically, so there is no need to do so explicitly yet we want to look under the hood so we call run rockcraft create-rock:
$ devpack-for-spring run rockcraft create-rock
All the tasks available for Rockcraft plugin are:
- Building the application itself as an OCI container image:
- create-rock – Creates
rockcraft.yaml - build-rock – Builds rock image (default task as we saw in YAML)
- push-rock – Pushes rock to the local docker daemon
- create-rock – Creates
- Creating an OCI container image that includes entire build environment:
- create-build-rock – Creates build container
rockcraft.yaml - build-build-rock – Builds build rock image
- push-build-rock – Pushes build rock to the local docker daemon
- create-build-rock – Creates build container
- dependencies-export
You can always check those in .devpack-for-spring/plugin-configuration.yaml:
rockcraft:
gradle:
id: io.github.rockcrafters.rockcraft
[ ... ]
tasks:
create-rock: create-rock
build-rock: build-rock
create-build-rock: create-build-rock
build-build-rock: build-build-rock
push-rock: push-rock
push-build-rock: push-build-rock
Feel free to experiment with {create,build,push}-rock commands, but today we are going to focus on their *-build-rock counterparts today. *-rock commands will keep the final rock under build/rock and *-build-rock commands output to build/build-rock/rock.
Going back to create-rock-output, the rockcraft.yaml can be found under build/, you can take a look at what’s included.
At this stage it may be a good idea to run devpack-for-spring run dependencies. It stores project dependencies under build/build-rock/dependences/. By default, the task exports all resolvable configurations of the project and buildscript. See java-rockcraft-plugins docs for further details. It may take a while to resolve and download all dependencies. The task will be called automatically as a pre-requisite for *build-rock task, and you may want to run it separately.
Run run rockcraft push-build-rock (it builds a rock and publishes it locally, right now a bug makes build-build-rock and push-build-rock invocation less efficient than simple push-build-rock – to be fixed soon) and check local registry with docker images:
$ devpack-for-spring run rockcraft push-build-rock
[...]
$ docker images
The rock itself is located in the build/build-rock directory. If something fails, you should be able to launch the build manually from the .devpack-for-spring/devpack-for-spring-cli subdirectory. This is where the plugin keeps its own modified source tree.
Let’s clean up the current build environment and stop gradle daemon, we will not need it anymore:
$ ./gradlew clean
$ ./gradlew --stop
We are ready to launch the build process using the pre-packaged environment:
Hint: do not forget --rm when calling the build container, otherwise finished instances will linger and you will have to remove them explicitly looking at ps --all output.
$ docker run --rm -v $(pwd):$(pwd) --user $UID:$(id -g) --env PEBBLE=/tmp build-devpack-for-spring-cli:latest exec build $(pwd) --no-daemon bootJar
Note: container will keep gradle-related files in $PWD/.gradle, which is the root directory of your project.
Command line explanation:
--rmmake sure the instance is automatically removed when it is no longer running-v $(pwd):$(pwd)map the current directory at the same path--user $UID:$(id -g)run container using the IDs of the current user to ensure the produced files have correct permissions--env PEBBLE=/tmp`PEBBLE` environment variable sets Pebble’s configuration directory. See Pebble Environment Variables: PEBBLE. We essentially set an empty Pebble config here because we do not want it to intercept the control flow and need to provide a writable area for Pebble.build-devpack-for-spring-cli:latest– image name, usedocker imagesto see available optionsexec build $(pwd) --no-daemon bootJarinvoke the pre-packaged wrapper script (“build”) to launch gradle in the specified directory (“$(pwd)”) with supplied parameters (“–no-daemon bootJar”).
Now look under build/libs, a directory that did not exist before running the container because we removed it by calling ./gradlew clean:
$ ls -1 build/libs/*.jar
devpack-for-spring-cli-0.14.4.jar
$ java -jar build/libs/devpack-*[0-9].jar
DEVPACK-FOR-SPRING
type "help" to see the list of available commands
In non interactive mode, it expected to have at least one argument: the command to execute or the script file
Congratulations, you now have a self-contained build environment that you can share with your team. You can push it to a local shared registry and have your CI/CD boxed pull it to avoid fetching all dependencies every time.
When you are done experimenting with devpack-for-spring plugins, you can remove the multipass VM with the following command:
$ multipass delete --purge devpack
Additional publications about devpack-for-spring:
- Using devpack-for-spring for non-interactive development environment setup.
- Project repository and direct link to documentation.
- Java Rockcraft plugins repository.
- For updates on
devpack-for-springdevelopment, read Foundations Team updates on Discourse.