Categories
DevOps

How to inspect and improve docker image using dive utility

Inspect and improve docker image using dive utility for exploring each layer in a docker image.

Download dive utility.

$ wget https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.deb

Install dive utility.

$ sudo apt install dive_0.9.2_linux_amd64.deb

Display help information.

$ dive help
This tool provides a way to discover and explore the contents of a docker image. Additionally the tool estimates
the amount of wasted space and identifies the offending files from the image.

Usage:
  dive [IMAGE] [flags]
  dive [command]

Available Commands:
  build       Builds and analyzes a docker image from a Dockerfile (this is a thin wrapper for the `docker build` command).
  help        Help about any command
  version     print the version number and exit (also --version)

Flags:
      --ci                                Skip the interactive TUI and validate against CI rules (same as env var CI=true)
      --ci-config string                  If CI=true in the environment, use the given yaml to drive validation rules. (default ".dive-ci")
      --config string                     config file (default is $HOME/.dive.yaml, ~/.config/dive/*.yaml, or $XDG_CONFIG_HOME/dive.yaml)
  -h, --help                              help for dive
      --highestUserWastedPercent string   (only valid with --ci given) highest allowable percentage of bytes wasted (as a ratio between 0-1), otherwise CI validation will fail. (default "0.1")
      --highestWastedBytes string         (only valid with --ci given) highest allowable bytes wasted, otherwise CI validation will fail. (default "disabled")
  -j, --json string                       Skip the interactive TUI and write the layer analysis statistics to a given file.
      --lowestEfficiency string           (only valid with --ci given) lowest allowable image efficiency (as a ratio between 0-1), otherwise CI validation will fail. (default "0.9")
      --source string                     The container engine to fetch the image from. Allowed values: docker, podman, docker-archive (default "docker")
  -v, --version                           display version number

Use "dive [command] --help" for more information about a command.

Display summary of the dokuwiki-container.

$ CI=true dive sleeplessbeastie/dokuwiki:latest
Using default CI config
Image Source: docker://sleeplessbeastie/dokuwiki:latest
Fetching image... (this can take a while for large images)
Analyzing image...
  efficiency: 71.8643 %
  wastedBytes: 28743992 bytes (29 MB)
  userWastedPercent: 63.0335 %
Inefficient Files:
Count  Wasted Space  File Path
    2        639 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/arm.php
    2        507 kB  /opt/dokuwiki/lib/scripts/jquery/jquery-ui.min.js
    2        413 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi.php
    2        376 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
    2        343 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
    2        294 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/mathematica.php
    2        265 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/thinbasic.php
    2        252 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
    2        248 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/autoit.php
    2        225 kB  /opt/dokuwiki/inc/JpegMeta.php
    2        224 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
    2        209 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/java5.php
    2        207 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
    2        206 kB  /opt/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php
    2        201 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
    2        198 kB  /opt/dokuwiki/vendor/simplepie/simplepie/library/SimplePie/Item.php
    2        190 kB  /opt/dokuwiki/vendor/simplepie/simplepie/library/SimplePie.php
    2        179 kB  /opt/dokuwiki/lib/scripts/jquery/jquery.min.js
    2        160 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/tsql.php
    2        154 kB  /opt/dokuwiki/inc/media.php
    2        151 kB  /opt/dokuwiki/inc/html.php
    2        143 kB  /opt/dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
    2        142 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/wolfram.php
    2        141 kB  /opt/dokuwiki/vendor/geshi/geshi/src/geshi/php.php
    2        134 kB  /opt/dokuwiki/lib/plugins/extension/images/icons.xcf
    2        134 kB  /opt/dokuwiki/inc/common.php
    2        128 kB  /opt/dokuwiki/inc/parser/xhtml.php
[...]
    2          48 B  /opt/dokuwiki/lib/plugins/usermanager/lang/ia/add.txt
    2          48 B  /opt/dokuwiki/lib/plugins/usermanager/lang/no/delete.txt
    2          48 B  /opt/dokuwiki/inc/lang/zh-tw/adminplugins.txt
    2          46 B  /opt/dokuwiki/lib/plugins/usermanager/lang/no/list.txt
    2          46 B  /opt/dokuwiki/lib/plugins/usermanager/lang/id/add.txt
    2          46 B  /opt/dokuwiki/inc/lang/fr/adminplugins.txt
    2          46 B  /opt/dokuwiki/VERSION
    2          46 B  /opt/dokuwiki/lib/plugins/usermanager/lang/id/list.txt
    2          44 B  /opt/dokuwiki/lib/plugins/usermanager/lang/en/list.txt
    2          44 B  /opt/dokuwiki/lib/plugins/usermanager/lang/en/edit.txt
    2          44 B  /opt/dokuwiki/lib/plugins/usermanager/lang/id/delete.txt
    2          44 B  /opt/dokuwiki/lib/plugins/usermanager/lang/ca/add.txt
    2          42 B  /opt/dokuwiki/lib/plugins/usermanager/lang/en/add.txt
    2          42 B  /opt/dokuwiki/lib/plugins/usermanager/lang/id/edit.txt
    2          40 B  /opt/dokuwiki/inc/lang/uz/adminplugins.txt
    2          40 B  /opt/dokuwiki/inc/lang/uz/conflict.txt
    2          32 B  /opt/dokuwiki/inc/lang/uz/denied.txt
    2          30 B  /opt/dokuwiki/inc/lang/uz/admin.txt
    2          26 B  /opt/dokuwiki/inc/lang/uz/index.txt
    2          16 B  /opt/dokuwiki/lib/images/_deprecated.txt
    2          16 B  /opt/dokuwiki/inc/lang/uz/diff.txt
    2          16 B  /opt/dokuwiki/vendor/geshi/geshi/build.properties.dist
    3           0 B  /lib/apk/db/lock
    2           0 B  /usr/bin/passwd
    2           0 B  /usr/sbin/chpasswd
    3           0 B  /var/cache/misc
    2           0 B  /bin/su
    2           0 B  /bin/login
Results:
  FAIL: highestUserWastedPercent: too many bytes wasted, relative to the user bytes added (%-user-wasted-bytes=0.6303351645455055 > threshold=0.1)
  SKIP: highestWastedBytes: rule disabled
  FAIL: lowestEfficiency: image efficiency is too low (efficiency=0.7186429045469663 < threshold=0.9)
Result:FAIL [Total:3] [Passed:0] [Failed:2] [Warn:0] [Skipped:1]

Inspect docker image using the text-based user interface.

$ dive sleeplessbeastie/dokuwiki:latest

It is not very efficient as the chown operation should be performed during the COPY step.

[...]
ARG UID=5000
ARG GID=5000
ARG BUILD_DATE

[...]

COPY --from=source-code /opt/dokuwiki /opt/dokuwiki

RUN apk add --no-cache shadow \
 && groupadd -r -g $GID  dokuwiki \
 && useradd --no-log-init -u $UID -r -g dokuwiki dokuwiki  \
 && chown -R dokuwiki:dokuwiki /opt/dokuwiki \
 && apk del shadow
[...]

Update Dockerfile, build and push it.

[...]
ARG UID=5000
ARG GID=5000
ARG BUILD_DATE

[...]

COPY --chown=$UID:$GID --from=source-code /opt/dokuwiki /opt/dokuwiki

RUN apk add --no-cache shadow \
 && groupadd -r -g $GID  dokuwiki \
 && useradd --no-log-init -u $UID -r -g dokuwiki dokuwiki  \
 && apk del shadow
[...]

The new image will be more space-efficient.

$ CI=true dive sleeplessbeastie/dokuwiki:latest
  Using default CI config
Image Source: docker://sleeplessbeastie/dokuwiki:latest
Fetching image... (this can take a while for large images)
Analyzing image...
  efficiency: 99.7517 %
  wastedBytes: 120787 bytes (121 kB)
  userWastedPercent: 0.3860 %
Inefficient Files:
Count  Wasted Space  File Path
    3         72 kB  /lib/apk/db/installed
    3         35 kB  /lib/apk/db/scripts.tar
    3        3.7 kB  /etc/passwd
    2        2.4 kB  /etc/passwd-
    3        2.1 kB  /etc/group
    2        1.4 kB  /etc/group-
    2        1.3 kB  /var/lib/unit/conf.json
    3        1.3 kB  /etc/shadow
    2         867 B  /etc/shadow-
    2         345 B  /opt/dokuwiki/conf/plugins.php
    3         240 B  /etc/apk/world
    3         228 B  /lib/apk/db/triggers
    2           0 B  /bin/login
    2           0 B  /usr/bin/passwd
    2           0 B  /usr/sbin/chpasswd
    3           0 B  /var/cache/misc
    2           0 B  /bin/su
    3           0 B  /lib/apk/db/lock
Results:
  PASS: highestUserWastedPercent
  SKIP: highestWastedBytes: rule disabled
  PASS: lowestEfficiency
Result:PASS [Total:3] [Passed:2] [Failed:0] [Warn:0] [Skipped:1]

This is so cool!