<p><em>Assuming the deployment of a Java microservice (Dropwizard) via Docker and Kubernetes.</em></p>

<p>An example microservice starts and runs flawlessly with <code>192Mi</code> HeapSize. 
This is determined as the basic memory requirement.</p>

<p><strong>An example Dockerfile</strong>, using <code>openjdk-runtime:11-hotspot</code></p>

<pre><code>FROM some-container-reg/openjdk-runtime:11-hotspot
# prepare build
COPY --chown=1001:1001 build/install/svc-example .
COPY --chown=1001:1001 config.yml .
# exposing port(s)
EXPOSE 8080
# setting entry point...
ENTRYPOINT ["bin/svc-example", "server", "config.yml"]
</code></pre>

<p><strong>Note:</strong> 
Since using <code>openjdk &gt; 10</code> the JVM detects if it's running in a container. 
Therefore there is no need to enable experimental VM features to achieve this like back in Java 8. 
For Details, please see the link below.</p>

<blockquote>
  <p><a href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115" rel="nofollow noreferrer">https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115</a></p>
</blockquote>

<p><strong>Corresponding k8s Deployment</strong></p>

<pre><code>resources:
  limits:
    cpu: 250m
    memory: 288Mi 
  requests:
    cpu: 100m
    memory: 192Mi
env:
  - name: JAVA_OPTS
    value: "-XX:MaxRAMPercentage=75.0"
</code></pre>

<p>The container request equals the <em>working</em> amount from the java application itself. 
The limits have been defined as the request plus an offset of <code>96Mi</code>. 
By doing this I want to ensure that the requirements besides the JVM-Heap have enough resources to work properly - <code>MetaspaceSize, CodeCache, ...</code>.</p>

<p>Also defining <code>JAVA_OPTS</code> within the container deployment by applying <code>-XX:MaxRAMPercentage=75.0</code> which defines a limit of 75% of total memory for the JVM.
Why not defining explicit heap limitations within <code>-XX:Xmx=192Mi</code>? For details, please see the link below.</p>

<blockquote>
  <p><a href="https://bugs.openjdk.java.net/browse/JDK-8186315" rel="nofollow noreferrer">https://bugs.openjdk.java.net/browse/JDK-8186315</a></p>
</blockquote>

<p>So, now to my questions:</p>

<ul>
<li>Am I correct with the suggestions above?</li>
<li>How do you determine the limits to achieve a low-cost deployment?</li>
<li>Is it required to apply additional params to the JVM, like <code>GC</code> or <code>MaxMetaspaceSize</code> to prevent memory usage above the limits?</li>
<li>Do I need to define JVM-Args to the Dockerfile too? More clearly, the JVM of Docker and the JVM of the Java-Microservice are the same?</li>
</ul>

leidenheit
<p>You need to profile your app using profilers and monitor it using APM tools to fine tune memory requirements as and when its needed and its a continuous activity. Regarding the last question whatever JRE/JDK the docker image have is the JDK/JRE used to create the container for the pod in kubernetes. Also I noticed you are using a JDK which is not recommend for production deployment...rather use a JRE.</p>

<p>The thing to remember from Kubernetes quota perspective is that at any point if the memory consumption by the java app goes beyond the value defined in the limits the pod will be terminated.</p>

<p>And pod will be not be scheduled at all if there is no node which has that much free memory defined in the requests.</p>
