<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Docker COntainer &#8211; Best DevOps</title>
	<atom:link href="https://www.bestdevops.com/tag/docker-container/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bestdevops.com</link>
	<description>Lets Learn, Do it &#38; Share! Thats a Best DevOps!!!</description>
	<lastBuildDate>Mon, 12 Oct 2026 11:34:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>Testing Ansible in a Docker Container: How to Configure Networking</title>
		<link>https://www.bestdevops.com/testing-ansible-in-docker-container-how-to-set-networks/</link>
					<comments>https://www.bestdevops.com/testing-ansible-in-docker-container-how-to-set-networks/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Mon, 19 Jun 2017 06:51:15 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker COntainer]]></category>
		<category><![CDATA[network settings]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Testing ansible]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1872</guid>

					<description><![CDATA[Learn why Ansible cannot reach sibling Docker containers over localhost and how to correctly configure container networking so Ansible can connect to its target hosts.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Original context: Docker for Mac. The networking behaviour described here is most pronounced on macOS, but the underlying Docker networking concepts apply generally.</em></p>



<h2 class="wp-block-heading">The Problem</h2>



<p class="wp-block-paragraph">A common goal when learning or testing Ansible is to spin up a small cluster of Docker containers: one container acting as the Ansible control node and one or more containers acting as managed targets. The setup seems straightforward, but many people hit the same wall immediately: Ansible reports that every target is <strong>UNREACHABLE</strong>.</p>



<p class="wp-block-paragraph">A typical error looks like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">fatal: &#91;<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>]: UNREACHABLE! =&gt; {<span class="hljs-string">"changed"</span>: <span class="hljs-keyword">false</span>, <span class="hljs-string">"msg"</span>: <span class="hljs-string">"&#91;Errno None] Unable to connect to port 9800 on 127.0.0.1"</span>, <span class="hljs-string">"unreachable"</span>: <span class="hljs-keyword">true</span>}</code></span></pre>


<p class="wp-block-paragraph">The Ansible inventory (<code>hosts</code> file) in this scenario looks like:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-attr">&#91;docker-hosts]</span>
127<span class="hljs-selector-class">.0</span><span class="hljs-selector-class">.0</span><span class="hljs-selector-class">.1</span><span class="hljs-selector-pseudo">:9800</span>
127<span class="hljs-selector-class">.0</span><span class="hljs-selector-class">.0</span><span class="hljs-selector-class">.1</span><span class="hljs-selector-pseudo">:9801</span></code></span></pre>


<p class="wp-block-paragraph">And a minimal <code>playbook.yml</code> targeting those hosts:</p>


<pre class="wp-block-code"><span><code class="hljs">---
- hosts: docker-hosts
  remote_user: root
  become: yes
  become_method: sudo

  tasks:
    - name: pulling docker image
      docker_image:
        name: centos</code></span></pre>


<p class="wp-block-paragraph">Run with:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-tag">ansible-playbook</span> <span class="hljs-selector-tag">playbook</span><span class="hljs-selector-class">.yml</span> <span class="hljs-selector-tag">-f</span> 10</code></span></pre>


<p class="wp-block-paragraph">Both <code>127.0.0.1</code> and <code>0.0.0.0</code> fail as target addresses. Here is why, and how to fix it.</p>



<h2 class="wp-block-heading">Why 127.0.0.1 Does Not Work Between Containers</h2>



<p class="wp-block-paragraph">Inside any Docker container, <code>127.0.0.1</code> (loopback) refers to <strong>that container itself</strong>, not to the Docker host and not to any sibling container. When the Ansible control container tries to SSH to <code>127.0.0.1:9800</code>, it is attempting to connect to a port on its own loopback interface — which has nothing listening on it.</p>



<p class="wp-block-paragraph">Even if you published the target containers&#8217; SSH ports to the Docker host (e.g., <code>-p 9800:22</code>), the host&#8217;s loopback is a separate network namespace from the container&#8217;s loopback. On Linux you <em>might</em> be able to reach the host via the default bridge gateway IP, but on Docker for Mac there is an additional networking layer (a Linux VM) that makes <code>127.0.0.1</code> from inside a container even less reliable for this purpose.</p>



<h2 class="wp-block-heading">Solution 1: Use a User-Defined Docker Bridge Network</h2>



<p class="wp-block-paragraph">The cleanest approach is to put all containers on the same user-defined bridge network. Docker then provides automatic DNS resolution by container name, so you can address targets by name rather than by IP address.</p>



<h3 class="wp-block-heading">Step 1 — Create a dedicated network</h3>


<pre class="wp-block-code"><span><code class="hljs">docker network create ansible-test</code></span></pre>


<h3 class="wp-block-heading">Step 2 — Start the target containers on that network</h3>


<pre class="wp-block-code"><span><code class="hljs">docker run -d --name target1 --network ansible-test --rm centos:latest /usr/sbin/sshd -D
docker run -d --name target2 --network ansible-test --rm centos:latest /usr/sbin/sshd -D</code></span></pre>


<p class="wp-block-paragraph"><em>Note: A base CentOS image does not run SSH by default. You will need a custom image that installs and configures <code>openssh-server</code> and sets up SSH keys. See Solution 3 below for an alternative that avoids SSH entirely.</em></p>



<h3 class="wp-block-heading">Step 3 — Start the Ansible control container on the same network</h3>


<pre class="wp-block-code"><span><code class="hljs">docker run -it --name ansible-control --network ansible-test --rm your-ansible-image bash</code></span></pre>


<h3 class="wp-block-heading">Step 4 — Update the Ansible inventory to use container names</h3>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-attr">&#91;docker-hosts]</span>
<span class="hljs-selector-tag">target1</span>
<span class="hljs-selector-tag">target2</span></code></span></pre>


<p class="wp-block-paragraph">Docker&#8217;s embedded DNS resolves <code>target1</code> and <code>target2</code> to the correct container IP addresses automatically. No port mapping to the host is required.</p>



<h2 class="wp-block-heading">Solution 2: Use Docker Compose to Manage the Network Automatically</h2>



<p class="wp-block-paragraph">Docker Compose creates a dedicated bridge network for each project by default, so all services within one Compose file can reach each other by service name.</p>


<pre class="wp-block-code"><span><code class="hljs language-php">version: <span class="hljs-string">"3"</span>
services:
  ansible-control:
    image: your-ansible-image
    depends_on:
      - target1
      - target2
    volumes:
      - ./playbooks:/playbooks

  target1:
    image: your-ssh-enabled-centos-image

  target2:
    image: your-ssh-enabled-centos-image</code></span></pre>


<p class="wp-block-paragraph">Your Ansible inventory then simply references <code>target1</code> and <code>target2</code> by service name.</p>



<h2 class="wp-block-heading">Solution 3: Use the Docker Connection Plugin Instead of SSH</h2>



<p class="wp-block-paragraph">If the goal is purely to test Ansible playbooks against containers (rather than to test SSH connectivity itself), you can skip SSH altogether. Ansible ships with a <code>docker</code> connection plugin that uses <code>docker exec</code> internally.</p>



<p class="wp-block-paragraph">Set the connection type in your inventory:</p>


<pre class="wp-block-code"><span><code class="hljs">&#91;docker-hosts]
target1 ansible_connection=docker
target2 ansible_connection=docker</code></span></pre>


<p class="wp-block-paragraph">With this approach:</p>



<ul class="wp-block-list">
<li>No SSH daemon is needed in the target containers.</li>
<li>No port publishing or network configuration is required.</li>
<li>The Ansible control node must be able to run <code>docker exec</code> — either by running on the Docker host itself, or by mounting the Docker socket into the control container (<code>-v /var/run/docker.sock:/var/run/docker.sock</code>).</li>
</ul>



<h2 class="wp-block-heading">Why Port-Mapping to the Host Is Not Enough on Its Own</h2>



<p class="wp-block-paragraph">Some guides suggest publishing SSH ports to the host (e.g., <code>-p 9800:22 -p 9801:22</code>) and then pointing Ansible at the host&#8217;s IP. This <em>can</em> work when Ansible runs directly on the host, because the host&#8217;s loopback or LAN IP is reachable. However, when Ansible itself runs <em>inside</em> a container, the situation changes:</p>



<ul class="wp-block-list">
<li>On <strong>Linux</strong>, the default Docker bridge gateway (typically <code>172.17.0.1</code>) is the host&#8217;s bridge IP and is reachable from containers. You could use that IP in the inventory.</li>
<li>On <strong>Docker for Mac</strong>, the Docker engine runs inside a Linux VM. The host&#8217;s <code>localhost</code> is not directly reachable from inside a container using <code>127.0.0.1</code>. Docker for Mac provides the special hostname <code>host.docker.internal</code> to reach the host machine, but this adds unnecessary complexity.</li>
</ul>



<p class="wp-block-paragraph">Using a user-defined network (Solution 1) or the Docker connection plugin (Solution 3) avoids all of this complexity.</p>



<h2 class="wp-block-heading">Summary</h2>



<figure class="wp-block-table"><table><thead><tr><th>Approach</th><th>Needs SSH in target?</th><th>Works on Docker for Mac?</th><th>Complexity</th></tr></thead><tbody><tr><td>User-defined bridge network + SSH</td><td>Yes</td><td>Yes</td><td>Low</td></tr><tr><td>Docker Compose network + SSH</td><td>Yes</td><td>Yes</td><td>Low</td></tr><tr><td>Docker connection plugin (<code>docker exec</code>)</td><td>No</td><td>Yes</td><td>Very low</td></tr><tr><td>Port-map to host + host IP in inventory</td><td>Yes</td><td>Fragile</td><td>Medium</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">For most local Ansible testing workflows, a user-defined Docker network with container-name-based inventory, or the <code>docker</code> connection plugin, is the recommended approach. Avoid addressing sibling containers via <code>127.0.0.1</code> — it refers to the container&#8217;s own loopback, not to any other container or to the host.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/testing-ansible-in-docker-container-how-to-set-networks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Deploy Java Apps With Docker: A Step-by-Step Guide</title>
		<link>https://www.bestdevops.com/how-to-deploy-java-apps-with-docker/</link>
					<comments>https://www.bestdevops.com/how-to-deploy-java-apps-with-docker/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Sat, 17 Jun 2017 07:30:00 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Deploy Java Apps]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker COntainer]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1862</guid>

					<description><![CDATA[Learn how to deploy a Java application inside a Docker container on Linux, from installing Docker and Java to running and persisting your app with Docker volumes.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Docker is a platform for packaging, deploying, and running applications in lightweight, portable containers that are isolated from the underlying hardware and operating system. If you have a Java application you want to containerize, this guide walks you through every step: installing Docker, building a Java-capable image, deploying a Java application, and persisting data across container restarts.</p>




<p class="wp-block-paragraph"><strong>Note:</strong> This tutorial was originally written for an early version of Docker on Ubuntu 12.10 and uses the legacy <code>lxc-docker</code> package and <code>docker commit</code> workflow. The core concepts still apply, but modern Docker installations should use the official Docker Engine packages from <a href="https://docs.docker.com/engine/install/">docs.docker.com</a> and prefer Dockerfiles over interactive commits. See the review notes at the bottom for details.</p>




<h2 class="wp-block-heading">Prerequisites</h2>



<p class="wp-block-paragraph">Docker runs on Linux, macOS, Windows, Windows Server, and major cloud platforms including AWS and Azure. The examples below use Ubuntu Linux. The demonstration application is <strong>Bitbucket Server</strong> (Atlassian&#8217;s self-hosted Git repository manager, previously called Stash), but you can substitute any Java application.</p>



<p class="wp-block-paragraph">Before you start, install a few common utilities on your host machine:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo apt-<span class="hljs-keyword">get</span> install vim curl git</code></span></pre>


<h2 class="wp-block-heading">Step 1: Install Docker</h2>



<p class="wp-block-paragraph">The following commands show the historical installation path used in the original tutorial (Ubuntu 12.10, <code>lxc-docker</code> package). For current Ubuntu versions, follow the <a href="https://docs.docker.com/engine/install/ubuntu/">official Docker installation guide</a> instead.</p>



<p class="wp-block-paragraph">Install kernel extras required by Docker:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo apt-<span class="hljs-keyword">get</span> install linux-image-extra-$(uname -r)</code></span></pre>


<p class="wp-block-paragraph">Install <code>software-properties-common</code> to gain access to <code>add-apt-repository</code>:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo apt-<span class="hljs-keyword">get</span> install software-properties-common</code></span></pre>


<p class="wp-block-paragraph">Add the Docker PPA and update package lists:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo add-apt-repository ppa:dotcloud/lxc-docker
sudo apt-<span class="hljs-keyword">get</span> update</code></span></pre>


<p class="wp-block-paragraph">Install Docker:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo apt-<span class="hljs-keyword">get</span> install lxc-docker</code></span></pre>


<p class="wp-block-paragraph">Pull a base Ubuntu image to use as your starting point:</p>


<pre class="wp-block-code"><span><code class="hljs">docker pull base</code></span></pre>


<p class="wp-block-paragraph">Docker will download the image layers and confirm when the pull is complete. If the Docker daemon is not already running, start it in the background:</p>


<pre class="wp-block-code"><span><code class="hljs">sudo docker -d &amp;</code></span></pre>


<p class="wp-block-paragraph">You can list all images available locally at any time:</p>


<pre class="wp-block-code"><span><code class="hljs">docker images</code></span></pre>


<p class="wp-block-paragraph">After pulling the base image you should see output similar to:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-tag">REPOSITORY</span>   <span class="hljs-selector-tag">TAG</span>              <span class="hljs-selector-tag">ID</span>             <span class="hljs-selector-tag">CREATED</span>
<span class="hljs-selector-tag">base</span>         <span class="hljs-selector-tag">ubuntu-quantal</span>   <span class="hljs-selector-tag">b750fe79269d</span>   10 <span class="hljs-selector-tag">weeks</span> <span class="hljs-selector-tag">ago</span>
<span class="hljs-selector-tag">base</span>         <span class="hljs-selector-tag">latest</span>           <span class="hljs-selector-tag">b750fe79269d</span>   10 <span class="hljs-selector-tag">weeks</span> <span class="hljs-selector-tag">ago</span>
<span class="hljs-selector-tag">base</span>         <span class="hljs-selector-tag">ubuntu-12</span><span class="hljs-selector-class">.10</span>     <span class="hljs-selector-tag">b750fe79269d</span>   10 <span class="hljs-selector-tag">weeks</span> <span class="hljs-selector-tag">ago</span></code></span></pre>


<h2 class="wp-block-heading">Step 2: Install Java Inside a Docker Container</h2>



<p class="wp-block-paragraph">Start an interactive shell inside the base container:</p>


<pre class="wp-block-code"><span><code class="hljs">docker run -i -t base /bin/bash</code></span></pre>


<p class="wp-block-paragraph">Docker creates a new container, assigns it a unique ID and an internal IP address, and drops you into a root shell:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">root@<span class="hljs-number">298</span>af82e71ef:/<span class="hljs-comment">#</span></code></span></pre>


<p class="wp-block-paragraph">Inside the container, install the prerequisite package and add the Java PPA:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">apt-<span class="hljs-keyword">get</span> install software-properties-common
add-apt-repository ppa:webupd8team/java
apt-<span class="hljs-keyword">get</span> update</code></span></pre>


<p class="wp-block-paragraph">Install Java (you may be prompted to accept the Oracle license agreement):</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">apt-<span class="hljs-keyword">get</span> install git curl oracle-java7-installer</code></span></pre>


<p class="wp-block-paragraph">Exit the container with <code>exit</code> or <kbd>Ctrl+D</kbd>, then list all containers (including stopped ones) to find its ID:</p>


<pre class="wp-block-code"><span><code class="hljs">docker ps -a</code></span></pre>

<pre class="wp-block-code"><span><code class="hljs language-php">ID             IMAGE          COMMAND      CREATED          STATUS
<span class="hljs-number">8e07</span>a84ea97a   base:latest    /bin/bash    <span class="hljs-number">12</span> minutes ago   <span class="hljs-keyword">Exit</span> <span class="hljs-number">0</span>
...</code></span></pre>


<p class="wp-block-paragraph">Commit the most recent container (the one where you installed Java) as a new named image:</p>


<pre class="wp-block-code"><span><code class="hljs">docker commit 8e07a84ea97a durdn/java7</code></span></pre>


<p class="wp-block-paragraph">Verify it appears in your local image list:</p>


<pre class="wp-block-code"><span><code class="hljs">docker images

REPOSITORY     TAG      ID             CREATED
durdn/java7    latest   ab6396541f9a   2 hours ago
base           latest   b750fe79269d   10 weeks ago</code></span></pre>


<p class="wp-block-paragraph">You now have a reusable Docker image with Java installed. Any future container launched from <code>durdn/java7</code> starts with Java already present.</p>



<h2 class="wp-block-heading">Step 3: Install the Java Application in Your Container</h2>



<p class="wp-block-paragraph">Spin up an interactive shell from your new <code>durdn/java7</code> image. Map container port <code>7990</code> to the host and declare a persistent volume at <code>/opt/stash-home</code> for application data:</p>


<pre class="wp-block-code"><span><code class="hljs">docker run -i -t -p :7990 -v /opt/stash-home durdn/java7 /bin/bash</code></span></pre>


<p class="wp-block-paragraph">Inside the container, download Bitbucket Server (formerly called Stash — hence the file and directory names below):</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">curl -Lks https:<span class="hljs-comment">//www.atlassian.com/software/stash/downloads/binary/atlassian-bitbucket-4.13.0.tar.gz \</span>
     -o /root/stash.tar.gz</code></span></pre>


<p class="wp-block-paragraph">Unpack the archive and set up the application home directory:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">mkdir /opt/stash
tar zxf /root/stash.tar.gz --strip=<span class="hljs-number">1</span> -C /opt/stash
mkdir /opt/stash-home
<span class="hljs-keyword">export</span> STASH_HOME=<span class="hljs-regexp">/opt/</span>stash-home</code></span></pre>


<p class="wp-block-paragraph">Add the container&#8217;s hostname to <code>/etc/hosts</code> to avoid startup errors (replace <code>298af82e71ef</code> with your actual container ID as shown in the shell prompt):</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">echo <span class="hljs-string">"127.0.0.1 298af82e71ef"</span> &gt;&gt; <span class="hljs-regexp">/etc/</span>hosts</code></span></pre>


<p class="wp-block-paragraph">Start the application in the foreground:</p>


<pre class="wp-block-code"><span><code class="hljs">/opt/stash/bin/start-stash.sh -fg</code></span></pre>


<p class="wp-block-paragraph">Open <code>http://localhost:7990/stash</code> in your browser to confirm the application is running.</p>



<p class="wp-block-paragraph">Exit the container, then commit the state to a new image:</p>


<pre class="wp-block-code"><span><code class="hljs">docker commit aec2feb8cdea durdn/stash</code></span></pre>


<p class="wp-block-paragraph">You now have a <code>durdn/stash</code> image with Bitbucket Server installed and ready to launch.</p>



<h2 class="wp-block-heading">Ephemeral Containers and Persistent Storage</h2>



<p class="wp-block-paragraph">Docker containers are <strong>ephemeral</strong>: when a container is removed, its writable layer is discarded and the container resets to its image state. Without persistence, application data is lost every time you stop and remove a container.</p>



<p class="wp-block-paragraph">The solution is Docker <strong>volumes</strong>. Volumes exist independently of any individual container and can be shared between containers. In the older Docker API shown here, the <code>--volumes-from</code> flag reuses the volume from a previously run container.</p>



<p class="wp-block-paragraph">Start Bitbucket Server interactively, reusing the data volume from the earlier container:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">docker run -i -t -p :<span class="hljs-number">7990</span> --volumes-<span class="hljs-keyword">from</span> aec2feb8cdea durdn/stash \
  /bin/bash -c <span class="hljs-string">'STASH_HOME=/opt/stash-home /opt/stash/bin/start-stash.sh -fg'</span></code></span></pre>


<p class="wp-block-paragraph">To run the container in the background (detached mode), replace <code>-i -t</code> with <code>-d</code>:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">docker run -d -p :<span class="hljs-number">7990</span> --volumes-<span class="hljs-keyword">from</span> aec2feb8cdea durdn/stash \
  /bin/bash -c <span class="hljs-string">'STASH_HOME=/opt/stash-home /opt/stash/bin/start-stash.sh -fg'</span></code></span></pre>


<p class="wp-block-paragraph">Confirm the container is running:</p>


<pre class="wp-block-code"><span><code class="hljs">docker ps</code></span></pre>


<p class="wp-block-paragraph">Your application is now running in the background with data persisted across container restarts.</p>



<h2 class="wp-block-heading">Modern Alternatives: Dockerfiles and Official Images</h2>



<p class="wp-block-paragraph">The interactive <code>docker commit</code> workflow demonstrated above is useful for understanding how Docker layers work, but production workflows typically use <strong>Dockerfiles</strong>. A Dockerfile codifies every step as a reproducible build instruction, making images auditable and easy to rebuild.</p>



<p class="wp-block-paragraph">For Java applications, Docker Hub provides official images such as <code>eclipse-temurin</code> and <code>amazoncorretto</code> that eliminate the need to manually install a JDK. A minimal Dockerfile for a Java application might look like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># Use an official JDK base image</span>
FROM eclipse-temurin:<span class="hljs-number">21</span>-jre

<span class="hljs-comment"># Copy the application JAR into the image</span>
COPY target/myapp.jar /app/myapp.jar

<span class="hljs-comment"># Expose the application port</span>
EXPOSE <span class="hljs-number">8080</span>

<span class="hljs-comment"># Run the application</span>
CMD &#91;<span class="hljs-string">"java"</span>, <span class="hljs-string">"-jar"</span>, <span class="hljs-string">"/app/myapp.jar"</span>]</code></span></pre>


<p class="wp-block-paragraph">Build the image with:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-tag">docker</span> <span class="hljs-selector-tag">build</span> <span class="hljs-selector-tag">-t</span> <span class="hljs-selector-tag">myapp</span><span class="hljs-selector-pseudo">:latest</span> .</code></span></pre>


<p class="wp-block-paragraph">And run it with a named volume for data persistence:</p>


<pre class="wp-block-code"><span><code class="hljs">docker run -d -p 8080:8080 -v myapp-data:/data myapp:latest</code></span></pre>


<h2 class="wp-block-heading">Key Takeaways</h2>



<ul class="wp-block-list">
<li>Docker containers provide a portable, repeatable runtime environment for Java applications without requiring configuration changes on the host system.</li>
<li>The <code>docker commit</code> approach turns a running container into a reusable image — useful for learning, but Dockerfiles are the standard for production builds.</li>
<li>Containers are ephemeral by default. Use Docker volumes (<code>-v</code> or <code>--volumes-from</code>) to persist data between container runs.</li>
<li>For modern Java workloads, start from an official JDK image on Docker Hub rather than installing Java manually inside a generic base image.</li>
<li>Use <code>docker ps</code> to list running containers and <code>docker ps -a</code> to include stopped ones.</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/how-to-deploy-java-apps-with-docker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Using Docker Behind a Corporate Proxy</title>
		<link>https://www.bestdevops.com/using-docker-behind-a-proxy/</link>
					<comments>https://www.bestdevops.com/using-docker-behind-a-proxy/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Mon, 03 Apr 2017 07:59:20 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Process]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker COntainer]]></category>
		<category><![CDATA[Docker Proxy Configuration]]></category>
		<category><![CDATA[Docker Proxy Settings]]></category>
		<category><![CDATA[Proxy Configuration]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1124</guid>

					<description><![CDATA[Running Docker inside a corporate network with a web proxy? Learn how to configure the Docker daemon, Dockerfile ENV variables, and build arguments so that both image pulls and in-container package managers work correctly behind a proxy.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Running Docker inside a large corporate network often means that direct internet access is blocked and all outbound traffic must pass through an HTTP proxy. Docker&#8217;s default behavior assumes unrestricted internet access, so you will hit connectivity errors when trying to pull images or install packages inside a container. This article walks through every layer of proxy configuration you need to address: the Docker daemon, the container build environment, and the container runtime.</p>



<h2 class="wp-block-heading">The Problem: Two Separate Network Contexts</h2>



<p class="wp-block-paragraph">A proxy misconfiguration with Docker almost always comes down to one misunderstood fact: <strong>there are two separate network contexts that each need independent proxy settings</strong>.</p>



<ul class="wp-block-list">
<li><strong>The Docker daemon</strong> — responsible for pulling base images from registries such as Docker Hub.</li>
<li><strong>The container build/run environment</strong> — the isolated environment in which your <code>RUN</code> instructions execute. Tools like <code>apt-get</code>, <code>yum</code>, <code>curl</code>, and <code>pip</code> run here and have no knowledge of the host&#8217;s proxy settings.</li>
</ul>



<p class="wp-block-paragraph">Configuring one without the other will leave you with partial failures. The sections below address each context in turn.</p>



<h2 class="wp-block-heading">A Simple Example Dockerfile</h2>



<p class="wp-block-paragraph">Throughout this article we will use a minimal Ubuntu-based image that installs <code>curl</code> via <code>apt-get</code>. This is intentionally simple, but it exercises both proxy contexts.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">FROM ubuntu

RUN apt-<span class="hljs-keyword">get</span> update &amp;&amp; apt-<span class="hljs-keyword">get</span> install -y curl</code></span></pre>


<p class="wp-block-paragraph">Attempting to build this image on a network with no direct internet access produces an error immediately at the <code>FROM</code> step:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$ sudo docker build -t curl .
Sending build context to Docker daemon <span class="hljs-number">12.29</span> kB
Step <span class="hljs-number">0</span> : FROM ubuntu
Pulling repository ubuntu
INFO&#91;<span class="hljs-number">0002</span>] Get https:<span class="hljs-comment">//index.docker.io/v1/repositories/library/ubuntu/images: dial tcp 52.22.146.88:443: connection refused</span></code></span></pre>


<p class="wp-block-paragraph">The daemon cannot reach Docker Hub because outbound TCP connections are blocked. Fix this first.</p>



<h2 class="wp-block-heading">Step 1 — Configuring the Docker Daemon to Use a Proxy (Ubuntu host)</h2>



<p class="wp-block-paragraph">On Ubuntu hosts that use the older SysV init system, Docker&#8217;s environment is sourced from <code>/etc/default/docker</code>. That file includes a commented-out proxy line:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># If you need Docker to use an HTTP proxy, it can also be specified here.</span>
<span class="hljs-comment">#export http_proxy="http://127.0.0.1:3128/"</span></code></span></pre>


<p class="wp-block-paragraph">Uncomment the line and replace the placeholder with your actual proxy address:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># If you need Docker to use an HTTP proxy, it can also be specified here.</span>
export http_proxy=<span class="hljs-string">"http://192.168.33.10:3128/"</span></code></span></pre>


<p class="wp-block-paragraph">If your proxy requires authentication, embed the credentials in the URL:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">export</span> http_proxy=<span class="hljs-string">"http://username:password@192.168.33.10:3128/"</span></code></span></pre>


<h3 class="wp-block-heading">systemd-based hosts</h3>



<p class="wp-block-paragraph">Most modern Ubuntu and Debian installations (16.04 and later) manage Docker with <strong>systemd</strong>, which does not read <code>/etc/default/docker</code> for environment variables. For systemd, create a drop-in override file instead:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf &lt;&lt;EOF
&#91;Service]
Environment=<span class="hljs-string">"HTTP_PROXY=http://192.168.33.10:3128/"</span>
Environment=<span class="hljs-string">"HTTPS_PROXY=http://192.168.33.10:3128/"</span>
Environment=<span class="hljs-string">"NO_PROXY=localhost,127.0.0.1"</span>
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker</code></span></pre>


<p class="wp-block-paragraph">For the SysV approach, restart Docker with the <code>service</code> command:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># service docker restart</span>
docker stop/waiting
docker start/running, process <span class="hljs-number">32703</span></code></span></pre>


<p class="wp-block-paragraph">After restarting, <code>docker pull</code> and the <code>FROM</code> step of a build will route through your proxy. However, <code>RUN</code> instructions that use <code>apt-get</code> or other network tools will still fail because the container environment has no proxy configured.</p>



<h2 class="wp-block-heading">Step 2 — Configuring the Proxy Inside the Container</h2>



<p class="wp-block-paragraph">After configuring the daemon proxy, re-running the build pulls the Ubuntu base image successfully — but <code>apt-get update</code> immediately fails:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">Step <span class="hljs-number">1</span> : RUN apt-<span class="hljs-keyword">get</span> update &amp;&amp; apt-<span class="hljs-keyword">get</span> install -y curl
 ---&gt; Running in 39b964be90bc
Err:1 http://archive.ubuntu.com/ubuntu xenial InRelease
  Cannot initiate the connection to archive.ubuntu.com:80. - connect (101: Network is unreachable)
E: Unable to locate package curl</code></span></pre>


<p class="wp-block-paragraph">This happens because the container&#8217;s network environment is isolated from the host. The <code>http_proxy</code> variable set on the host is not inherited inside the container&#8217;s build shell.</p>



<h3 class="wp-block-heading">Option A — Pass proxy settings as build arguments</h3>



<p class="wp-block-paragraph">Use <code>--build-arg</code> to inject the proxy at build time without hardcoding it in the Dockerfile:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$ sudo docker build -t curl \
  --build-arg http_proxy=http:<span class="hljs-comment">//192.168.33.10:3128 \</span>
  --build-arg https_proxy=http:<span class="hljs-comment">//192.168.33.10:3128 \</span>
  .</code></span></pre>


<p class="wp-block-paragraph">This approach is preferred when you want to keep the Dockerfile portable — colleagues on networks without a proxy can build the same file without modification.</p>



<h3 class="wp-block-heading">Option B — Set proxy variables in the Dockerfile with ENV</h3>



<p class="wp-block-paragraph">Alternatively, declare the proxy variables directly in the Dockerfile using <code>ENV</code> instructions:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">FROM ubuntu

ENV http_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
ENV https_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
RUN apt-<span class="hljs-keyword">get</span> update &amp;&amp; apt-<span class="hljs-keyword">get</span> install -y curl</code></span></pre>


<p class="wp-block-paragraph">Both <code>apt-get</code> and <code>curl</code> respect the standard <code>http_proxy</code> / <code>https_proxy</code> environment variables, so this is sufficient for most Linux package managers and command-line HTTP tools.</p>



<h2 class="wp-block-heading">Step 3 — Verifying the Build and Runtime Behaviour</h2>



<p class="wp-block-paragraph">With proxy variables set, the build completes successfully:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$ sudo docker build -t curl .
...
Step <span class="hljs-number">1</span> : ENV http_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
Step <span class="hljs-number">2</span> : ENV https_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
Step <span class="hljs-number">3</span> : RUN apt-<span class="hljs-keyword">get</span> update &amp;&amp; apt-<span class="hljs-keyword">get</span> install -y curl
Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease &#91;247 kB]
Get:2 http://archive.ubuntu.com/ubuntu xenial-updates InRelease &#91;102 kB]
...</code></span></pre>


<p class="wp-block-paragraph">Running the container and making an outbound request with <code>curl</code> shows that traffic is also routed through the proxy at runtime:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$ sudo docker run curl curl -v http:<span class="hljs-comment">//example.com</span>
*   Trying <span class="hljs-number">192.168</span><span class="hljs-number">.33</span><span class="hljs-number">.10</span>...
&gt; GET http:<span class="hljs-comment">//example.com/ HTTP/1.1</span>
&gt; <span class="hljs-built_in">Proxy</span>-Connection: Keep-Alive
&lt; HTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">200</span> OK</code></span></pre>


<p class="wp-block-paragraph">Notice the <code>Proxy-Connection</code> header — the request was forwarded via the proxy.</p>



<h2 class="wp-block-heading">Unsetting Proxy Variables After the Build Step</h2>



<p class="wp-block-paragraph">Because <code>ENV</code> instructions persist into the running container, any process that respects <code>http_proxy</code> will automatically use the proxy at runtime — which may not be what you want if the proxy is only reachable from the build network. To scope proxy settings to the build phase only, unset them after your package installation step:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">FROM ubuntu

ENV http_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
ENV https_proxy <span class="hljs-string">"http://192.168.33.10:3128"</span>
RUN apt-<span class="hljs-keyword">get</span> update &amp;&amp; apt-<span class="hljs-keyword">get</span> install -y curl
ENV http_proxy ""
ENV https_proxy ""</code></span></pre>


<p class="wp-block-paragraph">When the container is launched with <code>docker run</code>, the proxy variables will be empty and outbound connections from application code will go directly to the network (or fail gracefully if the runtime network also requires a proxy).</p>



<p class="wp-block-paragraph">Alternatively, you can override environment variables at runtime without modifying the Dockerfile:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$ sudo docker run -e http_proxy=<span class="hljs-string">""</span> -e https_proxy=<span class="hljs-string">""</span> curl curl http:<span class="hljs-comment">//example.com</span></code></span></pre>


<h2 class="wp-block-heading">Docker Desktop (Mac and Windows)</h2>



<p class="wp-block-paragraph">Docker Desktop on macOS and Windows exposes proxy settings through the application&#8217;s graphical preferences panel. Navigate to <strong>Settings → Resources → Proxies</strong> and enable <em>Manual proxy configuration</em> to specify HTTP and HTTPS proxy addresses.</p>



<p class="wp-block-paragraph">This configures the Docker Desktop daemon&#8217;s outbound proxy for image pulls. It does <strong>not</strong> automatically inject proxy variables into container build or run environments — you still need to use <code>ENV</code> instructions or <code>--build-arg</code> for that.</p>



<h2 class="wp-block-heading">Quick Reference: Which Setting Does What</h2>



<figure class="wp-block-table"><table><thead><tr><th>Configuration</th><th>What it affects</th><th>Required for image pulls</th><th>Required for in-container network access</th></tr></thead><tbody><tr><td><code>/etc/default/docker</code> or systemd drop-in</td><td>Docker daemon process</td><td>Yes</td><td>No</td></tr><tr><td><code>--build-arg http_proxy=…</code></td><td>Build-time environment only</td><td>No</td><td>Yes (build only)</td></tr><tr><td><code>ENV http_proxy</code> in Dockerfile</td><td>Build-time and runtime environment</td><td>No</td><td>Yes (build and run)</td></tr><tr><td><code>docker run -e http_proxy=…</code></td><td>Runtime environment only</td><td>No</td><td>Yes (run only)</td></tr><tr><td>Docker Desktop Proxies UI</td><td>Docker daemon process on Mac/Windows</td><td>Yes</td><td>No</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">Getting Docker to work behind a corporate proxy requires addressing two independent layers:</p>



<ol class="wp-block-list">
<li><strong>The Docker daemon</strong> — configure <code>HTTP_PROXY</code> / <code>HTTPS_PROXY</code> via the systemd drop-in file (modern systems) or <code>/etc/default/docker</code> (older SysV systems), then restart the service.</li>
<li><strong>The container environment</strong> — pass proxy settings via <code>--build-arg</code> or <code>ENV</code> instructions in the Dockerfile so that package managers and other tools inside the container can reach external repositories.</li>
</ol>



<p class="wp-block-paragraph">Remember that <code>ENV</code>-declared proxy variables persist into the running container. Unset them after your installation steps, or override them with <code>docker run -e</code>, if you do not want runtime traffic to traverse the proxy.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/using-docker-behind-a-proxy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Customizing Your Docker Container for Jenkins on Mesosphere DC/OS</title>
		<link>https://www.bestdevops.com/customizing-your-docker-container/</link>
					<comments>https://www.bestdevops.com/customizing-your-docker-container/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Sat, 18 Mar 2017 08:03:15 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Events]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Docker COntainer]]></category>
		<category><![CDATA[Docker container Customization]]></category>
		<category><![CDATA[Docker Customization]]></category>
		<category><![CDATA[Docker Customization Tutorial]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Mesosphere]]></category>
		<category><![CDATA[Mesosphere DC/OS]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=973</guid>

					<description><![CDATA[Learn how to build custom Docker images for Jenkins build agents running on Mesosphere DC/OS, including extending the jenkins-dind base image, managing SSH host keys, and wiring up your custom image in the Jenkins UI.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on documentation originally published by Mesosphere for DC/OS and the Jenkins for DC/OS package.</em></p>



<h2 class="wp-block-heading">Overview</h2>



<p class="wp-block-paragraph">By default, Mesosphere DC/OS runs workloads inside Docker containers to minimize host OS dependencies and to provide resilience against node failures. When you use Jenkins on DC/OS, the underlying Mesos scheduler dynamically creates Jenkins build agents as Mesos tasks, each running inside a Docker container. Your configured build steps then execute inside that same container.</p>



<p class="wp-block-paragraph">Because builds commonly invoke Docker commands such as <code>docker build</code> or <code>docker push</code>, Mesosphere provides the <code>mesosphere/jenkins-dind</code> image (Docker-in-Docker) and configures Jenkins for DC/OS to use it by default. The image ships with several widely-used tools; the authoritative list is in the upstream Dockerfile.</p>



<p class="wp-block-paragraph">If your builds require environment-specific packages or configurations that are not present in the default image, you can create a custom Docker image, push it to Docker Hub or a private registry, and point Jenkins at it. That registry must be reachable from every DC/OS agent node.</p>



<h2 class="wp-block-heading">Minimum Requirements for a Custom Agent Image</h2>



<p class="wp-block-paragraph">At a minimum, every custom Jenkins agent image must include:</p>



<ul class="wp-block-list">
<li><strong>OpenJDK 8</strong> — Required by Jenkins to launch the agent process and register it with the Jenkins master.</li>
<li><strong>CA certificates</strong> — Required to verify SSL/TLS certificates when the agent communicates with external services.</li>
</ul>



<p class="wp-block-paragraph">The following packages are not strictly required but are commonly needed by build scripts:</p>



<ul class="wp-block-list">
<li><strong>Bash</strong> — Many Jenkins build scripts rely on Bash as their shell interpreter.</li>
<li><strong>Git</strong> — Required to check out source code from Git repositories.</li>
<li><strong>OpenSSH client</strong> — Required when cloning repositories over SSH.</li>
</ul>



<h2 class="wp-block-heading">Creating a Custom Image Based on mesosphere/jenkins-dind</h2>



<p class="wp-block-paragraph">The recommended approach is to extend the official <code>mesosphere/jenkins-dind</code> base image rather than building a new image from scratch. This ensures you inherit the correct Java runtime, CA certificates, Docker daemon setup, and other baseline configuration.</p>



<p class="wp-block-paragraph">The following example Dockerfile adds <code>sbt</code> (Scala Build Tool) to the base image. The <code>RUN</code> instruction downloads and extracts the <code>sbt</code> tarball into <code>/usr/local</code> and records the installed version in a build manifest file. (This pattern is adapted from the <a href="https://github.com/1science/docker-sbt/blob/latest/Dockerfile">1science/docker-sbt</a> Dockerfile.)</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">FROM mesosphere/jenkins-dind:<span class="hljs-number">0.2</span><span class="hljs-number">.2</span>

ENV SBT_VERSION <span class="hljs-number">0.13</span><span class="hljs-number">.8</span>
ENV SBT_HOME /usr/local/sbt
ENV PATH ${PATH}:${SBT_HOME}/bin

RUN curl -sL <span class="hljs-string">"http://dl.bintray.com/sbt/native-packages/sbt/$SBT_VERSION/sbt-$SBT_VERSION.tgz"</span> \
    | gunzip | tar -x -C /usr/local \
    &amp;&amp; echo <span class="hljs-string">"- with sbt $SBT_VERSION"</span> &gt;&gt; <span class="hljs-regexp">/root/</span>.built</code></span></pre>


<p class="wp-block-paragraph">After writing your Dockerfile, build and push the image:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># Build the image</span>
docker build -t myorg/jenkins-agent-scala:latest .

<span class="hljs-comment"># Push to Docker Hub (or substitute your private registry hostname)</span>
docker push myorg/jenkins-agent-scala:latest</code></span></pre>


<p class="wp-block-paragraph">Ensure the image is accessible from all DC/OS agent nodes. If you are using a private registry, configure DC/OS agent credentials accordingly.</p>



<h2 class="wp-block-heading">Managing SSH Host Keys</h2>



<p class="wp-block-paragraph">The default <code>jenkins-dind</code> image ships with GitHub&#8217;s SSH public keys pre-populated in <code>/etc/ssh/ssh_known_hosts</code>. If your Git server is not GitHub, SSH-based cloning will fail with a host-key verification error unless you add your server&#8217;s public key to that file.</p>



<p class="wp-block-paragraph">Add the following lines to your Dockerfile, replacing <code>my.git.server</code> with your actual Git server hostname:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">ENV SSH_KNOWN_HOSTS github.com my.git.server
RUN ssh-keyscan $SSH_KNOWN_HOSTS | tee /etc/ssh/ssh_known_hosts</code></span></pre>


<p class="wp-block-paragraph"><code>ssh-keyscan</code> contacts each hostname and writes its public key to stdout. Piping the output to <code>tee</code> appends the keys to the known-hosts file inside the image, so the SSH client will not prompt for confirmation at clone time.</p>



<h2 class="wp-block-heading">Configuring Jenkins to Use the Custom Image</h2>



<p class="wp-block-paragraph">Once your custom image is available in a registry, you need to register it as a slave configuration in Jenkins so it can be selected by individual jobs.</p>



<ol class="wp-block-list">
<li>In the Jenkins web UI, go to <strong>Manage Jenkins</strong> → <strong>Configure System</strong>.</li>
<li>Scroll to the <strong>Cloud</strong> section and click <strong>Advanced</strong>. A grey <strong>Add Slave Info</strong> button will appear.

<figure class="wp-block-image"><img decoding="async" src="https://docs.mesosphere.com/wp-content/uploads/2017/03/velocity-add-slave-info.png" alt="Add Slave Info button in Jenkins Cloud configuration" /></figure>

</li>
<li>Fill in the slave info fields. Key settings include:
<ul>
<li><strong>Label string</strong> — A unique label you will use in job configurations to target this agent (for example, <code>scala-agent</code>).</li>
<li><strong>Usage</strong> — Leave as the default (<em>Utilize this node as much as possible</em>) unless you have a specific reason to restrict it.</li>
<li><strong>Jenkins slave CPUs</strong> — CPU shares allocated to the agent container itself.</li>
<li><strong>Jenkins slave memory in MB</strong> — Memory allocated to the agent container itself.</li>
<li><strong>Maximum number of executors per slave</strong> — How many Jenkins executors will run inside the single container.</li>
<li><strong>Jenkins executor CPUs</strong> — Estimated CPU shares per executor.</li>
<li><strong>Jenkins executor memory</strong> — Estimated memory per executor.</li>
</ul>
<p>The actual resources requested from Mesos are calculated as follows:</p>
<pre class="wp-block-code"><span><code class="hljs">actualCpus = slaveCpus + (maxExecutors * executorCpus)
actualMem  = slaveMem  + (maxExecutors * executorMem)</code></span></pre>

<figure class="wp-block-image"><img decoding="async" src="https://docs.mesosphere.com/wp-content/uploads/2017/03/velocity-jenkins-slave-info.png" alt="Jenkins slave info configuration fields" /></figure>

</li>
<li>Click <strong>Advanced</strong> again to expose the containerizer options. Select <strong>Use Docker Containerizer</strong> and enter your custom image name in the <strong>Docker Image</strong> field (for example, <code>myorg/jenkins-agent-scala:latest</code>).

<figure class="wp-block-image"><img decoding="async" src="https://docs.mesosphere.com/wp-content/uploads/2017/03/velocity-docker-containerizer-settings.png" alt="Docker Containerizer settings panel" /></figure>

<p><strong>Note:</strong> If your custom image is a Docker-in-Docker image (that is, it needs to run Docker commands inside the container), you must also enable <strong>Docker Privileged Mode</strong> and specify a custom Docker command shell in this panel.</p>
</li>
<li>Click <strong>Save</strong>.</li>
</ol>



<h2 class="wp-block-heading">Targeting the Custom Agent from a Jenkins Job</h2>



<p class="wp-block-paragraph">After the slave configuration is saved, you can restrict any job to run on the new agent by referencing its label.</p>



<ol class="wp-block-list">
<li>Open the job and click <strong>Configure</strong>.</li>
<li>Check <strong>Restrict where this project can be run</strong>.</li>
<li>Enter the <strong>Label String</strong> you defined in the slave configuration (for example, <code>scala-agent</code>).

<figure class="wp-block-image"><img decoding="async" src="https://docs.mesosphere.com/wp-content/uploads/2017/03/velocity-job-build-label-string.png" alt="Job configuration showing label string restriction" /></figure>

</li>
<li>Click <strong>Save</strong>.</li>
</ol>



<p class="wp-block-paragraph">When the job is triggered, the Mesos scheduler will spin up a new agent container using your custom image and route the build to it.</p>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">Customizing Docker containers for Jenkins agents on DC/OS follows a straightforward workflow:</p>



<ul class="wp-block-list">
<li>Extend <code>mesosphere/jenkins-dind</code> with your dependencies.</li>
<li>Add any required SSH host keys at image build time.</li>
<li>Push the image to a registry accessible by all DC/OS agent nodes.</li>
<li>Register the image as a new slave configuration in Jenkins, assigning it a label.</li>
<li>Restrict individual jobs to that label so they run on the correct agent image.</li>
</ul>



<p class="wp-block-paragraph">This pattern keeps build environments reproducible and version-controlled without modifying the DC/OS host nodes directly.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/customizing-your-docker-container/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Containers: What Makes Them So Portable?</title>
		<link>https://www.bestdevops.com/docker-containers-what-makes-them-so-portable/</link>
					<comments>https://www.bestdevops.com/docker-containers-what-makes-them-so-portable/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Tue, 15 Nov 2016 07:44:45 +0000</pubDate>
				<category><![CDATA[IT Training]]></category>
		<category><![CDATA[Application Design]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker COntainer]]></category>
		<category><![CDATA[Docker Directory]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=58</guid>

					<description><![CDATA[Docker containers are renowned for their portability across on-premises and cloud environments. Learn how layered filesystems, image layers, and the copy-on-write strategy make this possible.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on a topic originally sourced from networkcomputing.com. The explanation below is an independent technical overview of Docker container portability.</em></p>



<h2 class="wp-block-heading">Why Docker Container Portability Matters</h2>



<p class="wp-block-paragraph">One of the most compelling reasons teams adopt Docker is the ability to build an application once and run it consistently across laptops, on-premises servers, and public cloud environments. A container that passes QA on a developer&#8217;s workstation behaves identically in staging and production because the entire runtime environment — libraries, configuration, and application code — is bundled into the container image.</p>



<p class="wp-block-paragraph">This stands in sharp contrast to traditional deployment models, where differences in operating system versions, installed packages, or environment variables frequently caused the dreaded &#8220;works on my machine&#8221; problem.</p>



<h2 class="wp-block-heading">The Foundation: Docker Images and Layers</h2>



<p class="wp-block-paragraph">A Docker image is not a single monolithic file. Instead, it is composed of a stack of read-only <strong>layers</strong>, each representing a discrete set of filesystem changes. When you write a <code>Dockerfile</code>, each instruction (<code>FROM</code>, <code>RUN</code>, <code>COPY</code>, <code>ADD</code>, etc.) typically produces a new layer on top of the previous one.</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># Example Dockerfile illustrating layer creation</span>
FROM ubuntu:<span class="hljs-number">22.04</span>          <span class="hljs-comment"># Layer 1 – base OS</span>
RUN apt-get update &amp;&amp; \
    apt-get install -y python3  <span class="hljs-comment"># Layer 2 – installed packages</span>
COPY app/ /app             <span class="hljs-comment"># Layer 3 – application code</span>
CMD &#91;<span class="hljs-string">"python3"</span>, <span class="hljs-string">"/app/main.py"</span>]</code></span></pre>


<p class="wp-block-paragraph">Each layer is content-addressed using a cryptographic hash. Docker (and the OCI image specification it influenced) can therefore:</p>



<ul class="wp-block-list">
<li><strong>Cache layers locally</strong> — if a layer already exists on the host, it is not downloaded again.</li>
<li><strong>Share layers between images</strong> — two images that share the same base layer store that layer only once on disk.</li>
<li><strong>Verify integrity</strong> — any tampering with a layer changes its hash, making it immediately detectable.</li>
</ul>



<h2 class="wp-block-heading">Copy-on-Write: The Key to Efficient Portability</h2>



<p class="wp-block-paragraph">When Docker starts a container from an image, it does <em>not</em> copy all the image data into a new location. Instead, it adds a thin, writable <strong>container layer</strong> on top of the read-only image layers. This is the <strong>copy-on-write (CoW)</strong> strategy.</p>



<p class="wp-block-paragraph">Here is how CoW works in practice:</p>



<ol class="wp-block-list">
<li><strong>Read operations</strong> are served directly from whichever image layer contains the file — no copying occurs.</li>
<li><strong>Write operations</strong> trigger a copy of the targeted file from the image layer up into the writable container layer. Subsequent writes to the same file stay in the container layer.</li>
<li><strong>Deletes</strong> are recorded as a &#8220;whiteout&#8221; marker in the container layer; the underlying image layer is left untouched.</li>
</ol>



<p class="wp-block-paragraph">The practical result is that spinning up dozens of containers from the same image consumes very little additional disk space — each container only stores its own delta, not a full copy of the image.</p>



<h2 class="wp-block-heading">Storage Drivers That Implement CoW</h2>



<p class="wp-block-paragraph">Docker delegates the actual CoW filesystem work to a pluggable <strong>storage driver</strong>. Common options include:</p>



<figure class="wp-block-table"><table><thead><tr><th>Storage Driver</th><th>Underlying Technology</th><th>Typical Use Case</th></tr></thead><tbody><tr><td><code>overlay2</code></td><td>Linux OverlayFS</td><td>Default for most modern Linux distributions</td></tr><tr><td><code>devicemapper</code></td><td>Linux Device Mapper</td><td>Older RHEL/CentOS environments (now deprecated)</td></tr><tr><td><code>btrfs</code></td><td>Btrfs filesystem</td><td>Hosts already using Btrfs</td></tr><tr><td><code>zfs</code></td><td>ZFS filesystem</td><td>Hosts already using ZFS</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><code>overlay2</code> is the recommended and most widely used driver. It uses the Linux kernel&#8217;s OverlayFS to merge multiple directory trees into a single unified view, providing excellent performance and broad compatibility.</p>



<h2 class="wp-block-heading">How Portability Is Achieved End-to-End</h2>



<p class="wp-block-paragraph">Combining layered images with CoW storage enables the full portability workflow:</p>



<ol class="wp-block-list">
<li><strong>Build</strong> — <code>docker build</code> assembles layers from a <code>Dockerfile</code> and tags the resulting image.</li>
<li><strong>Push</strong> — <code>docker push</code> uploads only the layers that the target registry does not already have.</li>
<li><strong>Pull</strong> — on any Docker host, <code>docker pull</code> downloads only the missing layers.</li>
<li><strong>Run</strong> — <code>docker run</code> instantiates a container in seconds by adding a writable CoW layer; no full image copy is needed.</li>
</ol>



<p class="wp-block-paragraph">Because the image layers are immutable and content-addressed, the container running in a CI pipeline is byte-for-byte identical to the one that will run in production — regardless of the underlying host OS distribution, cloud provider, or hardware architecture (assuming the same CPU architecture).</p>



<h2 class="wp-block-heading">Additional Factors That Reinforce Portability</h2>



<p class="wp-block-paragraph">Layered storage is the core mechanism, but several other Docker features reinforce portability:</p>



<ul class="wp-block-list">
<li><strong>Self-contained environment</strong> — the image bundles all dependencies, eliminating reliance on host-installed libraries.</li>
<li><strong>Environment variables and secrets injection</strong> — runtime configuration is passed at <code>docker run</code> time, keeping images environment-agnostic.</li>
<li><strong>Docker Compose and orchestration manifests</strong> — multi-container applications are described declaratively, making entire stacks reproducible across environments.</li>
<li><strong>OCI standards</strong> — Docker images conform to the Open Container Initiative (OCI) image specification, meaning they can be run by any OCI-compliant runtime (containerd, Podman, etc.), not just the Docker Engine.</li>
</ul>



<h2 class="wp-block-heading">Limitations to Keep in Mind</h2>



<p class="wp-block-paragraph">Docker container portability is powerful but not absolute. Key constraints include:</p>



<ul class="wp-block-list">
<li><strong>CPU architecture</strong> — an image built for <code>amd64</code> will not run natively on <code>arm64</code> without multi-platform build support (<code>docker buildx</code>).</li>
<li><strong>Kernel dependencies</strong> — containers share the host kernel. Workloads that require a specific kernel version or kernel module may not be fully portable.</li>
<li><strong>Persistent data</strong> — data written inside the CoW container layer is ephemeral. Production applications must use Docker volumes or bind mounts for data that must survive container restarts.</li>
<li><strong>Windows vs. Linux containers</strong> — Windows and Linux containers require matching host operating systems; they are not interchangeable.</li>
</ul>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">Docker&#8217;s portability stems from a well-designed combination of immutable, content-addressed image layers and a copy-on-write strategy implemented by the host&#8217;s storage driver. Together, these mechanisms allow teams to build an application image once and deploy it reliably across development, staging, and production environments — on-premises or in any public cloud — with minimal overhead and maximum consistency.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/docker-containers-what-makes-them-so-portable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
