Podman Desktop for Java Development

Install Podman Desktop for managing containers and learn how to use it for Java development (Spring Boot, Quarkus, Testcontainers, Buildpacks).

Cute seal on crystal clear water.

Podman is a solution to manage containers, pods, and images in a container or Kubernetes environment. It complies with OCI standards and can be used as an alternative to Docker.

Podman Desktop is a convenient GUI on top of Podman to simplify container management across different operating systems and runtimes, including Kubernetes.

Both Podman and Podman Desktop are fully open-source and free to use. They are part of a broader set of container tools backed by an active community and supported by Red Hat.

This article will show how to install Podman and Podman Desktop, and how to configure them to make them ready for Java development.

Installing Podman Desktop

Let's start by installing Podman and Podman Desktop. On macOS and Linux, you can use the Homebrew package manager.

brew install podman
brew install podman-desktop

On Windows, you can use the Winget package manager.

winget install -e --id RedHat.Podman
winget install -e --id RedHat.Podman-Desktop

For additional install options, check the project documentation.

After the installation is complete, open Podman Desktop. If you have Docker Desktop running, ensure you stop it before moving on.

Next, go to Settings > Resources and click the "Create new..." button to initialize a new Podman Machine, which will start a lightweight virtual machine with Linux and the Podman Engine installed.

Podman Desktop. From Settings > Resources, it's possible to create a new Podman Machine clicking the "Create new..." button.
💡
The Podman CLI provides the podman machine subcommands to create and manage Podman Machines. Podman Desktop is not required, but it simplifies and automates the process.

Leave the default name for the Podman Machine and configure CPU, memory, and disk space based on your needs.

Configuration settings in Podman Desktop to create a new Podman Machine. Name, CPU, memory, disk space.

Finally, click the "Run" button to start the Podman Machine you have just created.

You can start a Podman Machine from Podman Desktop (Settings > Resources).

Next time you start Podman Desktop, the Podman Machine you have configured will be automatically started. That's one of the advantages of using Podman Desktop.

Let's now verify that Podman is working correctly by running a container. We'll use one of the Chainguard Images ("hardened images with 0-known vulnerabilities, a minimal footprint, and SBOMs").

podman run --name demo-podman cgr.dev/chainguard/busybox echo Hello Podman!

The result should be the "Hello Podman!" message printed on the console. You can get more information about the container from Podman Desktop.

Podman Desktop. The "Containers" section shows a list of running and stopped containers.

Awesome! Podman Desktop is now correctly installed. Next, I'll show you how you can keep using the Docker and Docker Compose CLIs on top of Podman.

Using Docker and Docker Compose with Podman

The most used commands in the Docker CLI are also available in the Podman CLI. For most use cases, you can define an alias to replace docker commands with podman commands (for example, alias docker=podman).

However, you don't need to configure any alias with Podman Desktop as it provides compatibility with Docker out-of-the-box, which makes it possible to keep using the Docker and Docker Compose CLIs on top of Podman.

Let's try that out by running the same container image as before, but this time using the Docker CLI.

docker run --name demo-docker cgr.dev/chainguard/busybox echo Hello Podman!
💡
On macOS, depending on which version of Docker Desktop is installed on your machine, you might get the following error when using the Docker CLI on top of Podman: Cannot connect to the Docker daemon at unix:///Users/<user>/.docker/run/docker.sock. Is the docker daemon running?. In that case, make sure you switch to the default Docker context with docker context use default and try again. For more information why that is needed, check out the GitHub issues on the Podman and Podman Desktop projects where this issue is being addressed.

Even if using the Docker CLI, the container ran on Podman.

podman ps -a --format '{{ .Names }} {{ .Image }}'

The result should be similar to the following.

demo-podman cgr.dev/chainguard/busybox:latest
demo-docker cgr.dev/chainguard/busybox:latest

Similarly, you can keep using Docker Compose for running containers on Podman. Create a docker-compose.yml file with the following content.

services:
  postgres:
    image: "cgr.dev/chainguard/postgres:15"
    container_name: postgres
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=books

Then, use Docker Compose to run the PostgreSQL service on Podman.

docker compose up -d

Even if using Docker Compose, the container is running on Podman. You can check its logs with the following command.

podman logs postgres

Podman Desktop shows the status of the Docker and Docker Compose compatibility in Podman (bottom-left part of the console).

In the bottom-left side of the Podman Desktop GU, info is shown about the status of the Docker and Docker Compose compatibility in Podman.

The out-of-the-box compatibility layer works well with both the Docker and Docker Compose CLIs. The next section will cover how to extend the compatibility layer to cover more use cases when root permissions are required.

Configuring Podman as Rootful

