<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="https://perrotta.dev/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Docker on ¬ just serendipity 🍀</title>
    <link>https://perrotta.dev/</link>
    <description>Recent content in Docker on ¬ just serendipity 🍀</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <managingEditor>serendipity@perrotta.dev (Thiago Perrotta)</managingEditor>
    <webMaster>serendipity@perrotta.dev (Thiago Perrotta)</webMaster>
    <copyright>© 2013 - 2026 Thiago Perrotta ·
  a fork of [hugo ʕ•ᴥ•ʔ bear](https://github.com/janraasch/hugo-bearblog/)
</copyright>
    <lastBuildDate>Mon, 23 Mar 2026 12:05:21 +0100</lastBuildDate>
    <atom:link href="https://perrotta.dev/tags/docker/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Kubernetes: one-off env exec
      </title>
      <link>https://perrotta.dev/2026/03/kubernetes-one-off-env-exec/</link>
      <pubDate>Mon, 23 Mar 2026 11:56:33 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2026/03/kubernetes-one-off-env-exec/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: run an one-off script and/or binary within a kubernetes&#xA;pod. It needs a certain environment variable (&lt;code&gt;VAULT_TOKEN&lt;/code&gt;) to be set.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Wrong&lt;/strong&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;ubuntu@my-deploy-server:~ $  kubectl exec -n vault vault-1 -- VAULT_TOKEN=hvs.mysupersecrettoken vault read auth/kubernetes/role/vault-init&#xA;error: Internal error occurred: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec &amp;#34;7455bd5880fe41c177a47702e3dfacbe4240207d53a19ac13edf74b62c626e61&amp;#34;: OCI runtime exec failed: exec failed: unable to start container process: exec: &amp;#34;VAULT_TOKEN=hvs.mysupersecrettoken&amp;#34;: executable file not found in $PATH&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It is trying to look for a file named &lt;code&gt;VAULT_TOKEN=hvs.mysupersecrettoken&lt;/code&gt; in&#xA;the &lt;code&gt;$PATH&lt;/code&gt;. Surely that&amp;rsquo;s not we want here!&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Right&lt;/strong&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;ubuntu@my-deploy-server:~ $  kubectl exec -n vault vault-1 -- env VAULT_TOKEN=hvs.mysupersecrettoken vault read auth/kubernetes/role/vault-init&#xA;Key                                         Value&#xA;---                                         -----&#xA;alias_name_source                           serviceaccount_uid&#xA;bound_service_account_names                 [vault-init]&#xA;bound_service_account_namespace_selector    n/a&#xA;bound_service_account_namespaces            [vault]&#xA;policies                                    [vault-init]&#xA;token_bound_cidrs                           []&#xA;token_explicit_max_ttl                      0s&#xA;token_max_ttl                               0s&#xA;token_no_default_policy                     false&#xA;token_num_uses                              0&#xA;token_period                                168h&#xA;token_policies                              [vault-init]&#xA;token_ttl                                   0s&#xA;token_type                                  default&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;just pass it via &lt;a href=&#34;https://man.archlinux.org/man/env.1&#34;&gt;&lt;code&gt;env(1)&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;env — run a program in a modified environment&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Also, if you pay attention, you&amp;rsquo;ll notice there are two spaces between &lt;code&gt;$&lt;/code&gt; and&#xA;&lt;code&gt;kubectl&lt;/code&gt;. This is intentional. See &lt;a href=&#34;https://unix.stackexchange.com/questions/115917/why-is-bash-not-storing-commands-that-start-with-spaces&#34;&gt;Why is bash not storing commands that start&#xA;with&#xA;spaces?&lt;/a&gt;&#xA;for context. &lt;code&gt;bash&lt;/code&gt; won&amp;rsquo;t record the command in the shell history if it starts&#xA;with spaces — though that behavior depends on the &lt;code&gt;HISTCONTROL&lt;/code&gt; setting. We&#xA;do not want to store our &lt;code&gt;VAULT_TOKEN&lt;/code&gt; in plain text in the shell history&#xA;(&lt;code&gt;~/.bash_history&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Kubernetes: one-off env exec&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker: AWS ECR: list recent image tags
      </title>
      <link>https://perrotta.dev/2025/08/docker-aws-ecr-list-recent-image-tags/</link>
      <pubDate>Mon, 18 Aug 2025 15:38:21 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2025/08/docker-aws-ecr-list-recent-image-tags/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: Given a docker repository hosted in&#xA;&lt;a href=&#34;https://aws.amazon.com/ecr/&#34;&gt;ECR&lt;/a&gt; (AWS), list its &lt;strong&gt;most recent&lt;/strong&gt; image tags.&lt;/p&gt;&#xA;&lt;p&gt;Assuming you&amp;rsquo;re already authenticated to AWS in the CLI:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% aws ecr describe-images \&#xA;  --repository-name {corp}/{repo} \&#xA;  --filter tagStatus=TAGGED \&#xA;  --query &amp;#39;reverse(sort_by(imageDetails, &amp;amp;imagePushedAt))[*].{Tag: imageTags[0], PushedAt: imagePushedAt}&amp;#39; \&#xA;  [--output table]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The output looks like this:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;-------------------------------------------------------------------------------------------&#xA;|                                     DescribeImages                                      |&#xA;&amp;#43;-----------------------------------&amp;#43;-----------------------------------------------------&amp;#43;&#xA;|             PushedAt              |                         Tag                         |&#xA;&amp;#43;-----------------------------------&amp;#43;-----------------------------------------------------&amp;#43;&#xA;|  2025-08-14T14:44:49.285000&amp;#43;02:00 |  1.0.2                                              |&#xA;|  2025-08-14T14:07:53.526000&amp;#43;02:00 |  app-839403421                                      |&#xA;|  2025-08-07T19:38:21.452000&amp;#43;02:00 |  app-1134bfa1d                                      |&#xA;|  2025-08-06T14:54:23.314000&amp;#43;02:00 |  app-pr-5033-07f01dd66                              |&#xA;|  2025-08-06T14:33:27.171000&amp;#43;02:00 |  app-pr-5033-643536a2b                              |&#xA;|  2025-07-23T09:36:20.368000&amp;#43;02:00 |  app-pr-4947-fe5f4c618                              |&#xA;|  2025-04-17T03:17:30.937000&amp;#43;02:00 |  1.0.1                                              |&#xA;|  2024-12-18T18:50:18.990000&amp;#43;01:00 |  latest                                             |&#xA;|  2024-12-05T17:52:09.775000&amp;#43;01:00 |  1.0.0                                              |&#xA;&amp;#43;-----------------------------------&amp;#43;-----------------------------------------------------&amp;#43;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you omit &lt;code&gt;--output table&lt;/code&gt;, it emits JSON instead.&lt;/p&gt;&#xA;&lt;p&gt;This is faster than logging into the AWS Console.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Docker: AWS ECR: list recent image tags&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Dockerfile: CMD and ENTRYPOINT: shell and exec forms
      </title>
      <link>https://perrotta.dev/2025/08/dockerfile-cmd-and-entrypoint-shell-and-exec-forms/</link>
      <pubDate>Mon, 18 Aug 2025 15:09:28 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2025/08/dockerfile-cmd-and-entrypoint-shell-and-exec-forms/</guid>
      <description>&lt;p&gt;♠ Today I filed a github issue against the&#xA;&lt;a href=&#34;https://github.com/reteps/dockerfmt/&#34;&gt;&lt;code&gt;dockerfmt&lt;/code&gt;&lt;/a&gt; project, which I copy&#xA;verbatim here given its surprising behavior.&lt;/p&gt;&#xA;&lt;h2 id=&#34;retepsdockerfmt33&#34;&gt;&#xA;  &lt;a href=&#34;https://github.com/reteps/dockerfmt/issues/33&#34;&gt;reteps/dockerfmt#33&lt;/a&gt;&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2025/08/dockerfile-cmd-and-entrypoint-shell-and-exec-forms/#retepsdockerfmt33&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Consider this sample &lt;code&gt;Dockerfile&lt;/code&gt; (abridged version of a real-world scenario):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;ENTRYPOINT sleep infinity&#xA;CMD sleep infinity&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s run &lt;code&gt;dockerfmt&lt;/code&gt; (v0.3.7) in it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;% dockerfmt Dockerfile&#xA;ENTRYPOINT [&amp;#34;sleep&amp;#34;, &amp;#34;infinity&amp;#34;]&#xA;CMD [&amp;#34;sleep&amp;#34;, &amp;#34;infinity&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;At first glance, everything looks OK. The problem is that this transformation is not a no-op.&lt;/p&gt;&#xA;&lt;p&gt;Looking at the docs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/reference/dockerfile/#cmd&#34;&gt;https://docs.docker.com/reference/dockerfile/#cmd&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/reference/dockerfile/#shell-and-exec-form&#34;&gt;https://docs.docker.com/reference/dockerfile/#shell-and-exec-form&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;If CMD is used to provide default arguments for the ENTRYPOINT instruction, both the CMD and ENTRYPOINT instructions should be specified in the &lt;a href=&#34;https://docs.docker.com/reference/dockerfile/#exec-form&#34;&gt;exec form&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The difference is:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;the original code yields &lt;code&gt;sleep infinity&lt;/code&gt; (correct!)&lt;/li&gt;&#xA;&lt;li&gt;the transformed code yields &lt;code&gt;sleep infinity sleep infinity&lt;/code&gt;, which is an error (sleep: &lt;code&gt;no such argument sleep&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;One could argue that the original code is odd – the following would be conceptually simpler, and more idiomatic:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;ENTRYPOINT [&amp;#34;sleep&amp;#34;]&#xA;CMD [&amp;#34;infinity&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Or even:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;ENTRYPOINT [&amp;#34;sleep&amp;#34;, &amp;#34;infinity&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Nonetheless, IMHO &lt;code&gt;dockerfmt&lt;/code&gt; should not change the behavior in this case.&lt;/p&gt;&#xA;&lt;h2 id=&#34;notes&#34;&gt;&#xA;  Notes&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2025/08/dockerfile-cmd-and-entrypoint-shell-and-exec-forms/#notes&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://docs.docker.com/reference/dockerfile/#shell-and-exec-form&#34;&gt;&lt;code&gt;shell&lt;/code&gt; and &lt;code&gt;exec&lt;/code&gt;&#xA;forms&lt;/a&gt; have&#xA;distinct forms:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;INSTRUCTION [&amp;quot;executable&amp;quot;, &amp;quot;param1&amp;quot;, &amp;quot;param2&amp;quot;]&lt;/code&gt; (exec form)&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;INSTRUCTION command param1 param2&lt;/code&gt; (shell form)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The exec form makes it possible to avoid shell string munging, and to invoke&#xA;commands using a specific command shell, or any other executable. It uses a&#xA;JSON array syntax, where each element in the array is a command, flag, or&#xA;argument.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The shell form is more relaxed, and emphasizes ease of use, flexibility, and&#xA;readability. The shell form automatically uses a command shell, whereas the&#xA;exec form does not.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;code&gt;dockerfmt&lt;/code&gt;&#xA;&lt;a href=&#34;https://github.com/reteps/dockerfmt/blob/290b5f78fbf3134024eb3366880754beee5dbe69/lib/format.go#L483&#34;&gt;prefers&lt;/a&gt;&#xA;the exec form, for whatever reason.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s even a &lt;a href=&#34;https://github.com/reteps/dockerfmt/blob/290b5f78fbf3134024eb3366880754beee5dbe69/lib/format.go#L480&#34;&gt;code&#xA;comment&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;code&gt;// this can technically change behavior. https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Surprise surprise! The issue I reported is precisely due to a change of&#xA;behavior.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Dockerfile: CMD and ENTRYPOINT: shell and exec forms&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>docker: dive into images
      </title>
      <link>https://perrotta.dev/2025/08/docker-dive-into-images/</link>
      <pubDate>Mon, 11 Aug 2025 13:20:08 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2025/08/docker-dive-into-images/</guid>
      <description>&lt;p&gt;♠ Recently bitnami has &lt;a href=&#34;https://github.com/bitnami/charts/issues/35164&#34;&gt;pulled the&#xA;plug&lt;/a&gt; off their public docker&#xA;images offering&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/08/docker-dive-into-images/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We are relying on their&#xA;&lt;a href=&#34;https://hub.docker.com/r/bitnami/kubectl&#34;&gt;&lt;code&gt;bitnami/kubectl&lt;/code&gt;&lt;/a&gt; image. Now what?&lt;/p&gt;&#xA;&lt;p&gt;We could build our own, or use another upstream image. Looking at the &lt;a href=&#34;https://hub.docker.com/search?q=kubectl&#34;&gt;Docker&#xA;Hub&lt;/a&gt; catalog, I was pleased to find&#xA;&lt;a href=&#34;https://hub.docker.com/r/rancher/kubectl&#34;&gt;&lt;code&gt;rancher/kubectl&lt;/code&gt;&lt;/a&gt; (backed by SUSE)&#xA;there.&lt;/p&gt;&#xA;&lt;p&gt;This is enough for our needs.&lt;/p&gt;&#xA;&lt;p&gt;It would have been trivial to build our own image otherwise if needed:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM alpine:3.22&#xA;RUN apk add --no-cache kubectl&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;How can we ensure these images are equivalent, for practical purposes?&lt;/p&gt;&#xA;&lt;p&gt;One way is to use &lt;a href=&#34;https://github.com/wagoodman/dive&#34;&gt;&lt;code&gt;dive&lt;/code&gt;&lt;/a&gt; to introspect&#xA;each of them:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A tool for exploring each layer in a docker image&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% dive bitnami/kubectl:latest&#xA;% dive rancher/kubectl:v1.30.14&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The rancher image has 50MB in size and contains &lt;em&gt;only&lt;/em&gt; the &lt;code&gt;kubectl&lt;/code&gt; binary.&#xA;There&amp;rsquo;s no shell, not even &lt;code&gt;/bin/sh&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The bitnami image has 326MB and contains a bunch of other stuff.&lt;/p&gt;&#xA;&lt;p&gt;It turns out we will get some (unexpected) efficiency gains out of this&#xA;migration!&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Enshittification&#34;&gt;&amp;ldquo;&amp;ldquo;&amp;ldquo;Recession&amp;rdquo;&amp;rdquo;&amp;rdquo;&lt;/a&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/08/docker-dive-into-images/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: docker: dive into images&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Alpine Linux: Dockerfile: install package from edge
      </title>
      <link>https://perrotta.dev/2025/06/alpine-linux-dockerfile-install-package-from-edge/</link>
      <pubDate>Wed, 04 Jun 2025 12:37:47 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>alpine-linux</category>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2025/06/alpine-linux-dockerfile-install-package-from-edge/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: Given a &lt;code&gt;Dockerfile&lt;/code&gt; based on a fixed release of Alpine&#xA;Linux (e.g. &lt;code&gt;FROM alpine:3.22&lt;/code&gt;), install a package from &lt;code&gt;edge&lt;/code&gt; (i.e. a package&#xA;that did not yet make it to a fixed release).&lt;/p&gt;&#xA;&lt;p&gt;The approach is similar to package &lt;a href=&#34;https://perrotta.dev/2025/01/alpine-linux-install-/-pin-old-packages/&#34;&gt;pinning&lt;/a&gt;, by providing a custom&#xA;&lt;code&gt;--repository&lt;/code&gt; to &lt;code&gt;apk add&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;RUN apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing gliderlabs-sigil vals&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Replace &amp;ldquo;testing&amp;rdquo; with &amp;ldquo;community&amp;rdquo; or &amp;ldquo;main&amp;rdquo; as needed.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Alpine Linux: Dockerfile: install package from edge&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/alpine-linux/&#34;&gt;#alpine-linux&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ skopeo: operate container images and registries
      </title>
      <link>https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/</link>
      <pubDate>Tue, 17 Dec 2024 17:49:31 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>aws</category>
      <category>bestof</category>
      <category>dev</category>
      <category>docker</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/</guid>
      <description>&lt;p&gt;♠ When working with &lt;code&gt;docker&lt;/code&gt; and private image registries, a common workflow is to copy images from one private registry in the cloud to another. This can be done with &lt;a href=&#34;https://github.com/containers/skopeo/&#34;&gt;&lt;code&gt;skopeo&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This post includes some common recipes for it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;usage-1-default--root-to-staging&#34;&gt;&#xA;  Usage 1) Default / Root to Staging&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/#usage-1-default--root-to-staging&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;From the default / root account registry to the staging registry:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;skopeo sync \&#xA;  --src-creds &amp;#34;AWS:$(aws ecr get-login-password --region {region} --profile default)&amp;#34; \&#xA;  --dest-creds &amp;#34;AWS:$(aws ecr get-login-password --region {region} --profile staging)&amp;#34; \&#xA;  --override-os linux --override-arch amd64 \&#xA;  --src docker --dest docker \&#xA;  {account_id_root}.dkr.ecr.{region}.amazonaws.com/{org}/{repository}:{tag} \&#xA;  {account_id_staging}.dkr.ecr.{region}.amazonaws.com/{org}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Example values&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;repository: &lt;code&gt;argocd-gitops-tools&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;tag (version): &lt;code&gt;1.0.1&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;region: &lt;code&gt;us-east-1&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;usage-2-public-to-mfa&#34;&gt;&#xA;  Usage 2) Public to MFA&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/#usage-2-public-to-mfa&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;From a public registry to a private registry that uses MFA (multi-factor authentication).&lt;/p&gt;&#xA;&lt;p&gt;First, it&amp;rsquo;s necessary to get MFA credentials. Source the script below&#xA;(&lt;code&gt;china.mfa.sh&lt;/code&gt;):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/usr/bin/env bash&#xA;# shellcheck disable=SC2155&#xA;&#xA;export AWS_PROFILE=china&#xA;&#xA;echo -n &amp;#34;Enter the MFA token code for your AWS China account: &amp;#34; &amp;amp;&amp;amp; read -r token&#xA;&#xA;mfa_arn=&amp;#34;$(aws iam --profile &amp;#34;$AWS_PROFILE&amp;#34; get-user --output text --query User.Arn | sed &amp;#39;s/:user\//:mfa\//&amp;#39;)&amp;#34;&#xA;credentials=&amp;#34;$(aws --profile &amp;#34;$AWS_PROFILE&amp;#34; sts get-session-token --serial-number &amp;#34;$mfa_arn&amp;#34; --token-code &amp;#34;$token&amp;#34; --duration-seconds 86400)&amp;#34;&#xA;&#xA;echo &amp;#34;Got credentials: $credentials&amp;#34;&#xA;&#xA;export AWS_ACCESS_KEY_ID=$(echo &amp;#34;$credentials&amp;#34; | jq -r &amp;#39;.Credentials.AccessKeyId&amp;#39;)&#xA;export AWS_SECRET_ACCESS_KEY=$(echo &amp;#34;$credentials&amp;#34; | jq -r &amp;#39;.Credentials.SecretAccessKey&amp;#39;)&#xA;export AWS_SESSION_TOKEN=$(echo &amp;#34;$credentials&amp;#34; | jq -r &amp;#39;.Credentials.SessionToken&amp;#39;)&#xA;&#xA;[[ -n &amp;#34;$AWS_SESSION_TOKEN&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;Success!&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: It is necessary to do &lt;code&gt;source china-mfa.sh&lt;/code&gt;. Doing &lt;code&gt;./china-mfa.sh&lt;/code&gt;&#xA;will &lt;strong&gt;not&lt;/strong&gt; work.&lt;/p&gt;&#xA;&lt;p&gt;Then we can proceed with the image sync:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;skopeo sync \&#xA;  --dest-creds &amp;#34;AWS:$(aws ecr get-login-password --region cn-north-1)&amp;#34; \&#xA;  --override-os linux --override-arch amd64 \&#xA;  --src docker \&#xA;  --dest docker \&#xA;  quay.io/argoproj/argocd:v2.12.6 \&#xA;  {account_id_mfa}.dkr.ecr.cn-north-1.amazonaws.com.cn/quay.io/argoproj&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Notes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A public registry does not need authentication, hence there&amp;rsquo;s no &lt;code&gt;--src-creds&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;--dest-creds&lt;/code&gt; does not specify a &lt;code&gt;--profile&lt;/code&gt;. Likewise, no &lt;code&gt;AWS_PROFILE&lt;/code&gt; env var should be defined.&lt;/li&gt;&#xA;&lt;li&gt;In this example, China (&lt;code&gt;cn-north-1&lt;/code&gt;) is an AWS account with MFA enabled.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;potpourri&#34;&gt;&#xA;  Potpourri&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/#potpourri&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It&amp;rsquo;s possible to pass &lt;code&gt;--scoped&lt;/code&gt; to prefix images at destination using the&#xA;full source image path as scope.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;To sync multiple image architectures, pass &lt;code&gt;-a&lt;/code&gt; or &lt;code&gt;--all&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;If syncing from/to Azure (ACR), use &lt;code&gt;az acr login&lt;/code&gt;. Find the &lt;code&gt;username&lt;/code&gt; in the&#xA;Azure portal. For example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;az acr login -n {container registry name} --expose-token | jq -r &amp;#39;.accessToken&amp;#39; | skopeo login {registry} --password-stdin --username {username}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;image = registry (includes the org name) + repository + tag&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/skopeo-operate-container-images-and-registries/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: skopeo: operate container images and registries&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/aws/&#34;&gt;#aws&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker build: ignore cache
      </title>
      <link>https://perrotta.dev/2024/12/docker-build-ignore-cache/</link>
      <pubDate>Tue, 10 Dec 2024 19:45:42 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>aws</category>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2024/12/docker-build-ignore-cache/</guid>
      <description>&lt;p&gt;♠ To build a docker image completely from scratch, without reusing cache layers on&#xA;your system:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;docker build --no-cache -f Dockerfile . -t {image name}:{image tag} --platform&#xA;linux/amd64&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Pass an explicit platform in case e.g. you&amp;rsquo;re building on a Mac M1 (arm64)&#xA;with the intent of running it on Linux in the cloud (amd64 typically).&lt;/li&gt;&#xA;&lt;li&gt;The docker image full specification is: image =&#xA;&lt;code&gt;{registry}/{repository}:{tag}&lt;/code&gt;. For example, the registry could be an AWS ECR&#xA;URL, whereas the repository is something like &amp;ldquo;bitnami/sealed-secrets&amp;rdquo;, and&#xA;the tag typically follows semantic versioning.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Docker build: ignore cache&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/aws/&#34;&gt;#aws&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker image size
      </title>
      <link>https://perrotta.dev/2024/12/docker-image-size/</link>
      <pubDate>Thu, 05 Dec 2024 13:05:44 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2024/12/docker-image-size/</guid>
      <description>&lt;p&gt;♠ When trying to optimize docker images in terms of size, the workflow is as&#xA;follows:&lt;/p&gt;&#xA;&lt;h2 id=&#34;terminal-1&#34;&gt;&#xA;  Terminal 1&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/docker-image-size/#terminal-1&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% docker build -f Dockerfile . -t argocd-download-tools&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;possibly paired up with &lt;code&gt;entr&lt;/code&gt; or &lt;code&gt;fswatch&lt;/code&gt; depending on your eagerness for&#xA;automatic builds.&lt;/p&gt;&#xA;&lt;h2 id=&#34;terminal-2&#34;&gt;&#xA;  Terminal 2&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/docker-image-size/#terminal-2&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% docker image inspect argocd-download-tools | jq -r &amp;#39;.[0].Size&amp;#39; | numfmt --to=iec&#xA;134M&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;possibly prepended with &lt;code&gt;watch&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I wasn&amp;rsquo;t aware of &lt;a href=&#34;https://man.archlinux.org/man/numfmt.1&#34;&gt;&lt;code&gt;numfmt&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;numfmt — Convert numbers from/to human-readable strings&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&amp;hellip;instead of displaying plain bytes, it converts numbers to human-readable&#xA;strings (à la &lt;code&gt;df -h&lt;/code&gt; or &lt;code&gt;free -h&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Regarding the &lt;a href=&#34;https://en.wikipedia.org/wiki/Binary_prefix&#34;&gt;units&lt;/a&gt;: they don&amp;rsquo;t&#xA;matter much, because we are only interested in an approximation, no need to&#xA;shave bytes off here. &lt;code&gt;SI&lt;/code&gt; has 1k = 1000, whereas &lt;code&gt;IEC&lt;/code&gt; has 1Ki = 1024.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Docker image size&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Github Actions: multiple docker images
      </title>
      <link>https://perrotta.dev/2024/11/github-actions-multiple-docker-images/</link>
      <pubDate>Tue, 05 Nov 2024 17:05:22 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2024/11/github-actions-multiple-docker-images/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: Given a monorepo on Github with multiple docker images in&#xA;it, write a github workflow to build and push all of them.&lt;/p&gt;&#xA;&lt;p&gt;Here is an abridged version of the resulting workflow. The images are listed one&#xA;by one for fine-grained control purposes, but it would also be possible to glob&#xA;them with a single command.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;name: Global services&#xA;&#xA;permissions:&#xA;  id-token: write&#xA;  contents: read&#xA;&#xA;# Replace with workflow trigger conditions.&#xA;on: {}&#xA;&#xA;jobs:&#xA;  global-services:&#xA;    name: ${{ matrix.image }}&#xA;    runs-on: ubuntu-latest&#xA;    strategy:&#xA;      fail-fast: false&#xA;      matrix:&#xA;        include:&#xA;          # keep-sorted start&#xA;          - dockerfile: path/to/one/Dockerfile&#xA;            image: org/one&#xA;          - dockerfile: path/to/two/Dockerfile&#xA;            image: org/two&#xA;          # keep-sorted end&#xA;    steps:&#xA;      - name: Check out source code&#xA;        uses: actions/checkout@v4&#xA;&#xA;      - name: Get git SHA&#xA;        id: git-sha&#xA;        run: |&#xA;          ./scripts/get-versions.sh&#xA;          echo &amp;#34;sha=$(grep &amp;#39;^services_sha&amp;#39; versions.yaml | cut -d&amp;#39; &amp;#39; -f 2)&amp;#34; &amp;gt;&amp;gt; &amp;#34;$GITHUB_OUTPUT&amp;#34;&#xA;&#xA;      - uses: ./.github/actions/setup-ecr-buildx&#xA;        id: setup-ecr-buildx&#xA;&#xA;      - name: Build and push global service images&#xA;        uses: docker/build-push-action@6.9.0&#xA;        with:&#xA;            cache-from: type=gha&#xA;            cache-to: type=gha,mode=max&#xA;            context: path/to&#xA;            file: ${{ matrix.dockerfile }}&#xA;            provenance: false&#xA;            push: true&#xA;            tags: ${{ steps.setup-ecr-buildx.outputs.ecr_registry }}/${{ matrix.image }}:${{ steps.git-sha.outputs.sha }}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A matrix strategy kicks off independent multiple build jobs all at once.&lt;/p&gt;&#xA;&lt;p&gt;Docs: &lt;a href=&#34;https://github.com/docker/build-push-action&#34;&gt;https://github.com/docker/build-push-action&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Github Actions: multiple docker images&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Check if docker image exists in registry
      </title>
      <link>https://perrotta.dev/2024/10/check-if-docker-image-exists-in-registry/</link>
      <pubDate>Fri, 25 Oct 2024 14:11:14 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>aws</category>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2024/10/check-if-docker-image-exists-in-registry/</guid>
      <description>&lt;p&gt;♠ Given a docker registry, image and tag, run the following command:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% docker manifest inspect 9876543210.foo.ecr.us-east-1.amazonaws.com/org/image:123456789&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If it does not exist, you&amp;rsquo;ll see:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;no such manifest: 9876543210.foo.ecr.us-east-1.amazonaws.com/org/image:123456789&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Ensure you are authenticated and/or connected to the VPN in case of a private registry.&lt;/p&gt;&#xA;&lt;p&gt;When using ECR (AWS&amp;rsquo;s registry), you can authenticate this way:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% which docker_login&#xA;docker_login () {&#xA;&#x9;aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 9876543210.foo.ecr.us-east-1.amazonaws.com&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Check if docker image exists in registry&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/aws/&#34;&gt;#aws&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker on Alpine Linux
      </title>
      <link>https://perrotta.dev/2024/07/docker-on-alpine-linux/</link>
      <pubDate>Tue, 30 Jul 2024 22:56:58 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>alpine-linux</category>
      <category>dev</category>
      <category>docker</category>
      <guid>https://perrotta.dev/2024/07/docker-on-alpine-linux/</guid>
      <description>&lt;p&gt;♠ In this post: how to properly start &lt;code&gt;docker&lt;/code&gt; on an Alpine Linux server.&lt;/p&gt;&#xA;&lt;p&gt;First, install &lt;code&gt;docker&lt;/code&gt; and friends:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;doas apk add docker docker-cli docker-compose&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then start the &lt;code&gt;docker&lt;/code&gt; service:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;doas service docker start&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Check if it started successfully:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;service docker status&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If not, then look at the logs:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;less /var/log/docker.log&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I got an error:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;failed to start daemon: error initializing graphdriver: driver not supported&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The suggestion was to change the driver to &lt;code&gt;overlay2&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% $EDITOR /etc/docker/daemon.json&#xA;{&#xA;  &amp;#34;storage-driver&amp;#34;: &amp;#34;overlay2&amp;#34;&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then restart &lt;code&gt;docker&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I got another error:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;level=error msg=&amp;#34;failed to mount overlay: no such device&amp;#34; storage-driver=overlay2&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The suggestion was to reboot:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;doas reboot&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then start &lt;code&gt;docker&lt;/code&gt; again:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;doas service docker start&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And now everything works!&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Docker on Alpine Linux&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/alpine-linux/&#34;&gt;#alpine-linux&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Adding a healthcheck to chartmuseum in AWS Fargate
      </title>
      <link>https://perrotta.dev/2024/05/adding-a-healthcheck-to-chartmuseum-in-aws-fargate/</link>
      <pubDate>Fri, 17 May 2024 11:15:09 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>aws</category>
      <category>dev</category>
      <category>docker</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2024/05/adding-a-healthcheck-to-chartmuseum-in-aws-fargate/</guid>
      <description>&lt;p&gt;♠ Assume that you have a &lt;a href=&#34;https://chartmuseum.com/&#34;&gt;Chartmuseum&lt;/a&gt; container running&#xA;in &lt;a href=&#34;https://aws.amazon.com/fargate/&#34;&gt;AWS Fargate&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Chartmuseum is a repository for helm charts. AWS Fargate is an Amazon service to&#xA;run containers (&amp;ldquo;serverless&amp;rdquo;), being part of ECS (Elastic Container Service).&lt;/p&gt;&#xA;&lt;p&gt;Problem statement: Add a container &lt;em&gt;healthcheck&lt;/em&gt; to the chartmuseum task&#xA;definition associated with the container.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_HealthCheck.html&#34;&gt;official&#xA;docs&lt;/a&gt;&#xA;suggest using &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;[&amp;#34;CMD-SHELL&amp;#34;, &amp;#34;curl -f http://localhost/ || exit 1&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;For Chartmuseum specifically we&amp;rsquo;re interested in its &lt;code&gt;/health&lt;/code&gt; endpoint, as per&#xA;&lt;a href=&#34;https://github.com/helm/chartmuseum/issues/28&#34;&gt;this reference&lt;/a&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;[&amp;#34;CMD-SHELL&amp;#34;, &amp;#34;curl -f http://localhost/health || exit 1&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;But we&amp;rsquo;re using port 8080:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;[&amp;#34;CMD-SHELL&amp;#34;, &amp;#34;curl -f http://localhost:8080/health || exit 1&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you use this healthcheck for the official chartmuseum image&#xA;(&lt;code&gt;ghcr.io/helm/chartmuseum&lt;/code&gt;) it will fail, because the Alpine Linux environment&#xA;it uses does not contain &lt;code&gt;curl&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;A straightforward fix is to use &lt;code&gt;wget&lt;/code&gt; instead:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;[&amp;#34;CMD-SHELL&amp;#34;, &amp;#34;wget -q --spider http://localhost:8080/health || exit 1&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;--spider&lt;/code&gt; is needed because we do not want to download anything, &lt;code&gt;-q&lt;/code&gt; is&#xA;optional and short for &amp;ldquo;quiet&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;/health&lt;/code&gt; endpoint merely returns a simple JSON:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&amp;#34;healthy&amp;#34;:true}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;References: &lt;a href=&#34;https://stackoverflow.com/questions/47722898/how-can-i-make-a-docker-healthcheck-with-wget-instead-of-curl&#34;&gt;https://stackoverflow.com/questions/47722898/how-can-i-make-a-docker-healthcheck-with-wget-instead-of-curl&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Adding a healthcheck to chartmuseum in AWS Fargate&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/aws/&#34;&gt;#aws&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/docker/&#34;&gt;#docker&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
