command: docker debug
short: Get a shell into any container or image. An alternative to debugging with `docker exec`.
long: |-
  Docker Debug is a CLI command that helps you follow best practices by keeping your images small and secure. 
  With Docker Debug, you can debug your images while they contain the bare minimum to run your application.
  It does this by letting you create and work with slim images or containers that are often difficult to debug because all tools have been removed. 
  For example, while typical debug approaches like `docker exec -it my-app bash` may not work on a slim container, `docker debug` will work.
  
  With `docker debug` you can get a debug shell into any container or image, even if they don't contain a shell. 
  You don't need to modify the image to use Docker Debug. 
  However, using Docker Debug still won't modify your image.
  Docker Debug brings its own toolbox that you can easily customize.
  The toolbox comes with many standard Linux tools pre-installed, such as `vim`, `nano`, `htop`, and `curl`.
  Use the builtin `install` command to add additional tools available on https://search.nixos.org/packages.
  Docker Debug supports `bash`, `fish`, and `zsh`. 
  By default it tries to auto-detect your shell.
  
  
  Custom builtin tools:
  - `install [tool1] [tool2]`: Add Nix packages from: https://search.nixos.org/packages, see [example](#managing-your-toolbox-using-the-install-command).
  - `uninstall [tool1] [tool2]`: Uninstall Nix packages.
  - `entrypoint`: Print, lint, or run the entrypoint, see [example](#understanding-the-default-startup-command-of-a-container-entry-points).
  - `builtins`: Show custom builtin tools.
  
  > [!NOTE]
  >
  > For images and stopped containers, all changes are discarded when leaving the shell. 
  > At no point, do changes affect the actual image or container. 
  > When accessing running or paused containers, all filesystem changes are directly visible to the container. 
  > The `/nix` directory is never visible to the actual image or container.


usage: debug [OPTIONS] {CONTAINER|IMAGE}
pname: docker
plink: docker.yaml
options:
  - option: shell
    value_type: shell
    default_value: "auto"
    description: "Select a shell. Supported: `bash`, `fish`, `zsh`, `auto`."
    deprecated: false
    hidden: false
    experimental: false
    experimentalcli: false
    kubernetes: false
    swarm: false
  - option: command
    shorthand: c
    value_type: string
    default_value: false
    description: Evaluate the specified commands instead of starting an interactive session, see [example](#running-commands-directly-eg-for-scripting).
    deprecated: false
    hidden: false
    experimental: false
    experimentalcli: false
    kubernetes: false
    swarm: false
  - option: host
    value_type: string
    default_value: false
    description: "Daemon docker socket to connect to. E.g.: `ssh://root@example.org`, `unix:///some/path/docker.sock`, see [example](#remote-debugging-using-the---host-option)."
    deprecated: false
    hidden: false
    experimental: false
    experimentalcli: false
    kubernetes: false
    swarm: false
deprecated: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
examples: |-
  ### Debugging containers that have no shell (slim containers)
  
  The `hello-world` image is very simple and only contains the `/hello` binary.
  It's a good example of a slim image.
  There are no other tools and no shell.

  Run a container from the `hello-world` image:
  
  ```console
  $ docker run --name my-app hello-world
  ```
  
  The container exits immediately. To get a debug shell inside, run:
  
  ```console
  $ docker debug my-app
  ```
  
  The debug shell allows you to inspect the filesystem:
  
  ```console
  docker > ls
  dev  etc  hello  nix  proc  sys
  ```
  
  The file `/hello` is the binary that was executed when running the container.
  You can confirm this by running it directly:
  
  ```console
  docker > /hello
  ```
  
  After running the binary, it produces the same output.
  
  ### Debugging (slim) images
  
  You can debug images directly by running:
  
  ```console
  $ docker debug hello-world
  ...
  docker > ls
  dev  etc  hello  nix  proc  sys
  ```
  
  You don't even need to pull the image as `docker debug` will do this automatically like the `docker run` command.
  
  ### Modifying files of a running container
  
  Docker debug lets you modify files in any running container. 
  The toolbox comes with `vim` and `nano` pre-installed.
  
  Run an nginx container and change the default `index.html`:
  
  ```console
  $ docker run -d --name web-app -p 8080:80 nginx
  d3d6074d0ea901c96cac8e49e6dad21359616bef3dc0623b3c2dfa536c31dfdb
  ```
  
  To confirm nginx is running, open a browser and navigate to http://localhost:8080.
  You should see the default nginx page.
  Now, change it using vim:
  
  ```console
  vim /usr/share/nginx/html/index.html
  ```
  
  Change the title to "Welcome to my app!" and save the file.
  Now, reload the page in the browser and you should see the updated page.
  
  ### Managing your toolbox using the `install` command
  
  The builtin `install` command lets you add any tool from https://search.nixos.org/packages to the toolbox.
  Keep in mind adding a tool never modifies the actual image or container.
  Tools get added to only your toolbox.
  Run `docker debug` and then install `nmap`:
  
  ```console
  $ docker debug nginx
  ...
  docker > install nmap
  Tip: You can install any package available at: https://search.nixos.org/packages.
  installing 'nmap-7.93'
  these 2 paths will be fetched (5.58 MiB download, 26.27 MiB unpacked):
  /nix/store/brqjf4i23fagizaq2gn4d6z0f406d0kg-lua-5.3.6
  /nix/store/xqd17rhgmn6pg85a3g18yqxpcya6d06r-nmap-7.93
  copying path '/nix/store/brqjf4i23fagizaq2gn4d6z0f406d0kg-lua-5.3.6' from 'https://cache.nixos.org'...
  copying path '/nix/store/xqd17rhgmn6pg85a3g18yqxpcya6d06r-nmap-7.93' from 'https://cache.nixos.org'...
  building '/nix/store/k8xw5wwarh8dc1dvh5zx8rlwamxfsk3d-user-environment.drv'...
  
  docker > nmap --version
  Nmap version 7.93 ( https://nmap.org )
  Platform: x86_64-unknown-linux-gnu
  Compiled with: liblua-5.3.6 openssl-3.0.11 libssh2-1.11.0 nmap-libz-1.2.12 libpcre-8.45 libpcap-1.10.4 nmap-libdnet-1.12 ipv6
  Compiled without:
  Available nsock engines: epoll poll select
  ```
  
  You can confirm `nmap` is now part of your toolbox by getting a debug shell into a different image:
  
  ```console
  $ docker debug hello-world
  ...
  docker > nmap --version
  
  Nmap version 7.93 ( https://nmap.org )
  Platform: x86_64-unknown-linux-gnu
  Compiled with: liblua-5.3.6 openssl-3.0.11 libssh2-1.11.0 nmap-libz-1.2.12 libpcre-8.45 libpcap-1.10.4 nmap-libdnet-1.12 ipv6
  Compiled without:
  Available nsock engines: epoll poll select
  
  docker > exit
  ```
  
  `nmap` is still there.
  
  
  ### Understanding the default startup command of a container (entry points)
  
  Docker Debug comes with a builtin tool, `entrypoint`.
  Enter the `hello-world` image and confirm the entrypoint is `/hello`:
  
  ```console
  $ docker debug hello-world
  ...
  docker > entrypoint --print
  /hello
  ```
  
  The `entrypoint` command evaluates the `ENTRYPOINT` and `CMD` statement of the underlying image 
  and lets you print, lint, or run the resulting entrypoint.
  However, it can be difficult to understand all the corner cases from [Understand how CMD and ENTRYPOINT interact](/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact). 
  In these situations, `entrypoint` can help.
  
  Use `entrypoint` to investigate what actually happens when you run a container from the Nginx image:
  
  ```console
  $ docker debug nginx
  ...
  docker > entrypoint
  Understand how ENTRYPOINT/CMD work and if they are set correctly.
  From CMD in Dockerfile:
   ['nginx', '-g', 'daemon off;']
  
  From ENTRYPOINT in Dockerfile:
   ['/docker-entrypoint.sh']
  
  By default, any container from this image will be started with following   command:
  
  /docker-entrypoint.sh nginx -g daemon off;
  
  path: /docker-entrypoint.sh
  args: nginx -g daemon off;
  cwd:
  PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  
  Lint results:
   PASS: '/docker-entrypoint.sh' found
   PASS: no mixing of shell and exec form
   PASS: no double use of shell form
  
  Docs:
  - https://docs.docker.com/reference/dockerfile/#cmd
  - https://docs.docker.com/reference/dockerfile/#entrypoint
  - https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
  ```
  
  The output tells you that on startup of the nginx image, a script `/docker-entrypoint.sh` is executed with the arguments `nginx -g daemon off;`.
  You can test the entrypoint by using the `--run` option:
  
  ```console
  $ docker debug nginx
  ...
  docker > entrypoint --run
  /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
  /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
  /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
  10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
  10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
  /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
  /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
  /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
  /docker-entrypoint.sh: Configuration complete; ready for start up
  2024/01/19 17:34:39 [notice] 50#50: using the "epoll" event method
  2024/01/19 17:34:39 [notice] 50#50: nginx/1.25.3
  2024/01/19 17:34:39 [notice] 50#50: built by gcc 12.2.0 (Debian 12.2.0-14)
  2024/01/19 17:34:39 [notice] 50#50: OS: Linux 5.15.133.1-microsoft-standard-WSL2
  2024/01/19 17:34:39 [notice] 50#50: getrlimit(RLIMIT_NOFILE): 1048576:1048576
  2024/01/19 17:34:39 [notice] 50#50: start worker processes
  2024/01/19 17:34:39 [notice] 50#50: start worker process 77
  ...
  ```
  
  This starts nginx in your debug shell without having to actually run a container.
  You can shutdown nginx by pressing `Ctrl`+`C`.
  
  ### Running commands directly (e.g., for scripting)
  
  Use the `--command` option to evaluate a command directly instead of starting an interactive session. 
  For example, this is similar to `bash -c "arg1 arg2 ..."`.
  The following example runs the `cat` command in the nginx image without starting an interactive session.
  
  ```console
  $ docker debug --command "cat /usr/share/nginx/html/index.html" nginx

  <!DOCTYPE html>
  <html>
  <head>
  <title>Welcome to nginx!</title>
  <style>
  html { color-scheme: light dark; }
  body { width: 35em; margin: 0 auto;
  font-family: Tahoma, Verdana, Arial, sans-serif; }
  </style>
  </head>
  <body>
  <h1>Welcome to nginx!</h1>
  <p>If you see this page, the nginx web server is successfully installed and
  working. Further configuration is required.</p>
  
  <p>For online documentation and support please refer to
  <a href="http://nginx.org/">nginx.org</a>.<br/>
  Commercial support is available at
  <a href="http://nginx.com/">nginx.com</a>.</p>
  
  <p><em>Thank you for using nginx.</em></p>
  </body>
  </html>
  ```
  
  ### Remote debugging using the --host option
  
  The following examples shows how to use the `--host` option. The first example uses SSH to connect to a remote Docker instance at `example.org` as the `root` user, and get a shell into the `my-container` container.
  
  ```console
  $ docker debug --host ssh://root@example.org my-container
  ```
  
  The following example connects to a different local Docker Engine, and gets a
  shell into the `my-container` container.
  
  ```console
  $ docker debug --host=unix:///some/path/docker.sock my-container
  ```
