<?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: Dockerlinux</title>
    <description>The latest articles on DEV Community by Dockerlinux (@dockerlinux).</description>
    <link>https://dev.to/dockerlinux</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4141846%2Fc9a4b610-06ba-4cac-88b5-4ca046cc9f6d.png</url>
      <title>DEV Community: Dockerlinux</title>
      <link>https://dev.to/dockerlinux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dockerlinux"/>
    <language>en</language>
    <item>
      <title>How I turned Docker incidents into game levels (with postmortems)</title>
      <dc:creator>Dockerlinux</dc:creator>
      <pubDate>Sat, 03 Oct 2026 08:01:00 +0000</pubDate>
      <link>https://dev.to/dockerlinux/how-i-turned-docker-incidents-into-game-levels-with-postmortems-jon</link>
      <guid>https://dev.to/dockerlinux/how-i-turned-docker-incidents-into-game-levels-with-postmortems-jon</guid>
      <description>&lt;p&gt;Every tutorial teaches you how to start a container. Almost none teach you what to do when one is down at 3am and people are waiting.&lt;/p&gt;

&lt;p&gt;So I added "boss levels" to &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=oncall" rel="noopener noreferrer"&gt;DockerLinux&lt;/a&gt;&lt;/strong&gt;, my free game for learning Linux and Docker in a simulated terminal (&lt;a&gt;here's what shipped last time&lt;/a&gt;). Type &lt;code&gt;oncall&lt;/code&gt; and you take the pager.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqh0ecgt53bfod82lv35j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqh0ecgt53bfod82lv35j.gif" alt="A real on-call run: the page, the investigation, the fix and the postmortem" width="420" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The page.&lt;/strong&gt; A ticket arrives: &lt;code&gt;SEV-1 · INC-101 · The shop is down&lt;/code&gt;. Support says customers can't load the shop; an ops bot mentions the server rebooted at 03:12 for kernel updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're on prod-01.&lt;/strong&gt; The terminal logs in to a pretend production server where something is broken, and a clock starts (5 minutes for this one). Your own machine is untouched and comes back afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You investigate with real commands:&lt;/strong&gt; &lt;code&gt;docker ps -a&lt;/code&gt;, &lt;code&gt;docker logs&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;docker network inspect&lt;/code&gt;. There's a &lt;code&gt;runbook.md&lt;/code&gt; to &lt;code&gt;cat&lt;/code&gt;, and hints if you're stuck (they cost XP).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You fix it, any correct way.&lt;/strong&gt; Broken containers crash again on restart, like real ones, so "just restart it" doesn't always work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The postmortem:&lt;/strong&gt; time, stars, the root cause and the lesson.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7guh5acfc1l52o6n9k8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7guh5acfc1l52o6n9k8.png" alt="The page and the postmortem" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are six incidents, unlocked as you finish the levels that teach what you need:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Unlocks after&lt;/th&gt;
&lt;th&gt;You'll need&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The shop is down&lt;/td&gt;
&lt;td&gt;Level 5 (container lifecycle)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker ps -a&lt;/code&gt;, &lt;code&gt;docker start&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Welcome to nginx?!&lt;/td&gt;
&lt;td&gt;Level 6 (networking &amp;amp; ports)&lt;/td&gt;
&lt;td&gt;reading the PORTS column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database unreachable&lt;/td&gt;
&lt;td&gt;Level 6&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker network inspect&lt;/code&gt;, &lt;code&gt;docker network connect&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad deploy&lt;/td&gt;
&lt;td&gt;Level 8 (building images)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker logs&lt;/code&gt;, rolling back to the previous tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The data vanished&lt;/td&gt;
&lt;td&gt;Level 7 (volumes)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker volume ls&lt;/code&gt;, &lt;code&gt;docker inspect&lt;/code&gt; → Mounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compose half up&lt;/td&gt;
&lt;td&gt;Level 9 (Docker Compose)&lt;/td&gt;
&lt;td&gt;reading Compose's warnings, &lt;code&gt;docker compose logs&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(Spoiler for the first one only: the server rebooted and &lt;code&gt;shop-web&lt;/code&gt; had no restart policy. &lt;code&gt;docker ps&lt;/code&gt; hides stopped containers; &lt;code&gt;docker ps -a&lt;/code&gt; doesn't.)&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;Everything runs in the browser: a small shell, a virtual file system and a simulated Docker daemon (images, containers, ports, networks, volumes). Incidents are just &lt;strong&gt;data&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inc_shop_down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INC-101&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The shop is down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEV-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;requires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;// unlocks when Level 5 is complete&lt;/span&gt;
  &lt;span class="nx"&gt;slaMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// the time target&lt;/span&gt;
  &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* break a fresh prod-01: shop-web exited, redis still up */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;resolved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nf"&gt;serving&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shop:1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;hints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="cm"&gt;/* where to look → what it means → the fix */&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker ps -a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker start shop-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;curl localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;rootCause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two decisions made it work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;resolved()&lt;/code&gt; checks the state, not your commands.&lt;/strong&gt; It asks "is something serving &lt;code&gt;shop:1.0&lt;/code&gt; on port 8080?", not "did they type &lt;code&gt;docker start shop-web&lt;/code&gt;?". So &lt;code&gt;docker start&lt;/code&gt;, &lt;code&gt;docker restart&lt;/code&gt; or a brand-new &lt;code&gt;docker run&lt;/code&gt; with the right port all count, just like in real life.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;solution&lt;/code&gt; is replayed by the tests.&lt;/strong&gt; Every incident ships with a known fix, and the test suite runs it against a fresh broken server, so an incident can never become impossible after an engine change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scoring is deliberately simple: &lt;strong&gt;1 star for fixing it, +1 within the time target, +1 without hints.&lt;/strong&gt; Replay for three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I think this matters
