<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Westgaard</title>
    <description>The latest articles on DEV Community by Daniel Westgaard (@danielwe).</description>
    <link>https://dev.to/danielwe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3876610%2F1d0996da-2e1c-4cac-979f-f2a9d33d8b15.jpg</url>
      <title>DEV Community: Daniel Westgaard</title>
      <link>https://dev.to/danielwe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danielwe"/>
    <language>en</language>
    <item>
      <title>How to Find Every Consumer of Your Docker Base</title>
      <dc:creator>Daniel Westgaard</dc:creator>
      <pubDate>Mon, 13 Apr 2026 19:16:20 +0000</pubDate>
      <link>https://dev.to/danielwe/how-to-find-every-consumer-of-your-docker-base-e32</link>
      <guid>https://dev.to/danielwe/how-to-find-every-consumer-of-your-docker-base-e32</guid>
      <description>&lt;p&gt;&lt;em&gt;You maintain a shared base image. A CVE drops. Which repos are affected? Here's why the answer is harder than it should be.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;You maintain an internal Docker base image. Maybe it's &lt;code&gt;platform/node-base&lt;/code&gt; or &lt;code&gt;company/python-runtime&lt;/code&gt;. A dozen repos use it. Or thirty. Or you're not sure how many, because nobody's counted since the last team reorganisation.&lt;/p&gt;

&lt;p&gt;Then a critical CVE hits the base OS layer, and you need to push a patched version. The question that matters is simple: &lt;strong&gt;which repos across our org pull this image, and at which version?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This should be easy to answer. It isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scenario
&lt;/h2&gt;

&lt;p&gt;Here's what this looks like in practice. Your platform team builds and publishes &lt;code&gt;registry.company.com/platform/base-image&lt;/code&gt;. Across the org, Dockerfiles reference it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; registry.company.com/platform/base-image:v2.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some repos pin to a specific tag. Some use &lt;code&gt;latest&lt;/code&gt;. Some have &lt;code&gt;ARG&lt;/code&gt;-parameterized &lt;code&gt;FROM&lt;/code&gt; statements where the tag is injected at build time. Some reference the image not in a Dockerfile but in a &lt;code&gt;docker-compose.yml&lt;/code&gt; or a CI pipeline config.&lt;/p&gt;

&lt;p&gt;You need to find all of them, check which version each one uses, and coordinate the update. Right now, most teams do this by grepping, asking on Slack, or checking CI logs. None of these give you a complete, current answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What existing tools give you (and where they stop)
&lt;/h2&gt;

&lt;p&gt;Several tools address parts of the Docker base image problem. Each one is useful. None of them answer the full question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Scout
&lt;/h3&gt;

&lt;p&gt;Docker Scout analyzes a &lt;em&gt;built image&lt;/em&gt; and tells you what base image it uses, whether that base is outdated, and what vulnerabilities it contains. &lt;code&gt;docker scout recommendations&lt;/code&gt; will suggest updated base images with fewer CVEs.&lt;/p&gt;

&lt;p&gt;This is valuable, but it works per-image, not per-org. It answers "what base image does &lt;em&gt;this&lt;/em&gt; image use?" It doesn't answer "which of my 200 repos use &lt;em&gt;this&lt;/em&gt; base image?" You'd need to run Scout against every image in your registry and correlate the results back to source repos — which is a project in itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Renovate
&lt;/h3&gt;

&lt;p&gt;Renovate detects &lt;code&gt;FROM&lt;/code&gt; statements in Dockerfiles and can open pull requests when a newer tag is available. It &lt;em&gt;implicitly&lt;/em&gt; knows who consumes what, because it's configured per-repo and parses the Dockerfiles.&lt;/p&gt;

&lt;p&gt;But Renovate doesn't expose this as a queryable view. You can't ask Renovate "show me every repo that references &lt;code&gt;platform/base-image&lt;/code&gt;." It reacts when a new version appears. It doesn't give you the pre-release blast radius: before you push the patched image, which repos and teams will need to update?&lt;/p&gt;

&lt;h3&gt;
  
  
  Backstage / Roadie Tech Insights
&lt;/h3&gt;

&lt;p&gt;Roadie (a managed Backstage provider) has a Tech Insights feature that can parse Dockerfiles via regex, extract base image versions, and create scorecards tracking migration progress. This is the closest existing solution to the consumer-tracking problem.&lt;/p&gt;

&lt;p&gt;The limitation is that it requires Backstage to be set up with &lt;code&gt;catalog-info.yaml&lt;/code&gt; per repo. You're tracking Docker base images through a service catalog that depends on manual registration. If a repo isn't in the catalog, its Dockerfile is invisible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Container registries
&lt;/h3&gt;

