<?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>Skopeo on avni.sh</title>
    <link>http://www.avni.sh/tags/skopeo/</link>
    <description>Recent content in Skopeo 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>Fri, 10 Feb 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://www.avni.sh/tags/skopeo/index.xml" rel="self" type="application/rss+xml" />
    <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"><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></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"><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></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"><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></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"><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></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"><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></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"><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></div><p>To execute a command or script inside the container we use Podman&rsquo;s <code>exec</code> subcommand.</p>
<div class="highlight"><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></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"><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></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"><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></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"><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></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"><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></div><p>Then we execute the script inside the container in interactive mode</p>
<div class="highlight"><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></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"><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></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"><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></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"><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></div><p>Upon restarting container will run the entrypoint command, starting a new process.</p>
<div class="highlight"><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></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"><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></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"><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></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"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman stats
</span></span></code></pre></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"><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></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>
<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>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>
<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>
