Docker Ecosystem Tools

Docker Ecosystem Tools

Bitnesia Sep 14, 2026 11 ID

The official docker CLI command is sufficient to run almost all daily needs, but as the number of containers grows, Sysadmins/DevOps Engineers and Developers often need faster ways to monitor, clean up, and manage those resources. This is where the third-party tool ecosystem around Docker comes into play: some provide visual web-based interfaces, some take the form of interactive dashboards in the terminal, some specialize in analyzing image layer contents to find wasted space, some automate container updates, and some unite the entire development environment into a container for consistency across all machines. This chapter covers five popular tools: Portainer, lazydocker and ctop, Dive, Watchtower, and Dev Containers in VS Code, complete with installation methods, basic usage, and risk notes for each.

44.1 Portainer: GUI Management for Docker

Portainer is a web interface that displays containers, images, volumes, and networks in a visual dashboard, allowing Sysadmins/DevOps Engineers newly entering a Docker host to immediately view the overall system status without typing a series of docker ps, docker inspect, or docker logs commands one by one. This tool also helps Developers who are not yet familiar with the Docker CLI to still run, stop, or view container logs via clicks in a browser.

44.1.1 Installing Portainer CE with Docker

Portainer Community Edition (CE) is distributed as an official Docker image, so the most practical way to run it is through a container itself. First, create a named volume to store Portainer configuration data so it is not lost when the container is updated.

docker volume create portainer_data

Run the Portainer container by mounting the Docker daemon socket, allowing Portainer to read and control all Docker resources on that host.

docker run -d -p 8000:8000 -p 9443:9443 \
  --name portainer --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

Port 9443 serves the web interface over HTTPS, while port 8000 is used for the tunnel server feature when connecting Portainer to an Edge Agent in another environment. Once the container is running, open https://localhost:9443 (replace localhost with the appropriate host address) to create an admin account for the first time. It should be noted that mounting /var/run/docker.sock into a container grants Portainer full root-equivalent access to the Docker daemon on the host, so restrict network access to Portainer ports only to authorized users, especially on production servers exposed to the internet.

44.1.2 Managing Containers via Portainer

After logging in, Portainer displays an Environment representing a single Docker daemon (which can be a local host or remote via the Docker API). From the environment dashboard, we can see a summary of the number of running and stopped containers, total images, volumes, and networks, then navigate to the Containers menu to start, stop, restart, or delete containers directly via buttons without typing CLI commands.

The Stacks menu in Portainer accepts a docker-compose.yml file directly through a built-in editor or file upload, then deploys it as a single stack unit, equivalent to running docker compose up -d but through a web interface. In practice, this combination is often used by small teams wanting to give non-technical members limited access to monitor application status without teaching them Docker CLI commands, using the Users and Role-Based Access Control features in Portainer to limit which environments or stacks they are allowed to view and modify.

Verify that Portainer correctly reads the Docker daemon state by comparing the number of containers displayed on the dashboard with the output of a standard CLI command.

docker ps -a --format '{{.Names}}: {{.Status}}'

If Portainer fails to connect or displays empty data even though containers are clearly running, the most common cause is a socket mount of /var/run/docker.sock that does not match its actual path on the host, or permissions on that socket preventing access by the user inside the Portainer container.

44.2 Lazydocker and ctop: Terminal-Based Monitoring

Not all Sysadmins/DevOps Engineers have direct browser access to a server, especially when working over SSH connections to remote machines. For such conditions, terminal-based dashboards like lazydocker and ctop serve as lighter alternatives to Portainer because they run directly in the terminal without opening additional ports or a browser at all.

44.2.1 Lazydocker Installation and Usage

Lazydocker is an interactive text interface summarizing container statuses, images, volumes, and logs onto a single screen, with navigation using keyboard or mouse. The fastest installation on Linux or macOS uses the following official script.

curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash

A more transparent method (without running scripts directly from the internet) is via Homebrew on macOS or Linux with brew installed.

brew install jesseduffield/lazydocker/lazydocker

Run lazydocker directly from the terminal after installation.

lazydocker

