<p>I have a spring boot application with the below docker file.</p>

<pre><code>FROM docker.com/base/jdk1.8:latest

MAINTAINER Application Engineering [ https://docker.com/ ]

RUN mkdir -p /opt/docker/svc

COPY application/weather-service.war /opt/docker/svc/

CMD java -jar /opt/docker/svc/weather-service.war --spring.config.location=file:/conf/application.properties -Dlogging.config=/conf/logback.xml
</code></pre>

<p>I can use kubernetes configMap or secrets for application.properties and use the volume mount option as below.</p>

<pre><code>"spec": {
        "volumes": [
          {
            "name": "svc-prop",
            "configMap": {
              "name": "svc-app-config",
              "items": [
                {
                  "key": "application.properties",
                  "path": "application.properties"
                }
              ]
            }
          }
         ],
        "containers": [
          "volumeMounts": [
              {
                "name": "svc-prop",
                "mountPath": "/conf"
              }
         ]
</code></pre>

<p>How can i achieve the samething for logback.xml. Do i need to use secrets as a file in this case?</p>

<p>I dont want to bundle logback.xml file with the image as we might be changing the log level at runtime.</p>

<p>Is there any other better approach for keeping logback.xml for spring boot app in Kubernetes?</p>

<p>Usually you do not want to provide the whole <code>logback.xml</code> file but rather it's <code>logger</code> list which requires updating at runtime most frequently. 
In order to achieve this you can use <a href="https://logback.qos.ch/manual/configuration.html#fileInclusion" rel="noreferrer">Logback's file inclusion</a> feature:</p>

<ol>
<li>Write your <code>logback.xml</code> file as usual except <code>logger</code> list. Use <code>include</code> element instead:</li>
</ol>

<pre class="lang-xml prettyprint-override"><code>    &lt;configuration scan="true" scanPeriod="10 seconds" debug="true"&gt;
        &lt;appender ...&gt;&lt;/appender&gt;
        &lt;root level="INFO"&gt;...&lt;/root&gt;

        &lt;!-- Import loggers configuration from external file --&gt;
        &lt;include file="config/mount/loggers-include.xml"/&gt;
    &lt;/configuration&gt;
</code></pre>

<p>Note those <code>scan*</code> attributes. They are essential for log config reloading at runtime.</p>

<ol start="2">
<li><p>Define all the loggers in Kubernetes ConfigMap with <code>loggers-include.xml</code> data section:
</p>

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: microservice-loggers    # the name to refer to from deployment (see below)
  namespace: upc
data:
  loggers-include.xml: |+
    &lt;included&gt;
      &lt;logger name="org.springframework.cloud.netflix.zuul" level="INFO"/&gt;
      &lt;logger name="com.netflix.zuul" level="INFO"/&gt;                              
      &lt;logger name="com.netflix.hystrix" level="INFO"/&gt;                          
      &lt;logger name="com.netflix.ribbon" level="DEBUG"/&gt;
      &lt;logger name="com.netflix.loadbalancer" level="INFO"/&gt;                     
    &lt;/included&gt;
</code></pre>

<p>Note that all the included content must be enclosed in <code>included</code> tag in order to be correctly parsed by Logback.</p></li>
<li><p>Mount your ConfigMap's data into container as <code>config/mount/loggers-include.xml</code> file:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
...
spec:
  ...
  template:
    ...
    spec:
      # declare the volume created from ConfigMap
      volumes:
        - name: config-volume             # used with this name below
          configMap:
            name: microservice-loggers    # declared in previous step
      containers:
      - name: microservice
        ...
        ports:
          ...
        # mount the volume declared above to container's file system
        volumeMounts:
          - mountPath: /microservice/config/mount
            name: config-volume       # declared above
</code></pre>

<p>Note that <code>mount</code> directory must not be created neither by container itself nor its image. Moreover, if such a directory exists, all its content <strong>will be removed</strong> during mounting.</p></li>
<li><p><a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-configmaps-from-files" rel="noreferrer">Apply the ConfigMap</a> and <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment" rel="noreferrer">run the declared deployment</a>. To check if loggers file is correctly mounted execute the following command:</p>

<pre><code>$ kubectl exec restorun-7d757b7c6-wcslx -- ls -l /microservice/config/mount
total 0
lrwxrwxrwx    1 root     root            26 Aug 14 05:52 loggers-include.xml -&gt; ..data/loggers-include.xml
</code></pre>

<p>Also if you've set  <code>debug=true</code> attribute in Logback's <code>configuration</code> element (see step 1) then you should see the following record in STDOUT during application startup:</p>

<pre><code>05:52:17,031 |-INFO in ch.qos.logback.core.joran.util.ConfigurationWatchListUtil@6e06451e - Adding [file:/microservice/config/mount/loggers-include.xml] to configuration watch list.
</code></pre></li>
<li><p>Now you can edit your ConfigMap (e.g. set <code>com.netflix.hystrix</code> to level <code>WARN</code>), save its file and tell Kubernetes to apply the changes to the application:</p>

<pre><code>$ kubectl apply -f microservice-log-configmap.yaml
configmap "microservice-loggers" configured
</code></pre>

<p>Again, Logback should reflect the changes by logging with the following message to standard output:</p>

<pre><code>    05:59:16,974 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.netflix.hystrix] to WARN
</code></pre>

<p>You can also check the effective logging level by directly asking it from the Spring Boot Actuator (if you have an access to this endpoint):</p>

<pre><code>$ curl http://&lt;k8s-external-ip&gt;/actuator/loggers/com.netflix.hystrix
{
  "configuredLevel" : "WARN",
  "effectiveLevel" : "WARN"
}
</code></pre></li>
</ol>

<p>If the level stays the same, wait for a minute and check again: it takes some time for changes to propagate through Kubernetes and Logback. More info on this topic:</p>

<ul>
<li><a href="https://logback.qos.ch/manual/configuration.html#autoScan" rel="noreferrer">Logback auto reloading</a></li>
<li><a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-configmaps-from-files" rel="noreferrer">Kubernetes ConfigMap mounting</a><br>
(see <em>Mounted ConfigMaps are updated automatically</em> section)</li>
</ul>
