<?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: Mel Wang</title>
    <description>The latest articles on DEV Community by Mel Wang (@mel_wang_bd07bd519fc32037).</description>
    <link>https://dev.to/mel_wang_bd07bd519fc32037</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%2F3766665%2F5efb7e58-070c-4c38-bd4c-7a7177889e48.jpeg</url>
      <title>DEV Community: Mel Wang</title>
      <link>https://dev.to/mel_wang_bd07bd519fc32037</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mel_wang_bd07bd519fc32037"/>
    <language>en</language>
    <item>
      <title>Docker Part 1: Installation and Hello World</title>
      <dc:creator>Mel Wang</dc:creator>
      <pubDate>Fri, 06 Mar 2026 14:10:39 +0000</pubDate>
      <link>https://dev.to/mel_wang_bd07bd519fc32037/docker-part-1-installation-and-hello-world-2k37</link>
      <guid>https://dev.to/mel_wang_bd07bd519fc32037/docker-part-1-installation-and-hello-world-2k37</guid>
      <description>&lt;p&gt;This is a post for myself to take notes on Udemy's course &lt;em&gt;"Complete Docker and Kubernetes Course - learn all core Docker features including Dockerfiles and Docker Compose"&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Download Docker&lt;/li&gt;
&lt;li&gt;Run hello-world image in Docker&lt;/li&gt;
&lt;li&gt;Run ubuntu image in Docker&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Download Docker
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;I have a mac, so I installed it from this link: &lt;a href="https://docs.docker.com/desktop/setup/install/mac-install/" rel="noopener noreferrer"&gt;https://docs.docker.com/desktop/setup/install/mac-install/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A docker.dmg file is downloaded. After it's done downloading, double click it and move it in the Applications folder. &lt;/li&gt;
&lt;li&gt;Run:
&lt;code&gt;docker --help&lt;/code&gt;. If it shows the following then you installed docker successfully.&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.amazonaws.com%2Fuploads%2Farticles%2Fy86un9mq5c3d2cj0twal.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.amazonaws.com%2Fuploads%2Farticles%2Fy86un9mq5c3d2cj0twal.png" alt="output" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: if it returns: &lt;br&gt;
&lt;code&gt;zsh: command not found: docker&lt;/code&gt;&lt;br&gt;
then it may not be pointed correctly in the path. Run: &lt;br&gt;
&lt;code&gt;echo $PATH&lt;/code&gt; to see if docker is present. If not, run:&lt;br&gt;
&lt;code&gt;export PATH="/Applications/Docker.app/Contents/Resources/bin:$PATH"&lt;/code&gt; and try &lt;code&gt;docker --help&lt;/code&gt; again.&lt;/p&gt;
&lt;h1&gt;
  
  
  Run hello-world image in Docker
&lt;/h1&gt;

&lt;p&gt;When learning a new programming language, people often start with a Hello World program. In Docker, we do something similar using the hello-world container.&lt;/p&gt;

&lt;p&gt;Running this container helps verify that Docker is installed correctly and introduces the basic components of Docker.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: The Command
&lt;/h3&gt;

&lt;p&gt;We start with the following command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.amazonaws.com%2Fuploads%2Farticles%2Fghs462x0ddg60yz955lj.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.amazonaws.com%2Fuploads%2Farticles%2Fghs462x0ddg60yz955lj.png" alt="hello-world" width="800" height="396"&gt;&lt;/a&gt;&lt;br&gt;
So what happened here?&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Actors
&lt;/h3&gt;

&lt;p&gt;Before we walk through the steps, it helps to understand the actors involved in the process.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Docker Client (CLI)
&lt;/h4&gt;

&lt;p&gt;The Docker client is the program you interact with in the terminal.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run
docker ps
docker build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client’s job is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;receive commands from the user&lt;/li&gt;
&lt;li&gt;send requests to the Docker daemon&lt;/li&gt;
&lt;li&gt;display the results back to the terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it like a remote control for Docker.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Docker Daemon (Docker Engine)
&lt;/h4&gt;

&lt;p&gt;The Docker daemon is the background service that does the real work. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;downloads images&lt;/li&gt;
&lt;li&gt;builds containers&lt;/li&gt;
&lt;li&gt;starts containers&lt;/li&gt;
&lt;li&gt;manages networks and storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The daemon is always running in the background once Docker is installed.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Docker Registry (Docker Hub)
&lt;/h4&gt;

