Build containers without using Docker
Tags: buildpacks, docker
Published: 2022-04-01 14:44:38

<p>In this post, I will quickly show you multiple ways of building your containers without having to worry about the details of Dockerfiles.</p>
<h2>Why</h2>
<p>Most developers that have set up a pipeline that uses Docker already are familiar with the details that come with building your own Docker image, but for someone that is new, this can be a bit overwhelming. Things that you have to keep into account like:</p>
<ul>
<li>Advanced caching</li>
<li>Apply best practices regarding security</li>
<li>Multi-stage setup to have a lightweight final image</li>
<li>Keeping your base images up to date</li>
<li>Reproducibility of an image</li>
</ul>
<p>If this is all completely new to you, your best bet to start with containers is by learning Buildpacks as the first step.</p>
<h1>What</h1>
<p><img src="https://miro.medium.com/max/1400/1*oe6npZ6MQRKInb8VJ4T8XQ.png" alt="image" title="buildpacks logo" /></p>
<p>Buildpacks was started by Heroku back in 2011 and is now officially part of the Cloud Native Computing Foundation and recently went from sandbox to incubation (<a href="https://medium.com/buildpacks/buildpacks-promoted-to-cncf-incubation-bcfff8f7273">see post</a>). It allows you to automatically detect based on source code which build tooling you need and it transforms your code into a ready to use image.</p>
<h2>Gitlab</h2>
<p>On Gitlab you have 2 approaches currently used:</p>
<ul>
<li>docker-in-docker</li>
<li>Kaniko build executor</li>
</ul>
<p>Both use a Dockerfile as a starting point, whereas Kaninko doesn't even need a docker daemon to run. This is why this is the most preferred (and advanced) approach in building containers. Below I will show different approaches in building your application starting with Auto DevOps. You can also find these approaches on an example Git repository <a href="https://git.inthepocket.org/glenn.bostoen/fastify-example-buildpacks">fastify-example-buildpacks</a></p>
<h3>Buildpacks with Auto DevOps</h3>
<p>On Gitlab you can use Buildpacks out of the box with &quot;Auto DevOps&quot;. &quot;Auto DevOps&quot; automatically uses a Herokuish builds as a default to build your project and publish it to your Gitlab registry. You can override this by making use of an <code>AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED</code> environment variable on your GitLab agent. This allows you to make use of Buildpacks which is part of the Cloud Native Foundation. For now, this is still in Beta on Gitlab, but they expect this to become a replacement for the current Herokuish builds.</p>
<pre class="language-yml"><code class="language-yml"><span class="token key atrule">include</span><span class="token punctuation">:</span><br />  <span class="token punctuation">-</span> <span class="token key atrule">template</span><span class="token punctuation">:</span> Auto<span class="token punctuation">-</span>DevOps.gitlab<span class="token punctuation">-</span>ci.yml<br /><br /><span class="token key atrule">variables</span><span class="token punctuation">:</span><br />  <span class="token key atrule">AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED</span><span class="token punctuation">:</span> <span class="token string">'true'</span></code></pre>
<h3>Buildpacks with Pack CLI</h3>
<p>If you want to have more control on which Buildpacks that are used, you can use Pack CLI which needs to be installed on your agent. This is easily done with the following example:</p>
<pre class="language-yml"><code class="language-yml"><span class="token key atrule">docker</span><span class="token punctuation">:</span><br />  <span class="token key atrule">stage</span><span class="token punctuation">:</span> build<br />  <span class="token key atrule">services</span><span class="token punctuation">:</span><br />    <span class="token punctuation">-</span> docker<span class="token punctuation">:</span>19.03.12<span class="token punctuation">-</span>dind<br />  <span class="token key atrule">variables</span><span class="token punctuation">:</span><br />    <span class="token key atrule">DOCKER_HOST</span><span class="token punctuation">:</span> tcp<span class="token punctuation">:</span>//docker<span class="token punctuation">:</span><span class="token number">2375</span><br />    <span class="token key atrule">DOCKER_TLS_CERTDIR</span><span class="token punctuation">:</span> <span class="token string">''</span><br />  <span class="token key atrule">image</span><span class="token punctuation">:</span> docker<span class="token punctuation">:</span>19.03.12<br />  <span class="token key atrule">before_script</span><span class="token punctuation">:</span><br />    <span class="token punctuation">-</span> wget https<span class="token punctuation">:</span>//github.com/buildpacks/pack/releases/download/v0.13.1/pack<span class="token punctuation">-</span>v0.13.1<span class="token punctuation">-</span>linux.tgz<br />    <span class="token punctuation">-</span> tar xvf pack<span class="token punctuation">-</span>v0.13.1<span class="token punctuation">-</span>linux.tgz<br />    <span class="token punctuation">-</span> rm pack<span class="token punctuation">-</span>v0.13.1<span class="token punctuation">-</span>linux.tgz<br />  <span class="token key atrule">script</span><span class="token punctuation">:</span><br />    <span class="token punctuation">-</span> ./pack build $IMAGE_NAME <span class="token punctuation">-</span><span class="token punctuation">-</span>builder gcr.io/buildpacks/builder</code></pre>
<p>This explicitly uses the Buildpacks provided by Google. You can find more information about these on <a href="https://github.com/GoogleCloudPlatform/buildpacks">Github</a></p>
<h3>Buildpacks with Google Cloud Platform</h3>
<p>You can now even deploy your app directly to cloud Run. The only command you need is the following:</p>
<pre class="language-shell"><code class="language-shell">gcloud beta run deploy --source<span class="token operator">=</span><span class="token punctuation">[</span>DIRECTORY<span class="token punctuation">]</span> <span class="token punctuation">[</span>CLOUD_RUN_SERVICE<span class="token punctuation">]</span></code></pre>
<h2>Downsides</h2>
<p>Custom build scripts are not supported so you still need to compile your typescript for example to allow your application to be packages as an image. Additionally, certain native dependencies could be an argument to start from your base images in the first place which makes the use of Buildpacks a bit obsolete. Last the images that are created are bigger because they serve a wider variety of use cases that could not be needed by your application.</p>
<h2>Summary</h2>
<p>Start with buidpacks and if you need to customize your container you can opt-out of the default image created for you and fully customize it to your liking with a Dockerfile.</p>