skip to Main Content

As a summary:
No commands exist in Busybox "sh" in a Portainer Docker container.

Nuances, as always:

There is a Portainer tool image I’d like to have shell access in.
Why I need shell access there? It’s because I’d like to discover the ability to connect more than one docker context (other than default)
via additional docker socket file mapping.

Portainer developers take some steps (they say for security reasons) to disable the ablity to get an interactive console inside the running container – there are no bin/bash, bin/sh etc.

I’ve downloaded Busybox from
https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox

and created my own debug container based on th original Portainer one:

Dockerfile:

FROM portainer/portainer-ce:2.9.3
LABEL destiny="Portainer debug"

ADD busybox busybox
ENTRYPOINT [""]
CMD [""]

Executed image build command:

docker build -f Dockerfile -t portainer_debug:latest .

… and started a container with it:

docker run --name ppp -it portainer_debug /busybox sh

I entered into a shell inside of the running container.
Unfortunately, I found that there are no commands available.
For example, ls command returns:

/ # ls
sh: ls: not found
/ # 

It also means that Busybox commands (sh above) work as a parameter at container start. I checked it with "ls" as a paramater:

$ docker run --name ppp -it portainer_debug /busybox ls
busybox         docker-compose  kubectl         sys
data            etc             portainer       tmp
dev             helm            proc
docker          kompose         public
$

Note: "exit" command works inside "sh".

The same excercise with alpine image works as expected:

/ # ls
bin      busybox  dev      etc      home     lib      media    mnt      opt      proc     root     run      sbin     srv      sys      tmp      usr      var
/ # 

I’d be glad and very thankful if somebody could suggest the next steps to understand why busybox "forgets" all commands.

2

Answers


  1. From https://busybox.net/downloads/BusyBox.html :

    USAGE

    BusyBox is a multi-call binary. A multi-call binary is an executable
    program that performs the same job as more than one utility program.
    That means there is just a single BusyBox binary, but that single
    binary acts like a large number of utilities. This allows BusyBox to
    be smaller since all the built-in utility programs (we call them
    applets) can share code for many common operations.

    You can also invoke BusyBox by issuing a command as an argument on the
    command line. For example, entering

        /bin/busybox ls
    

    will also cause BusyBox to behave as ‘ls’.

    Of course, adding ‘/bin/busybox’ into every command would be painful.
    So most people will invoke BusyBox using links to the BusyBox binary.

    For example, entering

        ln -s /bin/busybox ls
        ./ls
    

    will cause BusyBox to behave as ‘ls’ (if the ‘ls’ command has been
    compiled into BusyBox). Generally speaking, you should never need to
    make all these links yourself, as the BusyBox build system will do
    this for you when you run the ‘make install’ command.

    If you invoke BusyBox with no arguments, it will provide you with a
    list of the applets that have been compiled into your BusyBox binary.

    You only copied the binary busybox into the image. You can do ./busybox ls or create the symlink, and add the directory with symlinks to $PATH if you want shell to find them.

    why busybox "forget" all commands.

    Busybox didn’t "forget" anything, it is inanimate, you just haven’t correctly used.


    For example, below I do:

    • Execute portainer docker image.
    • Because I am lazy, I do not write a Dockerfile, I just mount busybox executable that I have installed on my host to inside the docker container. It’s the same as COPY in container.
    • The docker container executes a /busybox sh shell
      • -c which executes a script
      • the script creates the directory /busybox mkdir /bin
      • the script for each tool from busybox – for i in $(/busybox list)
        • creates a symlink to busybox executable inside /bin directory – /busybox ln -s /busybox /bin/$i
      • the above two steps are exactly as explained in Busybox faq https://busybox.net/FAQ.html#getting_started
      • then the script executes an interactive shell to interact with me

    Because /bin is by default in PATH, after creating the directory and symlinks, all Busybox tools are available. Note that all commands are prepended with /busybox to facilitate the Busybox invoking explained in the documentation above, before the creation of directory in PATH with symlinks.

    $ docker run -ti --rm --entrypoint '' -v /bin/busybox:/busybox:ro portainer/portainer-ce:2.9.3 /busybox sh -c '/busybox mkdir /bin; for i in $(/busybox --list); do /busybox ln -s /busybox /bin/$i; done; sh -li'
    / # ls
    bin             data            docker          etc             kompose         portainer       public          tmp
    busybox         dev             docker-compose  helm            kubectl         proc            sys
    / # echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    
    Login or Signup to reply.
  2. ln -s /bin/busybox /bin/ash

    if ls works after executing ash, then do
    ln -s /bin/busybox /bin/sh

    I assume busybox is in /bin but it may be /sbin (depending on distribution decisions) as well.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search