&lt;p&gt;Docker images are stored in a registry. The default public registry is &lt;em&gt;Docker Hub&lt;/em&gt;. Docker Hub contains thousands of images such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nginx&lt;/li&gt;
&lt;li&gt;redis&lt;/li&gt;
&lt;li&gt;postgres&lt;/li&gt;
&lt;li&gt;hello-world&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Docker can't find an image locally, it will download it from Docker Hub.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Docker Image
&lt;/h4&gt;

&lt;p&gt;An image is a template used to create containers. You can think of it as a &lt;em&gt;blueprint&lt;/em&gt; for an application. Images are read-only and contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application code&lt;/li&gt;
&lt;li&gt;runtime&lt;/li&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5. Docker Container
&lt;/h4&gt;

&lt;p&gt;A container is a running instance of an image.&lt;/p&gt;

&lt;p&gt;Relationship:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image → Blueprint&lt;/li&gt;
&lt;li&gt;Container → Running program&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multiple containers can be created from the same image.&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.amazonaws.com%2Fuploads%2Farticles%2Fab8ayynhwdhnyicl6o2d.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.amazonaws.com%2Fuploads%2Farticles%2Fab8ayynhwdhnyicl6o2d.png" alt="image" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — What Happens When You Run the Command
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;You type the command in the terminal. &lt;code&gt;docker run hello-world&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The Docker client sends this request to the Docker daemon.&lt;/li&gt;
&lt;li&gt;The Docker daemon checks whether the hello-world image already exists on your computer.&lt;/li&gt;
&lt;li&gt;If the image exists locally, it'll use local image. If not, the daemon will pull image from Docker Hub.&lt;/li&gt;
&lt;li&gt;The Docker daemon pulls (downloads) the image from Docker Hub. Once downloaded, the image is stored locally. You might see output like:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Pulling from library/hello-world&lt;br&gt;
Digest: sha256:...&lt;br&gt;
Status: Downloaded newer image&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;After the image is available locally, Docker creates a new &lt;strong&gt;container&lt;/strong&gt; from that image. Think of it like:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Image = blueprint&lt;br&gt;
Container = running machine&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;The hello-world container runs a very small program. Its only job is to print the following message:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Hello from Docker!&lt;br&gt;
This message shows that your installation appears to be working correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the message is printed, the container finishes execution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The container exits automatically. You can confirm there are no running containers with:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output will be empty.&lt;/p&gt;

&lt;h1&gt;
  
  
  Run ubuntu image in Docker
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Step 1: The Command
&lt;/h3&gt;

&lt;p&gt;Run the command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that nothing is done and the container is stopped after running &lt;code&gt;/bin/bash&lt;/code&gt;. Why?&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2F2buxp6u0n89uopnwhqwu.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.amazonaws.com%2Fuploads%2Farticles%2F2buxp6u0n89uopnwhqwu.png" alt="ubuntu" width="800" height="206"&gt;&lt;/a&gt;&lt;br&gt;
This is because there was no command that was executed inside of this ubuntu container. We can check that the ubuntu container is exited by running either of the following to see docker container run history (both yields the same results):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps -a
docker container ls -a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then how do we start ubuntu and let it keep running? The following command does the trick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it ubuntu       // "i" - interactive mode (user can key in input)
                            // "t" - pseudo-TTY (terminal)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're inside the ubuntu container! You can treat it as a Linux shell and can run any Linux command.&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fc9ye3y7y9eshyrlj97lb.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.amazonaws.com%2Fuploads%2Farticles%2Fc9ye3y7y9eshyrlj97lb.png" alt="run ubuntu" width="800" height="355"&gt;&lt;/a&gt;&lt;br&gt;
To exit the ubuntu container, run &lt;code&gt;exit&lt;/code&gt;. As soon as you exit, the &lt;em&gt;process bash&lt;/em&gt; of ubuntu gets terminated, and the container will stop running.&lt;/p&gt;

&lt;p&gt;Additional Information: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;busybox is smallest Linux image with minimal Linux utilities&lt;/li&gt;
&lt;li&gt;alpine is based on top of busybox&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rate Limiting Explained Simply - Part 1</title>
      <dc:creator>Mel Wang</dc:creator>
      <pubDate>Wed, 11 Feb 2026 18:43:44 +0000</pubDate>
      <link>https://dev.to/mel_wang_bd07bd519fc32037/rate-limiting-explained-simply-part-1-48o6</link>
      <guid>https://dev.to/mel_wang_bd07bd519fc32037/rate-limiting-explained-simply-part-1-48o6</guid>
      <description>&lt;p&gt;It’s a normal day. Your API is running smoothly. Then suddenly…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU spikes&lt;/li&gt;