&lt;/h2&gt;

&lt;p&gt;Most of the job isn't typing &lt;code&gt;docker run&lt;/code&gt;. It's reading &lt;code&gt;docker ps -a&lt;/code&gt; calmly, finding the one log line that matters, and fixing the right thing, under a bit of pressure. A game is a safe place to practise that before it's real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which real outage should become incident #5?&lt;/strong&gt; A full disk, a DNS surprise, a volume mounted in the wrong place, an OOM-killed container…&lt;/li&gt;
&lt;li&gt;If you run Docker in production: where does the simulation behave differently from the real thing in a way that could mislead someone?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=oncall" rel="noopener noreferrer"&gt;dockerlinux.com&lt;/a&gt;&lt;/strong&gt;: free, in your browser, no install. Finish Level 5, then type &lt;code&gt;oncall&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>sre</category>
      <category>linux</category>
    </item>
    <item>
      <title>I built "boss levels" for my Linux &amp; Docker game: you're on call and prod is down</title>
      <dc:creator>Dockerlinux</dc:creator>
      <pubDate>Wed, 30 Sep 2026 20:49:20 +0000</pubDate>
      <link>https://dev.to/dockerlinux/i-built-boss-levels-for-my-linux-docker-game-youre-on-call-and-prod-is-down-3p22</link>
      <guid>https://dev.to/dockerlinux/i-built-boss-levels-for-my-linux-docker-game-youre-on-call-and-prod-is-down-3p22</guid>
      <description>&lt;p&gt;Every tutorial teaches you how to start a container. Almost none teach you what to do when one is down at 3am and people are waiting.&lt;/p&gt;

