Knowasiak
Java Train on an Apple M1 – A One Year Review

Java Train on an Apple M1 – A One Year Review

Hello reader! Welcome, let's start-

It has been nearly a 300 and sixty five days since I’ve sold the MacBook Devoted M1 (arm64 processor) for my day to day Java building as a contract advisor. I had my first contact with the Apple M1 when one amongst my route students raised an effort that the originate doesn’t pass on Apple’s fresh flagship notebook computer. I became first shy to stumble upon hardware incompatibilities in 2021. To solve those complications (no longer my primary intent, but I told myself so) and ride if that processor is on the total that snappily, I made a decision to buy the MacBook Devoted.

This text will share my preliminary pitfalls when working with the Apple M1 and a series of friendly methods and workarounds for developing and sorting out Java capabilities.

Cowl: At some level of this article, both arm64 or aarch64 consult with the Apple M1 chip. I will consult with the passe Intel/AMD processors as x64  (it’s most likely you’ll per chance presumably salvage the next synonyms: x86_64, amd64).

Installing Java Train Tools

The primary ingredient we install as Java developers on a brand fresh machine is a JDK. While browsing for a arm64 successfully matched JDK abet in 2021, the Azul Zulu JDK originate popped Up first.

There’s no incompatibility within the set Up route of of a JDK in comparison to an x64 Mac. When we have downloaded and installed a successfully matched JDK originate, we possess now the baseline for our Java building for our Apple M1:

java version

openjdk version “17” 20210914 LTS

OpenJDK Runtime Atmosphere Zulu17.28+13CA (originate 17+35LTS)

OpenJDK 64Bit Server VM Zulu17.28+13CA (originate 17+35LTS, blended mode, sharing)

In its place of the Azul Zulu JDK, many diversified JDK distributors possess adopted and now provide an arm64 originate:

The brew system for openjdk is furthermore inserting in a successfully matched Apple M1 JDK originate. For managing diversified Java variations, sdkman or jEnv is a ideal likelihood.

With Apple’s Rosetta 2 emulation, we are able to furthermore strive to work with an x64 JDK originate. However, we would possibly perhaps hobble into points and/or obtained’t salvage the expected performance.

What’s next is Docker. Installing a most fresh Docker for Mac version comes with Apple M1 reinforce. In the early days, there were some minor points. Nonetheless having labored with it for nearly a 300 and sixty five days now, many possess been repeatedly fastened.

All diversified building instruments that we exhaust on a day to day foundation both present an arm64 originate or the emulated x64 version works graceful: IntelliJ IDEA, Visual Studio Code, Slack, Thought, Docker for Mac, Spotify, Firefox, Microsoft Teams, Postman.

Rule one: At any time when there is a native arm64 originate of any building instrument for the M1, dart for it. Completely strive to salvage the x64 originate working if there’s no arm64 originate accessible (yet).

To further examine the compatibility and optimization for diversified diversified instruments for Apple’s M1, checkout out isapplesiliconready.

Integration Tests with Docker and Testcontainers

By system of working our integration tests that exhaust Testcontainers, the principle ingredient we stumble over with our M1 machine are most likely take a look at screw ups on account of missing arm64 platform reinforce.

Docker photos are built for particular processor architectures. We are able to name the accessible platforms by searching on the OS/Arch column on Docker Hub for a specific Docker image:

Docker Hub Image Platform Example

The instance above is a screenshot of the legitimate Keycloak Docker image. It handiest comes with reinforce for x64 machines.

If we strive to hobble this Docker image on our arm64 Apple M1 machine, we salvage the next warning:

$ docker hobble jboss/keycloak: 16.1.1

WARNING: The requested image’s platform (linux/amd64) does no longer match the detected host platform (linux/arm64/v8) and no particular platform became requested

While we salvage past this warning and Docker tries to hobble a image for a diversified platform, it internally makes exhaust of emulation to study out to salvage the x64 container Up and working. However, this emulation for x64 reinforce for arm64 is an awfully most intelligent effort.

Pictures for a diversified platform would possibly perhaps or would possibly perhaps no longer work on our Apple M1. There’s no guarantee that the container will originate and possess as expected.

The Keycloak image, as an illustration, unfortunately, crashes at some stage within the bootstrap share:

#

[thread 378 also had an error]

[thread 374 also had an error]

# A fatal error has been detected by the Java Runtime Atmosphere:

#

#  [thread 381 also had an error]

[thread 331 also had an error]

[thread 372 also had an error]

[thread 377 also had an error]

SIGSEGV (0xb) at notebook computer=0x000000401de90af2, pid=310, tid=334

