Explore and analyze a Docker container with DockerSlim X-Ray

Understanding container composition
Martin Wimpress
Apr 20, 2021

Prerequisites to complete this example

  1. Basic knowledge of Linux commands and a terminal
  2. Docker Desktop installed on your host machine.
  3. A text editor or browser to view .JSON files

For video instructions, click here: Understand what’s inside a Docker container

Download and test DockerSlim

  • Download DockerSlim from here: https://dockersl.im/
  • Create a folder and copy the files from the DockerSlim download into the folder. My folder looks like this.

  • Run DockerSlim to check if it’s working.

Type docker-slim help into a terminal window.

Note: I added the folder path I created to the /etc/paths file. If the directory where you extracted the binaries is not in your PATH then you’ll need to run your docker-slim commands from that directory. You can type ./docker-slim help to run DockerSlim in this case.

  • DockerSlim has a cool menu driven command line. To try that:

Type docker-slim into a terminal window then type help at the interactive prompt

We use the xray command for this example.

Find a publicly available container on DockerHub to examine with DockerSlim xray

I decided to use a container with nuxt.js and node.js for this example. Nuxt.js is gaining popularity as a web app framework for vue.js. My team has been working with nuxt.js lately, so its interesting to me.

  • Open DockerHub and type nuxt into the search bar. You can also just click this link:

https://hub.docker.com/search?q=nuxt&type=image

I selected the first result for simplicity. It’s been downloaded a bunch of times and seems to have nuxt.js and node.js foundations and a decent GitHub page.

  • Pull the container using the Docker Pull Command

From a terminal window type docker pull gerardojunior/nuxtjs

Note: You need Docker Desktop installed on your host to continue this example.

After the pull command completes, check to see that the image is loaded using the docker images command

Run the DockerSlim xray command on the target container

From a terminal window type

xray --target gerardojunior/nuxtjs:latest

DockerSlim creates a .json report file named slim.report.json

Examine the DockerSlim xray results

  • Basic facts about this container found in the xray report

Created date = 2/1/2019 — the image has not been updated in 2 years
Image Size = 69MB
Exposed Ports = 3000/TCP

From the slim.report.json file:

    "source_image": {
        "id": "sha256:602502213c4a3e53ed290235ac955eac6fecd77808942b0e962e83946a62ab70",
        "name": "gerardojunior/nuxtjs:latest",
        "size": 68552646,
        "size_human": "69 MB",
        "create_time": "2019-02-01T04:21:20Z",
        "all_names": [
          "gerardojunior/nuxtjs:latest"
        ],
        "docker_version": "18.03.1-ee-3",
        "architecture": "amd64",
        "user": "node",
        "exposed_ports": [
          "3000/tcp"
        ]
      }
  • Exploring the container’s layers listed in the xray report

The report file contains a listing (“image_stack label”) of the docker image layers ordered by layer detailing Dockerfile command(s) that contributed to each layer.

Find the image_stack: array in the slim.report.json file.

This container has a single image. Each Dockerfile command is listed in the "instructions": array. In the snippet below notice that the "ADD" instruction contibuted to "layer_index": 0,. Peruse the report to find the total number if layer indices. This container has a total of 8 layers.

