<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Docker on avni.sh</title>
    <link>http://www.avni.sh/tags/docker/</link>
    <description>Recent content in Docker on avni.sh</description>
    <image>
      <title>avni.sh</title>
      <url>http://www.avni.sh/cover.webp</url>
      <link>http://www.avni.sh/cover.webp</link>
    </image>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Wed, 31 May 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://www.avni.sh/tags/docker/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Container Storage Interfaces (CSI)</title>
      <link>http://www.avni.sh/posts/cloud-native/container-storage-interfaces/</link>
      <pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/container-storage-interfaces/</guid>
      <description>Container Storage Interface (CSI) plugins are developed by storage providers to establish a consistent interface between container orchestrators and storage solutions</description>
      <content:encoded><![CDATA[<p>There is a multitude of choices for storage solutions (Amazon S3, Ceph, Google Cloud Storage, etc.) and combined with the choices of container orchestrators (Kubernetes, Apache Mesos, Docker Swarm, etc.) the permutations are endless.</p>
<p>A <strong>Container Storage Interface (CSI)</strong> plugin is implemented by the storage providers (Amazon, Google, IBM) as an interface to provision and mount volumes for workloads when requested by container orchestrators. The CSI plugin provisions the volume, procures it from the node hosting the container, and mounts it to the requesting container. It standardizes the process of allocating storage for containers between different orchestrators.</p>
<h1 id="volume-plugin">Volume Plugin</h1>
<p>Before CSIs, the <strong>Volume Plugins</strong> were used to link the storage solutions and container orchestrators.</p>
<p>Limitations of Volume Plugins</p>
<ul>
<li>Volume Plugins were a part of Kubernetes core. Thus, their development and release were tightly coupled with Kubernetes.</li>
<li>Instability and reliability issues with volume plugins could lead to the failure of core Kubernetes components.</li>
<li>Every container orchestrator required a different implementation of the plugin.</li>
<li>Orchestrators had to communicate with the storage solution throughout the lifecycle of the volume to avoid failures.</li>
<li>Volume Plugins had to be open source.</li>
</ul>
<h2 id="lifecycle-of-a-volume-with-volume-plugins">Lifecycle of a Volume with Volume Plugins</h2>
<p align="center"><img src="VolumePlugin.png" alt="Volume Plugins"></p>
<p align="center"><small><i>Volume Plugins</i></small></p>
<h1 id="csi-specification">CSI Specification</h1>
<p>The CSI specification defines interfaces for implementing a plugin</p>
<ul>
<li>The plugin should work seamlessly across all container orchestrators.</li>
<li>Ability to dynamically provision and unprovisioned volumes.</li>
<li>Mounting, unmounting, attaching, and detaching volumes on the node.</li>
<li>Ability to work with block and mountable volumes.</li>
<li>Performing snapshots of volumes, that could be used for provisioning a new volume.</li>
</ul>
<h1 id="architecture-of-a-csi">Architecture of a CSI</h1>
<p>The orchestrator interacts with the CSI plugin through gRPCs, a cross-platform Remote Procedure Call framework introduced by Google.</p>
<p><strong>Remote Procedure Calls (RPCs)</strong> are used in distributed systems to execute a procedure (subroutine) on a remote system. The CSI&rsquo;s RPCs are idempotent i.e. a call should not change the result beyond its initial application.</p>
<h2 id="rpc-endpoints">RPC endpoints</h2>
<p>There are three sets of gRPCs provided by the CSI Plugin: Identity, Controller, and Node service.</p>
<h3 id="identity-service-rpcs">Identity Service RPCs</h3>
<p>The <strong>Identity Service</strong> provides gPRC endpoints that allow an orchestrator to query the capabilities of the plugin, its health, and the metadata associated with the plugin.</p>
<p>gRPC endpoints provided by the identity service:</p>
<ul>
<li><code>GetPluginInfo</code>: Returns the plugin metadata</li>
<li><code>GetPluginCapabilities</code>: Returns the plugin capabilities (fetched from controller service)</li>
<li><code>Probe</code>: Returns the health of the plugin</li>
</ul>
<h3 id="controller-service-rpcs">Controller Service RPCs</h3>
<p><strong>Controller Service</strong> groups all the gRPC endpoints responsible for</p>
<ul>
<li>Creating and deleting the volume</li>
<li>Publishing and unpublishing the volume to the nodes</li>
<li>Creating snapshots of the volumes</li>
</ul>
<p>gRPC endpoints provided by the controller service:</p>
<ul>
<li><code>CreateVolume</code>: Creates the volumes on the storage solution. The volume could be created as an empty new volume or from an existing snapshot or from an existing volume.</li>
<li><code>DeleteVolume</code>: Deletes a provisioned volume on the storage solution. Although the volume is deleted its snapshots are functional and available as sources for new volumes.</li>
<li><code>ControllerPublishVolume</code>: Performs the necessary operations to make the volume available to the requesting node.</li>
<li><code>ControllerUnpublishVolume</code>: Reverts the operations performed in <code>ContainerPublishVolume</code>.</li>
<li><code>ValidateVolumeCapabilities</code>: Verifies the provisioned volume for capabilities requested by the orchestrator.</li>
<li><code>ListVolumes</code>: Returns information about all the volumes.</li>
<li><code>ControllerGetVolume</code>: Called by the orchestrator to fetch the current information associated with a specific volume.</li>
<li><code>GetCapacity</code>: Queries the storage pool for its current capacity.</li>
<li><code>ControllerGetCapabilities</code>: Returns the details of the capabilities of the controller service.</li>
<li><code>CreateSnapshot</code>: Creates a snapshot of an existing volume.</li>
<li><code>DeleteSnapshot</code>: Deletes the volume snapshot.</li>
<li><code>ListSnapshots</code>: Returns details of all snapshots.</li>
<li><code>ControllerExpandVolume</code>: Using this RPC the orchestrator can request for expansion in the size of a volume.</li>
</ul>
<h3 id="node-service-rpcs">Node Service RPCs</h3>
<p>These RPCs are called from the node where the volume is requested. They are responsible for the actions performed on the volume after it is mounted on the node.</p>
<p>gRPC endpoints provided by the controller service:</p>
<ul>
<li><code>NodeStageVolume</code>: After the workload (container) is scheduled on the orchestrator it calls <code>NodeStageVolume</code> on the volume provided by <code>ContainerPublishVolume</code>. The volume is mounted on the node on <code>stage_path</code> temporarily.</li>
<li><code>NodeUnstageVolume</code>: Reverts the actions performed by <code>NodeStageVolume</code>.</li>
<li><code>NodePublishVolume</code>: After <code>NodeStageVolume</code> is called the <code>NodePublishVolume</code> mounts the volume on <code>target_path</code> to be consumed by the workload.</li>
<li><code>NodeUnpublishVolume</code>: Reverts the actions performed by <code>NodeUnpublishVolume</code>.</li>
<li><code>NodeGetVolumeStats</code>: Returns the capacity statistics for a volume.</li>
<li><code>NodeGetCapabilities</code>: Called by the orchestrator to check the capabilities of the node services.</li>
<li><code>NodeGetInfo</code>: Returns the information for the node where the volume has to be mounted.</li>
<li><code>NodeExpandVolume</code>: Expands the volume mounted on the node. This call should be performed after <code>NodeStageVolume</code> and <code>NodePublishVolume</code>.</li>
</ul>
<h2 id="implementation-of-a-csi">Implementation of a CSI</h2>
<p>CSI specification provides examples of different implementations for plugins.</p>
<h3 id="centralized-controller-plugin">Centralized Controller Plugin</h3>
<p align="center"><img src="Centralized.png" alt="Centralized Controller CSI Plugin"></p>
<p align="center"><small><i>Centralized Controller CSI Plugin</i></small></p>
<p>The controller service RPCs could be packaged in a <strong>Controller Plugin</strong> located on the master node of the orchestrators. The node service RPCs are bundled as <strong>Node Plugin</strong> located on each worker node (or any node that could request volumes).</p>
<h3 id="headless-plugin">Headless Plugin</h3>
<p align="center"><img src="Headless.png" alt="Headless CSI Plugin"></p>
<p align="center"><small><i>Headless CSI Plugin</i></small></p>
<p>The Controller and Node Plugin could be placed together inside the worker node.</p>
<h3 id="controller-plugin">Controller Plugin</h3>
<p align="center"><img src="OnlyController.png" alt="Controller CSI Plugin"></p>
<p align="center"><small><i>Controller CSI Plugin</i></small></p>
<p>CSI could be deployed with just the Controller plugin on the worker node that provides both controller and node services.</p>
<h3 id="node-plugin">Node Plugin</h3>
<p align="center"><img src="OnlyNode.png" alt="Node CSI Plugin"></p>
<p align="center"><small><i>Node CSI Plugin</i></small></p>
<p>CSI could also be deployed with just a Node plugin on the worker node providing just the node services.</p>
<h2 id="volume-lifecycle-with-csi">Volume lifecycle with CSI</h2>
<p align="center"><img src="CSIVolumeLifecycle.webp" alt="Lifecycle of a Volume managed by CSI Plugin"></p>
<p align="center"><small><i>Lifecycle of a Volume managed by CSI Plugin</i></small></p>
<h3 id="mounting-a-volume-on-a-container">Mounting a Volume on a Container</h3>
<ol>
<li>A Workload is scheduled by the container orchestrator.</li>
<li>The orchestrator calls <code>CreateVolume</code> RPC to provision a volume on the storage solution.</li>
<li>Once the volume is provisioned on the storage solution the orchestrator calls <code>ContainerPublishVolume</code> to make it available to the node.</li>
<li>After the volume is available to the node, the orchestrator calls <code>NodeStageVolume</code> to mount the volume on the node at <code>stage_path</code>.</li>
<li>Finally, the orchestrator calls <code>NodePublishVolume</code> to mount the volume on <code>target_path</code>. Thus making it available for the container.</li>
</ol>
<h3 id="deleting-a-volume">Deleting a Volume</h3>
<ol>
<li>The volume to be deleted is unpublished by the orchestrator by calling <code>NodeUnpublishVolume</code> RPC.</li>
<li>Once unpublished from the container the volume is unstaged by <code>NodeUnstageVolume</code>.</li>
<li>The unstaged volume is then unpublished from the node by <code>ContainerUnpublishVolume</code>.</li>
<li>Finally, the unpublished volume is deleted by <code>DeleteVolume</code> RPC.</li>
</ol>
<h1 id="example-of-a-csi-intel-optane-persistent-memory-pmem-csi-storage-driver">Example of a CSI: Intel Optane Persistent Memory PMEM-CSI Storage Driver</h1>
<p>Intel Optane is a tiered persistent memory technology. It is used as a high-performance storage for desktop (improving system boot time) and enterprise (CAD, Modeling, Media editing) workloads.</p>
<p>The PMEM-CSI storage driver is provided by Intel to configure the Optane Persistent Memory as a storage solution for Kubernetes. The persistent volumes could be provisioned dynamically on the Optane memory and mounted on the containers present on the cluster.</p>
<p>Using this driver the developers can take advantage of Optane memory in their cache data store like <a href="/posts/computer-science/technologies/cloud-native/operator-sdk/#creating-a-go-based-operator" target="_blank">Memcached Operator</a>.</p>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://www.computerweekly.com/feature/Container-storage-101-What-is-CSI-and-how-does-it-work" target="_blank">Container storage 101: What is CSI and how does it work? | Computer Weekly</a><br>
<a href="https://medium.com/google-cloud/understanding-the-container-storage-interface-csi-ddbeb966a3b" target="_blank">Understanding the Container Storage Interface (CSI) | by anoop vijayan maniankara</a><br>
<a href="https://www.youtube.com/watch?v=ktwY1anKN58" target="_blank">Container Storage Interface: Present and Future - Jie Yu, Mesosphere, Inc.</a><br>
<a href="https://www.xenonstack.com/blog/container-storage-interface" target="_blank">Container Storage Interface (CSI) for Kubernetes</a><br>
<a href="https://kubernetes-csi.github.io/docs/" target="_blank">Introduction - Kubernetes CSI Developer Documentation</a><br>
<a href="https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/" target="_blank">Container Storage Interface (CSI) for Kubernetes GA</a><br>
<a href="https://github.com/container-storage-interface/spec/blob/master/spec.md" target="_blank">container-storage-interface/spec</a><br>
<a href="https://pmem.io/" target="_blank">Persistent Memory</a><br>
<a href="https://github.com/intel/pmem-csi" target="_blank">intel/pmem-csi</a><br>
<a href="https://www.intel.com/content/www/us/en/developer/articles/technical/persistent-memory-pmem-csi.html" target="_blank">Persistent Memory (PMEM) CSI</a><br>
<a href="https://github.com/intel/pmem-csi/blob/devel/examples/redis-operator.md" target="_blank">Redis-pmem operator</a><br>
<a href="https://github.com/intel/pmem-csi/blob/devel/examples/memcached.md" target="_blank">memcached with PMEM</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Container Network Interfaces (CNI)</title>
      <link>http://www.avni.sh/posts/cloud-native/container-network-interfaces/</link>
      <pubDate>Wed, 24 May 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/container-network-interfaces/</guid>
      <description>Container Network Interfaces provide plugin-based solutions for creating and configuring network interfaces for containers</description>
      <content:encoded><![CDATA[<p><a href="/posts/computer-science/technologies/cloud-native/containers/#container-runtime" target="_blank">Container runtimes</a> allocate <a href="/posts/computer-science/technologies/cloud-native/container-architecture/#network" target="_blank">network namespaces</a> for containers deployed on the host. A network interface (like <code>docker0</code>, <code>bridge</code>,  or <code>host</code>) is configured inside the namespace to facilitate the communication with host, the internet, or other containers.</p>
<p>The <strong>Container Network Interface (CNI)</strong> project provides specifications and libraries for implementing a plugin-based solution for managing network interfaces for containers. The runtime executes the CNI plugins provided as binary executable files.</p>
<p>A <strong>network configuration</strong> is passed to the runtime as a JSON file. It contains the details of the CNI plugins and the network interfaces to be configured.</p>
<p>Example of a network configuration file from CNI specification</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;cniVersion&#34;</span><span class="p">:</span> <span class="s2">&#34;1.0.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;dbnet&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;plugins&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;bridge&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// plugin specific parameters
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nt">&#34;bridge&#34;</span><span class="p">:</span> <span class="s2">&#34;cni0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;keyA&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;some more&#34;</span><span class="p">,</span> <span class="s2">&#34;plugin specific&#34;</span><span class="p">,</span> <span class="s2">&#34;configuration&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;ipam&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;host-local&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ipam specific
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nt">&#34;subnet&#34;</span><span class="p">:</span> <span class="s2">&#34;10.1.0.0/16&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;gateway&#34;</span><span class="p">:</span> <span class="s2">&#34;10.1.0.1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;routes&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span><span class="nt">&#34;dst&#34;</span><span class="p">:</span> <span class="s2">&#34;0.0.0.0/0&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;dns&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;nameservers&#34;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&#34;10.1.0.1&#34;</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;tuning&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;capabilities&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;mac&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;sysctl&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;net.core.somaxconn&#34;</span><span class="p">:</span> <span class="s2">&#34;500&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;portmap&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;capabilities&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;portMappings&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Runtime executes the CNI plugins with the following environment variables</p>
<ul>
<li><code>CNI_COMMAND</code>: Operation for CNI (<code>ADD</code>/<code>DELETE</code>/<code>CHECK</code>/<code>VERSION</code>)</li>
<li><code>CNI_ARGS</code>: Arguments for CNI</li>
<li><code>CNI_PATH</code>: Path to CNI binaries.</li>
<li><code>CNI_IFNAME</code>: Name of the network interface to be configured</li>
<li><code>CNI_NETNS</code>: Path to the container&rsquo;s network namespace</li>
<li><code>CNI_CONTAINERID</code>: Container ID assigned by the runtime</li>
</ul>
<h1 id="cni-operations">CNI Operations</h1>
<p>According to the CNI specification, a CNI plugin should have <code>ADD</code>, <code>DELETE</code>, <code>CHECK</code>, and <code>VERSION</code> operations.</p>
<h2 id="add"><code>ADD</code></h2>
<p>If the environment variable passed to the runtime by the CNI plugin is <code>CNI_COMMAND=ADD</code> then it will create or configure the network interfaces specified in the configuration.</p>
<p align="center"><img src="CNI_ADD.png" alt="Execution flow of ADD operation"></p>
<p align="center"><small><i>Execution flow of ADD operation</i></small></p>
<p>The interfaces will be created or configured in the order specified in the <code>plugins</code> key inside the network configuration. The result from the previous plugin execution will be passed to the next plugin and the final result will be stored with runtime.</p>
<p>So from the example above the <code>bridge</code> plugin will be executed first, followed by the <code>tuning</code> plugin, and finally the <code>portmap</code> plugin.</p>
<h2 id="delete"><code>DELETE</code></h2>
<p>The <code>DELETE</code> operation will undo operations performed by the <code>ADD</code>, deleting the created interfaces and reverting the configurations. It executes CNI plugins in the reverse order of their specification in network configuration. So the changes performed by the <code>portmap</code> plugin will be reverted first then the <code>tuning</code> plugin and lastly the <code>bridge</code> plugin.</p>
<p align="center"><img src="CNI_DELETE.png" alt="Execution flow of DELETE operation"></p>
<p align="center"><small><i>Execution flow of DELETE operation</i></small></p>
<p>It has to be preceded by an <code>ADD</code> operation because it takes the final result stored by the last <code>ADD</code> operation as input from container runtime.</p>
<h2 id="check"><code>CHECK</code></h2>
<p><code>CHECK</code> operation probes the container and network interfaces for their health and current status. The container runtime will go through the changes performed by each CNI plugin and validate its functionality. Similar to the <code>DELETE</code> operation it also uses the result from the previous <code>ADD</code> operation as input from container runtime.</p>
<h2 id="version"><code>VERSION</code></h2>
<p>The <code>VERSION</code> operation returns the version of the CNI plugin.</p>
<h1 id="reference-cni-plugins">Reference CNI Plugins</h1>
<h2 id="network-interface-plugins">Network Interface Plugins</h2>
<ul>
<li><code>bridge</code>: Creates a virtual switch that connects all the containers on a host. An IP address is assigned to each container by the bridge.</li>
<li><code>macvlan</code>: Creates a sub-interface from the host interface. Each virtual interface connected to <code>macvlan</code> has its own MAC address.</li>
</ul>
<ul>
<li><code>ipvlan</code>: Similar to <code>macvlan</code> but all connected devices share the same MAC address. Before transmitting a packet the kernel driver inspects the IP address of the destination virtual interface.</li>
<li><code>ptp</code>: Creates a point-to-point link between the container and its host by creating a Virtual Ethernet (veth) pair where one end resides inside the container and the other on the host.</li>
</ul>
<ul>
<li><code>host-device</code>: An existing device could be moved from the host&rsquo;s network namespace to the container&rsquo;s network namespace.</li>
<li><code>vlan</code>: Creates a Virtual Local Area Network (VLAN) interface between the host and the container.</li>
</ul>
<h2 id="windows-plugins">Windows Plugins</h2>
<p>These plugins are created specifically for Microsoft Windows containers.</p>
<ul>
<li><code>win-bridge</code>: All containers will be connected to a bridge network that has an endpoint on the host&rsquo;s network namespace.</li>
<li><code>win-overlay</code>: An <strong>Overlay network</strong> allows containers from different hosts to act as if they are on the same host. Using the <code>win-overlay</code> plugin all containers on a host could be connected to an Overlay network.</li>
</ul>
<h2 id="ip-address-allocation-plugin">IP Address Allocation Plugin</h2>
<ul>
<li><code>dhcp</code>: The IP leased by the DHCP server has to be renewed periodically. The <code>dhcp</code> plugin creates a daemon separate from the container to perform these requests.</li>
<li><code>host-local</code>: Allocates IPv4 and IPv6 addresses out of a provided range of addresses.</li>
<li><code>static</code>: Allocates static IPv4 and IPv6 addresses to the containers.</li>
</ul>
<h2 id="other-plugins">Other Plugins</h2>
<ul>
<li><code>tuning</code>: Used with other plugins to change system controls or interface attributes (like MTU and MAC address)</li>
<li><code>portmap</code>: Forwards traffic from the host&rsquo;s network ports to the container&rsquo;s network ports.</li>
<li><code>bandwidth</code>: Configures traffic bucket filter (tbf) to limit bandwidth on ingress and egress traffic.</li>
<li><code>sbr</code>: Configures source based routing (sbr) where the application (source) decides the correct network interface for outgoing traffic.</li>
<li><code>firewall</code>: Creates firewall rules to allow traffic to the container&rsquo;s IP address.</li>
</ul>
<h1 id="example-of-3rd-party-cni-plugin-weave">Example of 3rd Party CNI Plugin: Weave</h1>
<p>The <strong>Weave</strong> is a CNI plugin created by Weaveworks that creates an overlay mesh network that allows Dockers containers running on different hosts to connect.</p>
<p>Features of Weave:</p>
<ul>
<li>Containers from different hosts and data centers will act as if they are on the same network without any additional configuration.</li>
<li>Application containers (running on any host) could be exposed to the outside network.</li>
<li>It can create networks between legacy systems and containers.</li>
<li>Traffic could be encrypted.</li>
<li>Supports Amazon ECS, Apache Mesos, Kubernetes, etc.</li>
</ul>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://www.tigera.io/learn/guides/kubernetes-networking/kubernetes-cni/" target="_blank">Kubernetes CNI Explained</a><br>
<a href="https://www.youtube.com/watch?v=YjjrQiJOyME" target="_blank">Introduction to CNI, the Container Network Interface Project - Bryan Boreham &amp; Dan Williams</a><br>
<a href="https://www.youtube.com/watch?v=zChkx-AB5Xc" target="_blank">Deep Dive: CNI - Bryan Boreham, Weaveworks &amp; Dan Williams, Red Hat</a><br>
<a href="https://www.tigera.io/learn/guides/kubernetes-networking/" target="_blank">Kubernetes Networking: The Complete Guide | Tigera</a><br>
<a href="https://www.tigera.io/learn/guides/kubernetes-networking/container-networking/" target="_blank">Container Networking: What You Should Know</a><br>
<a href="https://github.com/containernetworking/cni/blob/main/SPEC.md" target="_blank">cni/SPEC.md at main · containernetworking/cni · GitHub</a><br>
<a href="https://www.youtube.com/watch?v=zmYxdtFzK6s" target="_blank">Kubernetes Networking: How to Write a CNI Plugin From Scratch - Eran Yanay, Twistlock</a><br>
<a href="https://www.redhat.com/sysadmin/cni-kubernetes" target="_blank">A brief overview of the Container Network Interface (CNI) in Kubernetes | Enable Sysadmin</a><br>
<a href="https://www.cni.dev/plugins/current/" target="_blank">CNI Plugins Overview</a><br>
<a href="https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/" target="_blank">Network Plugins | Kubernetes</a><br>
<a href="https://github.com/containernetworking/plugins" target="_blank">containernetworking/plugins</a><br>
<a href="https://www.weave.works/docs/net/latest/overview/" target="_blank">Introduction to Weave Net</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Building Container Images</title>
      <link>http://www.avni.sh/posts/cloud-native/building-container-images/</link>
      <pubDate>Mon, 20 Mar 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/building-container-images/</guid>
      <description>Container images are built from Containerfile, a plaintext file containing the steps to be executed during the build process.</description>
      <content:encoded><![CDATA[<p>Public registries provide container images for most use cases but they might not cover all of them. That&rsquo;s why container engines such as Podman &amp; Docker and CLI tools like <code>buildah</code> provide utilities for creating custom <a href="/posts/computer-science/technologies/cloud-native/container-images" target="_blank">container images</a>.</p>
<p>The build steps are written in a plaintext file called <strong>Containerfile</strong> and parsed by container engines (or <code>buildah</code>) during the build process.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="c"># Containerfile</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">FROM</span><span class="s"> node:18-alpine</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">LABEL</span> <span class="nv">version</span><span class="o">=</span><span class="s2">&#34;1.0&#34;</span> <span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">WORKDIR</span><span class="s"> /app</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">COPY</span> . .<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> yarn install --production<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">CMD</span> <span class="p">[</span><span class="s2">&#34;node&#34;</span><span class="p">,</span> <span class="s2">&#34;src/index.js&#34;</span><span class="p">]</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">EXPOSE</span><span class="s"> 3000</span><span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="containerfile-instructions">Containerfile Instructions</h2>
<p>Steps inside the containerfile are defined using instructions such as <code>FROM</code>, <code>RUN</code>, <code>ADD</code>, <code>COPY</code>, etc.
Container Engines go through the containerfile line-by-line and perform each step, stacking a new image layer on top of the previous one.</p>
<h3 id="from">FROM</h3>
<p><code>FROM</code> instruction specifies the base layer container image. The base layer image could be chosen based on OS preference (like Fedora, Kali, etc.) or programming language preference (like gcc, python, etc.), or any other preference.
It is mandatory to have a <code>FROM</code> instruction in the containerfile.</p>
<h3 id="arg">ARG</h3>
<p>Variables for <code>FROM</code> instruction are defined using <code>ARG</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">ARG</span> <span class="nv">IMAGE_VERSION</span><span class="o">=</span><span class="m">3</span>.7<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">FROM</span><span class="s"> python:${IMAGE_VERSION}</span><span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>After <code>FROM</code> instruction is executed, the value for the variable declared in <code>ARG</code> becomes inaccessible.</p>
<h3 id="env">ENV</h3>
<p>The Environment variables (used by other instructions or container at runtime) are declared using <code>ENV</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">ENV</span> <span class="nv">DEPLOYMENT_FOLDER</span><span class="o">=</span>src
</span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="s"> ${DEPLOYMENT_FOLDER}</span><span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>The <code>=</code> operator between the variable name and its value is optional.</p>
<h3 id="label">LABEL</h3>
<p><code>LABEL</code> is used to add metadata for container images in the form of key-value pairs. Metadata usually contains the author&rsquo;s name, author&rsquo;s email, version of the container image, etc.</p>
<h3 id="add">ADD</h3>
<p><code>ADD</code> instruction will copy files/directories from the source (host OS/URL/tarball) to the destination (container image). <code>ADD</code> allows permissions to be omitted on the copied files/directories with the <code>--chown</code> flag.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">ADD</span> --chown<span class="o">=</span>user:group src/ dest<span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>Builds are performed inside a build context directory on the host. <code>ADD</code> will fail if the source file/directory is outside the build context.</p>
<h3 id="copy">COPY</h3>
<p><code>COPY</code> is similar to <code>ADD</code> but it is limited to sources on the host, it doesn&rsquo;t support URLs or tarball. <code>COPY</code> is sufficient for most use cases, so it is preferred over <code>ADD</code>.</p>
<h3 id="workdir">WORKDIR</h3>
<p><code>WORKDIR</code> changes the current working directory (inside the image) for the next instructions.</p>
<h3 id="run">RUN</h3>
<p><code>RUN</code> instruction executes the shell command passed as an argument.</p>
<p>A temporary container is created to execute the shell command and the changes on the file system (after command execution) are layered on top of existing image layers. By default, the instruction <code>RUN apt-get update -y</code> will be executed as <code>/bin/bash -c apt-get update -y</code>.</p>
<p><code>SHELL</code> instruction is used in containerfile to change the default shell for <code>RUN</code>, for example, <code>SHELL [&quot;/bin/zsh&quot;, &quot;-c&quot;]</code> will change the default shell from <code>bash</code> to <code>zsh</code>.</p>
<h3 id="expose">EXPOSE</h3>
<p><code>EXPOSE</code> specifies the network ports to be used by the container on runtime. The ports still have to be published when the <a href="/posts/computer-science/technologies/cloud-native/container-lifecycle/#port-forwarding" target="_blank">container is provisioned</a>.</p>
<h3 id="cmd">CMD</h3>
<p><code>CMD</code> adds a shell command that will be executed on container startup. <code>CMD</code> instructions could be written as <code>CMD param1 param2</code> or <code>CMD [&quot;/bin/executable&quot;, &quot;param1&quot;, &quot;param2&quot;]</code>.</p>
<p>Adding a <code>CMD</code> instruction can define the behavior of the container on startup, for example, a webserver container should start the webserver automatically on startup by running the invocation command defined in <code>CMD</code>.</p>
<h3 id="entrypoint">ENTRYPOINT</h3>
<p>If the executable on container startup is expected to be the same in most conditions then it is preferable to add <code>ENTRYPOINT</code> over <code>CMD</code>. Parameters for the executable could be passed from <code>CMD</code> instruction.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">ENTRYPOINT</span> /bin/executable<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">CMD</span> <span class="p">[</span><span class="s2">&#34;param1&#34;</span><span class="p">,</span> <span class="s2">&#34;param2&#34;</span><span class="p">]</span><span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="volume">VOLUME</h3>
<p>To create a mount point inside the container, <code>VOLUME</code> instruction can be used. During runtime, the <code>--volume</code> flag is used to map a directory on the host to the mount point declared by <code>VOLUME</code> instruction. The data stored on the mount point will persist after container execution.</p>
<h3 id="onbuild">ONBUILD</h3>
<p>The command added in the <code>ONBUILD</code> instruction is executed when the built image is used as the base container image.</p>
<p>If container image <code>container-image-b</code> uses <code>container-image-a</code> as a base image, then the <code>ONBUILD</code> instruction defined in <code>container-image-a</code> will be triggered after <code>FROM</code> instruction is executed in <code>container-image-b</code>.</p>
<p align="center"><img src="on_build.png" alt="Execution of ONBUILD instruction"></p>
<p align="center"><small><i>Execution of ONBUILD instruction</i></small></p>
<p>Using <code>ONBUILD</code>, the developers can ensure that any new image built upon their container image has the latest source code or that packages are up-to-date.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">ONBUILD</span> <span class="k">RUN</span> git clone source-code-repo-link.git<span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="user">USER</h3>
<p><code>USER</code> instruction sets <code>UID</code> or <code>GID</code> during the build process.</p>
<h2 id="building-container-images-using-docker">Building container images using Docker</h2>
<p>Docker and Podman provide <code>build</code> subcommand for building container images from containerfile.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker build .
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>.</code> will be substituted with the current working directory on the host.</p>
<p>By default Docker expects <em>Dockerfile</em> (instead of <em>Containerfile</em>) in the build context, <code>--file</code> flag could be used to pass the path to containerfile.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker build --tag node-application:latest . --file ./Containerfile
</span></span></code></pre></td></tr></table>
</div>
</div><p>Container Engines cache the built layers to save time and storage. Cached layers are reused in other image builds to disable this behavior <code>--no-cache</code> flag could be used with the <code>build</code> subcommand.</p>
<p><code>--rm</code> flag ensures that the intermediate container images are removed once the build process is successful.</p>
<p>Adding files with sensitive data to <code>.dockerignore</code> will make sure that they aren&rsquo;t included in the container image.</p>
<h2 id="building-container-images-using-buildah">Building container images using buildah</h2>
<p><code>buildah</code> provides a <code>bud</code> subcommand for building container images from containerfile.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl">buildah bud --tag <span class="s2">&#34;webserver:latest&#34;</span> .<span class="err">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>Images built by <code>buildah</code> could then be executed using Podman and Docker or any other OCI image-compatible container engine. Podman also has a <code>build</code> subcommand for building container images and it uses the same code as <code>buildah</code>.</p>
<p><code>buildah</code> provides finer control over image building process that allows users to</p>
<ul>
<li>Create base images using the scratch image, an image with a minimal footprint.</li>
<li>Mount a container&rsquo;s root filesystem, useful for debugging container-related issues.</li>
<li>Create a container image from a working container, helpful if Containerfile isn&rsquo;t accessible.</li>
<li>Execution of containerfile instructions using subcommands. For example, <code>RUN</code> instruction could be executed on a container image using <code>buildah run</code>. Similarly for <code>COPY</code> and <code>ADD</code> instructions.</li>
<li>Debug image building process by executing instructions manually with buildah.</li>
<li>Making ad-hoc changes to existing container images.</li>
<li>Automating build process.</li>
</ul>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://opencontainers.org/about/overview/" target="_blank">About the Open Container Initiative</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/manifest.md" target="_blank">OCI Image Manifest Specification</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/layer.md" target="_blank">Image Layer Filesystem Changeset</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/config.md" target="_blank">OCI Image Configuration</a><br>
<a href="https://docs.docker.com/storage/storagedriver/" target="_blank">About storage drivers</a><br>
<a href="https://docs.docker.com/engine/reference/builder/" target="_blank">Dockerfile reference</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/build/" target="_blank">docker build</a><br>
<a href="https://github.com/containers/buildah/blob/main/README.md" target="_blank">buildah</a><br>
<a href="https://hub.docker.com/_/scratch" target="_blank">scratch container image</a><br>
<a href="https://github.com/containers/buildah/blob/main/docs/tutorials/01-intro.md" target="_blank">Buildah Tutorial 1</a><br>
<a href="https://github.com/containers/buildah#buildah-and-podman-relationship" target="_blank">Buildah and Podman relationship</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Container Images</title>
      <link>http://www.avni.sh/posts/cloud-native/container-images/</link>
      <pubDate>Fri, 17 Mar 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/container-images/</guid>
      <description>Container Images are static files containing the necessary resources for creating containers.</description>
      <content:encoded><![CDATA[<p>A container image is a static file that contains the necessary resources (packages, configuration, other dependencies) required to provision a container. It consists of multiple layered-filesystems and a <em>Manifest</em> file, containing its metadata.</p>
<h1 id="open-container-initiative-oci-specification">Open Container Initiative (OCI) Specification</h1>
<p>Open Container Initiative was established by The Linux Foundation in 2015 to provide</p>
<ul>
<li>Runtime specification</li>
<li>Image specification</li>
<li>Distribution specification
for container images.</li>
</ul>
<p>A container image created from OCI Image specification should have</p>
<ul>
<li>Layered Filesystem: Stores the packaged contents of the container.</li>
<li>Image Index and Manifest: Contains a manifest list that stores the container image metadata for multiple platforms.</li>
<li>Image Configuration: Arguments and environment variables for the applications inside the container.</li>
</ul>
<p>Images created from Docker, Podman, and buildah follow OCI Image Specification.</p>
<h2 id="layered-filesystems">Layered filesystems</h2>
<p>Each filesystem layer stores changes performed on top of the previous layer. They are differentiated using their SHA256 digest.</p>
<p align="center"><img src="container_image_layers.png" alt="Base and Image Layers"></p>
<p align="center"><small><i>Base and Image Layers</i></small></p>
<p>To build a container image the developer has to use another container image as a <strong>base layer</strong>. The base layer container image could be chosen based on OS preference (like Fedora, Kali, etc.) or programming language preference (like gcc, python, etc.), or any other preference. On top of the base layer developers can add changes (like installing packages and dependencies, performing configuration changes, etc.) by creating stacked <strong>image layers</strong>.</p>
<p>The layers are cached on the host to reduce the build time and storage space required by the image. Cached layers could also be reused in the build process of different images, for example, two images (on the same host) using base layer <code>ubuntu:22.0</code> will refer to the same cached layer.</p>
<p>When a container image is provisioned as a container, the base and image layers are locked as read-only.</p>
<p align="center"><img src="container_layer.png" alt="Read-Write layer added on top of Image Layers"></p>
<p align="center"><small><i>Read-Write layer added on top of Image Layers</i></small></p>
<p>A data state of image layers is generated and a writable <strong>container layer</strong> is added on top. It stores runtime changes (like file creation, configuration changes, etc.) and deleted with the container.</p>
<h2 id="image-index-and-manifest">Image Index and Manifest</h2>
<p>The <strong>Image Index</strong> of a container image contains the metadata related to the filesystem layers, the command to be executed once the container is provisioned and other information required by the container runtime.</p>
<p>To view the index of a container image, the <code>manifest</code> subcommand with <code>inspect</code> option could be used.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker manifest inspect docker.io/library/httpd:latest
</span></span></code></pre></td></tr></table>
</div>
</div><p>The output will be a JSON document with a <code>manifest</code> array containing references to multiple image variations based on the OS and CPU architecture of the host.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;schemaVersion&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;mediaType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/vnd.docker.distribution.manifest.list.v2+json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;manifests&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;mediaType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/vnd.docker.distribution.manifest.v2+json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;size&#34;</span><span class="p">:</span> <span class="mi">1366</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;digest&#34;</span><span class="p">:</span> <span class="s2">&#34;sha256:d866e5c91f31fc6a122aaf37149cc67ba2ca0de68ae73ab206747a190937967e&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;architecture&#34;</span><span class="p">:</span> <span class="s2">&#34;amd64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;linux&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;mediaType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/vnd.docker.distribution.manifest.v2+json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;size&#34;</span><span class="p">:</span> <span class="mi">1366</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;digest&#34;</span><span class="p">:</span> <span class="s2">&#34;sha256:32588e5c7552750100ad3110a64d163b1881ce92216d67e828c42d3322c439d1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;architecture&#34;</span><span class="p">:</span> <span class="s2">&#34;arm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;linux&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;variant&#34;</span><span class="p">:</span> <span class="s2">&#34;v5&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;mediaType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/vnd.docker.distribution.manifest.v2+json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;size&#34;</span><span class="p">:</span> <span class="mi">1366</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;digest&#34;</span><span class="p">:</span> <span class="s2">&#34;sha256:67586a7e127abd9b362884172b575a43b3342725ae310c339f4f7d5e5bdba918&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;architecture&#34;</span><span class="p">:</span> <span class="s2">&#34;arm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;linux&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;variant&#34;</span><span class="p">:</span> <span class="s2">&#34;v7&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;mediaType&#34;</span><span class="p">:</span> <span class="s2">&#34;application/vnd.docker.distribution.manifest.v2+json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;size&#34;</span><span class="p">:</span> <span class="mi">1366</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;digest&#34;</span><span class="p">:</span> <span class="s2">&#34;sha256:bc5f484630b50cec12a50035d22ed717d980c52c9871105e91e276ebcbee69a2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;architecture&#34;</span><span class="p">:</span> <span class="s2">&#34;arm64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;linux&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;variant&#34;</span><span class="p">:</span> <span class="s2">&#34;v8&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>An image could be built and distributed for different platforms with singular name and tag. The container engine verifies from the manifest if a compatible image is available for the host.</p>
<h2 id="image-configuration">Image Configuration</h2>
<p>The changes to be implemented on the filesystem during the creation of the container are stored in the <strong>image configuration</strong> . It also stores parameters and environment variables for applications inside the container.</p>
<p><code>docker image inspect image-name</code> could be used to view the configuration of a container image in JSON format.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="cl">    <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Id&#34;</span>: <span class="s2">&#34;sha256:daab1fa13f8608841399e8552ab7833e90307543509ced13cd40b3f7411632a3&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;RepoTags&#34;</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;httpd:latest&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="o">]</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;RepoDigests&#34;</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;httpd@sha256:76618ddd53f315a1436a56dc84ad57032e1b2123f2f6489ce9c575c4b280c4f4&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="o">]</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Parent&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Comment&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Created&#34;</span>: <span class="s2">&#34;2023-03-07T20:24:12.062824222Z&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Container&#34;</span>: <span class="s2">&#34;30df81c7e4e9fcec6990ff7a5aee09f0b8d765a65d575599d92fa3d2c2da6048&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;DockerVersion&#34;</span>: <span class="s2">&#34;20.10.23&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Author&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Config&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Hostname&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Domainname&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;User&#34;</span>: <span class="s2">&#34;&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;AttachStdin&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;AttachStdout&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;AttachStderr&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;ExposedPorts&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;80/tcp&#34;</span>: <span class="o">{}</span>
</span></span><span class="line"><span class="cl">            <span class="o">}</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Tty&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;OpenStdin&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;StdinOnce&#34;</span>: false,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Env&#34;</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;HTTPD_PREFIX=/usr/local/apache2&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;HTTPD_VERSION=2.4.56&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;HTTPD_SHA256=d8d45f1398ba84edd05bb33ca7593ac2989b17cb9c7a0cafe5442d41afdb2d7c&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;HTTPD_PATCHES=&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="o">]</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Cmd&#34;</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;httpd-foreground&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="o">]</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Image&#34;</span>: <span class="s2">&#34;sha256:a5930d7e9b3c7fa530cff2806db329c228e08a75d9db73314b3b5724c0858b60&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Volumes&#34;</span>: null,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;WorkingDir&#34;</span>: <span class="s2">&#34;/usr/local/apache2&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Entrypoint&#34;</span>: null,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;OnBuild&#34;</span>: null,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Labels&#34;</span>: null,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;StopSignal&#34;</span>: <span class="s2">&#34;SIGWINCH&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="o">}</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Architecture&#34;</span>: <span class="s2">&#34;amd64&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Os&#34;</span>: <span class="s2">&#34;linux&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Size&#34;</span>: 145140075,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;VirtualSize&#34;</span>: 145140075,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;RootFS&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Type&#34;</span>: <span class="s2">&#34;layers&#34;</span>,
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Layers&#34;</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sha256:650abce4b096b06ac8bec2046d821d66d801af34f1f1d4c5e272ad030c7873db&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sha256:2309cdaf4afb9ce407a51c6d3ae54fb915bfbcc480e596e72417206902b4c51f&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sha256:849b101b0e3b3f03fad010462b6ab14f1372d449a1fb803750182547e7df3d28&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sha256:a30707f342ec97e05e57d91804d8ae3d5f93d5e6c9ef2c4e8a3d805b70b0d53e&#34;</span>,
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sha256:087e3023406cdd4c0765ee68d24c88da0c0335ac2ce82d991bd336a648c033c6&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="o">]</span>
</span></span><span class="line"><span class="cl">        <span class="o">}</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Metadata&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;LastTagTime&#34;</span>: <span class="s2">&#34;0001-01-01T00:00:00Z&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="distributing-container-images">Distributing container images</h1>
<h2 id="tarfile">Tarfile</h2>
<h3 id="exporting-containers">Exporting containers</h3>
<p>Containers could be exported as tar archives using the <code>export</code> subcommand.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">export</span> httpd-container &gt; httpd.tar
</span></span></code></pre></td></tr></table>
</div>
</div><p>To import this tarfile as a container image, the <code>import</code> subcommand is used.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker import httpd.tar
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>import</code> also supports URL for tarfile as an argument.</p>
<h3 id="exporting-container-images">Exporting container images</h3>
<p>To export container images as tarfile we can use the <code>save</code> subcommand. Output from the command needs to be redirected using <code>&gt;</code> operator into a <code>*.tar</code> file.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker save httpd:latest &gt; httpd.tar
</span></span></code></pre></td></tr></table>
</div>
</div><p>This tarfile could be loaded as a container image using the <code>load</code> subcommand and <code>&lt;</code> operator.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker load &lt; httpd.tar
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="container-registry">Container Registry</h2>
<p align="center"><img src="image_pull.png" alt="Distributing images using Container Registry"></p>
<p align="center"><small><i>Distributing images using Container Registry</i></small></p>
<p><strong>Container Registry</strong> is a service that allows the distribution of container images. It also provides features such as</p>
<ul>
<li>Access control to images</li>
<li>Vulnerability scanning</li>
<li>Control over distribution</li>
<li>High availability</li>
</ul>
<p>Some of the commonly used container registries are Quay.io, DockerHub, and Google Container Registry.</p>
<p>A registry account is necessary to distribute an image. The credentials from the registry will be used to log in from the container engine.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker login quay.io
</span></span></code></pre></td></tr></table>
</div>
</div><p>The image to be pushed should be tagged/renamed in format <code>&lt;registry-name&gt;/&lt;username&gt;/&lt;image-name&gt;:&lt;image-tag&gt;</code>, for example, <code>quay.io/username/webserver:latest</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker tag webserver:latest quay.io/username/webserver:latest
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>push</code> subcommand is used to upload the tagged image to the registry.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker push quay.io/username/webserver:latest
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="creating-images-from-existing-containers">Creating images from existing containers</h3>
<p align="center"><img src="containers_commit.png" alt="Commit running containers to container image"></p>
<p align="center"><small><i>Commit running containers to container image</i></small></p>
<p>To create a container image from a running container, the <code>commit</code> subcommand could be used.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker commit webserver-container quay.io/username/webserver:latest
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://opencontainers.org/about/overview/" target="_blank">About the Open Container Initiative</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/manifest.md" target="_blank">OCI Image Manifest Specification</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/layer.md" target="_blank">Image Layer Filesystem Changeset</a><br>
<a href="https://github.com/opencontainers/image-spec/blob/main/config.md" target="_blank">OCI Image Configuration</a><br>
<a href="https://docs.docker.com/storage/storagedriver/" target="_blank">About storage drivers</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/export/" target="_blank">docker export</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/import/" target="_blank">docker import</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/save/" target="_blank">docker save</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/load/" target="_blank">docker load</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/commit/" target="_blank">docker commit</a><br>
<a href="https://docs.docker.com/engine/reference/commandline/push/" target="_blank">docker push</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Container Lifecycle</title>
      <link>http://www.avni.sh/posts/cloud-native/container-lifecycle/</link>
      <pubDate>Fri, 10 Feb 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/container-lifecycle/</guid>
      <description>The state of a container is managed using the utilities provided by container engines.</description>
      <content:encoded><![CDATA[<p>Container Engines like Podman and Docker provide GUI and CLI utilities for managing the state of containers. They also provide features such as container image management, metrics, logging, and debugging tools. The examples in this article use Podman but CLI commands are mostly interoperable with Docker.</p>
<p>We can install Podman on your system by following the steps in <a href="https://podman.io/getting-started/installation" target="_blank">Podman Installation Instructions</a>. Podman also provides a graphical interface for managing containers, images, and other resources called <a href="https://podman-desktop.io/" target="_blank">Podman Desktop</a>.</p>
<h1 id="accessing-container-images">Accessing Container Images</h1>
<p>To create a container first, we have to download its image from a registry. A <strong>container image</strong> is a file that contains all the dependencies and executable code for the container.</p>
<p>Images could be fetched from container registries such as  <a href="https://hub.docker.com/" target="_blank">DockerHub</a> or <a href="https://quay.io/search" target="_blank">Quay.io</a>.</p>
<h2 id="login-to-container-image-registry">Login to Container Image Registry</h2>
<p>A <strong>container image registry</strong> is a service that handles the storage and distribution of container images. It is necessary to log in to the container registry to access private images.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman login docker.io
</span></span></code></pre></td></tr></table>
</div>
</div><p>After executing this command a prompt will ask for your username and password, for that we need to have a container registry account. Images used in this article are public so we don&rsquo;t need to create an account or log in.</p>
<p>Once login is successful, Podman stores the encrypted user information in file <code>${XDG_RUNTIME_DIR}/containers/auth.json</code>. <code>XDG_RUNTIME_DIR</code> is an environment variable set by <code>systemd</code> that stores the path of the directory containing user-specific runtime files.</p>
<h2 id="pulling-container-images">Pulling Container Images</h2>
<p align="center"><img src="image_pull.png" alt="Pulling container images from registry"></p>
<p align="center"><small><i>Pulling container images from registries</i></small></p>
<p>Public registries provide an interface for searching images or Podman&rsquo;s subcommand <code>search</code> could also be used.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman search httpd
</span></span></code></pre></td></tr></table>
</div>
</div><p>Once we have the image name we can pull it on our machine using the <code>pull</code> subcommand</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman pull docker.io/library/httpd 
</span></span></code></pre></td></tr></table>
</div>
</div><p>or using the Podman Desktop app you can go to <strong>Images</strong> -&gt; <strong>Pull an Image</strong>.</p>
<p align="center"><img src="podman_desktop_image_pull.png" alt="Pulling container image using Podman Desktop"></p>
<p align="center"><small><i>Pulling container image using Podman Desktop</i></small></p>
<p>Different versions/variations of container images are managed by <strong>Tags</strong>. The image tag <code>latest</code> is pulled by default. You can view the list of available tags on the registry&rsquo;s webpage or use <code>skopeo list-tags</code>. Skopeo requires the <em>transport</em> (<code>docker</code> in our case) to be mentioned explicitly with the image name.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">skopeo list-tags docker://docker.io/library/httpd
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="managing-container-lifecycle">Managing Container Lifecycle</h1>
<p>Once we have access to the container image we can easily create one or more containers.</p>
<h2 id="creating-a-container">Creating a Container</h2>
<p align="center"><img src="create_containers.png" alt="Creating a container from the container image"></p>
<p align="center"><small><i>Creating a container from the container image</i></small></p>
<p>We use the <code>run</code> subcommand for creating containers. If the image specified in the command is not present in the system then Podman will attempt to pull it from the registry.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman run --name httpd-test docker.io/library/httpd
</span></span></code></pre></td></tr></table>
</div>
</div><p>After executing this command a container named <code>httpd-test</code> will be created on your system and its output will be attached to your terminal. To exit you can use the shortcut <strong>Ctrl+C</strong>. To run the container in the background <code>--detach</code> flag could be used.</p>
<p><code>podman ps</code> command will list running containers on the system.</p>
<p>On Podman Desktop, the <strong>Containers</strong> section provides utilities for managing the state of containers.</p>
<p align="center"><img src="podman_desktop_create_containers.png" alt="Creating container using Podman Desktop"></p>
<p align="center"><small><i>Creating container using Podman Desktop</i></small></p>
<h2 id="executing-commands-inside-a-container">Executing Commands inside a Container</h2>
<p>To run a container and access its shell we have to use options <code>--interactive</code> &amp; <code>--tty</code>.</p>
<p><code>--interactive</code> will allow us to provide inputs to the process running inside the container and <code>--tty</code> will attach a pseudo-terminal to the container.</p>
<p><strong>Entrypoint</strong> specifies a command that is executed during container initialization. It could be defined by default in the image, but you can override it with the <code>--entrypoint</code> flag.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman run -it --name httpd-test <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               --entrypoint<span class="o">=</span><span class="s2">&#34;/bin/bash&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               docker.io/library/httpd
</span></span></code></pre></td></tr></table>
</div>
</div><p>To execute a command or script inside the container we use Podman&rsquo;s <code>exec</code> subcommand.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman <span class="nb">exec</span> httpd-test <span class="nb">echo</span> <span class="s2">&#34;Hello, world&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="attaching-volumes">Attaching Volumes</h2>
<p>Directories from the host could be mounted on a container. It is useful when scripts are edited outside the container (an IDE/Code Editor on the host) or the files have to be shared between multiple containers.</p>
<p>To mount a directory from host to container flag <code>--volume</code> could be used with <code>run</code> subcommand and values are passed as <code>&lt;HOSTDIR&gt;:&lt;CONTAINERDIR&gt;</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman run -it --name python-test --detach <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               --entrypoint<span class="o">=</span><span class="s2">&#34;/bin/bash&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               --volume <span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>:/app:Z <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               docker.io/library/python:3.10.6-slim-bullseye
</span></span></code></pre></td></tr></table>
</div>
</div><p>This command starts a python container with contents of the present working directory (fetched from the <code>pwd</code> command) mounted on the <code>/app</code> directory inside the container. Both directory paths have to be absolute.</p>
<p>Before mounting the host directory we have to change its <a href="/posts/computer-science/technologies/cloud-native/container-architecture/#security-enhanced-linux-selinux" target="_blank">SELinux</a> context to <code>container_file_t</code> otherwise we could encounter permission issues while accessing directory contents. To change the SELinux context you can append either <code>:z</code> (if multiple containers need read-write access) or <code>:Z</code> (if only the current container needs read-write access).</p>
<p align="center"><img src="podman_desktop_volumes.png" alt="Accessing volumes on Podman Desktop"></p>
<p align="center"><small>Accessing volumes on Podman Desktop</small></p>
<h2 id="port-forwarding">Port Forwarding</h2>
<p>To communicate with the services running inside the container, port forwarding has to be established from the host using the <code>--publish</code> flag in  the <code>run</code> subcommand. The port specified for the host and container could be different for example the following command forwards the output from the <code>httpd-test</code> container&rsquo;s port <code>80</code> to port <code>8080</code> on the host.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman run --name httpd-test --detach <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>           --publish 8080:80 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>           docker.io/library/httpd           
</span></span></code></pre></td></tr></table>
</div>
</div><p>To view the output we can visit <a href="http://localhost:8080" target="_blank">localhost:8080</a> in our browser.
It is advised that only the necessary network ports should be forwarded from container to host.</p>
<h2 id="pausing-an-executing-container">Pausing an Executing Container</h2>
<p align="center"><img src="pause.png" alt="Pausing running container"></p>
<p align="center"><small><i>Pausing running container</i></small></p>
<p>To demonstrate a paused container we will take the help of the following Python script</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># This script runs an infinite loop </span>
</span></span><span class="line"><span class="cl"><span class="c1"># with the time interval of 2 seconds to slow down the output</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="n">i</span><span class="o">=</span><span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Value of i: </span><span class="si">{}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">i</span><span class="o">+=</span><span class="mi">1</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Assuming that this script is saved in the current directory with name <code>counting.py</code>, we run a container created from image <code>docker.io/library/python:3.10.6-slim-bullseye</code> in detached mode.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman run -it --name python-test --detach <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               --entrypoint<span class="o">=</span><span class="s2">&#34;/bin/bash&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               -v <span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span>:/app:Z <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>               docker.io/library/python:3.10.6-slim-bullseye
</span></span></code></pre></td></tr></table>
</div>
</div><p>Then we execute the script inside the container in interactive mode</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman <span class="nb">exec</span> -it python-test python3 /app/counting.py
</span></span></code></pre></td></tr></table>
</div>
</div><p>An infinite loop will be initiated and the output should be visible on the terminal. Now we open a new terminal window and pause this container.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman pause python-test
</span></span></code></pre></td></tr></table>
</div>
</div><p>If we go back to the first terminal we can observe that the script execution is paused. When unpaused the container will restart right where it left.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman unpause python-test
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="stopping-an-executing-container">Stopping an Executing Container</h2>
<p align="center"><img src="stop.png" alt="Stop running containers"></p>
<p align="center"><small><i>Stop running containers</i></small></p>
<p>While pausing a container stops its execution in its current state, <em>stopping</em> a container kills the executing process.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman stop python-test
</span></span></code></pre></td></tr></table>
</div>
</div><p>Upon restarting container will run the entrypoint command, starting a new process.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman start python-test
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="deleting-a-container">Deleting a Container</h2>
<p align="center"><img src="delete.png" alt="Deleting containers"></p>
<p align="center"><small><i>Deleting containers</i></small></p>
<p>Before we delete a running container we have to stop it or we can use the <code>--force</code> flag along with the <code>rm</code> subcommand.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman rm python-test
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="metrics-and-logging">Metrics and Logging</h1>
<h2 id="listing-containers">Listing Containers</h2>
<p>By default, the <code>ps</code> subcommand fetches the list of running containers but to view all the containers regardless of their state we can use the <code>--all</code> flag.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman ps --all
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="resource-utilization-statistics">Resource Utilization Statistics</h2>
<p><code>stats</code> subcommand provides live statistics of resource utilization by containers.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman stats
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="accessing-logs-from-a-container">Accessing Logs from a Container</h2>
<p>To access the logs of a running/completed container we use the <code>logs</code> subcommand. To view the live output from a running container <code>--follow</code> flag is added.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman logs --follow httpd-test
</span></span></code></pre></td></tr></table>
</div>
</div><p>To access the container logs from Podman Desktop we can click on the container name in the <strong>Containers</strong> section.</p>
<p align="center"><img src="podman_desktop_container_logs.png" alt="Accessing container logs from Podman Desktop"></p>
<p align="center"><small><i>Accessing container logs from Podman Desktop</i></small></p>
<p>We can also attach a terminal to the container from the <strong>Terminal</strong> tab.</p>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://podman.io/getting-started/installation" target="_blank">Podman Installation Instructions</a><br>
<a href="https://podman-desktop.io/" target="_blank">Podman Desktop</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-login.1.html" target="_blank">podman-login</a><br>
<a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables" target="_blank">XDG Base Directory Specification</a><br>
<a href="https://hub.docker.com/_/httpd" target="_blank">httpd container image</a><br>
<a href="https://hub.docker.com/_/python" target="_blank">python container image</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-search.1.html" target="_blank">podman-search</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-pull.1.html" target="_blank">podman-pull</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-run.1.html" target="_blank">podman-run</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-exec.1.html" target="_blank">podman-exec</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-pause.1.html" target="_blank">podman-pause</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-stop.1.html" target="_blank">podman-stop</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-stats.1.html" target="_blank">podman-stats</a><br>
<a href="https://docs.podman.io/en/latest/markdown/podman-logs.1.html" target="_blank">podman-logs</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Container Architecture</title>
      <link>http://www.avni.sh/posts/cloud-native/container-architecture/</link>
      <pubDate>Fri, 27 Jan 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/container-architecture/</guid>
      <description>Creation and execution of container is enabled using features like namespaces, Cgroups, seccomp, and SELinux</description>
      <content:encoded><![CDATA[<p>To isolate the processes running inside a <a href="/posts/computer-science/technologies/cloud-native/containers/" target="_blank">container</a> from its host system, container engine uses the following four features:</p>
<ul>
<li>Namespaces</li>
<li>Control Groups</li>
<li>Secure Computing</li>
<li>Security-Enhanced Linux</li>
</ul>
<h2 id="namespaces">Namespaces</h2>
<p><strong>Namespaces</strong> are created to limit the reach of a container to its host&rsquo;s resources. It helps with security and well as limits resources available to the container.</p>
<p>Linux command <code>lsns</code> could be used for listing details of namespaces.</p>
<p>The namespaces essential for containers are User, Mount, Unix Timesharing System, Process ID, Network, and Inter-Process Communication.</p>
<h3 id="user">User</h3>
<p>The users and groups created inside a container are different from its host. Processes running inside the container as a <code>root</code> user could be mapped to a non-root user on the host.</p>
<p>Using the <code>id</code> command you can verify that the containers are present on a different user namespace than other processes on your host.</p>
<p>Running <code>id</code> on host:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ id
</span></span><span class="line"><span class="cl"><span class="nv">uid</span><span class="o">=</span>1000<span class="o">(</span>username<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>1000<span class="o">(</span>username<span class="o">)</span> <span class="nv">groups</span><span class="o">=</span>1000<span class="o">(</span>username<span class="o">)</span>,10<span class="o">(</span>wheel<span class="o">)</span> <span class="nv">context</span><span class="o">=</span>unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
</span></span></code></pre></td></tr></table>
</div>
</div><p>Running <code>id</code> inside a container created from <code>docker.io/library/httpd:latest</code> container image:</p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 328 41"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='0' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='8' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>=</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>@</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='72' y='4' fill='currentColor' style='font-size:1em'>7</text>
<text text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='88' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='96' y='4' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='104' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='112' y='4' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='120' y='4' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'>=</text>
<text text-anchor='middle' x='128' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='136' y='4' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='144' y='4' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='152' y='4' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='160' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='168' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='176' y='4' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='184' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='192' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='200' y='4' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='208' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='216' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='224' y='4' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='232' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='240' y='4' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'>=</text>
<text text-anchor='middle' x='248' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='256' y='4' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='264' y='4' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='272' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='280' y='4' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='4' fill='currentColor' style='font-size:1em'>#</text>
<text text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='304' y='4' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='312' y='4' fill='currentColor' style='font-size:1em'>d</text>
</g>

    </svg>
  
</div>
<h3 id="process-id-pid">Process ID (<code>PID</code>)</h3>
<p>Each process running on the host has a unique Process ID (PID) assigned to it. The PIDs of processes running inside container are separate from PIDs assigned by the host. Due to process ID isolation, a container can&rsquo;t access the details of processes running on its host.</p>
<p>To fetch the list of PID namespaces you can use the command:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ lsns -t pid
</span></span><span class="line"><span class="cl">        NS TYPE NPROCS   PID USER  COMMAND
</span></span><span class="line"><span class="cl"><span class="m">4026531836</span> pid     <span class="m">128</span>  <span class="m">4996</span> user /usr/lib/systemd/systemd --user
</span></span><span class="line"><span class="cl"><span class="m">4026533251</span> pid      <span class="m">16</span>  <span class="m">4525</span> user nginx: worker process
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>Just like other processes, containers also have PIDs assigned to them by the host. You can fetch the PID of a running container using the following command:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$  docker inspect -f <span class="s1">&#39;{{.State.Pid}}&#39;</span> deploy-hugo-server-1
</span></span><span class="line"><span class="cl"><span class="m">7172</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>ps aux</code> command could be used to list the running processes on the system along with their details.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ ps aux <span class="p">|</span> grep <span class="m">7172</span>
</span></span><span class="line"><span class="cl">root        <span class="m">7172</span>  0.0  0.4 <span class="m">759596</span> <span class="m">68860</span> ?        Ssl  Jan22   0:32 /usr/lib/hugo/hugo server --buildFuture --bind<span class="o">=</span>0.0.0.0
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="mount-mnt">Mount (<code>mnt</code>)</h3>
<p>By using different mount namespaces for different processes we can ensure that they won&rsquo;t be able to access each other&rsquo;s files.</p>
<p>You can use <code>df</code> command to view the filesystems mounted on your system.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ df
</span></span><span class="line"><span class="cl">Filesystem     1K-blocks      Used Available Use% Mounted on
</span></span><span class="line"><span class="cl">devtmpfs            <span class="m">4096</span>         <span class="m">0</span>      <span class="m">4096</span>   0% /dev
</span></span><span class="line"><span class="cl">tmpfs            <span class="m">7849324</span>     <span class="m">42384</span>   <span class="m">7806940</span>   1% /dev/shm
</span></span><span class="line"><span class="cl">tmpfs            <span class="m">3139732</span>      <span class="m">2444</span>   <span class="m">3137288</span>   1% /run
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>A container has its separate file system hierarchy which could be viewed by using <code>df</code> command on its shell.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@14ed72afd62e:/usr/local/apache2# df
</span></span><span class="line"><span class="cl">Filesystem     1K-blocks      Used Available Use% Mounted on
</span></span><span class="line"><span class="cl">overlay        <span class="m">498443264</span> <span class="m">308159584</span> <span class="m">185270656</span>  63% /
</span></span><span class="line"><span class="cl">tmpfs              <span class="m">65536</span>         <span class="m">0</span>     <span class="m">65536</span>   0% /dev
</span></span><span class="line"><span class="cl">tmpfs            <span class="m">1569860</span>       <span class="m">276</span>   <span class="m">1569584</span>   1% /etc/hosts
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>It could also be viewed by the host in the file <code>/proc/&lt;CONTAINER_PID&gt;/mounts</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ docker inspect -f <span class="s1">&#39;{{.State.Pid}}&#39;</span> deploy-hugo-server-1
</span></span><span class="line"><span class="cl"><span class="m">7172</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ cat /proc/7172/mounts
</span></span><span class="line"><span class="cl">proc /proc proc rw,nosuid,nodev,noexec,relatime <span class="m">0</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">tmpfs /dev tmpfs rw,seclabel,nosuid,size<span class="o">=</span>65536k,mode<span class="o">=</span>755,inode64 <span class="m">0</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid<span class="o">=</span>5,mode<span class="o">=</span>620,ptmxmode<span class="o">=</span><span class="m">666</span> <span class="m">0</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="unix-timesharing-system-uts">Unix Timesharing System (UTS)</h3>
<p>Unix Time System (UTS) namespace allows containers to have hostnames. We can verify this with the <code>hostname</code> command.</p>
<p>On the host:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>username@host-1 ~<span class="o">]</span>$ hostname
</span></span><span class="line"><span class="cl">host-1
</span></span></code></pre></td></tr></table>
</div>
</div><p>Inside a container:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@14ed72afd62e:/usr/local/apache2# hostname
</span></span><span class="line"><span class="cl">14ed72afd62e
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="network">Network</h3>
<p>Each container has a IP address and network ports assigned to it by its network namespace. It allows the developer to run multiple processes inside the container and expose them over different network ports.</p>
<p>To access or communicate with a process inside the container, port forwarding should be established from the host.</p>
<h3 id="inter-process-communication-ipc">Inter-Process Communication (IPC)</h3>
<p>Processes in the same IPC namespace can share the resources such as memory, semaphores, and message queues. Keeping separate IPC namespaces ensures that the processes inside a container cannot access the resources used by the host&rsquo;s processes.</p>
<h3 id="time">Time</h3>
<p>Time namespaces are available since the release of Linux Kernel 5.6.<br>
Maybe in the future containers can have a different time than their host.</p>
<h2 id="control-groups-cgroups">Control Groups (Cgroups)</h2>
<p>A <strong>control group</strong> is created to effectively allocate resources of host its processes. These Cgroups are hierarchical i.e. a child Cgroup could be spawned from the parent and it will inherit its certain attributes.</p>
<p>By creating a Cgroup a process in it could be prioritized, paused, removed, or resumed based on the resources allocated to it. It also helps in monitoring the resources used by particular processes.</p>
<p>If you are using an OS with <code>systemd</code> init system (to verify this you can use the command <code>ps -p 1 -o comm=</code>) then you can use the command <code>systemctl list-units</code> to list all the Cgroups. It will open a table containing the Cgroup name, state, and description. The names of the Cgroup will be in the form <code>&lt;parent-cgroup&gt;.&lt;child-cgroup&gt;</code> like <code>sys-devices-platform-serial8250-tty-ttyS0.device</code>.</p>
<p>To view the hierarchy of Cgroups you can use the command <code>systemd-cgls</code>. It presents cgroups as a tree structure.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Control group /:
</span></span><span class="line"><span class="cl">-.slice
</span></span><span class="line"><span class="cl">├─user.slice <span class="o">(</span><span class="c1">#1309)</span>
</span></span><span class="line"><span class="cl">│ └─user-1000.slice <span class="o">(</span><span class="c1">#10010)</span>
</span></span><span class="line"><span class="cl">│   ├─user@1000.service <span class="o">(</span><span class="c1">#10106)</span>
</span></span><span class="line"><span class="cl">│   │ ├─session.slice <span class="o">(</span><span class="c1">#10394)</span>
</span></span><span class="line"><span class="cl">│   │ │ ├─dbus-broker.service <span class="o">(</span><span class="c1">#10442)</span>
</span></span><span class="line"><span class="cl">│   │ │ │ ├─ <span class="m">5088</span> /usr/bin/dbus-broker-launch --scope user
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="secure-computing-seccomp">Secure Computing (Seccomp)</h2>
<p>Using <strong>Secure Computing</strong> (or seccomp) you can disable the system calls your process can make to the host&rsquo;s kernel.</p>
<p>A <em>seccomp profile</em> is a definition with a set of restricted and allowed system calls stored in a file. Default seccomp profile used by Docker: <a href="https://github.com/moby/moby/blob/master/profiles/seccomp/default.json" target="_blank">default.json</a>.</p>
<p>Docker allows you to define your seccomp profile for a container in JSON format.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -it --security-opt <span class="nv">seccomp</span><span class="o">=</span>/path/to/seccomp/profile.json hello-world
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="security-enhanced-linux-selinux">Security-Enhanced Linux (SELinux)</h2>
<p><strong>SELinux</strong> is a security architecture for GNU/Linux-based OS that defines access to files and processes. It is enforced on users or processes to restrict their access to the resources.</p>
<p>SELinux checks the <em>SELinux context</em> of the file or process to make decisions related to its access control. To view the SELinux context of a file use command <code>ls -Z &lt;FILENAME&gt;</code> and to view it for a process using the command <code>ps -eZ | grep &lt;PROCESS_NAME&gt;</code>.</p>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://www.youtube.com/watch?v=sK5i-N34im8" target="_blank">Cgroups, namespaces, and beyond: what are containers made from?</a><br>
<a href="https://opensource.com/article/21/8/container-linux-technology" target="_blank">4 Linux technologies fundamental to containers</a><br>
<a href="https://man7.org/linux/man-pages/man1/init.1.html" target="_blank">systemd(1) — Linux manual page</a><br>
<a href="https://www.redhat.com/sysadmin/7-linux-namespaces" target="_blank">The 7 most used Linux namespaces</a><br>
<a href="https://opensource.com/article/19/4/interprocess-communication-linux-storage" target="_blank">Inter-process communication in Linux: Shared storage</a><br>
<a href="https://www.tenable.com/audits/items/DISA_STIG_Docker_Enterprise_2.x_Linux_Unix_v1r1.audit:f0aaa2cd4bcb66461902f47c69bf323b" target="_blank">DKER-EE-001250 - The Docker Enterprise hosts IPC namespace must not be shared.</a><br>
<a href="https://www.phoronix.com/news/Time-Namespace-In-Linux-5.6" target="_blank">It&rsquo;s Finally Time: The Time Namespace Support Has Been Added To The Linux 5.6 Kernel</a><br>
<a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/resource_management_guide/sec-obtaining_information_about_control_groups" target="_blank">Obtaining Information about Control Groups</a><br>
<a href="https://man7.org/linux/man-pages/man2/seccomp.2.html" target="_blank">seccomp(2) — Linux manual page</a><br>
<a href="https://www.redhat.com/en/topics/linux/what-is-selinux" target="_blank">What is SELinux?</a><br>
<a href="https://blog.christophersmart.com/2021/01/31/podman-volumes-and-selinux/" target="_blank">Podman volumes and SELinux</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Containers</title>
      <link>http://www.avni.sh/posts/cloud-native/containers/</link>
      <pubDate>Thu, 19 Jan 2023 00:00:00 +0000</pubDate>
      <guid>http://www.avni.sh/posts/cloud-native/containers/</guid>
      <description>A container is a set of one or more isolated processes running on an Operating System</description>
      <content:encoded><![CDATA[<p>While creating an application in any programming language or framework you have to install its dependencies on your system.
This could include the compiler for the programming language, libraries, and frameworks.</p>
<p>If the environment for the deployment of this application is different then the whole process of dependency installation has to repeat. You might have to some other changes, like setting up environment variables and making changes to the configuration files.</p>
<p>This problem becomes more challenging once you start collaborating with other people. The complete installation process has to be repeated on every development machine. Even if complete documentation of the setup process is available the developers could have a different environment. It is also possible that the developers want to work on two different projects simultaneously and there could be a conflict between their configurations (like different versions of the framework).</p>
<p>When an application is deployed directly on the OS running on the physical hardware it is called <strong>baremetal deployment</strong>.</p>
<p align="center"><img src="baremetal_deployment.png" alt="Deployment of application directly on physical hardware"></p>
<p align="center"><small><i>Baremetal Deployment</i></small></p>
<h1 id="virtual-machines-vms">Virtual Machines (VMs)</h1>
<p>A <strong>virtual machine</strong> as the name suggests is a machine running upon the OS installed on the physical hardware. It has its virtual CPU, memory, networking interfaces, and other resources that are provided by a <em>hypervisor</em>.</p>
<p>A <strong>hypervisor</strong> is a program that is used to create and manage virtual machines. Some common hypervisors are:</p>
<ul>
<li>Oracle VM VirtualBox</li>
<li>Hyper-V</li>
</ul>
<h2 id="advantages-of-using-vms-for-deploying-applications">Advantages of using VMs for deploying applications</h2>
<p align="center"><img src="virtual_machine_deployment.png" alt="Deployment of application using Virtualization"></p>
<p align="center"><small><i>Virtualized Deployment</i></small></p>
<p>So, what advantage does development over VMs provide over development on the OS deployed on the physical hardware?</p>
<ol>
<li>The environment is persistent across the machines.<br>
If you create your application&rsquo;s development environment inside a VM, then you can share it with anyone else who is interested to run it themselves.<br>
The environment will be the same irrespective of the OS installed on the physical hardware.</li>
<li>Load balancing is easier in the production environment.<br>
You can run multiple instances of the same application such that the load could be distributed effectively. If one of the instances is down (due to updates or outage) the traffic to it could be re-routed to another instance.</li>
<li>Effective distribution of physical hardware resources available.<br>
The hypervisor creates a pool of resources available to it from the OS. Then these resources could be effectively distributed among the VMs created. A deployment VM could use fewer resources compared to a development VM.</li>
<li>Provides an option to run multiple OS on a single hardware.</li>
</ol>
<h1 id="containers">Containers</h1>
<p>A <strong>container</strong> is a set of one or more isolated processes running on an OS, it could be on a VM or directly on the physical hardware. Usually, it requires fewer resources than a virtual machine and provides similar performance and benefits depending on your use case.</p>
<p>The workloads running inside a container have very limited exposure to the resources of its host i.e its CPUs, memory, network, and storage. It uses the same kernel as its host, that&rsquo;s why you can&rsquo;t spin up a Linux container on a machine running Windows (without provisioning the VM through Windows Subsystem for Linux or any other hypervisor).</p>
<h2 id="advantages-of-using-containers-over-virtual-machines">Advantages of using Containers over Virtual Machines</h2>
<p align="center"><img src="containerized_deployment.png" alt="Deployment of application using containerization"></p>
<p align="center"><small><i>Containerized Deployment</i></small></p>
<ol>
<li>Relatively lighter compared to VMs<br>
Containers don&rsquo;t need virtual resources. The size of the container could be shrunk down to the point where only the dependencies required for the application are present on it.</li>
<li>Faster deployment<br>
Due to their smaller size compared to VMs they could be deployed faster.</li>
<li>More scalable<br>
It is possible to execute multiple containers in the same amount of resources required by a VM for an application.</li>
</ol>
<p>Depending on your use case the deployment could be a mix of both virtualization and containerization. Like a service comprising of multiple containers could be deployed on a VM.</p>
<h1 id="managing-containers">Managing Containers</h1>
<h2 id="container-runtime">Container Runtime</h2>
<p>The container is executed through a <strong>container runtime</strong>. It sets up the namespaces for the container.</p>
<p>Examples of container runtimes:</p>
<ul>
<li>containerd: Developed by Docker and donated to Cloud Native Computing Foundation (CNCF). Used in Docker Engine.</li>
<li>cri-o: Container Runtime commonly used in Kubernetes.</li>
</ul>
<h2 id="container-images">Container Images</h2>
<p>A <strong>container image</strong> is a file that contains all the dependencies and executable code for the container. It is a way of storing and sharing containers.</p>
<h2 id="container-image-registries">Container Image Registries</h2>
<p>A <strong>container image registry</strong> is a service that handles the storage and distribution of container images.</p>
<p>Some of the common container registries are: DockerHub, Quay.io, etc.</p>
<h2 id="container-engine">Container Engine</h2>
<p>When a container runtime is expanded with CLI and/or GUI utility for</p>
<ul>
<li>Creation of containers</li>
<li>Changing the state of container (starting, stopping, resuming, deleting)</li>
<li>Managing container images</li>
<li>APIs for developers to create layered products on top of it</li>
</ul>
<p>it becomes a <strong>container engine</strong>. Some examples of container engines are:</p>
<ul>
<li>Docker</li>
<li>Podman</li>
</ul>
<h2 id="open-container-initiative-oci">Open Container Initiative (OCI)</h2>
<p>Open Container Initiative was established in 2015 for providing open specifications for:</p>
<ul>
<li>Container Runtime</li>
<li>Container Image</li>
<li>Container Image Distribution</li>
</ul>
<p>The objective is to establish a standardized format for the containers such that an OCI container image could be used between different container engines without any issues.</p>
<h2 id="docker">Docker</h2>
<p>One of the most commonly used container engines. It is developed by Docker, Inc.
It uses a daemon (<code>dockerd</code>) that provides all the management services for the container. This daemon runs with root privileges.</p>
<h2 id="podman">Podman</h2>
<p>The acronym for <em>Pod Manager tool</em> is a daemonless container engine originally developed by Red Hat.</p>
<p>Unlike docker, it doesn&rsquo;t use any daemon for interactions with containers.
It also has other security-focused features like the containers don&rsquo;t run as root by default. This reduces the attack surface as the host system cannot be accessed from the inside of the container.</p>
<h3 id="skopeo">Skopeo</h3>
<p><code>skopeo</code> is a CLI utility used alongside <code>podman</code> for the management, inspection, and transfer of container images.</p>
<h3 id="buildah">Buildah</h3>
<p><code>buildah</code> is another CLI utility used alongside <code>podman</code> and <code>skopeo</code> for building OCI container images.</p>
<hr>
<p>Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at <a href="mailto:blog@avni.sh"><a href="mailto:blog@avni.sh">blog@avni.sh</a></a>.</p>
<p>If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my <a href="https://www.avni.sh/index.xml" target="_blank">RSS Feed</a>.</p>
<h1 id="resources">Resources</h1>
<p><a href="https://www.virtualbox.org/" target="_blank">Oracle VM VirtualBox</a><br>
<a href="https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/about/" target="_blank">Hyper-V</a><br>
<a href="https://containerd.io/" target="_blank">containerd</a><br>
<a href="https://cri-o.io/" target="_blank">cri-o</a><br>
<a href="https://hub.docker.com/" target="_blank">DockerHub</a><br>
<a href="https://quay.io/" target="_blank">Quay.io</a><br>
<a href="https://opencontainers.org/" target="_blank">Open Container Initiative</a><br>
<a href="https://www.docker.com/" target="_blank">Docker</a><br>
<a href="https://podman.io/" target="_blank">Podman</a><br>
<a href="https://github.com/containers/skopeo" target="_blank">Skopeo</a><br>
<a href="https://buildah.io/" target="_blank">Buildah</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