&lt;p&gt;Your registry (Docker Hub, Harbor, ACR, ECR) knows which images have been &lt;em&gt;pulled&lt;/em&gt; and how often. Some provide pull statistics by tag. But pull logs don't tell you which &lt;em&gt;source repo&lt;/em&gt; initiated the pull. A CI pipeline pulling &lt;code&gt;base-image:v2.1&lt;/code&gt; shows up as a pull event, not as "repo &lt;code&gt;frontend-api&lt;/code&gt; depends on this image via its Dockerfile on line 3."&lt;/p&gt;

&lt;h3&gt;
  
  
  Grep
&lt;/h3&gt;

&lt;p&gt;The fallback everyone uses. Clone all the repos, run &lt;code&gt;grep -r "platform/base-image"&lt;/code&gt;, assemble the results. It works once. The results are stale immediately. It misses parameterized &lt;code&gt;FROM&lt;/code&gt; statements, compose files, and CI configs. And at a hundred repos, it takes long enough that nobody does it proactively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is harder than it looks
&lt;/h2&gt;

&lt;p&gt;The core difficulty is that Docker base image dependencies live in multiple places and multiple formats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfiles&lt;/strong&gt; are the obvious source, but &lt;code&gt;FROM&lt;/code&gt; statements can use &lt;code&gt;ARG&lt;/code&gt; substitution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BASE_TAG=v2.1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; registry.company.com/platform/base-image:${BASE_TAG}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple grep for the image name finds this. A simple grep for the &lt;em&gt;version&lt;/em&gt; doesn't, because the version is in a variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose files&lt;/strong&gt; reference images differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.company.com/platform/base-image:v2.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a dependency on the same image, declared in a completely different file format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI pipeline configs&lt;/strong&gt; often pull images directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.company.com/platform/base-image:v2.1&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A GitLab CI &lt;code&gt;image:&lt;/code&gt; directive or a GitHub Actions &lt;code&gt;container:&lt;/code&gt; field is another consumption point for the same base image, and it's in yet another file.&lt;/p&gt;

&lt;p&gt;Then there's the &lt;strong&gt;producer-side problem&lt;/strong&gt;. Knowing which repos &lt;em&gt;consume&lt;/em&gt; the image is half the story. You also need to know which repo &lt;em&gt;builds&lt;/em&gt; it. That's usually a CI pipeline with &lt;code&gt;docker build&lt;/code&gt; and &lt;code&gt;docker push&lt;/code&gt; commands, not something declared in a manifest. Connecting the consumer graph to the producer requires cross-referencing multiple file types within and across repos.&lt;/p&gt;

&lt;p&gt;No single tool today connects all of these surfaces into one view.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the full answer requires
&lt;/h2&gt;

&lt;p&gt;To reliably answer "who consumes this base image," you need a system that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scans every repo in the org&lt;/strong&gt;, not just the ones registered in a catalog&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parses Dockerfiles, Compose files, and CI configs&lt;/strong&gt;, because the same image can be referenced in all three&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handles variable substitution&lt;/strong&gt; in &lt;code&gt;FROM&lt;/code&gt; statements by resolving &lt;code&gt;ARG&lt;/code&gt; defaults&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detects which repos produce which images&lt;/strong&gt; by scanning CI configs for build and push commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeps the results current&lt;/strong&gt; through scheduled or event-triggered rescans&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Makes the graph queryable&lt;/strong&gt;: "show me every consumer of &lt;code&gt;platform/base-image&lt;/code&gt;, grouped by version"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is one of the specific problems I'm building &lt;a href="https://riftmap.dev" rel="noopener noreferrer"&gt;Riftmap&lt;/a&gt; to solve. It scans a GitLab or GitHub org, parses Dockerfiles (including multi-stage builds, ARG defaults, and Compose files), detects which repos produce which images via CI config analysis, and builds a cross-repo dependency graph you can query by artifact.&lt;/p&gt;

&lt;p&gt;The result: when that CVE drops, you click on the base image in the graph and immediately see every repo that depends on it, which version each one uses, and who owns them. No grepping. No Slack archaeology. No stale spreadsheet from last quarter.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;How is your team solving this today?&lt;/strong&gt; I'd genuinely like to know — drop a comment or find me at &lt;a href="https://riftmap.dev" rel="noopener noreferrer"&gt;riftmap.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>infrastructure</category>
      <category>security</category>
    </item>
  </channel>
</rss>
