{"id":93600,"date":"2019-05-16T08:00:35","date_gmt":"2019-05-16T08:00:35","guid":{"rendered":"https:\/\/fedoramagazine.org\/?p=27793"},"modified":"2019-05-16T08:00:35","modified_gmt":"2019-05-16T08:00:35","slug":"building-smaller-container-images","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2019\/05\/16\/building-smaller-container-images\/","title":{"rendered":"Building Smaller Container Images"},"content":{"rendered":"<p>Linux Containers have become a popular topic, making sure that a container image is not bigger than it should be is considered as a good practice. This article give some tips on how to create smaller Fedora container images.<\/p>\n<p> <span id=\"more-27793\"><\/span> <\/p>\n<h3>microdnf<\/h3>\n<p>Fedora&#8217;s DNF is written in Python and and it&#8217;s designed to be extensible as it has wide range of plugins. But Fedora has an alternative base container image which uses an smaller package manager called <a href=\"https:\/\/github.com\/rpm-software-management\/microdnf\">microdnf<\/a> written in C. To use this minimal image in a Dockerfile the FROM line should look like this:<\/p>\n<pre class=\"wp-block-preformatted\">FROM registry.fedoraproject.org\/fedora-minimal:30<\/pre>\n<p>This is an important saving if your image does not need typical DNF dependencies like Python. For example, if you are making a NodeJS image.<\/p>\n<h3>Install and Clean up in one layer<\/h3>\n<p>To save space it&#8217;s important to remove repos meta data using <em>dnf clean all<\/em> or its microdnf equivalent <em>microdnf clean all<\/em>. But you should not do this in two steps because that would actually store those files in a container image layer then mark them for deletion in another layer. To do it properly you should do the installation and cleanup in one step like this<\/p>\n<pre class=\"wp-block-preformatted\">FROM registry.fedoraproject.org\/fedora-minimal:30 <br \/>RUN microdnf install nodejs &amp;&amp; microdnf clean all<\/pre>\n<h3>Modularity with microdnf<\/h3>\n<p>Modularity is a way to offer you different versions of a stack to choose from. For example you might want non-LTS NodeJS version 11 for a project and old LTS NodeJS version 8 for another and latest LTS NodeJS version 10 for another. You can specify which stream using colon<\/p>\n<pre class=\"wp-block-preformatted\"># dnf module list <br \/># dnf module install nodejs:8<\/pre>\n<p>The <em>dnf module install<\/em> command implies two commands one that enables the stream and one that install nodejs from it.<\/p>\n<pre class=\"wp-block-preformatted\"># dnf module enable nodejs:8 <br \/># dnf install nodejs<\/pre>\n<p>Although microdnf does not offer any command related to modularity, it is possible to enable a module with a configuation file, and libdnf (which microdnf uses) <a href=\"https:\/\/bugzilla.redhat.com\/show_bug.cgi?id=1575626\">seems<\/a> to support modularity streams. The file looks like this<\/p>\n<pre class=\"wp-block-preformatted\">\/etc\/dnf\/modules.d\/nodejs.module <br \/>[nodejs] <br \/>name=nodejs <br \/>stream=8 <br \/>profiles= <br \/>state=enabled<\/pre>\n<p>A full Dockerfile using modularity with microdnf looks like this: <\/p>\n<pre class=\"wp-block-preformatted\">FROM registry.fedoraproject.org\/fedora-minimal:30 <br \/>RUN \\<br \/> echo -e \"[nodejs]\\nname=nodejs\\nstream=8\\nprofiles=\\nstate=enabled\\n\" &gt; \/etc\/dnf\/modules.d\/nodejs.module &amp;&amp; \\<br \/> microdnf install nodejs zopfli findutils busybox &amp;&amp; \\<br \/> microdnf clean all<\/pre>\n<h3>Multi-staged builds<\/h3>\n<p>In many cases you might have tons of build-time dependencies that are not needed to run the software for example building a Go binary, which statically link dependencies. Multi-stage build are an efficient way to separate the application build and the application runtime.<\/p>\n<p>For example the Dockerfile below builds <a href=\"https:\/\/github.com\/kelseyhightower\/confd\">confd<\/a> a Go application.<\/p>\n<pre class=\"wp-block-preformatted\"># building container <br \/>FROM registry.fedoraproject.org\/fedora-minimal AS build <br \/>RUN mkdir \/go &amp;&amp; microdnf install golang &amp;&amp; microdnf clean all <br \/>WORKDIR \/go <br \/>RUN export GOPATH=\/go; CGO_ENABLED=0 go get github.com\/kelseyhightower\/confd <br \/><br \/>FROM registry.fedoraproject.org\/fedora-minimal <br \/>WORKDIR \/ <br \/>COPY --from=build \/go\/bin\/confd \/usr\/local\/bin <br \/>CMD [\"confd\"] <\/pre>\n<p>The multi-stage build is done by adding <em>AS<\/em> after the <em>FROM<\/em> instruction and by having another <em>FROM<\/em> from a base container image then using C<em>OPY &#8211;from=<\/em> instruction to copy content from the <em>build<\/em> container to the second container.<\/p>\n<p>This Dockerfile can then be built and run using podman<\/p>\n<pre class=\"wp-block-preformatted\">$ podman build -t myconfd .<br \/>$ podman run -it myconfd<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Linux Containers have become a popular topic, making sure that a container image is not bigger than it should be is considered as a good practice. This article give some tips on how to create smaller Fedora container images. microdnf Fedora&#8217;s DNF is written in Python and and it&#8217;s designed to be extensible as it [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[45,61,46,47],"class_list":["post-93600","post","type-post","status-publish","format-standard","hentry","category-fedora-os","tag-fedora","tag-fedora-project-community","tag-magazine","tag-news"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/93600","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=93600"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/93600\/revisions"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=93600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=93600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=93600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}