<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Vadim Rutkovsky</title><author><name>Vadim Rutkovsky</name></author><id>https://teletype.in/atom/vrutkovs</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/vrutkovs?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@vrutkovs?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=vrutkovs"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/vrutkovs?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-21T22:47:38.898Z</updated><entry><id>vrutkovs:HysWqaPLH</id><link rel="alternate" type="text/html" href="https://teletype.in/@vrutkovs/HysWqaPLH?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=vrutkovs"></link><title>Remember - no Dockerfiles</title><published>2019-09-12T13:37:07.048Z</published><updated>2019-09-13T10:58:51.400Z</updated><summary type="html">Многие разработчики разочарованы в магии современного контейнерного подхода.</summary><content type="html">
  &lt;p&gt;Многие разработчики разочарованы в магии современного контейнерного подхода.&lt;/p&gt;
  &lt;p&gt;Кроме дополнительных требований к приложению (см. &lt;a href=&quot;https://12factor.net/&quot; target=&quot;_blank&quot;&gt;The Twelve-Factor Apps&lt;/a&gt;) им зачастую приходится еще и учить новый формат для сборки контейнеров - Dockerfile. Изначально формат был достаточно простым - &lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt; да &lt;code&gt;COPY&lt;/code&gt;, но затем этот формат оброс дополнительными конструкциями - &lt;code&gt;COPY --from&lt;/code&gt; и &lt;code&gt;FROM foo as bar&lt;/code&gt; для multistage builds, &lt;code&gt;ONBUILD&lt;/code&gt; и так далее. Кроме того, формат не стандартизирован никак и управляется целиком и полностью желаниями Docker Inc.&lt;/p&gt;
  &lt;p&gt;Но Dockerfile - не единственный способ сборки контейнерных образов. Рассмотрим некоторые из них.&lt;/p&gt;
  &lt;h2&gt;Buildah&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://buildah.io/&quot; target=&quot;_blank&quot;&gt;Buildah&lt;/a&gt; - это инструмент, который специально создан только для сборки контейнерных образов. В отличие от &lt;code&gt;docker&lt;/code&gt; он не требует демона, может быть &lt;a href=&quot;https://developers.redhat.com/blog/2019/08/14/best-practices-for-running-buildah-in-a-container&quot; target=&quot;_blank&quot;&gt;запущен в другом контейнере&lt;/a&gt; и позволяет более гибко собирать контейнерные образы.&lt;/p&gt;
  &lt;p&gt;Рассмотрим пример:&lt;/p&gt;
  &lt;pre&gt;echo &amp;quot;--- Сборка приложения, никаких контейнеров ---&amp;quot;
./configure --with-feature=a
make
echo &amp;quot;Приложение собрано в ./output/bin/my-app&amp;quot;

echo &amp;quot;--- Сборка контейнера ---&amp;quot;

echo &amp;quot;Создаем пустой контейнер и смонтируем его&amp;quot;
newcontainer=$(buildah from scratch)
scratchmnt=$(buildah mount $newcontainer)

echo &amp;quot;Устанавливаем bash и coreutils из репозиториев Fedora 30 в контейнер используя dnf из хоста&amp;quot;
dnf install --installroot $scratchmnt --releasever 30 bash coreutils --setopt install_weak_deps=false -y

echo &amp;quot;Копируем бинарный файл в /usr/bin/ контейнера&amp;quot;
cp ./output/bin/my-app $scratchmnt/usr/bin

echo &amp;quot;Устанавливаем CMD [&amp;#x27;/usr/bin/my-app&amp;#x27;]&amp;quot;
buildah config --cmd /usr/bin/my-app $newcontainer
buildah commit $newcontainer my-app:latest&lt;/pre&gt;
  &lt;p&gt;(для Debian/Ubuntu систем подход немного сложнее - &lt;code&gt;apt-get download package &amp;amp;&amp;amp; dpkg -i package.deb --force-not-root --root=$scratchmnt&lt;/code&gt;)&lt;/p&gt;
  &lt;p&gt;В чем приемущество такого подхода? Вот несколько примеров:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/distroless/blob/master/README.md&quot; target=&quot;_blank&quot;&gt;Distroless-подход&lt;/a&gt; - в образе не будет инструментов для сборки - нет dnf/apt-get&lt;/li&gt;
    &lt;li&gt;Для сборки не требуются привилегии для запуска приложений в контейнере -&amp;gt; сборку контейнерного образа можно запускать в другом контейнере без требования флага &lt;code&gt;priviledged&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Во всем контейнере создастся три слоя - &lt;code&gt;FROM scratch&lt;/code&gt;, &lt;code&gt;COPY &amp;lt;необходимые бинарные файлы из coreutils + bash + my-app&amp;gt;&lt;/code&gt; и &lt;code&gt;CMD [&amp;#x27;/usr/bin/app&amp;#x27;]&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Кэшированием артефактов для сборки управляет сборочный хост - можно свободно использовать &lt;a href=&quot;https://github.com/distcc/distcc&quot; target=&quot;_blank&quot;&gt;distcc&lt;/a&gt;, сетевые диски для кэша и т.д.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Эти образы совместимы со спецификацией OCI, а значит их можно запускать в docker, docker-compose или Kubernetes так же, как и собранные в docker.&lt;/p&gt;
  &lt;h3&gt;buildah bud&lt;/h3&gt;
  &lt;p&gt;Кроме того, &lt;code&gt;buildah&lt;/code&gt; поддерживает чтение инструкций из Dockerfile: &lt;code&gt;buildah bud -f Dockerfile .&lt;/code&gt;. Инструкции из Dockerfile преобразуются в инструкции по созданию новых контейнеров и копированию файлов аналогично предыдущему примеру.&lt;/p&gt;
  &lt;p&gt;Этот способ так же позволяет монтировать внешние директории для сборки контейнеров: &lt;code&gt;buildah bud --volume /var/lib/my-build-cache:/cache:ro,Z -t imageName .&lt;/code&gt;&lt;/p&gt;
  &lt;h2&gt;Source2Image&lt;/h2&gt;
  &lt;p&gt;Еще в древности люди заметили что фреймворк или целый язык программирования имеет стандартизированный алгоритм для сборки:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;golang&lt;/code&gt;: &lt;code&gt;go get &amp;amp;&amp;amp; go build&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;rust&lt;/code&gt;: &lt;code&gt;cargo build --release&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;python&lt;/code&gt;: &lt;code&gt;pip install -r requirements.txt &amp;amp;&amp;amp; pip install .&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Кроме того, при переходе на новую версию приходится менять все Dockerfile, убедится что базовый образ в один прекрасный день не обновит golang или python до неподдерживаемой версии и т.д.&lt;/p&gt;
  &lt;p&gt;Чтобы избежать копипаста кусков в Dockerfiles и упрощения процесса сборки был создан инструмент под названием &lt;a href=&quot;https://github.com/openshift/source-to-image&quot; target=&quot;_blank&quot;&gt;Source-to-Image&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt;После установки &lt;a href=&quot;https://github.com/openshift/source-to-image/releases&quot; target=&quot;_blank&quot;&gt;s2i&lt;/a&gt; сборка простого питоновского проекта сокращается до одной команды:&lt;/p&gt;
  &lt;pre&gt;s2i build https://github.com/sclorg/django-ex centos/python-36-centos7 hello-python
&lt;/pre&gt;
  &lt;p&gt;Это консольное приложение выполняет следующие действия:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt; Клонирует репозиторий &lt;code&gt;https://github.com/sclorg/django-ex&lt;/code&gt; во временную директорию &lt;/li&gt;
    &lt;li&gt; Тянет образ &lt;code&gt;docker.io/centos/python-36-centos7&lt;/code&gt; В этом образе хранятся инструкции (подробнее ниже) и необходимые инструменты &lt;/li&gt;
    &lt;li&gt; Используя питон и инструкции из &lt;code&gt;python-36-centos7&lt;/code&gt; создается новый образ &lt;code&gt;hello-python&lt;/code&gt; &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Если требуется собирать приложение с другой версией питона, то при сборке нужно лишь сменить сборочный образ - к примеру &lt;code&gt;docker.io/centos/python-27-centos7&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Вся &amp;quot;магия&amp;quot; сборки хранится в сборочном образе. &lt;a href=&quot;https://github.com/openshift/source-to-image#anatomy-of-a-builder-image&quot; target=&quot;_blank&quot;&gt;Краткое описание&lt;/a&gt; процесса сборки:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;s2i&lt;/code&gt; ищет каталог &lt;code&gt;s2i/bin/&lt;/code&gt; в сборочном образе&lt;/li&gt;
    &lt;li&gt;при сборке образа запускается скрипт из &lt;code&gt;s2i/bin/assemble&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;при старте собранного образа запускается &lt;code&gt;s2i/bin/run&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;(опционально) скрипт из &lt;code&gt;s2i/bin/usage&lt;/code&gt; добавит описание в контейнерный образ&lt;/li&gt;
    &lt;li&gt;(опционально) скрипт из &lt;code&gt;s2i/bin/save-artifact&lt;/code&gt; позволяет использовать предыдущие сборки для кэширования артефактов сборки&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Этот простой интерфейс позволяет отделить процедуру сборки приложения от исходников и обновлять их независимо. Source2Image, к примеру, используется в OpenShift (дистрибутиве kubernetes) для быстрого и безопасного создания пайпланов из git-репозиториев.&lt;/p&gt;
  &lt;h3&gt;Заключение&lt;/h3&gt;
  &lt;p&gt;Существует множество инструментов для сборки контейнерных образов без использования Dockerfile. Многие могут показаться черезчур усложненными (а некоторые - черезчур упрощенными), но фактически Dockerfiles до сих пор остаются неформализированным стандартом. Тем не менее важно знать преимущества других способов сборки - а так же из недостатки.&lt;/p&gt;
  &lt;p&gt;Эти и другие способы сборки имаджей предлагаю обсудить в &lt;a href=&quot;https://t.me/kubernetes_ru&quot; target=&quot;_blank&quot;&gt;https://t.me/kubernetes_ru&lt;/a&gt; или &lt;a href=&quot;https://t.me/ru_podman&quot; target=&quot;_blank&quot;&gt;https://t.me/ru_podman&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;---&lt;/p&gt;
  &lt;p&gt;Источник: &lt;a href=&quot;https://vrutkovs.eu/posts/source2image/&quot; target=&quot;_blank&quot;&gt;https://vrutkovs.eu/posts/source2image/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;К примеру, этот блогпост был собран с помощью &lt;a href=&quot;https://github.com/vrutkovs/sti-hugo&quot; target=&quot;_blank&quot;&gt;vrutkovs/sti-hugo&lt;/a&gt;&lt;/p&gt;

</content></entry></feed>