Docker requires root privileges to run containers. On the other hand, Podman runs without root privileges by default for enhanced security. That means that tools like Cloud Native Buildpacks, Testcontainers, and Spring Boot Docker Compose will not work if Podman runs in rootless mode.

A Podman Machine can be configured to run either in rootless (the default) or rootful mode. Stop and delete the machine created earlier from the Podman Desktop GUI or the CLI.

podman machine stop
podman machine rm

We'll now create a new Podman Machine in rootful mode. Open Podman Desktop, go to Settings > Resources and click the "Create new..." button to initialize a new Podman Machine. Like before, leave the default name for the Podman Machine and configure CPU, memory, and disk space based on your needs. Additionally, ensure the "Machine with root privileges" setting is set to "Enabled".

Configuration settings in Podman Desktop to create a new Podman Machine in rootful mode. Name, CPU, memory, disk space.

Finally, in the Settings > Resources page, click the "Run" button to start the Podman Machine you have just created.

Let's verify that it works. We'll use Spring Boot as an example. First, check out the following Git repository.

git clone https://github.com/ThomasVitale/spring-tutorials.git
cd spring-boot-docker-compose

Since version 3.1, Spring Boot can automatically start and stop containers from a Docker Compose file when running an application in development.

./gradlew bootRun
💡
The application requires Java 20. If you don't have it installed, you can do so with SDKMAN!: sdk install java 20-tem.

As you can see from the application logs, Spring Boot uses the docker-compose.yml file included in the repository (spring-boot-docker-compose/docker-compose.yml) to start a PostgreSQL container as part of the application lifecycle. Since we configured the Docker compatibility layer in Podman, the container is run on Podman.

Let's now try the Cloud Native Buildpacks integration in Spring Boot, which also requires a Docker daemon. Stop the previous process (Ctrl-C) and then use the bootBuildImage task to containerize the application.

./gradlew bootBuildImage

The result will be an OCI image called book-service that you can run on any OCI-compliant runtime, including Podman, Docker, and Kubernetes.

Similarly, you can use the Cloud Native Buildpacks integration in Quarkus on top of Podman using the ./gradlew build -Dquarkus.container-image.build=true command.

Configuring Testcontainers for Podman

Running Testcontainers on Podman requires the rootful mode, but that's not enough. You must also update the ~/.testcontainers.properties file with the following line (or create the file if it doesn't exist yet).

ryuk.container.privileged=true

Let's give it a try with another Spring Boot example.

git clone https://github.com/ThomasVitale/spring-tutorials.git
cd spring-boot-testcontainers

The application relies on a PostgreSQL database and uses Testcontainers to run integration tests against an actual database instance as a container.

./gradlew test

Starting from Spring Boot 3.1, Testcontainers can also be used to launch a PostgreSQL container when running the application at development time. Let's verify that works, too.

./gradlew bootTestRun

As you can see from the application logs, Spring Boot uses the Testcontainers configuration (TestBookServiceApplication.java) to start a container as part of the application lifecycle. Since we configured the Docker compatibility layer in Podman, the container is run on Podman.

Similarly, the Testcontainers integration in Quarkus can now work on Podman, including for running tests and dev services.

Working with Podman Compose

As described in a previous section, you can keep using the Docker Compose CLI on top of Podman. If you prefer not to install additional CLIs from Docker, check out the Podman Compose project.

Podman Compose is an implementation of the Docker Compose specification based on Podman. On macOS and Linux, you can install Podman Compose from the Homebrew package manager. Check the project documentation for additional installation options.

brew install podman-compose

Create a podman-compose.yml file with the following content.

services:
  postgres:
    image: "cgr.dev/chainguard/postgres:15"
    container_name: postgres
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=books

Then, use Podman Compose to run the PostgreSQL service on Podman.

podman-compose up -d

You can verify the container is up and running via the Podman CLI.

podman ps

When you're done testing, you can bring the container down as follows.

podman-compose down

Conclusion

Podman Desktop is an excellent solution for managing containers across different runtimes (such as Podman, Docker, and Lima). The only feature I miss and that's currently being planned is support for a light mode in the GUI, which would make it more accessible to a wider audience (follow the issue on GitHub for status updates).

If you're migrating from Docker, I recommend checking the blog post 5 things to know about Podman Desktop for a Docker user on the Podman Desktop website.

In this article, I covered the features related to container management and configurations relevant for Java development, but Podman Desktop can do much more than that.

It provides convenient features to work with Kubernetes. For example, you can start a new local cluster with kind, including the Contour ingress controller and the possibility to expose all your Kubernetes services to your localhost automatically. And it can be extended via plugins. For example, you can run an OpenShift cluster with one single click.

Are you using Podman or Podman Desktop? What's your experience? I'd like to hear from you in the comments section!

Cover picture from Pexels.