I am trying to integrate a javaagent for application monitoring. I'm using docker and I've setup an OpenJDK base image which is inherited by other application images.
Since javaagent requires a path to the jar file, for maintenance purposes I've defined the path in the base image as another env variable(AGENT_PATH) and I want to reuse the same env variable across all my app images. For some reason the environment variable isn't picked and the application container exits with error.
Base Image's Dockerfile
AGENT_PATH=/agent/agent.jar
This is how I've configured JAVA_TOOL_OPTIONS in application's Dockerfile.
JAVA_TOOL_OPTIONS="-javaagent:$AGENT_PATH + other JVM options"
This is the error message
Picked up JAVA_TOOL_OPTIONS: -javaagent:$AGENT_PATH
Error opening zip file or JAR manifest missing : $AGENT_PATH
Error occurred during initialization of VM
agent library failed to init: instrument
Why is AGENT_PATH not getting substituted properly ?
I've grepped through Hotspot implementation for understanding. I've found this.
This will depend on the Docker step. If you use RUN step the variables processing is not supported:
Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, RUN [ "echo", "$HOME" ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: RUN [ "sh", "-c", "echo $HOME" ]. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.
In dockerfiles, all directives require a certain codeword. Assigning an environment variable is no different from this and needs the ENV codeword (read here).
Using this, the excerpt of your dockerfile should read
ENV AGENT_PATH=/agent/agent.jar
I was facing the same issue where the environment variables set in the JAVA_TOOL_OPTIONS were not getting substituted. So I had to mention those variables as -D parameters along with java command.
java -Djavax.net.ssl.keyStorePassword=$KeyStore_Secret .....
You can check if that is the case by hardcoding the values in the JAVA_TOOL_OPTIONS and it should work. Meanwhile, I am still looking at the reason for this.
Related
For context, I'm building a java application compiled to GraalVM native image running on a distroless docker image in Kubernetes.
I've been trying to do something rather simple and hit a wall: I'd like to set custom heap size limits per environment via -XmxNNN. To do that, the options with which I'd like to run the application would be held in an environment variable. The problem arises due to the usage of a distroless image - which doesn't have bash and so ENTRYPOINT /application $OPTIONS doesn't work.
Is there an environment variable GraalVM supports on its own, or any other way of setting this?
I dont want to:
hardcode the values in the Docker image
hardcode the values by predefining them during native-image build
You could use busybox to get a shell inside a distroless container:
FROM gcr.io/distroless/base
...
COPY --from=amd64/busybox:1.31.1 /bin/busybox /busybox/busybox
RUN ["/busybox/busybox", "--install", "/bin"]
CMD ["/bin/sh", "-c", "java -version"]
You can find an example to this kind of Dockerfile here.
But I don't think this busybox shell is necessary needed.
Altough ENTRYPOINT /application $OPTIONS does not work, this will work ENTRYPOINT ["myapp", "arguments"]
Note that distroless images by default do not contain a shell. That means the Dockerfile ENTRYPOINT command, when defined, must be specified in vector form, to avoid the container runtime prefixing with a shell.
source: github
I'm not sure if it will work, but you could try setting the environment variable JAVA_TOOL_OPTIONS to the desired value:
JAVA_TOOL_OPTIONS=-XmxNNN
From the documentation:
This environment variable allows you to specify the initialization of
tools, specifically the launching of native or Java programming language
agents using the -agentlib or -javaagent options. In the following example
the environment variable is set so that the HPROF profiler is launched when > the application is started:
$ export JAVA_TOOL_OPTIONS="-agentlib:hprof"
This variable can also be used to augment the command line with other
options for diagnostic purposes. For example, you can supply the
-XX:OnError option to specify a script or command to be executed when a
fatal error occurs.
The GraalVM documentation itself provides an example of use as well, although in a different context.
Good day everyone.
I have a simple java-based cucumber application, that runs in Docker. I planing to specify which scenarios to run by using ENV for Cucumber tags.
My Dockerfile that able to run specified tags:
FROM maven:3.6.1-jdk-11
COPY target/cucumber-app.jar ./
CMD java -jar -Dcucumber.options='--tags #default' cucumber-app.jar
In this case, during docker run command all works perfectly.
I plan to set up a default scenario for not specified Tags and ability to set up special scenarios through ENV:
FROM maven:3.6.1-jdk-11
COPY target/cucumber-app.jar ./
ENV TAG '--tags #default'
CMD java -jar -Dcucumber.options=$TAG cucumber-app.jar
Unfortunately in this case after running docker container I got:
Error: could not open `default'
Possible you have any ideas why using ENV crash possibility to specify cucumber.options?
If you have a recent version of Cucumber rather then trying to squeeze command line options in through a system property via an environment variable, you can set the environment variable straight away. I.e:
ENV CUCUMBER_FILTER_TAGS '#Cucumber and not (#Gherkin or #Zucchini)'
CMD java -jar cucumber-app.jar
https://github.com/cucumber/cucumber-jvm/tree/main/core
I have set environment variable by executing the command
export test=abcd
I can see test=abcd when I run printenvcommand
I have deployed a springboot.jar application and I am passing the JAVA_OPTS from the springboot.conf file.
JAVA_OPTS='-Dspring.profiles.active=aaa -Denv=$test'
I started the app by service springboot start . When I check the process, env variable doesn't have the value of $test environment variable.
/usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -Dspring.profiles.active=aaa -Denv=.
How can I access the environment variable in the conf file? I read somewhere the environment variables will be stripped off when run as service. Basically I want to run as service springboot start which internally executes the below command
java -Dspring.profiles.active=aws -Denv=${whatever is set for env environment variable} -jar springboot.jar
I have tried the below configurations but nothing worked
JAVA_OPTS='-Dspring.profiles.active=aaa -Denv='$test
JAVA_OPTS='-Dspring.profiles.active=aaa -Denv='${test}
JAVA_OPTS='-Dspring.profiles.active=aaa -Denv=${test}'
JAVA_OPTS="-Dspring.profiles.active=aaa -Denv=$test"
Be careful about your quotes. Assuming that you use a "normal" shell, variables won't be substituted in single quotes.
java -Dspring.profiles.active=aws -Denv="$myvariable" -jar springboot.jar should lead to env being available in the JVM, no matter if you run it as a service or not.
If you can't get it to work, try to specify a hard coded value like this java -Dspring.profiles.active=aws -Denv=foo -jar springboot.jar. If env is now available in the JVM, your problem is with your shell or run mechanism. Verify that the user who runs the command (i.e. do you use sudo?) has the variable set.
I had the same problem where my .conf was referencing an environment variable which was in the .bashrc.
What I found out is:
The problem is service strips all environment variables but TERM, PATH and LANG which is a good thing. If you are executing the script directly nothing removes the environment variables so everything works.
https://unix.stackexchange.com/questions/44370/how-to-make-unix-service-see-environment-variables
One solution would be to install your app as a systemd service:
https://docs.spring.io/spring-boot/docs/1.3.x-SNAPSHOT/reference/html/deployment-install.html
Or another way is to use docker and you can specify extra configuration in the docker file, like loading a file which contains your environment variables.
As those solutions where not available in my case I ended up with having the value in the .conf file, like: -Denv=prod
I'm creating a Dockerfile for our Spring Boot application. The application takes a couple of command line parameters. At the end of Dockfile:
CMD java -jar Application.jar --bucket=bucket.list --key=lost
But is it a best practice to hardcode the values for bucket and key in the Dockfile?
If it is ok, then I can live with that. Otherwise, I would like to know how to parameterize the Dockfile.
The application will be deployed on AWS, if that opens the door for more suggestions.
Docker design focused in being independent as far as possible of Host environment, including when building a Docker image. There were a request to let Docker build accessing to host environmental variables but it was rejected looking for independence of host machine. There it is also commented some workaround that could fit your problem.
Anyway, what is supposed to do Application.jar? If it's an application supposed to be running inside the container (and not in building time) the correct way to launch it is using a custom script run when you start the container. There you can set your credential or any other information you wish to be accessed from a environment variable, that can be set when launching the container: docker run -e "MYKEY=secret" -e "MYBUCKET=bucket" myuser/myapp /my/custom/script
You can use environment variables or build arguments.
Build arguments allow you to specify parameters that are applied at buildtime when you execute docker build using the --build-arg ARG_NAME=ARG_VALUE command line parameter.
Environment variables allow you to specify parameters that are applied at runtime when you execute docker run using the -e "ENV_NAME=ENV_VALUE" command line parameter.
I have noticed that some of my environment variables are not being picked up by the JVM.
In my .bash_profile I defined the following:
IO_HOME='some_value'
export IO_HOME
and by doing in shell:
echo $IO_HOME
I get the correct result.
But neither System.getProperties() nor System.getenv() is showing this variable being set. I tried both Java 6 and Java 7.
Is there something I am missing?
Exporting environment to spawned processes is pretty stable; if System.getenv() is not including a variable then it is because it is not in the environment. A couple of things to check, both relating to how the process is started:
Are you starting the java process from an environment where the variable is exported? For example, if it is in your .bash_profile and you are executing the java program from a menu or desktop then you have to log out and log in after adding it in .bash_profile for your desktop to see the variable.
Is the variable explicitly removed from environment for the process? ProcessBuilder allows this, as do most of all APIs that spawn processes.
One thing to try is to start the process from command line shell, after ensuring the variable is exported in that shell.
From Windows, I recently saw some crazy behaviour where IntelliJ refused to show all env vars from System.getenv() after setting either user or system env vars. The trick was to launch IntelliJ from a DOS box. For Windows users: Maybe a reboot (or logoff/logon) will fix the issue.