- The App
- Create the distribution
- The Dockerfile
- Build the Docker image
- Run your Kotlin Docker image
- Gradle7 Update (12 August 2021)
Over the last few years, I have been programming more in Kotlin than Java; both for mobile and for the CLI.
I decided I wanted to determine what would be required to run Kotlin in Docker. I decided on a CLI app, instead of an Android app in an emulator. To be honest, Hello World is fine for this, because it is more about the process than the actual code being executed.
I’m also going to focus on Kotlin JVM rather than Multiplatform, just to keep this a minimalist example.
There is always a ton of configuration and optimizations that can be done as well. I wanted this post to focus on the minimal steps necessary. There are many other resources out there to help tweak your app or your docker image or your cloud environment.
The question is: What is the minimal steps to run a Kotlin CLI app inside a docker image?
First, we need a basic app. Since Hello World is sufficient, let’s auto-generate it.
Create a directory, and change into it.
malachi@enki:~/work$ mkdir ktDocker malachi@enki:~/work$ cd ktDocker/
Use gradle to auto-generate a Kotlin Application:
malachi@enki:~/work/ktDocker$ gradle init --dsl kotlin Select type of project to generate: 1: basic 2: application 3: library 4: Gradle plugin Enter selection (default: basic) [1..4] 2 Select implementation language: 1: C++ 2: Groovy 3: Java 4: Kotlin 5: Swift Enter selection (default: Java) [1..5] 4 Project name (default: ktDocker): Source package (default: ktDocker): com.malachid.ktdocker BUILD SUCCESSFUL in 20s 2 actionable tasks: 2 executed
And verify it works.
malachi@enki:~/work/ktDocker$ ./gradlew run > Task :run Hello world. BUILD SUCCESSFUL in 2s 2 actionable tasks: 2 executed
Create the distribution
We’re going to have Docker run the app, not build it (since we are talking about minimalist).
Create the distribution.
malachi@enki:~/work/ktDocker$ ./gradlew distTar BUILD SUCCESSFUL in 661ms 5 actionable tasks: 4 executed, 1 up-to-date
For this, we’ll just create a new
Dockerfile image in the current directory.
Use nano/vi/emacs/gedit/whatever and create the
# We are only running a pre-compiled app; so select a small JRE FROM openjdk:8-jre-alpine # Unpack from our `./gradlew distTar` into the docker image RUN mkdir /app ADD build/distributions/ktDocker.tar /app WORKDIR /app/ktDocker # Run the app CMD ["bin/ktDocker"]
Build the Docker image
Now we run the docker command to build the image.
malachi@enki:~/work/ktDocker$ docker build -t ktdocker . Sending build context to Docker daemon 2.118MB Step 1/5 : FROM openjdk:8-jre-alpine ---> f7a292bbb70c Step 2/5 : RUN mkdir /app ---> Running in e0a006eff828 ---> cdf980f50d10 Removing intermediate container e0a006eff828 Step 3/5 : ADD build/distributions/ktDocker.tar /app ---> 542b2cc0036d Removing intermediate container c6d235b58081 Step 4/5 : WORKDIR /app/ktDocker ---> 2ad29b79c278 Removing intermediate container 32362f112ae1 Step 5/5 : CMD bin/ktDocker ---> Running in 0854c39bed56 ---> 6a17d8001851 Removing intermediate container 0854c39bed56 Successfully built 6a17d8001851 Successfully tagged ktdocker:latest
Run your Kotlin Docker image
And now we run it.
malachi@enki:~/work/ktDocker$ docker run -it --rm ktdocker Hello world.
And that’s it, you’ve now built and deployed a Kotlin app to Docker by adding the
Dockerfile and using just these commands:
gradle init --dsl kotlin ./gradlew distTar docker build -t ktdocker . docker run -it --rm ktdocker
In case you are wondering about the directory structure of what is being deployed, you can run
./gradlew installDist and then look inside
Gradle7 Update (12 August 2021)
I was trying these instructions again today with a newer version of Gradle, and the instructions are slightly different now.
The auto-generated directory is now called
well as the jar, shell files, etc.
It’s a pretty simple fix. We just need to update our Dockerfile.
FROM openjdk:15-jdk # Unpack from our `./gradlew distTar` into the docker image ADD app/build/distributions/app.tar / WORKDIR /app # Run the app CMD ["bin/app"]
You’ll notice that we are no longer creating a directory.
That’s because the tar now includes an
app directory. As
such we are also extracting it one level higher.