The lazydocker screen is divided into several panels: container list, image list, volume list, and a log/details panel on the right side. Move between containers using arrow keys, then press specific letters (shown as hints at the bottom of the screen) to restart, stop, or exec into the selected container, without needing to manually type container names as in standard docker exec commands. For Developers working with multiple services via Docker Compose in local development, lazydocker is very helpful for monitoring logs of multiple services simultaneously without opening separate terminals for each docker compose logs -f.

44.2.2 ctop Installation and Usage

ctop has a narrower focus than lazydocker: displaying resource metrics (CPU, memory, network, disk I/O) for each container in real-time in a view similar to Linux's built-in top command. Installation on Linux can use the binary directly from official releases.

sudo wget https://github.com/bcicen/ctop/releases/download/v0.7.7/ctop-0.7.7-linux-amd64 \
  -O /usr/local/bin/ctop
sudo chmod +x /usr/local/bin/ctop

Run ctop without extra arguments; the tool automatically reads the Docker daemon via the default socket.

ctop

Press s to select sorting columns (such as highest CPU or memory usage), r to reverse sort order, and o to enter detailed view for a single container. In practice, ctop is often the first choice when Sysadmins/DevOps Engineers need to quickly check which container suddenly consumes CPU when monitoring alerts trigger, because its view is much more concise than scrolling through standard docker stats output on hosts with dozens of containers. Note that the ctop project rarely receives new release updates, so always check its official GitHub release page to ensure the installed version remains compatible with the latest Docker Engine version before installing on production servers.

44.3 Dive: Image Layer Analysis

Bloated image sizes are often not because the application itself is large, but because temporary files, package manager caches, or development dependencies remain stored in one layer despite being deleted in a subsequent layer. This issue is difficult to spot solely from docker images which only shows total size; this is where Dive serves as a dedicated tool to inspect the contents of each image layer individually.

44.3.1 Installing and Running Dive

On Debian/Ubuntu-based Linux, install Dive via the .deb package from its official release page.