"image_stack": [
  {
    "is_top_image": true,
    "id": "sha256:602502213c4a3e53ed290235ac955eac6fecd77808942b0e962e83946a62ab70",
    "full_name": "gerardojunior/nuxtjs:latest",
    "repo_name": "gerardojunior/nuxtjs",
    "version_tag": "latest",
    "raw_tags": [
      "gerardojunior/nuxtjs:latest"
    ],
    "create_time": "2019-02-01T04:21:20Z",
    "new_size": 68552646,
    "new_size_human": "69 MB",
    "instructions": [
      {
        "type": "ADD",
        "time": "2018-12-21T00:21:29Z",
        "is_nop": true,
        "local_image_exits": false,
        "layer_index": 0,
        "layer_id": "5491dce778832e33c284cd8185100e76d6daa18f8cbc32458c706776894127fc",
        "layer_fsdiff_id": "sha256:7bff100f35cb359a368537bb07829b055fe8e0b1cb01085a3a628ae9c187c7b8",
        "size": 4413428,
        "size_human": "4.4 MB",
        "params": "file:2ff00caea4e83dfade726ca47e3c795a1e9acb8ac24e392785c474ecf9a621f2 in /",
        "command_snippet": "ADD file:2ff00caea4e83dfade726ca47e3c795a1e9...",
        "command_all": "ADD file:2ff00caea4e83dfade726ca47e3c795a1e9acb8ac24e392785c474ecf9a621f2 /",
        "target": "/",
        "source_type": "file"
      },

The image layer information listed in the "image_layers": array is useful for understanding what files and consequently what software and related files are in the container. The layer information is organized by index indicated by the "index": tag. Search for index 0 in the image layers list.

Layer 0

Seek the "top": tag and you can view the files contained in layer 0. Layer 0 is comprised of common Linux OS files from the Alpine base image.

"top": [
  {
    "change": "A",
    "name": "lib/libcrypto.so.43.0.1",
    "size": 1734840,
    "mode": 493,
    "mod_time": "2018-06-14T02:30:35-04:00",
    "change_time": "0001-01-01T00:00:00Z"
  },
  {
    "change": "A",
    "name": "bin/busybox",
    "size": 796312,
    "mode": 493,
    "mod_time": "2018-12-06T10:13:58-05:00",
    "change_time": "0001-01-01T00:00:00Z"
  },
  {
    "change": "A",
    "name": "lib/ld-musl-x86_64.so.1",
    "size": 584168,
    "mode": 493,
    "mod_time": "2018-06-19T03:48:15-04:00",
    "change_time": "0001-01-01T00:00:00Z"
  },

Layer 1

Layer 1 contains files associated with node.js. It is the largest layer (56.8MB) and contains the largest single file usr/local/bin/node (36.4MB). This file is the node.js executable binary image.

{
  "id": "eaabbaf2e7fe2603c758103f3f9397a82ea9c1f39e421735753afef370323a1f",
  "index": 1,
  "path": "eaabbaf2e7fe2603c758103f3f9397a82ea9c1f39e421735753afef370323a1f/layer.tar",
  "stats": {
    "all_size": 56810567,
    "object_count": 4178,
    "dir_count": 711,
    "file_count": 3463,
    "link_count": 4,
    "max_file_size": 36468360,
    "max_dir_size": 0,
    "deleted_count": 1,
    "deleted_dir_count": 0,
    "deleted_file_count": 1,
    "deleted_link_count": 0,
    "deleted_size": 0,
    "added_size": 56786658,
    "modified_size": 23909
  },
  "changes": {
    "deleted": 1,
    "added": 4146,
    "modified": 31
  },
  "top": [
    {
      "change": "A",
      "name": "usr/local/bin/node",
      "size": 36468360,
      "mode": 493,
      "mod_time": "2018-12-26T20:40:30-05:00",
      "change_time": "0001-01-01T00:00:00Z"
    },

Layer 2

Layer 2 contains the files associated with the popular package manager Yarn. Yarn is used to configure this container for nuxt.js and also allows developers using this container to easily add and manage packages.

Note: Package managers are good to include in containers for development purposes but should generally be stripped out of production containers to ensure immutability and adhere to production-ready container best practices.

{
  "change": "A",
  "name": "opt/yarn-v1.12.3/README.md",
  "size": 3174,
  "mode": 420,
  "mod_time": "2018-11-07T10:13:08-05:00",
  "change_time": "0001-01-01T00:00:00Z"
},
{
  "change": "A",
  "name": "opt/yarn-v1.12.3/LICENSE",
  "size": 1355,
  "mode": 420,
  "mod_time": "2018-11-07T10:13:08-05:00",
  "change_time": "0001-01-01T00:00:00Z"
},
{
  "change": "M",
  "name": "root/.gnupg/trustdb.gpg",
  "size": 1200,
  "mode": 384,
  "mod_time": "2018-12-26T20:22:33-05:00",
  "change_time": "0001-01-01T00:00:00Z"
},
{
  "change": "A",
  "name": "opt/yarn-v1.12.3/bin/yarn",
  "size": 1025,
  "mode": 493,
  "mod_time": "2018-11-07T10:13:08-05:00",
  "change_time": "0001-01-01T00:00:00Z"
}

Layers 6,7 and 8

Layers 6,7 and 8 include the container entrypoint definition and the .sh scripts for nuxt.js.

Layer 6 snippet showing the ENTRYPOINT command

{
  "type": "USER",
  "time": "2019-01-17T18:19:19Z",
  "is_nop": true,
  "local_image_exits": false,
  "layer_index": 6,
  "layer_id": "ee754c9068ed8fccbbd95b642f4f4c069d54e94229a0595ce02b91e16c240c03",
  "layer_fsdiff_id": "sha256:a7f1fa57d58b715c742a983028810777b521e878812e61f26cab0290f967feeb",
  "size": 0,
  "params": "node",
  "command_snippet": "USER node",
  "command_all": "USER node",
  "empty_layer": true
},
{
  "type": "ENTRYPOINT",
  "time": "2019-01-17T18:19:19Z",
  "is_nop": true,
  "is_exec_form": true,
  "local_image_exits": false,
  "layer_index": 6,
  "layer_id": "ee754c9068ed8fccbbd95b642f4f4c069d54e94229a0595ce02b91e16c240c03",
  "layer_fsdiff_id": "sha256:a7f1fa57d58b715c742a983028810777b521e878812e61f26cab0290f967feeb",
  "size": 0,
  "params": "[\"/bin/sh\",\"/opt/tools/entrypoint.sh\"]",
  "command_snippet": "ENTRYPOINT [\"/bin/sh\",\"/opt/tools/entrypoint...",
  "command_all": "ENTRYPOINT [\"/bin/sh\",\"/opt/tools/entrypoint.sh\"]",
  "empty_layer": true
},

Layer 7 snippet showing the nuxt.js entrypoint shell script (opt/tools/entrypoint-nuxtjs.sh)

{
  "id": "a38c549dca9e68603ab2a47a06b1cdfe3d9d733f5e29d3efb953e36b9e17d8a9",
  "index": 7,
  "path": "a38c549dca9e68603ab2a47a06b1cdfe3d9d733f5e29d3efb953e36b9e17d8a9/layer.tar",
  "stats": {
    "all_size": 180,
    "object_count": 3,
    "dir_count": 2,
    "file_count": 1,
    "link_count": 0,
    "max_file_size": 180,
    "max_dir_size": 0,
    "deleted_count": 0,
    "deleted_dir_count": 0,
    "deleted_file_count": 0,
    "deleted_link_count": 0,
    "deleted_size": 0,
    "added_size": 180,
    "modified_size": 0
  },
  "changes": {
    "deleted": 0,
    "added": 1,
    "modified": 2
  },
  "top": [
    {
      "change": "A",
      "name": "opt/tools/entrypoint-nuxtjs.sh",
      "size": 180,
      "mode": 420,
      "mod_time": "2019-01-31T23:20:58-05:00",
      "change_time": "0001-01-01T00:00:00Z"
    },

From this analysis, we can see this container is primarily composed of:

  • Remnants of Alpine Linux including the busybox toolkit
  • Node.js and related packages
  • The Yarn package manager
  • Scripts and other tools to configure nuxt.js and set the entry point to invoke nuxt.

DockerSlim Resources

If you want to learn lots more about DockerSlim look here:

https://github.com/docker-slim/docker-slim

The full details of the DockerSlim xray command can be found here:

https://github.com/docker-slim/docker-slim#xray-command-options

Banner photo by Markus Winkler on Unsplash.

Related Articles

5 Most Commonly Asked DockerSlim Questions

We enlisted DockerSlim expert and Slim.AI Developer Experience Engineer to dive into how container slimming works.

Primož Ajdišek

Technical Staff

5 Ways Slim Containers Save You Money

Do slim containers really save you money on your cloud bill? Are there cost advantages to smaller containers? Find out here.

Chris Tozzi

Automating DockerSlim in Your CICD Pipeline

Using GitHub Actions, you can refine container images automatically making them smaller, faster to load, and more secure by default – all without sacrificing any capabilities.

Nicolas Bohorquez

Contributor

Building Apps Using Cloud Native Buildpacks

Getting started with this innovative technique

Vince Power

Contributor

Building DockerSlim into a Jenkins Pipeline

A step by step tutorial on building DockerSlim into your CI/CD pipeline.

Clarifying the Complex: Meet Ivan Velichko, Container Dude at Slim.AI

Ivan recently joined the team at Slim.AI, and we sat down with him to learn more about the path that led him here.

Ivan Velichko

Container Dude

Container Insights: Dissecting the World's Most Popular Containers

Join Ayse Kaya in this series, as she creates her 2022 Container Report Chalk Full of Important Security Findings for Developers.

Ayse Kaya

Analytics & Strategy

Container of the Week: Python & Flask

Our weekly breakdown of a popular container

What We Discovered Analyzing the Top 100 Public Container Images

Complexity abounds in modern development

Ayse Kaya

Analytics & Strategy

2022 Public Container Report

Vulnerabilities continue to increase and developers are struggling to keep up.

Ayse Kaya

Analytics & Strategy

Containerizing Python Apps for Lambda

A tutorial on deploying AWS Lambda using containers, Python edition.

Docker Containers for Your Raspberry Pi

Compact PCs need compact apps

Martin Wimpress

Community

Five Proven Ways to Debug a Container

When Things Just Are Not Working

Theofanis Despoudis

Contributor

Five Things You Should Never Ship to Production in a Container

Here is our take on five things to avoid when creating a container or shipping it to production.

Chris Tozzi

Increasing Your CI/CD Velocity with Slim Containers

We’ll explain what Slim Containers are, how they speed up the build process, and how they can improve the efficiency of your testing.

Mike Mackrory

Contributor

Integrate Testing into Your Container Pipeline

A closer look at testing within container pipelines, CI/CD, software delivery, and containerization.

Faith Kilonzi

Software Engineer

Reducing Docker Image Size - Slimming vs Compressing

Know the difference

Pieter van Noordennen

Growth

Serverless Applications and Docker

How to Scale the Latest Trend in Infrastructure

Pieter van Noordennen

Growth

Slim.AI Docker Extension for Docker Desktop

How to access our Docker Extension and try it for yourself.

Josh Viney

Product

Slimming a Rails Application with DockerSlim

Dissect a simple Rails application container using DockerSlim to analyze, optimize, and deploy your product more quickly.

Theofanis Despoudis

Contributor

Where Do You Store Your Container Images?

Container Registry Options are Growing in Number and Complexity

Pieter van Noordennen

Growth

Using AppArmor and SecComp Profiles for Security Audits

Conduct better container security audits using tools like SecComp, NGINX, and Docker.

What’s in your container?

Why Docker Layers matter for container optimization

Pieter van Noordennen

Growth

Why Developers Shouldn't Have to Be Infrastructure Experts, Too

Simplifying processes required to containerize and deploy cloud-native apps.

Chris Tozzi

A New Workflow for Cloud Development

Leverage the benefits of containerization without the headaches & hassle

John Amaral

CEO

Why Don’t We Practice Container Best Practices?

Container best practices are easy to understand, hard to do

John Amaral

CEO

Better Security Audits with AppArmor and SecComp via DockerSlim

Combine the power of tools like SecComp, NGINX, and Docker.

Automatically reduce Docker container size using DockerSlim

REST Web Service example using Python/Flask

John Amaral

CEO

Comparing Container Versions with DockerSlim and Slim.AI

See differences between your original and slimmed images

Pieter van Noordennen

Growth

In the Media: DockerSlim and Slim.AI

Latest Mentions

Slim.AI and OSI: Why We Advocate for Open Source

Slim.AI continues its support of OSI and sponsors the OSI licensing API as a part of its ongoing advocacy for open source

Pieter van Noordennen

Growth

The DockerSlim Origin Story

How DockerSlim got its start at Docker's Global Hack Day, and the creation of Slim.AI.

Kyle Quest

CTO

What DockerSlim Users Get Out of Slim's SaaS Platform

Scaling Your Container Game

Martin Wimpress

Community