Posts

How to create Java container images on a developer machine for other architectures

May 2, 2024
Dmitry Chuyko
12.7

Most software tools are targeted at the CPU architecture (and sometimes, the operating system) of the machine in use. A virtual machine is a viable solution if you want to build container images for an architecture different from the one you use for local development. 

With a virtual machine, you can create a container for x86_64 on an Apple Silicon mac. Or if you have ARM-based Graviton Linux instances in AWS, you can create a container for ARM on an x86 machine on Windows. Either way, a virtual machine is a great helper if you have to push an image to production urgently skipping the remote build systems.

In our previous guide, we installed a virtual machine on an M-series mac computer. In this article, we will look into building a container image for a Java application and running it inside Docker in a VM on an ARM-based mac. We will take Alpaquita Linux as a Linux distribution because it is not only a small OS for containers, it can be used for server development as well.

Create a virtual machine on macOS

We will use UTM as virtualization software for our macOS example. Refer to our previous guide to install it if you haven’t done it yet.

Before we proceed, we need to download an Alpaquita Linux VM image to use with our virtual machine. We provide special .qcow2 images suitable for UTM and other QEMU based VM managers so you don’t have to go through a lengthy configuration process. Go to Alpaquita Download Center, choose a musl-based .qcow2 bundle, and download it.

Open UTM, click Create a New Virtual Machine. In the next window, choose Emulate because we want to run Linux for a different architecture. Select Other and Skip ISO Boot.

Next, adjust the hardware settings. We allocated 8 GB of memory to our VM. Normally, a VM doesn’t need that much, but if we want to build native images, the process is very CPU demanding. We also allocated four cores: as a rule, you should give your VM half of the cores your machine utilizes.

Hardware settings

Next, specify the size of the drive for VM data. 10 GB should be enough.

After that, specify the path for a shared directory.

Verify the settings in the last window and press Save. Your new VM should be successfully created.

Created VM

We need to make some additional adjustments before running the virtual machine. Right click on the VM on the left-side panel and select Edit.

Here, go to System first to choose a CPU. Select Intel Core i7 9xx (Nehalem Core i7, IBRS update) in the drop-down menu.

Choosing CPU

Next, go to QEMU and unselect the UEFI Boot

Unselecting UEFI

The last thing to do is to create a new IDE Drive to boot our .qcow2 image.

Delete the IDE Drive that boots the ISO image, select New and specify the path to the Alpaquita Linux bundle.

Setting the IDE drive

That’s it! Run the Alpaquita VM. It will load quite rapidly thanks to the predefined settings. Finally, it will ask you to enter a login and password. Enter alpaquita for login and alpaquita for password.

An optional step is to enable access to the VM from macOS Terminal using SSH so that you can connect to the VM similar to other remote systems.

For that purpose, add the openssh package with the following command:

sudo apk add openssh-server

Start the service with

sudo service sshd start

To find out the IP address the virtual machine uses, run

ifconfig

The inet addr line contains the IP address you need.

Open the Terminal and run

ssh alpaquita@<ipaddress>

Where <ipaddress> is the IP you found in the config (in our case, the command was ssh [email protected]).

Enter login and password for alpaquita upon the prompt. You can now work with your VM from the Terminal!  

Enable directory sharing with a guest Linux

We will enable QEMU directory sharing by means of VirtFS. Alpaquita Linux supports 9pfs, but we need to add specific OS modules with

sudo apk add linux-lts-extra-modules

After that, let’s create a mount point with

sudo mkdir /mnt/host

Enable sharing with

sudo mount -t 9p -o trans=virtio share /mnt/host -oversion=9p2000.L

It is also possible to modify /etc/fstab and automatically mount the share on startup with the following command:

share /mnt/host 9p trans=virtio,version=9p2000.L,rw,_netdev,nofail 0 0

Finally, place the guest ownership into a file attribute to avoid the “access denied” error:

sudo chown -R alpaquita:alpaquita/mnt/host

Create a virtual machine on Windows

Running Linux on a Windows-based machine is extremely easy thanks to WSL, Windows Subsystem for Linux that enables the developers to work with Linux without setting up a separate virtual machine.

If you don’t have WSL installed, make sure that your Windows instance satisfies system requirements for WSL, and then run the following command in an administrator PowerShell or Windows Command Prompt:

wsl.exe --install

BellSoft provides a dedicated Alpaquita WSL installer for Alpaquita Linux. Go to Alpaquita Download Center and download the .appx package. After that, open the downloaded file and click Install in the Install Alpaquita window.

Alternatively, you can install Alpaquita using Windows PowerShell. For that purpose, run the following command specifying the path to the file:

Add-AppxPackage -Path "AppFilePath"

That’s it, you successfully installed Alpaquita in WSL! You can later start Alpaquita in Powershell using the following command with the distribution name:

wsl.exe -d Alpaquita-Glibc

No additional steps to enable directory sharing are required because you can access the local machine’s file system from within the Linux Bash shell: the local drives mounted under the /mnt folder.

Install JDK and Docker in the virtual machine

The next step is to install Java and Docker.

Alpaquita repository contains packages with various Liberica JDK versions, including the latest minor versions with the newest patches and fixes. Liberica JDK is recommended by Spring and is the default runtime in Spring buildpacks, so it is perfect for our Spring Boot example.

To install Java in the VM, run

sudo apk add liberica17-lite-jdk

This will install Liberica JDK Lite optimized for cloud. If you want to use another JDK version, run apk search liberica and select the necessary package from the list.

Next, install Docker with

sudo apk add docker docker-openrc

This will install Docker with OpenRC packages.

Start Docker with

sudo service docker start

Verify that docker has started with

docker --version
Docker version 25.0.3, build 4debf41

Now, we need to add a new user to the Docker service to manage it as a non-root user. For that purpose, run

sudo addgroup alpaquita docker

After adding a new user, we have to restart our VM. At this point, you can run the following command to automatically start the Docker service upon the VM start:

rc-update add docker

Restart the VM and login to it again. Repeat the steps with mounting the directory and starting the Docker service if necessary.

Build a container using buildpacks

We came right up to containerizing a Java application inside a VM!

We will use a Spring Petclinic demo application as an example so pull the project from the GitHub repository and move it to the shared directory. Go to the application directory from the Terminal where your VM is running.

To build a container using Paketo buildpacks, run the following command:

./mvnw -Dmaven.test.skip=true spring-boot:build-image

This command will skip the tests and build a container image of our application.

All you have to do now is wait: Maven will have to pull necessary dependencies into a local repository and then build the image. You can create a shared directory for .m2 to reuse the local Maven repository on your mac. This will accelerate the build process.

After the build is complete, verify the image was created with

docker images

You should see the information about the image on the list.

Run the container inside the virtual machine

The final touch is to run our container from the CM so that we can access it from the browser on the host system.

For that purpose, run

docker run --rm -it -p 8080:8080 [image-name]

Where [image-name] is the name of your image that was given to it automatically by Docker. The application will listen on the 8080 port.

We used an M1-based MacBook Air, and the application took 178 seconds to start. Don’t be surprised: emulation is a very resource-demanding process. If you use an M2- or M3-based mac, the process will be faster. 

Open your favorite browser and go to [VM-IP-address]:8080. You should see the following page:

Spring Petclinic home page

Congratulations, you have successfully built a Docker container image in the Linux VM!

If zou would like to get useful tips, recommendations, and tutorials on Java development and deployment, subscribe to our newsletter!

 

Subcribe to our newsletter

figure

Read the industry news, receive solutions to your problems, and find the ways to save money.

Further reading