Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jib - How to use environmental variables from base image

Tags:

maven

jib

I have a base java image with some pre defined java_opts as a environmental variable. How can I use them in plugin?

                    <plugin>
                        <groupId>com.google.cloud.tools</groupId>
                        <artifactId>jib-maven-plugin</artifactId>
                        <version>1.8.0</version>
                        <configuration>
                            <from>
                                <image>${docker.registry}java:11</image>
                            </from>
                            <to>
                                <image>${docker.registry}portal-backend:${dockerfile.tag}</image>
                            </to>
                            <container>
                                <jvmFlags>
                                    # This will fail
                                    <jvmFlag>$JAVA_OPTS</jvmFlag>
                                </jvmFlags>
                            </container>
                        </configuration>
                    </plugin>
like image 665
MaciejF Avatar asked Dec 16 '19 13:12

MaciejF


People also ask

How do I pass an environment variable in Dockerfile?

Use -e or --env value to set environment variables (default []). If you want to use multiple environments from the command line then before every environment variable use the -e flag. Note: Make sure put the container name after the environment variable, not before that.

How do I get environment variables in Kubernetes?

We can use the 'env' or 'envFrom' field to set Kubernetes environment variables. It overrides any environment variables specified in the container image. We also have dependent environment variables. We can use $(VAR_NAME) in the value of env in a configuration file to set dependent environment variables.

How do you read environment variables?

An environment variable is a variable whose value is set outside the program, typically through functionality built into the operating system or microservice. An environment variable is made up of a name/value pair, and any number may be created and available for reference at a point in time.


3 Answers

Variables defined as below

Option 1: Java System Properties (VM Arguments)

It's important that the -D parameters are before your application.jar otherwise they are not recognized.

java -jar -Dspring.profiles.active=prod application.jar

Option 2: Program arguments

java -jar application.jar --spring.profiles.active=prod --spring.config.location=c:\config

POM changes : When using jib as maven plugin - to change the loading of spring config file location : then entryPoint to be passed inside container, but seems jib plugin didn't pick that up . so below changes needs to be done in pom for the argument access for the location :

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>2.2.0</version>
    <configuration>
        <to>
            <image>image-url</image>
        </to>
        <container>
            <creationTime>${​​​​​​maven.build.timestamp}​​​​​​</creationTime>
            <mainClass>com.package.SpringBootMainClass</mainClass>
            <args>
                <arg>--spring.config.location=/demo/location/application.yml</arg>
            </args>
        </container>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Jib-maven plugin in pom how to pass the arguments , just shown a way through pom , jib don't pick up arguments from entrypoint for spring app, that's why thought of providing another way for the same. as above answer doesn't have it.

like image 23
Sandeep Jain Avatar answered Oct 22 '22 11:10

Sandeep Jain


(Before I start: even if $JAVA_OPTS were expanded when running a Maven build at compile time (it isn't expanded, obviously), <jvmFlag>$JAVA_OPTS<jvmFlag> would still fail, because the entire string value of $JAVA_OPTS containing multiple JVM flags would be passed as a single argument to the java binary. For example, -Xms1024m -Xmx2048m should be passed as two separate flags. The entire string including the whitespace as a single argument is not a valid JVM flag.)


If possible, have the base image define JAVA_TOOL_OPTIONS (note not JAVA_TOOL_OPTS nor JAVA_OPTS). Most JVMs will honor JAVA_TOOL_OPTIONS. See https://stackoverflow.com/a/58715040/1701388 for details. (Also note that, container runtimes (docker, Kubernetes, etc.) can always provide environment variables (and/or override whatever variables defined at build time as container configuration) at runtime. That is, you can dynamically set arguments at runtime.)


Another option is to define your own <entrypoint> to use a shell. (Therefore, you need a base image that includes a shell binary (such as /bin/bash). Note that the default base image prior to Jib 3.0 was Distroless and did not include a shell program. OTOH, Jib 3.0+ doesn't use Distroless.)

In this method, you'll need to know the right Java runtime classpath and the main class to use in your JVM launch command. To help this, starting with Jib >= 3.1, Jib creates two JVM argument files inside a built image; they will hold, respectively, the classpath and the main class inside a built image.

Knowing the entrypoint, you can write a shell script (my-entrypoint.sh):

#!/bin/sh

# Assumes `java` is on PATH in the base image.
exec java $JAVA_OPTS \
  -cp $( cat /app/jib-classpath-file ) \
  $( cat /app/jib-main-class-file )

Alternatively, if you are on Java 9+, you can leverage the @-argument file:

exec java $JAVA_OPTS -cp @/app/jib-classpath-file @/app/jib-main-class-file

Place my-entrypoint.sh under <project root>/src/main/jib. This is the default directory for Jib's <extraDirectories> feature, and Jib will place src/main/jib/my-entrypoint.sh at the root directory in the container image. Then set the default <entrypoint> to this script:

<container>
  <!-- Assumes you have /bin/sh as specified at the top of /my-entrypoint.sh. -->
  <entrypoint>/my-entrypoint.sh</entrypoint>
</container>
<!-- You also need to make the script executable. -->
<extraDirectories>
  <permissions>
    <permission>
      <file>/my-entrypoint.sh</file>
      <mode>755</mode>
    </permission>
  </permissions>
</extraDirectories>

Alternatively, if you invoke /bin/sh as below, you don't have to configure <extraDirectories> to make the file executable. This may not look customary; you would normally make the script executable and run it directly. But this is perfectly valid, and there is no difference in terms of actual execution (as long as the shebang of /entrypoint.sh is the same #!/bin/sh).

<container>
  <entrypoint>
    <arg>/bin/sh</arg>
    <arg>/my-entrypoint.sh</arg>
  </entrypoint>
</container>

It's also possible to do this without creating a script (basically embedding the entire script in pom.xml and passing it to a shell program). In this case, you don't need to configure <extraDirectories>.

          <container>
            <entrypoint>
              <arg>/bin/sh</arg>
              <arg>-c</arg>
              <arg>exec java $JAVA_OPTS -cp $( cat /app/jib-classpath-file ) $( cat /app/jib-main-class-file )</arg>
            </entrypoint>
          </container>
like image 70
Chanseok Oh Avatar answered Oct 22 '22 10:10

Chanseok Oh


My solution is to remove JVM memory parameters from jib-maven-plugin configuration at all. Instead I define JAVA_TOOL_OPTIONS environment variable (example: JAVA_TOOL_OPTIONS='-Xss=512k') for the container (for example: in docker-compose configuration file).

Please note that this environment variable DOESN'T NEED to be defined in a base image at all.

like image 34
Krzysztof Tomaszewski Avatar answered Oct 22 '22 11:10

Krzysztof Tomaszewski