&lt;p&gt;So I added "boss levels" to &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=oncall" rel="noopener noreferrer"&gt;DockerLinux&lt;/a&gt;&lt;/strong&gt;, my free game for learning Linux and Docker in a simulated terminal (&lt;a&gt;here's what shipped last time&lt;/a&gt;). Type &lt;code&gt;oncall&lt;/code&gt; and you take the pager.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqdc8b05xnhkmk0x7p490.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqdc8b05xnhkmk0x7p490.gif" alt="A real on-call run: the page, the investigation, the fix and the postmortem" width="420" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The page.&lt;/strong&gt; A ticket arrives: &lt;code&gt;SEV-1 · INC-101 · The shop is down&lt;/code&gt;. Support says customers can't load the shop; an ops bot mentions the server rebooted at 03:12 for kernel updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're on prod-01.&lt;/strong&gt; The terminal logs in to a pretend production server where something is broken, and a clock starts (5 minutes for this one). Your own machine is untouched and comes back afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You investigate with real commands:&lt;/strong&gt; &lt;code&gt;docker ps -a&lt;/code&gt;, &lt;code&gt;docker logs&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;docker network inspect&lt;/code&gt;. There's a &lt;code&gt;runbook.md&lt;/code&gt; to &lt;code&gt;cat&lt;/code&gt;, and hints if you're stuck (they cost XP).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You fix it, any correct way.&lt;/strong&gt; Broken containers crash again on restart, like real ones, so "just restart it" doesn't always work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The postmortem:&lt;/strong&gt; time, stars, the root cause and the lesson.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fayjkhin009gbuqugi7o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fayjkhin009gbuqugi7o8.png" alt="The page and the postmortem" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are four incidents, unlocked as you finish the levels that teach what you need:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Unlocks after&lt;/th&gt;
&lt;th&gt;You'll need&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The shop is down&lt;/td&gt;
&lt;td&gt;Level 5 (container lifecycle)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker ps -a&lt;/code&gt;, &lt;code&gt;docker start&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Welcome to nginx?!&lt;/td&gt;
&lt;td&gt;Level 6 (networking &amp;amp; ports)&lt;/td&gt;
&lt;td&gt;reading the PORTS column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database unreachable&lt;/td&gt;
&lt;td&gt;Level 6&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker network inspect&lt;/code&gt;, &lt;code&gt;docker network connect&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad deploy&lt;/td&gt;
&lt;td&gt;Level 8 (building images)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker logs&lt;/code&gt;, rolling back to the previous tag&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(Spoiler for the first one only: the server rebooted and &lt;code&gt;shop-web&lt;/code&gt; had no restart policy. &lt;code&gt;docker ps&lt;/code&gt; hides stopped containers; &lt;code&gt;docker ps -a&lt;/code&gt; doesn't.)&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;Everything runs in the browser: a small shell, a virtual file system and a simulated Docker daemon (images, containers, ports, networks, volumes). Incidents are just &lt;strong&gt;data&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inc_shop_down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INC-101&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The shop is down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEV-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;requires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;// unlocks when Level 5 is complete&lt;/span&gt;
  &lt;span class="nx"&gt;slaMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// the time target&lt;/span&gt;
  &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* break a fresh prod-01: shop-web exited, redis still up */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;resolved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nf"&gt;serving&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shop:1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;hints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="cm"&gt;/* where to look → what it means → the fix */&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker ps -a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker start shop-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;curl localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;rootCause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two decisions made it work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;resolved()&lt;/code&gt; checks the state, not your commands.&lt;/strong&gt; It asks, "is something serving &lt;code&gt;shop:1.0&lt;/code&gt; on port 8080?", not "did they type &lt;code&gt;docker start shop-web&lt;/code&gt;?". So &lt;code&gt;docker start&lt;/code&gt;, &lt;code&gt;docker restart&lt;/code&gt; or a brand-new &lt;code&gt;docker run&lt;/code&gt; with the right port all count, just like in real life.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;solution&lt;/code&gt; is replayed by the tests.&lt;/strong&gt; Every incident ships with a known fix, and the test suite runs it against a fresh broken server, so an incident can never become impossible after an engine change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scoring is deliberately simple: &lt;strong&gt;1 star for fixing it, +1 within the time target, +1 without hints.&lt;/strong&gt; Replay for three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I think this matters
&lt;/h2&gt;

&lt;p&gt;Most of the job isn't typing &lt;code&gt;docker run&lt;/code&gt;. It's reading &lt;code&gt;docker ps -a&lt;/code&gt; calmly, finding the one log line that matters, and fixing the right thing, under a bit of pressure. A game is a safe place to practise that before it's real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which real outage should become incident #5?&lt;/strong&gt; A full disk, a DNS surprise, a volume mounted in the wrong place, an OOM-killed container…&lt;/li&gt;
&lt;li&gt;If you run Docker in production: where does the simulation behave differently from the real thing in a way that could mislead someone?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=oncall" rel="noopener noreferrer"&gt;dockerlinux.com&lt;/a&gt;&lt;/strong&gt;: free, in your browser, no install. Finish Level 5, then type &lt;code&gt;oncall&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>sre</category>
      <category>showdev</category>
    </item>
    <item>
      <title>You asked, and I shipped it: pipes, real error messages and streak freezes in DockerLinux</title>
      <dc:creator>Dockerlinux</dc:creator>
      <pubDate>Tue, 29 Sep 2026 20:52:32 +0000</pubDate>
      <link>https://dev.to/dockerlinux/you-asked-and-i-shipped-it-pipes-real-error-messages-and-streak-freezes-in-dockerlinux-10ob</link>
      <guid>https://dev.to/dockerlinux/you-asked-and-i-shipped-it-pipes-real-error-messages-and-streak-freezes-in-dockerlinux-10ob</guid>
      <description>&lt;p&gt;Earlier this month I posted &lt;strong&gt;&lt;a&gt;DockerLinux&lt;/a&gt;&lt;/strong&gt; here: a free game that teaches Linux and Docker in a simulated terminal in your browser. At the end I asked one question: &lt;em&gt;where does the simulation behave differently from the real thing?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You answered, and some requests stood out in the comments, so I built both. Here's what changed and a few extras that came along for the ride.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Pipes
&lt;/h2&gt;

&lt;p&gt;In the first article I wrote: &lt;em&gt;"Pipes aren't supported yet. They're on the list!"&lt;/em&gt; It didn't stay on the list for long.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx9h3jum7dixayeng2jiy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx9h3jum7dixayeng2jiy.png" alt="Pipes" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's now a whole new &lt;strong&gt;Level 3, "Pipes: connecting commands"&lt;/strong&gt;, so the course is 10 levels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;                 &lt;span class="c"&gt;# how many files?&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;docker      &lt;span class="c"&gt;# "what was that command again?"&lt;/span&gt;
docker ps | &lt;span class="nb"&gt;grep &lt;/span&gt;web       &lt;span class="c"&gt;# find one container in a busy list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It covers &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt; and &lt;code&gt;wc&lt;/code&gt;, and your first pipe unlocks the &lt;strong&gt;Plumber&lt;/strong&gt; achievement.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Error messages, word for word
&lt;/h2&gt;

&lt;p&gt;The other request: make the errors identical to the real ones. That matters more than it sounds, because a beginner learns to &lt;em&gt;read&lt;/em&gt; errors as much as to type commands, and a "close enough" message teaches the wrong thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbia24cxw821p8a9s77lv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbia24cxw821p8a9s77lv.png" alt="A real Docker error" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Errors now match real bash and Docker &lt;strong&gt;word for word&lt;/strong&gt;, e.g. &lt;code&gt;Unable to find image 'x:latest' locally&lt;/code&gt;. When you meet it on a real machine, you've already seen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Your progress, on any device
&lt;/h2&gt;

&lt;p&gt;Playing still needs no account. But if you want one, it's just your email and a &lt;strong&gt;6-digit code&lt;/strong&gt;, no password. XP, levels, quiz answers, your streak and even the files you created in the simulated machine sync to any computer or phone. You can log out everywhere or delete the account from the menu.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Streaks that forgive a bad day
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq2q3niwm4qdh3p73a5uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq2q3niwm4qdh3p73a5uc.png" alt="The streak card" width="800" height="907"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One command a day keeps your 🔥 streak alive. What I didn't want was one missed day wiping out two weeks of practice, so you now &lt;strong&gt;earn streak freezes&lt;/strong&gt; by finishing levels (you can hold up to 2). Miss a day and a freeze is used for you: ❄️ &lt;em&gt;Streak saved!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. 35 achievements (7 of them secret)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzr3hx1p2d1pfdaw0asrm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzr3hx1p2d1pfdaw0asrm.png" alt="Achievements page" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a proper achievements page now: badges for getting started, levels, Docker, streaks and inviting friends, progress bars on the locked ones ("43/50"), a "Next up" card and a grid of your practice days over the last 6 months.&lt;/p&gt;

&lt;p&gt;Seven are secret. I'm not saying which. 👀&lt;/p&gt;

&lt;h2&gt;
  
  
  6. And two things just for fun
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Byte&lt;/strong&gt;, a pixel penguin who lives at the bottom of the terminal. He hatches on your first command, grows up as you practise, covers his eyes when you get an error and dances when you level up. Try &lt;code&gt;pet dance&lt;/code&gt; or &lt;code&gt;pet style arctic&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;movie&lt;/code&gt;&lt;/strong&gt;: a ~50-second ASCII film, "OUT OF MEMORY". A container leaks memory, the OOM Killer chases it, and &lt;code&gt;docker update --memory 1g&lt;/code&gt; saves the day. The credits end with the actual lesson: set memory limits (&lt;code&gt;docker run -m 512m&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The same question as last time, because it worked: &lt;strong&gt;what should I build next?&lt;/strong&gt; On my list are permissions, processes, environment variables and multi-stage builds. Tell me which one you'd want first, or what else confused you.&lt;/p&gt;

&lt;p&gt;And if you know Docker well: where does the simulation still differ from the real thing in a way that would mislead a beginner? Every answer to that has made the game better.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=update1" rel="noopener noreferrer"&gt;dockerlinux.com&lt;/a&gt;&lt;/strong&gt;: still free, still nothing to install.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>beginners</category>
      <category>showdev</category>
    </item>
    <item>
      <title>You asked, we shipped it: pipes, real Docker errors and streak freezes</title>
      <dc:creator>Dockerlinux</dc:creator>
      <pubDate>Sun, 27 Sep 2026 18:15:39 +0000</pubDate>
      <link>https://dev.to/dockerlinux/you-asked-we-shipped-it-pipes-real-docker-errors-and-streak-freezes-2o10</link>
      <guid>https://dev.to/dockerlinux/you-asked-we-shipped-it-pipes-real-docker-errors-and-streak-freezes-2o10</guid>
      <description>&lt;p&gt;Most people learn Docker by copying commands into a real machine. It works until something breaks and nobody explains why.&lt;/p&gt;

&lt;p&gt;DockerLinux is a free game that fixes that: a simulated Linux + Docker terminal in the browser, with 10 levels of small missions, from pwd to Docker Compose. Nothing to install, nothing real to break.&lt;/p&gt;

&lt;p&gt;After the launch, developers in the comments asked for two things: pipes and error messages identical to real Docker. Both are live now, plus a few more things:&lt;/p&gt;

&lt;p&gt;🔗 A new level on pipes: ls | wc -l, grep, head, tail, docker ps | grep web&lt;br&gt;
💬 Error messages that match real bash and Docker word for word, so nothing surprises you on a real server&lt;br&gt;
❄️ Daily streaks with freezes: finish a level to earn one, and it covers a day you miss.&lt;br&gt;
🏆 An achievements page with 29 badges (5 are secret), progress bars and a practice-day grid&lt;br&gt;
💾 An optional free account with no password (a 6-digit email code) to continue on any device&lt;/p&gt;

&lt;p&gt;It's aimed at students, junior devs and anyone moving into DevOps or cloud, and it works on a phone too.&lt;/p&gt;

&lt;p&gt;If you know Docker well, we'd love your eye on it: where does the simulation behave differently from the real thing in a way that could mislead a beginner?&lt;/p&gt;

&lt;p&gt;Play for Free: &lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=update2" rel="noopener noreferrer"&gt;No account needed to start&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Docker #Linux #DevOps #CloudComputing #LearnToCode #CareerDevelopment
&lt;/h1&gt;

</description>
      <category>docker</category>
      <category>learning</category>
      <category>linux</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a free game to learn Linux &amp; Docker in your browser 🐳🎮</title>
      <dc:creator>Dockerlinux</dc:creator>
      <pubDate>Thu, 24 Sep 2026 20:49:13 +0000</pubDate>
      <link>https://dev.to/dockerlinux/i-built-a-free-game-to-learn-linux-docker-in-your-browser-2p8j</link>
      <guid>https://dev.to/dockerlinux/i-built-a-free-game-to-learn-linux-docker-in-your-browser-2p8j</guid>
      <description>&lt;p&gt;Most people learn Docker by pasting commands from a tutorial into a real machine. It works, right up until it doesn't, and then the terminal feels like a minefield.&lt;/p&gt;

&lt;p&gt;I wanted somewhere beginners could type the real commands, get things wrong and get instant feedback, with nothing to install and nothing real to break. So I built &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch" rel="noopener noreferrer"&gt;DockerLinux&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk17b6tjo1b86ditskcno.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk17b6tjo1b86ditskcno.gif" alt=" " width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/sYn8gdEsqNI" width="315" height="560"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;A simulated Linux machine with Docker, in a browser tab, wrapped in a small game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missions and XP&lt;/strong&gt;: each level is a checklist of small tasks. Finish them to level up, unlock achievements and, at the end, download a certificate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A lesson after every task&lt;/strong&gt;: run &lt;code&gt;pwd&lt;/code&gt; and it tells you what &lt;code&gt;/root/app&lt;/code&gt; actually means. Run &lt;code&gt;docker run -d&lt;/code&gt; and it explains what "detached" is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A quiz at the end of each level&lt;/strong&gt;, and your progress is saved in your browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works on phones too&lt;/strong&gt;, with on-screen Tab/↑/↓ keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9 levels, from zero to Compose
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fifl3h62h638ttdsrmbjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fifl3h62h638ttdsrmbjt.png" alt=" " width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It starts with the absolute basics (&lt;code&gt;pwd&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, hidden files) and ends with building your own image and running a multi-container app with &lt;code&gt;docker compose up&lt;/code&gt;. The last level is a sandbox where you can play freely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stuck? Never for long
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fievppn4lpy2wtx26vvcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fievppn4lpy2wtx26vvcb.png" alt=" " width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hints come in three steps: &lt;strong&gt;the idea&lt;/strong&gt;, then &lt;strong&gt;the syntax&lt;/strong&gt;, then &lt;strong&gt;the answer&lt;/strong&gt;. Each step costs a bit of XP, so you're nudged to think first, but you're never left stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;There's no real VM or container behind it. It's all JavaScript in your browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A tiny shell&lt;/strong&gt;: a tokenizer that understands quotes, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; redirects, plus an argument parser for flags like &lt;code&gt;-d&lt;/code&gt;, &lt;code&gt;--name web-server&lt;/code&gt; and &lt;code&gt;-p 8080:80&lt;/code&gt;. (Pipes aren't supported yet. They're on the list!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A virtual file system&lt;/strong&gt; with real paths, so &lt;code&gt;cd ..&lt;/code&gt;, &lt;code&gt;ls -la&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;mkdir&lt;/code&gt; and &lt;code&gt;echo "hi" &amp;gt; file.txt&lt;/code&gt; behave the way you'd expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A simulated Docker daemon&lt;/strong&gt;: images you can pull, a container lifecycle (&lt;code&gt;run&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;logs&lt;/code&gt;), name and port conflicts, volumes, networks, &lt;code&gt;docker build&lt;/code&gt; that reads the Dockerfile in the virtual file system, and &lt;code&gt;docker compose up&lt;/code&gt; that reads the YAML. &lt;code&gt;curl localhost:8080&lt;/code&gt; even answers once a container publishes that port.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Levels are data&lt;/strong&gt;: each task has a &lt;code&gt;check(ctx)&lt;/code&gt; function that runs after every successful command, so the game reacts to what you actually did rather than to one exact string.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Start an Nginx web server container in the background, named 'web-server'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;`docker run` creates and starts a container...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker run -d --name &amp;lt;name&amp;gt; &amp;lt;image&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docker run -d --name web-server nginx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;runningContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nginx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI is &lt;strong&gt;Vue 3 + Vite + Tailwind&lt;/strong&gt;. Terminal output is rendered as structured segments (no &lt;code&gt;v-html&lt;/code&gt; anywhere), which made it possible to ship a strict Content Security Policy. It's hosted on &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;, with &lt;strong&gt;D1&lt;/strong&gt; (SQLite) for the optional newsletter signup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dockerlinux.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch" rel="noopener noreferrer"&gt;dockerlinux.com&lt;/a&gt;&lt;/strong&gt;: free, no account needed.&lt;/p&gt;

&lt;p&gt;I'd love feedback, especially from people who are just starting out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What confused you?&lt;/li&gt;
&lt;li&gt;Which command did you expect to work that didn't?&lt;/li&gt;
&lt;li&gt;What should the next levels cover: permissions, pipes and &lt;code&gt;grep&lt;/code&gt;, processes, environment variables, and multi-stage builds?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you're experienced with Docker: where does the simulation behave differently from the real thing in a way that could mislead a beginner? That's the feedback I value most. 🙏&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>beginners</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
