Run Code Anywhere: A Modern Guide to Docker


Run Code Anywhere: A Modern Guide to Docker

Imagine a world where your code runs flawlessly across any environment – from your laptop to production servers – without the dreaded "but it works on my machine" syndrome.

That's the promise of containers, and they've revolutionized how we develop, test, and deploy applications.

Containers emerged as a solution to the chaos of maintaining traditional servers, where applications would conflict with each other and overwrite data.

Using Linux namespaces, containers create isolated environments that efficiently allocate resources without interfering with neighboring processes. Which is a fancy way to say you can split CPU and memory without starving other process on the host.

This technology has evolved from virtual machines to the containerization we know today, making development more consistent and deployment more reliable, but most importantly, more resource efficient.

What's the Problem?

Back in the day (10-20 years ago), companies used to hold in-house massive servers in their basements.

These servers ran multiple applications that frequently conlicting with each other – requiring different versions of utilities, fighting over disk space and memory, and as a result sometimes overwriting each other's data.

It was a maintenance nightmare (although at the time, it was just "IT life").

Virtual Machines Changed Everything

The tech world's first attempt at solving this was virtual machines – completely isolated environments with their own operating systems.

While this worked, it was resource-intensive and inefficient.
Don't get me wrong, this technology was born in the seventies, and was the go-to approach for about three decades, but we're here to talk about modern days.

Virtual machines essentially duplicate entire operating systems, consuming significant resources.

The Container Approach: Lightweight Isolation

Containers emerged based on Linux namespaces, creating efficient isolation without the overhead.

They allow different applications to run side-by-side without conflict, sharing the same underlying system while maintaining separation.

This means you can:

  1. Run multiple applications without conflicts
  2. Ensure consistent environments from development to production
  3. Use minimal resources compared to virtual machines
  4. Package applications with all their dependencies

“With Docker, you can spin up a new container in seconds, which is significantly faster than provisioning a full virtual machine, leading to faster development cycles and improved agility.”

- The Docker documentation

Essential Container Commands

Basic Commands:

  • podman/docker ps - List running containers
  • podman/docker ps -a - List all containers (including stopped ones)
  • podman/docker images - View stored container images
  • podman/docker pull [image] - Download container images
  • podman/docker run [image] - Start a container
  • podman/docker run -it [image] sh - Start a container with interactive shell
  • podman/docker run -d [image] - Run container in detached mode
  • podman/docker run -p [host:container] - Map ports between host and container
  • podman/docker run -P - Map random ports
  • podman/docker stop [container] - Stop a running container
  • podman/docker container prune - Remove all stopped containers

Build and Management:

  • podman/docker build -t [name] . - Build a container from Dockerfile
  • podman/docker tag [id] [name] - Add a name to an existing image
  • podman/docker exec -it [container] sh - Get a shell in a running container

Compose Commands:

  • podman/docker compose up - Start multi-container environment
  • podman/docker compose down - Stop and remove multi-container environment
  • podman/docker compose logs - View logs from compose environment
  • podman/docker compose stop [service] - Stop specific service in compose
  • podman/docker compose start [service] - Start specific service in compose

Building Efficient Containers

Building containers is rather easy, and while there are tools to help with that, here's a simple Golang image:

FROM golang:alpine
WORKDIR /app
COPY . .
RUN go build
EXPOSE 8080
CMD ["./main"]

Run `docker build -f my-container.Dockerfile .` (can skip the -f

A pro tip is the multi-stage build approach.

This dramatically reduces container size by using one container to build the application and another minimal container to run it (basically implementing a CI pipeline into your container build process):

FROM golang:alpine AS builder
WORKDIR /app
COPY . .
RUN go build

FROM scratch
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

What we did here is to build the app as usual, then take only the binary artifact into a distro-less image!

This approach reduced the container size from 340MB to just 7MB!!!


Development Workflow Enhancement

For development, mounting your local directory to the container creates a powerful workflow:

services:
app:
image: myapp
volumes:
- ./:/app
command: tail -f /dev/null

This setup lets you make code changes on your local machine and see them instantly reflected in the container, streamlining the development-test cycle.

All that's left is to `docker exec -it

Containers have transformed development workflows from frustrating environment mismatches to seamless, consistent experiences.

Whether you're a solo developer or part of a large team, mastering containers is now an essential skill that will make your code run smoothly anywhere, and makes team work, open source, or just life-long projects because infinitely easier to maintain and work on!


Thank you for reading.
Feel free to reply directly with any question or feedback.
Have a great weekend!

ESPRESSO FRIDAYS

Every once in a while I send hand picked things I've learned. Kind of like your filter to the tech internet. No spam, I promise!

Read more from ESPRESSO FRIDAYS

Google's Git Killer Is INSANELY Better (and it's open source) You saw the title. Bold claim, right? "Insanely better"? Than Git? Git is the foundation of modern software development. It started back around 20 years ago, when Linus tried to build his first Linux kernel, and had enough of SVN. So Linus being Linus, he just went ahead and built his own. But what if the way we've always done version control isn't the only way, or even the best way anymore? That's the core idea behind Jujutsu (jj)...

You Need To Learn Docker Swarm! Ever felt like you're overcomplicating your container deployments? You might be. Today, we're diving into a Docker orchestrator that's likely already on your machine (run `docker service` for a second will ya?), but you're probably overlooking: Docker Swarm. The Underdog Orchestrator For years (for me, the past 11 years to be exact), the path has seemed to be either simple Docker Compose or the more, WAY MORE complex, Kubernetes. Compose is great for local...

LimaVM Is Probably The Best MacOS Virtual Machine I've Ever Used If you're tired of Docker Desktop bogging down your machine, or simply don't like fuff of mapping ports, mounting volumes when all you need is a small virtual environment, this one's for you. I recently discovered LimaVM, and it's a game-changer for local development. It lets you spin up Linux VMs with ease, offering a faster, lighter alternative to Docker and other VM managers for many tasks, but especially for development....