DIVE_VERSION=$(curl -sL "https://api.github.com/repos/wagoodman/dive/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
curl -fOL "https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_amd64.deb"
sudo apt install ./dive_${DIVE_VERSION}_linux_amd64.deb

On macOS, installation is simpler via Homebrew.

brew install dive

Analyze an existing local image by referencing its name and tag directly.

dive nginx:1.27-alpine

Dive can also build an image directly from a Dockerfile and analyze it in a single command, ideal for repeated use when optimizing a Dockerfile.

dive build -t web-app:dev .

44.3.2 Reading Efficiency Score and Wasted Space

Dive's interface is divided into two main panels: the left panel contains a list of layers along with the Dockerfile commands that generated them, while the right panel displays the file structure inside the currently selected layer, color-coded for files added, modified, or removed relative to the previous layer. At the bottom of the screen, Dive displays an efficiency score percentage and estimated wasted space, which is the total size of files no longer used in the final layer but still occupying space because they were written in earlier layers.

The most common pitfall discovered via Dive is the pattern RUN apt-get update && apt-get install ... split across multiple RUN instructions, causing package manager cache to persist permanently in the initial layer even if RUN apt-get clean is executed later in a separate layer; the solution is combining installation and cache cleanup steps within the same RUN instruction so both reside in the same layer. For automation needs in CI/CD pipelines, run Dive in non-interactive mode via the CI environment variable, causing Dive to exit with a non-zero exit code if the efficiency score falls below a specified threshold, rather than displaying an interactive interface requiring manual input.

CI=true dive web-app:dev

A non-zero exit code from the command above can be directly used as a build failure condition in CI/CD pipeline stages, ensuring space-inefficient images do not proceed to deployment without requiring manual inspection of each output.

44.4 Watchtower: Automated Container Updates

Watchtower monitors images currently used by running containers, periodically pulls them, and automatically recreates those containers if a newer image version is detected in the registry. This tool is popular among Developers running homelabs or personal development environments because it eliminates the need to manually run docker compose pull and docker compose up -d every time an image updates.

44.4.1 Running Watchtower

Run Watchtower as a standard container by mounting the Docker daemon socket, similar to Portainer, since Watchtower requires access to inspect and replace other containers.

docker run -d --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

Without additional arguments, Watchtower monitors all running containers on that host. To limit monitoring to specific containers, specify the container names as extra arguments after the image name.

docker run -d --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower web-app db-postgres

44.4.2 Interval, Cleanup, and Notification Configuration

By default, Watchtower checks for new images every 86,400 seconds (24 hours). Change this interval using the --interval flag if checks need to occur more frequently.

docker run -d --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower --interval 3600

Add the --cleanup flag so Watchtower automatically deletes old images no longer used by any container after the update process completes, preventing disk bloat from accumulating unused older image versions.

docker run -d --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower --cleanup --interval 3600

To test configurations without waiting for scheduled intervals, use the --run-once flag to check and update containers a single time and then exit.

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower --run-once web-app

Before deploying Watchtower in production, evaluate the risks honestly: automatic updates mean containers can switch versions at any time without prior review or testing, which is dangerous if a new image introduces breaking changes. Therefore, Watchtower is much better suited for development environments, homelabs, or internal services tolerant of brief downtime, compared to critical production services that ideally rely on CI/CD pipelines with explicit testing stages before deploying new images. It is also worth noting that the official Watchtower repository (containrrr/watchtower) has been archived by its owner and marked as no longer actively maintained; older images on Docker Hub can still be pulled and used as shown above, but check the current status of the project or consider actively maintained alternatives before relying on it for long-term needs.

44.5 Dev Containers: Integrated Development Environment with VS Code

The classic "it works on my laptop, but fails on my teammate's laptop" issue often arises due to differing versions of programming languages, system libraries, or CLI tools installed on each Developer's machine. Dev Containers addresses this problem by running the complete development environment—from language runtimes to editor extensions—inside a container defined by a single configuration file committed alongside the source code.

44.5.1 devcontainer.json Structure

Dev Containers configuration is stored in the .devcontainer/devcontainer.json file at the project root. The following example defines a development environment for a Node.js project using an official base image, while automatically enabling a VS Code extension.

{
  "name": "node-app-dev",
  "image": "node:20-bookworm",
  "forwardPorts": [3000],
  "postCreateCommand": "npm install",
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint"]
    }
  },
  "remoteUser": "node"
}

The image property specifies the base image used (which can be replaced by a build property containing dockerfile and context if the environment requires a custom Dockerfile rather than a prebuilt image). The forwardPorts property automatically forwards ports from inside the container to the host machine, while postCreateCommand runs a command once after the container is first created, ideal for installing dependencies like npm install above. The customizations.vscode.extensions property ensures relevant extensions (such as linters or formatters) are automatically installed as soon as VS Code connects to the container, eliminating manual installation steps for other Developers.

Additional tools such as Git, Docker CLI inside the container, or other language runtimes can be added via the features property, pulling ready-to-use components from the Dev Container Features registry without writing manual installation steps in a Dockerfile.

{
  "name": "node-app-dev",
  "image": "node:20-bookworm",
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  }
}

44.5.2 Opening a Project with Dev Containers

First, install the official Dev Containers extension (published by Microsoft) from the VS Code Marketplace. Once the .devcontainer/devcontainer.json file is available in the project root, open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P on macOS) and run the command Dev Containers: Reopen in Container. VS Code will build (or pull) the image according to configuration, start the container, and attach the editor window directly into it, including an integrated terminal running inside the container rather than on the host machine.

Verify that the environment is running inside the container by checking the runtime version via the newly connected VS Code terminal.

node --version
which npm

If the result displays the Node.js version defined under image in devcontainer.json, rather than a potentially different version installed on the host machine, the Dev Containers configuration is working correctly. Beyond VS Code, the same devcontainer.json configuration can also be executed using the devcontainer CLI (@devcontainers/cli package) in CI/CD pipelines, ensuring testing environments in CI remain identical to local development environments across team members' laptops, closing the "environment discrepancy" gap that often causes hard-to-reproduce bugs.