- Small Alpine Linux containers with Java
- Intro
- Creating Containers
- Building a HelloWorld application
- Installing Oracle Java
- How to install oracle jdk11 in alpine linux docker image?
- Method 1: Downloading JDK Tarball and Setting JAVA_HOME
- Step 1: Download the JDK Tarball
- Step 2: Extract the JDK Tarball
- Step 3: Set the JAVA_HOME Environment Variable
- Step 4: Update the PATH Environment Variable
- Method 2: Using SDKMAN to Manage Java Versions
- Method 3: Installing Oracle JDK 11 with apk
- Docker alpine + oracle java: cannot find java
- How to install Java 8 on Alpine Linux?
- Solution 2
- Related videos on Youtube
- Maxim
- Comments
Small Alpine Linux containers with Java
The original post was about Java 13. Oracle is changing JDK versions quite frequently. The newest version of JDK is 14: https://download.java.net/java/early_access/alpine/15/binaries/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz
Intro
Quite often I hear a complaint from developers that Java containers are too big and how much smaller this would be with Go or other languages. With this new project called Portola it is possible to make very small (~40MB) containers running Java applications. Alpine Linux became the de facto standard for small containers but until now it was a rather complex process to create a Java environment using it. This is not anymore the case. Let’s see how we can leverage Project Portola to create these small containers.
Creating Containers
FROM alpine:latest as build ADD https://download.java.net/java/early_access/alpine/15/binaries/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz /opt/jdk/ RUN tar -xzvf /opt/jdk/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz -C /opt/jdk/ RUN ["/opt/jdk/jdk-14/bin/jlink", "--compress=2", \ "--module-path", "/opt/jdk/jdk-14/jmods/", \ "--add-modules", "java.base", \ "--output", "/jlinked"] FROM alpine:latest COPY --from=build /jlinked /opt/jdk/ CMD ["/opt/jdk/bin/java", "--version"]
The rest of the article is not concerned with JDK version. Output from docker build might reflect earlier version. We can start to build the container:
[v@alpine-java jdk14_v]$ sudo docker build . Sending build context to Docker daemon 2.56kB Step 1/8 : FROM alpine:latest as build latest: Pulling from library/alpine bdf0201b3a05: Pull complete Digest: sha256:28ef97b8686a0b5399129e9b763d5b7e5ff03576aa5580d6f4182a49c5fe1913 Status: Downloaded newer image for alpine:latest ---> cdf98d1859c1 Step 2/8 : ADD https://download.java.net/java/early_access/alpine/16/binaries/openjdk-13-ea+16_linux-x64-musl_bin.tar.gz /opt/jdk/ Downloading [==================================================>] 195.2MB/195.2MB ---> Using cache ---> b1a444e9dde9 Step 3/7 : RUN tar -xzvf /opt/jdk/openjdk-13-ea+16_linux-x64-musl_bin.tar.gz -C /opt/jdk/ ---> Using cache ---> ce2721c75ea0 Step 4/7 : RUN ["/opt/jdk/jdk-13/bin/jlink", "--compress=2", "--module-path", "/opt/jdk/jdk-13/jmods/", "--add-modules", "java.base", "--output", "/jlinked"] ---> Using cache ---> d7b2793ed509 Step 5/7 : FROM alpine:latest ---> cdf98d1859c1 Step 6/7 : COPY --from=build /jlinked /opt/jdk/ ---> Using cache ---> 993fb106f2c2 Step 7/7 : CMD ["/opt/jdk/bin/java", "--version"] - to check JDK version ---> Running in 8e1658f5f84d Removing intermediate container 8e1658f5f84d ---> 350dd3a72a7d Successfully built 350dd3a72a7d
[v@alpine-java jdk13_v]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE 350dd3a72a7d 21 seconds ago 41.7MB d7b2793ed509 25 minutes ago 565MB alpine latest cdf98d1859c1 2 weeks ago 5.53MB [v@alpine-java jdk13_v]$ sudo docker tag 350dd3a72a7d jdk-13-musl/jdk-version:v1 [v@alpine-java jdk13_v]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE jdk-13-musl/jdk-version v1 350dd3a72a7d About a minute ago 41.7MB d7b2793ed509 27 minutes ago 565MB alpine latest cdf98d1859c1 2 weeks ago 5.53MB
[v@alpine-java jdk13_v]$ sudo docker run jdk-13-musl/jdk-version:v1 openjdk 13-ea 2019-09-17 OpenJDK Runtime Environment (build 13-ea+16) OpenJDK 64-Bit Server VM (build 13-ea+16, mixed mode)
Building a HelloWorld application
Now we have a base container that we can use to create one with a Java app. Lets use a simple HelloWorld.java.
public class HelloWorld public static void main(String[] args) System.out.println("Hello, World"); > >
FROM jdk-13-musl/jdk-version:v1 ADD HelloWorld.class / CMD ["/opt/jdk/bin/java", "HelloWorld"]
sudo docker run jdk-13-musl/hello-world:v1 Hello, World
Installing Oracle Java
Using java requires having grsec play nice with the binaries. You may also want to install the JDK instead of the JRE depending on your needs.
This guide assumes you’re running as root.
mkdir -p /opt/java cd /opt/java sudo tar -zxvf XXX-XXX-linux-x64.tar.gz
Take note of the directory, e.g. /opt/java/jdk1.8.0_121, create a symbolic link as the current version:
ln -s /opt/java/jdk1.8.0_121 /opt/java/current
Create a file in /etc/profile.d/java.sh:
export JAVA_HOME=/opt/java/current export PATH=$PATH:$JAVA_HOME/bin
Execute this script or restart your shell:
Now we need manage grsec with paxctl. Use this command to check if its installed:
If nothing comes up install it:
Now in your /opt/java/XXX/bin folder, execute:
paxctl -c java paxctl -m java
If you have the JDK, you need to do the same to javac:
paxctl -c javac paxctl -m javac
You can do this for any other binary you need to use.
NOTE: some users have reported they had to use this command to get it working:
setfattr -n user.pax.flags -v "mr" java setfattr -n user.pax.flags -v "mr" javac
Alternative installation of Oracle Java on Linux Alpine
1. Run apk update && apk upgrade 2. Edit vim /etc/profile, add the value before the string: append_path "/user/local/sbin", value: append_path "/opt/java/current/bin" 3. Download XXX-XXX-linux-x64.tar.gz and jce_policy-8.zip from official oracle suite. 4. Сreate a directory in the root: mkdir -p /opt/java 5. Copy XXX-XXX-linux-x64.tar.gz in the java directory: scp /home/username/XXX-XXX-linux-x64.tar.gz /opt/java/ 6. Let's go to the catalog java: cd /opt/java and unpack the file: XXX-XXX-linux-x64.tar.gz, tar -zxvf XXX-XXX-linux-x64.tar.gz 7. Create simlink: ln -s /opt/java/jdkX.X.X_XXX /opt/java/current 8. Download and install the certificate: wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub 9. Download glibc: wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.34-r0/glibc-2.34-r0.apk 10. Install glibc: apk add glibc-2.34-r0.apk 11. Download glibc-bin: wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.34-r0/glibc-bin-2.34-r0.apk 12. Install glibc-bin: apk add glibc-bin-2.34-r0.apk 13. Install the license jce_policy-8.zip, сopy the file: scp /home/username/jce_policy-8.zip /opt/java/current/jre/lib/security/ 14. Let's go to the folder /opt/java/current/jre/lib/security/: cd /opt/java/current/jre/lib/security/ and unpack it: unzip -o -j jce_policy-8.zip UnlimitedJCEPolicyJDK8/*.jar 15. Delete the archive file: rm -f jce_policy-8.zip 16. Restart the computer or virtual machine: reboot 17. Let's check the version of Java installed: java -version 18. If it displays: java version "X.X.X_XXX", then we did everything correctly.
How to install oracle jdk11 in alpine linux docker image?
Installing Oracle JDK 11 in an Alpine Linux Docker image can be a challenge, especially when trying to keep the image size minimal. Alpine Linux is a popular choice for Docker images due to its small footprint, however, it does not have a package repository for Oracle JDK 11. In this scenario, manual installation is required to get Oracle JDK 11 running in an Alpine Linux Docker image.
Method 1: Downloading JDK Tarball and Setting JAVA_HOME
This tutorial will guide you through the steps to install Oracle JDK 11 in an Alpine Linux Docker image using the method of downloading the JDK tarball and setting the JAVA_HOME environment variable.
Step 1: Download the JDK Tarball
First, download the Oracle JDK 11 tarball from the official website. You can use the following command to download the tarball:
wget https://download.oracle.com/otn-pub/java/jdk/11.0.11+9/55eed80b163941c8885ad9298e6d786a/jdk-11.0.11_linux-x64_bin.tar.gz --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-securebackup-cookie" -P /tmp
Step 2: Extract the JDK Tarball
Next, extract the downloaded tarball to a directory of your choice. For example, you can use the following command to extract the tarball to the /opt directory:
tar -xzf /tmp/jdk-11.0.11_linux-x64_bin.tar.gz -C /opt
Step 3: Set the JAVA_HOME Environment Variable
After extracting the tarball, set the JAVA_HOME environment variable to point to the JDK installation directory. You can use the following command to set the environment variable:
export JAVA_HOME=/opt/jdk-11.0.11
Step 4: Update the PATH Environment Variable
Finally, add the JDK bin directory to the PATH environment variable so that you can run the java and javac commands without specifying the full path. You can use the following command to update the PATH environment variable:
export PATH=$PATH:$JAVA_HOME/bin
Method 2: Using SDKMAN to Manage Java Versions
SDKMAN is a command-line tool that can be used to manage multiple versions of Java on a single machine. In this tutorial, we will show how to install Oracle JDK 11 in an Alpine Linux Docker image using SDKMAN.
Before we start, make sure that you have the following:
- Docker installed on your machine
- A Dockerfile that uses Alpine Linux as the base image
- Install SDKMAN
RUN apk add --no-cache curl unzip RUN curl -s "https://get.sdkman.io" | bash RUN source "$HOME/.sdkman/bin/sdkman-init.sh"
RUN sdk install java 11.0.10-zulu
RUN sdk default java 11.0.10-zulu
Method 3: Installing Oracle JDK 11 with apk
Here are the steps to install Oracle JDK 11 in Alpine Linux Docker Image using apk:
apk add --no-cache wget ca-certificates gnupg wget -qO - https://www.oracle.com/webapps/redirect/signon?nexturl=https://download.oracle.com/otn-pub/java/jdk/11.0.11+9/f411702ca7704a54b1b8b4eadec7d1e9/jdk-11.0.11_linux-x64_bin.tar.gz | grep 'oraclelicense=a' > /tmp/agreement.txt wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" "https://download.oracle.com/otn-pub/java/jdk/11.0.11+9/f411702ca7704a54b1b8b4eadec7d1e9/jdk-11.0.11_linux-x64_bin.tar.gz" -O /tmp/jdk.tar.gz mkdir -p /opt/java/openjdk tar -xzf /tmp/jdk.tar.gz -C /opt/java/openjdk --strip-components=1 rm -rf /tmp/*
export JAVA_HOME=/opt/java/openjdk
This should output the version of Java installed.
That’s it! You have successfully installed Oracle JDK 11 in Alpine Linux Docker Image using apk.
Docker alpine + oracle java: cannot find java
I’ve been trying to create an alpine-based docker image with Oracle Java (rather than openjdk). I have been specifically asked to create our own image here. This is the Dockerfile I’ve come up with:
FROM alpine:3.6 RUN apk add --no-cache curl wget RUN mkdir /opt/ && \ wget -c --header "Cookie: oraclelicense=accept-securebackup-cookie"\ http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz && \ tar xvf jdk-8u131-linux-x64.tar.gz -C /opt/ && \ rm jdk-8u131-linux-x64.tar.gz && \ ln -s /opt/jdk1.8.0_131 /opt/jdk ENV JAVA_HOME /opt/jdk ENV PATH $PATH:/opt/jdk/bin RUN echo $JAVA_HOME && \ echo $PATH RUN which java RUN java -version
There are some unnecessary commands (like echoing the JAVA_HOME dir) which were added to help with debugging, but now I’m stuck: RUN which java returns /opt/jdk/bin/java as expected, but RUN java -version returns /bin/sh: java: not found . I’ve tried a few things, including symlinking the executable(s) into /usr/bin, to no avail. What am I missing? EDIT: Final output from docker is: The command ‘/bin/sh -c java -version’ returned a non-zero code: 127 Final edit: Thanks to diginoise for putting me on to MUSL vs libc. I found adding the following to my Dockerfile allowed me to build a working image:
RUN apk --no-cache add ca-certificates && \ wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub && \ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.25-r0/glibc-2.25-r0.apk && \ apk add glibc-2.25-r0.apk
How to install Java 8 on Alpine Linux?
openjdk is in the community repo. It seems that you didn’t enable community repo. Go ahead and first enable community repo by uncommenting the community repo in /etc/apk/repositories , then run apk update then execute apk add openjdk11 .
Solution 2
RUN apk add openjdk8=8.242.08-r0
Related videos on Youtube
Maxim
Updated on September 18, 2022
Comments
When I look at package lists they suggest that all sorts of Java 8 packages exist for Alpine, but when I try to install them I always get:
apk add openjdk8 ERROR: unsatisfiable constraints: openjdk8-jre (missing): required by: world[openjdk8]
And this also happens with other Java 8 packages, such as openjdk8-jre. According to this: https://pkgs.alpinelinux.org/packages?name=openjdk8&branch=v3.10&arch=x86_64 the package exists for version 3.10 64 bit, which I’m using, so why wouldn’t it install?
@valiano After looking at that file, I noticed that most repos were commented out, after uncommenting them «openjdk8» installed, thanks