Docker Desktop Was Too Heavy, So I Migrated to LazyDocker on WSL2
Memory pressure in a development environment is a serious problem.
Even with 32GB of RAM in your machine, running a browser, an IDE, and — more recently — a local LLM (Ollama and the like) at the same time will exhaust your resources in no time.
Open Task Manager, and the processes sitting at the top are consistently Docker Desktop-related processes and a bloated Vmmem.
What is Vmmem?
It is the Windows-side process that manages the memory and CPU resources used by virtual machines such as WSL2.
When you use memory on the WSL2 side, the memory usage of this Vmmem on the Windows side increases accordingly.
All you want is to “check container status in a GUI,” yet keeping a heavyweight virtual machine management process resident just for that is hardly the optimal answer from a resource-efficiency standpoint.
So in this article, I’ll show how to uninstall Docker Desktop and migrate to a WSL2-native Docker Engine + LazyDocker.
On top of that, I’ll build an operational flow that “starts only when you need it and releases memory immediately when you’re done,” squeezing every bit of performance out of your development machine.
Prerequisite: systemd must be enabled in WSL2.
/etc/wsl.confneedssystemd=trueset in a[boot]section.
Goals of This Article
- Install the latest version of Go on WSL2
- Set up the native Docker Engine and disable its automatic startup
- Set up LazyDocker for a comfortable, mouse-free management environment
- Create a powerful alias that goes “start → work → fully stop” with a single command
Step 1. Installing Go (Golang)
LazyDocker is a tool written in Go.
You could download the binary directly, but keeping a Go environment in place makes update management easier and makes it simpler to install other modern CLI tools, so we’ll set it up first.
Run the following on WSL2 (Ubuntu).
Note: apt install golang often ships an outdated version, so here we’ll fetch and install the binary from the official site (if you’d rather manage it with something like nvm, that’s fine too).
# Remove any existing old Go installation
sudo rm -rf /usr/local/go
# Download and extract the latest version
# Check https://go.dev/dl/ for the latest version
wget https://go.dev/dl/go1.26.1.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.26.1.linux-amd64.tar.gz
# Add to PATH (also add $HOME/go/bin for go install binaries)
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc
# Verify
go version
Step 2. Installing the Native Docker Engine and Making It On-Demand
This is the heart of the article.
We’ll remove Docker Desktop, install the pure Linux version of the Docker Engine, and then go all the way to configuring it so that it “doesn’t start on its own at PC boot (disabling systemd auto-start)” in one pass.
Save the following script as setup_docker.sh and run it.
#!/bin/bash
set -e
echo ">>> [Phase 1] Removing old Docker-related files..."
# Clean out Docker Desktop and old packages
sudo apt-get remove -y docker docker-engine docker.io containerd runc || true
echo ">>> [Phase 2] Setting up the repository..."
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# Add the GPG key and repository (official up-to-date steps)
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Register the repository in DEB822 format
sudo tee /etc/apt/sources.list.d/docker.sources << EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
echo ">>> [Phase 3] Installing the Native Docker Engine..."
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Allow running docker commands without sudo
sudo usermod -aG docker $USER
# Apply the group change (re-login also works)
newgrp docker
echo ">>> [Phase 4] Disabling auto-start (preparing on-demand operation)..."
# This is the important part. Don't let Docker start at PC boot.
sudo systemctl disable docker
sudo systemctl disable containerd
sudo systemctl stop docker.service docker.socket
echo ">>> Setup complete."
Command to run:
chmod +x setup_docker.sh
./setup_docker.sh
Step 3. Installing LazyDocker
Since the Go environment is in place, installation takes just a moment.
go install github.com/jesseduffield/lazydocker@latest
If it doesn’t work due to Go path configuration or the like, you can also install it with the following installation script.
curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash
The script method installs it to ~/.local/bin. If that isn’t on your PATH, add it:
echo 'export PATH=$PATH:$HOME/.local/bin' >> ~/.bashrc
Now the lazydocker command is available.
Step 4. Operation: Setting Up the Magic Alias
With the setup so far, we’ve reached a state where “Docker is installed but not running (zero memory usage).” Now we’ll write configuration into .bashrc so we can wake it up only when we need it and release memory immediately when we’re done.
Append the following to the end of ~/.bashrc.
# --- Docker Control Center ---
# 1. Manual start function
# Start the service and wait until the Docker socket responds
dstart() {
if systemctl is-active --quiet docker; then
echo "Docker is already running."
else
echo "Wake up Docker..."
sudo systemctl start docker
# Wait until the socket is ready (without this you'll get an error)
while ! docker info > /dev/null 2>&1; do
printf "."
sleep 1
done
echo -e "\nDocker is ready."
fi
}
# 2. Full stop function
# Stop the service and socket, and release memory
dstop() {
echo "Shutting down Docker..."
sudo systemctl stop docker.service docker.socket
echo "Docker is dead. RAM released."
}
# 3. Convenient alias
# [start] -> [work in LazyDocker] -> [auto-stop on exit]
alias lazy='dstart && lazydocker && dstop'
Apply the configuration.
source ~/.bashrc
The Actual Workflow
Everything is ready.
All that’s left is to type this command in the terminal.
lazy
With just that, the following flow runs automatically.
- Docker starts: the engine spins up only when you need it.
- LazyDocker starts: a rich TUI lets you check container logs, restart, and clean up.
- Work ends: press the q key to close LazyDocker.
- Auto-stop: dstop runs immediately, and the Docker process is killed.
Mouse operation is possible too, but being able to work snappily with the keyboard alone is a real pleasure.
The Last Resort for Freeing Memory
When using WSL2, you may find that the memory usage of the Vmmem process is slow to drop even after you stop your Docker containers (because the page cache on the Linux side lingers).
When you truly want to reclaim memory, running the following command after exiting via lazy returns physical memory to the Windows side.
# Clear the cache and forcibly release memory
sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
Summary
- Docker Desktop is convenient, but it eats resources (memory in particular).
- With LazyDocker, you can keep the comfort of a TUI while eliminating resident processes.
- In a WSL2-native environment, even releasing memory can be controlled with a single command.
The 4GB you free up can go toward whatever you want to do — loading a larger LLM model, opening more browser tabs, and so on.
If you’re thinking about putting your development environment on a diet, give it a try.