&lt;li&gt;Database connections max out&lt;/li&gt;
&lt;li&gt;Latency explodes&lt;/li&gt;
&lt;li&gt;Users start seeing errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Maybe a bot started hammering your endpoint.&lt;br&gt;
Maybe a client had a retry bug.&lt;br&gt;
Maybe you just went viral.&lt;/p&gt;

&lt;p&gt;Whatever the reason, your system was not prepared for the flood. What you needed was a way to control how fast requests are allowed in. That’s where rate limiting comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Rate Limiting?
&lt;/h2&gt;

&lt;p&gt;A rate limiter controls how many requests are allowed within a specific time window. It protects your system from overload and ensures fair usage.&lt;/p&gt;

&lt;p&gt;Think of it like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A toll booth controlling traffic on a highway&lt;/li&gt;
&lt;li&gt;A dam regulating water flow&lt;/li&gt;
&lt;li&gt;A bouncer letting people into a club at a controlled pace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not about blocking users. It’s about keeping your system &lt;strong&gt;alive&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do We Need Rate Limiting?
&lt;/h2&gt;

&lt;p&gt;Rate limiting isn’t just a “nice-to-have.” It solves very real problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Protect Infrastructure
&lt;/h3&gt;

&lt;p&gt;Without limits, a sudden spike can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exhaust database connections&lt;/li&gt;
&lt;li&gt;Overwhelm CPU&lt;/li&gt;
&lt;li&gt;Trigger cascading failures&lt;/li&gt;
&lt;li&gt;Rate limiting acts as a safety valve.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Prevent Abuse
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Attackers and bots don’t politely slow down.&lt;/li&gt;
&lt;li&gt;Common abuse scenarios:

&lt;ul&gt;
&lt;li&gt;Brute-force login attempts&lt;/li&gt;
&lt;li&gt;Credential stuffing&lt;/li&gt;
&lt;li&gt;Scraping&lt;/li&gt;
&lt;li&gt;DDoS-style request floods&lt;/li&gt;
&lt;li&gt;Rate limiting is often your first line of defense.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Ensure Fair Usage
&lt;/h3&gt;

&lt;p&gt;If one client sends 10,000 requests per second and another sends 5. Should the first client consume everything? Probably not. Rate limiting ensures that no single user can monopolize your resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Control Costs
&lt;/h3&gt;

&lt;p&gt;Many systems rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paid third-party APIs&lt;/li&gt;
&lt;li&gt;Database operations&lt;/li&gt;
&lt;li&gt;Cloud compute&lt;/li&gt;
&lt;li&gt;Uncontrolled traffic = higher bills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rate limiting protects your wallet too.&lt;/p&gt;

&lt;h2&gt;
  
  
  So How Do I Add It Into My App?
&lt;/h2&gt;

&lt;p&gt;At this point you might be thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This all makes sense. But how do I actually add rate limiting to my system?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are three common approaches. Which one you choose depends on how your app is structured.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add It Inside Your Application
&lt;/h3&gt;

&lt;p&gt;The simplest way is to implement it directly in your &lt;strong&gt;backend&lt;/strong&gt; code.&lt;/p&gt;

&lt;p&gt;You keep a counter per user (or IP), track how many requests they’ve made, and reset it every time window.&lt;/p&gt;

&lt;p&gt;This works great if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a single server&lt;/li&gt;
&lt;li&gt;You’re building something small&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the moment you scale to multiple instances behind a load balancer, each instance keeps its own counter. Your “100 requests per second” limit can quietly turn into 500. That’s usually not what you intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Let Your API Gateway Handle It
&lt;/h3&gt;

&lt;p&gt;In many production systems, rate limiting lives at the gateway level. Tools like NGINX, API Gateway, or Cloudflare can enforce limits before traffic even reaches your application.&lt;/p&gt;

&lt;p&gt;This has a big advantage: You don’t touch your code.&lt;/p&gt;

&lt;p&gt;You configure rules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100 requests per minute per IP&lt;/li&gt;
&lt;li&gt;1000 requests per minute per API key
And the gateway enforces them consistently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For many teams, this is the cleanest solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Use a Shared Store (Like Redis)
&lt;/h3&gt;

&lt;p&gt;Once you’re running multiple instances, you need shared state. That’s where something like &lt;strong&gt;Redis&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;Instead of each server counting independently, they all increment the same counter stored in Redis. Because Redis operations can be atomic, you avoid race conditions and keep your limits accurate. This is the typical solution in distributed systems.&lt;/p&gt;

&lt;p&gt;Stay tuned for Part 2!&lt;/p&gt;

</description>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