#

# JRE version: OpenJDK Runtime Atmosphere 18.9 (11.0.14+9) (originate 11.0.14+9-LTS)

# Java VM: OpenJDK 64-Bit Server VM 18.9 (11.0.14+9-LTS, blended mode, sharing, tiered, compressed oops, g1 gc, linux-amd64)

# Problematic frame:

# J 546 c2 java.lang.AbstractStringBuilder.append(Ljava/lang/String;)Ljava/lang/AbstractStringBuilder;

When working our take a look at suite for the principle time on an Apple M1, we possess now to name the Docker containers that fail to birth.

If the image itself doesn’t present arm64 reinforce, we are able to demand for an different. For the most frequently veteran Docker photos, these are most likely conceivable choices:

  • PostgreSQL: The everyday photos comprise arm64 reinforce, no adjustments required
  • Webdriver photos: Standalone arm64 reinforce comes with seleniarm photos
  • Keycloak: No arm64 originate for the jboss variant, nonetheless, there are neighborhood multi-architecture builds (richardjkendall or mihaibob) accessible
  • LocalStack: Starting Up with version 0.13, LocalStack publishes multi-architecture Docker photos
  • MySQL: Starting Up with version 8, the oracle version gives an arm64 originate. One other different is the MariaDB image
  • MongoDB: The everyday photos comprise arm64 reinforce, no adjustments required
  • Kafka: No arm64 originate for the bitnami image, but the wurstmeister originate helps arm64

Dynamically Replace Docker Pictures For ARM64 Reinforce

At any time after we uncover ourselves shopping for an different to the default Testcontainers Docker image, we opt to override the default image. If we’re working on a venture on our gather or know that the total team is utilizing an arm64 processor, we are able to hardcode the arm64 successfully matched Docker image. In any other case, we are able to originate the image substitution extra dynamic and handiest change the Docker image when working on the particular architecture.

Let’s exhaust the Selenium Webdriver container as an illustration for a dynamic override:

@Container

static BrowserWebDriverContainer?> webDriverContainer =

  fresh BrowserWebDriverContainer(

    Scheme.getProperty(“os.arch”).equals(“aarch64”) ?

      DockerImageName.parse(“seleniarm/standalone-chromium”)

        .asCompatibleSubstituteFor(“selenium/standalone-chrome”)

      : DockerImageName.parse(“selenium/standalone-chrome”)

  ).withCapabilities(fresh ChromeOptions());

In accordance to the machine property os.arch we determined which image to make exhaust of for our BrowserWebDriverContainer.

As a replacement to this workaround, we are able to exhaust Testcontainers Cloud. With Testcontainers Cloud, we hobble the backing containers for our integration tests within the cloud. There’s no switch required for our take a look at. The containers will excellent hobble on somebody else machine. Since its deepest beta, I had the likelihood to demo this extra special instrument and am convinced that this is able to per chance power the productiveness (e.g., faster builds) for sorting out with Testcontainers even further.

As a last resort, we are able to furthermore disable particular tests within the occasion that they obtained’t hobble at all on our M1 processor. In accordance to the os.arch Java machine property we are able to detect the processor architecture and  exhaust a JUnit Jupiter annotation to disable tests for our M1:

@DisabledIfSystemProperty(named = “os.arch”, suits = “aarch64”, disabledReason = “No ARM64 reinforce”)

class SomeIT {

}

We are able to exhaust this annotation on high of a take a look at class or for a specific take a look at. While right here’s no longer an optimal solution, no no longer Up to it helps the Apple M1 developers on our team to study a green originate.

These take a look at disabling annotations needs to be short-time duration. We must take a look at if there is a solution accessible (e.g. a successfully matched Docker image) occasionally. The ideal originate on our CI pipeline must make certain that to hobble all tests (frequently a x64 machine).

Docker Shopper JNA Failure with Testcontainers

One other pitfall we would possibly perhaps tumble into sooner than we are able to really hobble our Java integration take a look at with Testcontainers is the next error:

