21/12/2021

[Docker] Include Dockerfile in another Dockerfile

Docker does not support including a Dockerfile in another Dockerfile, luckily the Dockerfile plus project comes to the rescue.

Simply setup your Dockerfile with:

# syntax = edrevo/dockerfile-plus:0.1.0

INCLUDE+ someDockerfile

FROM someimage

You might need to enable Docker buildkit in order to use this extension, simply set the environment variable:

DOCKER_BUILDKIT=1

[Docker] Redirect app log file to container output

When running applications in containers, we might have log files that are relevant to monitor but are not automatically printed with the container output.

A workaround for this is to force the redirect in our Dockerfile by adding a symbolic link:

RUN ln -sf /dev/stdout /path/to/logfile.log 

Can also be applied to /dev/stderr of course


[Docker] Set Java UTF-8 encoding

Sometimes a Java based app running in a container requires UTF8 encoding. Not all available images enable that by default, this can be fixed by adding one line to your Dockerfile setting the JAVA_TOOL_OPTIONS environment variable:

ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF8

This also works outside containers of course.

03/12/2021

[Python] Simple command line options and menu

I recently needed to make a script automatable, meaning I had to provide all inputs to it from the CLI command used to execute it, rather than wait for it to prompt me during execution.

Turns out Python has a nice module dedicated to this: argparse

The usage is very simple and will also create the help menu automatically for us:

 import argparse  
   
 parser = argparse.ArgumentParser("myScript")  
 parser.add_argument("-a_flag_input", help="This is a true/false flag", action='store_true')  
 parser.add_argument("-a_string_input", help="This is a string input", type=str)  
 args = parser.parse_args()  
 options = vars(args)  
 print(args)  
   
 if options["a_flag_input"]:  
  print("a_string_input")  

Basically, we define each input parameter along with its type, if the input is a flag (true/false) we can specify an action on it to determine the value it would receive if set.

The inputs will be collected in a Namespace object, which we can convert to dictionary and get easy access to the inputs from the code.

29/11/2021

[Docker] Multi stage builds

I've been recently introduced to a nice Docker feature: multi-stage builds.

The idea is simple, if the build is containerized as well, the build itself is a developer responsability as well and the operations team need only provide a build server with docker installed on all worker nodes.


To achieve the result, we use a simple Dockerfile where we specify multiple FROM statements and tag each layer as necessary. The last layer will be the one responsible to run the application, while the previous layers are only used for the build. A sample file for a SpringBoot app looks like this:

 # syntax=docker/dockerfile:1  
 # build layer  
 FROM adoptopenjdk/openjdk11:latest as build  
   
 WORKDIR /app  
   
 # copy project files into container workdir  
 COPY . .  
   
 # build jar, skip tests, avoid daemon  
 RUN ./gradlew build -x test --no-daemon  
   
 # run layer  
 FROM adoptopenjdk/openjdk11:latest as prod  
   
 WORKDIR /app  
   
 #copy fat jar from previous layer into current workdir and rename it  
 COPY --from=build /app/build/libs/*.jar ./myApp.jar  
   
 # not mandatory, must use -p 8080:8080 later anyway  
 EXPOSE 8080  
   
 # start the spring boot app  
 CMD ["java", "-jar", "myApp.jar"]  
   

Then it can be placed in the project directory and we can trigger the build with:

docker build -t TAG .

Finally run it with (binding for example port 8080 and executing it in background):

docker run -p 8080:8080 -d TAG

We can also see the container output with (find container name with docker ps first):

docker logs -f CONTAINER_NAME

13/10/2021

[Java] Kerberos login and retrieve GSSCredentials from KerberosTicket

A scenario that popped up recently was to login a user via Java code to Kerberos and retrieve a GSSCredential object containing the Kerberos ticket. I used Java 8, but this works since Java 7 onwards.

Java offers a Krb5LoginModule class which can be used in conjuction with a LoginContext to achieve this.

The flow is quite simple (once you have read all the Kerberos documentation):

  • on the machine where the code runs, place a correct krb5.conf file in the default location for your OS (Windows uses krb5.ini) OR set the java.security.krb5.conf system property pointing to the file
  • define a PasswordCallback handler class
  • create a LoginContext with a configuration using Krb5LoginModule and provide the password callback handler. The configuration must force the login to request a user input, which will then be routed to the callback handler. It is possible to use a keytab or cache credentials, but it's not shown here
  • login the user and get its KerberosTicket
  • create a GSSCredentials object using the ticket

This procedure allows handling multiple login mechanisms in the application and even multiple Kerberos realms.

11/10/2021

[Java] Calculate the angle between clock hands

return null;

Unless it's an analog clock, in which case:

The hour hand makes a 360 degree turn every 12 hours or 12*60 = 720 minutes, therefore each minute the hand moves 360/720 = 0.5 degrees

The minute hand makes a 360 degree turn every hour or 60 minutes, therefore each minute the hand moves 360/60 = 6 degrees

Setting 12 as the 0 position, to calculate the angle of each hand we can:

  •     hours = 0.5 * current minutes for that hour (60 * hours + minutes)
  •     minutes = 6 * minutes


We now have the position of both hand with respect to the 12 o'clock, the angle between them will simply be the difference, between the two positions (absolute value!)

If the difference is more than 180 degrees, the angle is a reflex angle and since we want the smallest angle between the hands, we take its complement by subtracting it from 360 (again, absolute value unless we did a modulo before to account for 24 hour format)

You can check my implementation of clockAngle on my Gist along with some tests in ClockAngleJTests.