06: 49: 41.241 [main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy – Might well no longer salvage a sound Docker atmosphere. Please take a look at configuration. Attempted configurations were:

06: 49: 41.241 [main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy –     UnixSocketClientProviderStrategy: failed with exception RuntimeException

(java.lang.UnsatisfiedLinkError: /Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp: dlopen(/Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp, 0x0001):

tried: ‘/Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp’ (plump file, but missing successfully matched architecture (possess ‘i386,x86_64’, need ‘arm64e’)), ‘/usr/lib/jna11180227188626594160.tmp’

(no such file)). Root cause UnsatisfiedLinkError (/Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp: dlopen(/Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp, 0x0001):

tried: ‘/Users/rieckpil/Library/Caches/JNA/temp/jna11180227188626594160.tmp’ (plump file, but missing successfully matched architecture (possess ‘i386,x86_64’, need ‘arm64e’)), ‘/usr/lib/jna11180227188626594160.tmp’ (no such file))

06: 49: 41.241 [main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy –     UnixSocketClientProviderStrategy: failed with exception RuntimeException (java.lang.NoClassDefFoundError:

Might well no longer initialize class org.testcontainers.shadowy.com.github.dockerjava.okhttp.UnixSocketFactory$1). Root cause NoClassDefFoundError (Might well no longer initialize class org.testcontainers.shadowy.com.github.dockerjava.okhttp.UnixSocketFactory$1)

The underlying effort is a JNA (Java Native Entry) dependency incompatibility with Apple’s M1 chip. Testcontainers transitively depends on this library. Starting Up with JNA 5.7.0, this effort is resolved.

To fix this relate for our tasks, we are able to both give a enhance to our Testcontainers version (preferred) or manually override the JNA version. Starting Up with Testcontainers 1.15.3, Tesctonainers transitively depends on a JNA version (5.7.0) that’s working for the Apple M1.

Recount we composed hit upon the identical take a look at failure even after bumping the Testcontainers version. If that is the case, the potentialities are high that one more dependency furthermore transitively depends on JNA and overrides the version.

On this topic, we are able to both exclude the JNA dependency from any diversified dependency that capabilities it or exhaust the dependencyManagement share to force the option of a specific version of it:

  

    

      get.java.dev.jna

      jna

      5.7.0

    

  

To hit upon dependencies that transitively encompass JNA, hobble mvn dependency:tree after which gaze JNA within the consequence.

Native Train Atmosphere with Docker Compose

Many tasks exhaust a docker-compose.yml for working the wanted infrastructure when locally developing or sorting out a Java utility.

Searching on the amount and diversity of required infrastructure (e.g., messaging queues, databases, caches, etc.), tweaking the docker-compose.yml to work for both x64 and arm64 would possibly perhaps no longer be an likelihood.

The the same Docker image arm64 availability effort as for sorting out applies right here. Every so incessantly the neighborhood Docker builds handiest reinforce one platform and no longer both.

As a conceivable workaround, we are able to introduce a 2d docker-compose-arm64.yml file to augment team members working with an M1 (or any diversified arm64 machine).

I’m utilizing this thought for the Making an strive out Spring Boot Application Masterclass, the put the Amazon SQS and Keycloak image needs to salvage replaced with an arm64 successfully matched image.

This adds some minute upkeep effort as the team has to preserve the 2 Docker compose files in sync. However, as soon as the supply and adoption of arm64 photos is bettering, the devoted arm64 Docker compose file would possibly perhaps furthermore furthermore be deleted.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

version: ‘3.8’

services and products:

  # …

  keycloak:

    image: mihaibob/keycloak: 15.0.1

    atmosphere:

       KEYCLOAK_USER=keycloak

       KEYCLOAK_PASSWORD=keycloak

       DB_VENDOR=h2

       JAVA_OPTS=-Dkeycloak.migration.circulation=import -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=/tmp/keycloak-dump.json

    volumes:

      – kind: bind

        source: ./tmp/keycloak-dump.json

        target: /tmp/keycloak-dump.json

        read_only: excellent

    ports:

     “8888: 8080”

  sqs:

    image: softwaremill/elasticmq-native

    volumes:

      – kind: bind

        source: ./tmp/sqs-queue-definition.conf

        target: /decide/elasticmq.conf

        read_only: excellent

    ports:

       “9324: 9324”

       “9325: 9325”

We are able to then pass the underlying compose file to our docker-compose originate repeat:

docker-compose –file docker-compose-arm64-reinforce.yml Up

The plan back of this extra compose file is the duplicated upkeep. We must make certain that both our composes files (x64 and arm64) are in sync. Connected to the workarounds for making our Testcontainers integration tests pass, this must furthermore be a short-time duration solution that we reassess occasionally.

Java Train: Spring Boot Netty Warning on Startup

Upon beginning a Spring Boot utility on an Apple M1, we would possibly perhaps stumble upon an ERROR log from Netty with a sizable stack mark at some stage within the bootstrap share:

20220321 06: 52: 09.885 ERROR 17220 [main] i.n.r.d.DnsServerAddressStreamProviders  : Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider, fallback to machine defaults. This would possibly perhaps consequence in fallacious DNS resolutions on MacOS.

java.lang.possess.InvocationTargetException: null

        at java.terrifying/jdk.internal.possess.NativeConstructorAccessorImpl.newInstance0(Native Diagram) ~[na:na]

        at java.terrifying/jdk.internal.possess.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java: 77) ~[na:na]

        at java.terrifying/jdk.internal.possess.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java: 45) ~[na:na]

        at java.terrifying/java.lang.possess.Constructor.newInstanceWithCaller(Constructor.java: 499) ~[na:na]

        at java.terrifying/java.lang.possess.Constructor.newInstance(Constructor.java: 480) ~[na:na]

        at io.netty.resolver.dns.DnsServerAddressStreamProviders.(DnsServerAddressStreamProviders.java: 64)

While our utility must composed feature as expected, this log is noisy and can confuse developers. As long as we salvage no longer hobble our Spring Boot utility on an Apple M1 in production, or no longer it’s furthermore less primary if we salvage no longer fix it.

For many who opt to fix this startup error message, be distinct that to make exhaust of Netty> 4.1.68.Ultimate and add the next dependency to our venture:

  io.netty

  netty-resolver-dns-native-macos

  ${netty.version}

  osx-aarch_64

After making this switch, the Spring Boot utility must originate one more time with a neat bootstrap log.

Building Multiplatform Docker Pictures on an Apple M1

When building Docker photos, the resulted image will handiest work on the platform we’re working on. Any output of docker originate -t myimage . on an Apple M1 will handiest work on one more arm64 machine.

While right here’s fully glaring, it took me a 2 hour debug session to be responsive to it. I became building a brand fresh feature for a Spring Boot utility (Stratospheric) and wished to push the resulting Docker image on to the ECR (Elastic Container Registry) from my local machine. While we possess now a working CI/CD in remark, I wished to short-circuit this route of and save time. After pushing the image to the container registry, I encountered uncommon error logs, and the ECS (Elastic Container Service) task became unable to birth.

That’s since the underlying EC2 instance is an x64 machine. Even the glaring issues occasionally uncover it the laborious system to attain them.

At any time after we uncover ourselves in a the same topic, the put we opt to originate a Docker image for a diversified processor architecture, we possess now two alternate choices:

  • Produce the target Docker image on a CI/CD server working on an x64 machine (or any architecture)
  • Use Docker’s buildx, a CLI plugin, to salvage salvage entry to to all aspects of the Moby BuildKit  (e.g., multiplatform photos)

We obtained’t dart further into the principle likelihood, as a CI/CD workflow (e.g., GitHub actions) needs to be already in remark for (hopefully) most tasks.

The 2d likelihood is extra intelligent to us as this is able to per chance permit us to originate locally arm64 and x64 successfully matched Docker photos.

As a prerequisite for this to work, we possess now to make certain that our Docker terrifying image (FROM phase of the Dockerfile) gives a variant for all architectures we opt to originate the last Docker image for. We are able to examine this by visiting Docker Hub and the tags share of our Docker terrifying image.

Taking eclipse-temurin (OpenJDK originate of the Adoptium venture, historical AdoptOpenJDK) as a Docker terrifying image instance, we are able to hit upon that this image helps diversified architectures:

Eclipse Temurin Docker Image Multi Platform Example
Once our Dockerfile exhaust a terrifying image with reinforce for plenty of architectures, we are able to exhaust the Docker buildx repeat to originate the image for plenty of platforms:

docker buildx originate –platform linux/amd64,linux/arm64 -t todo-app:most fresh .

In the instance above, we originate both an arm64 and x64 image for our Java Spring Boot utility:

FROM eclipse-temurin: 17-jre

ARG JAR_FILE=originate/libs/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT [“java”, “-jar”, “-Dspring.profiles.active=aws”, “/app.jar”]

We are able to furthermore straight away push the consequence correct into a container registry with:

docker buildx originate –platform linux/amd64,linux/arm64 –push -t some.ecr.amazonaws.com/todo-app:most fresh .

The utilization of this trend, we now can originate fresh Docker photos locally and deploy them to hobble on x64 machines within the cloud. This presents us wide flexibility for the Java building on our Apple M1.

Building ARM64 Pictures on GitHub Actions

If we’re within the lucky remark to originate and publish our gather Docker photos, we would possibly perhaps opt to adopt arm64 builds to broaden the final adoption rate.

We’re utilizing a personalised ActiveMQ Docker image for the Stratospheric venture for sorting out and local building capabilities. We were all utilizing a classic Intel processor at some stage within the inception share of this venture and when developing this Docker image. Things modified with my MacBook Devoted steal, and therefore, we began searching into multiplatform reinforce.

The ActiveMQ message dealer runs on the JVM. Resulting from this truth any ingredient of our Dockerfile must furthermore be accessible for an arm64 architecture. For our instance, we were utilizing fabric8/java-alpine-openjdk11-jre as the terrifying image. Unfortunately, this image handiest helps linux/amd64 (i.e. x64) and therefore we had to interchange it with a JRE terrifying image that helps all platforms we opt to originate our image for.

We went for eclipse-temurin: 11-jre-focal as the terrifying Docker image because it helps plenty of architectures:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

FROM eclipse-temurin: 11-jre-focal

# …

RUN tar xzf $ACTIVEMQ-bin.tar.gz -C /decide &&

    ln -s /decide/$ACTIVEMQ $ACTIVEMQ_HOME &&

    groupadd activemq &&

    useradd -m -d $ACTIVEMQ_HOME -g activemq activemq &&

    chown -R activemq:activemq /decide/$ACTIVEMQ &&

    chown -h activemq:activemq $ACTIVEMQ_HOME

EXPOSE 1883 5672 8161 61613 61614 61616

USER activemq

WORKDIR $ACTIVEMQ_HOME

CMD [“/bin/sh”, “-c”, “bin/activemq console”]

Given the multiplatform reinforce from the terrifying image, we are able to now locally originate an arm64 variant of the Docker image (utilizing buildx of the last share) and push it to a Docker registry.

As a replacement, we are able to automate this route of on GitHub Actions and originate a multiplatform image on every commit. The Docker team gives intriguing-to-exhaust actions to originate and push a multiplatform Docker image.

For our customized ActiveMQ image, we adjusted our GitHub Actions as the next:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

name: Publish Docker image

on: [push]

jobs:

  build_push_to_registry:

    name: Push Docker image to Docker Hub

    runs-on: ubuntu-most fresh

    steps:

      – name: Check out

      – name: Attach of abode Up QEMU

        with:

          platforms: arm64, amd64

      – name: Attach of abode Up Docker Buildx

      – name: Login to Docker Hub

        with:

          username: ${{ secrets.DOCKER_USERNAME }}

          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}

      – name: Produce Docker image and push to Docker Hub

        with:

          context: .

          file: ./Dockerfile

          platforms: linux/amd64, linux/arm64

          push: ${{ github.ref == ‘refs/heads/primary’ }}

          tags: stratospheric/activemq-docker-image:most fresh

These 5 steps automate every part from sorting out the source code, building a multiplatform image for arm64 and x64 after which within the shatter pushing this image to Docker Hub.

What’s left for us is to configure a username and salvage entry to token for Docker Hub. We retailer them as GitHub secrets for our repository.

Given the GitHub automation, we deploy fresh variations of our Docker image to DockerHub on every push to our primary department:

Multiple Platform Docker Build Example using GitHub Actions

Summary: Java Train on an Apple M1

Having labored with an Apple M1 essentially for Java building for nearly a 300 and sixty five days now, I salvage no longer remorse the preference. It took me some time to resolve the preliminary hurdles and salvage every part working. The talked about methods listed right here solved all my sorting out and developing issues for Java capabilities on the M1.

The good news is that with every passing day, extra instruments adopt arm64 as Apple continues to commence fresh flagship products working on arm64 processors. It’s handiest a topic of time till the last Java building instrument works perfectly graceful on an Apple M1.

The performance of the notebook computer (Apple MacBook Devoted M1 2021) is terribly marvelous, and a wide productiveness enhance as my Java builds, and tests hobble faster in comparison to an x64 Mac. I composed preserve my outdated Ubuntu desktop PC around as there are occasionally tasks the put I desire a excellent outdated x64 machine.

Let me be taught about your pointers & methods for Java building on an Apple M1 within the feedback.

Gay sorting out,

Philip

!–>>
Read More

About the author: Vanic
“Simplicity, patience, compassion. These three are your greatest treasures. Simple in actions and thoughts, you return to the source of being. Patient with both friends and enemies, you accord with the way things are. Compassionate toward yourself, you reconcile all beings in the world.” ― Lao Tzu, Tao Te Ching
Advertisements

Get involved!

Get Connected!
One of the Biggest Social Platform for Entrepreneurs, College Students and all. Come and join our community. Expand your network and get to know new people!

Discussion(s)

No comments yet
Knowasiak We would like to show you notifications so you don't miss chats & status updates.
Dismiss
Allow Notifications