CLOVER🍀

That was when it all began.

BusyBoxを使って、単一で実行可能なコマンドのバイナリをDockerコンテナ内に放り込む

これは、なにをしたくて書いたもの?

Dockerコンテナ内で解析などの作業をする必要が出た時に、コマンドなどが入っていないDockerイメージが相手の場合は
どうすればいい?という時の選択肢のひとつとして、BusyBoxが使えそうな気がしたので。

BusyBox

Case

例えば、以下のようにDebianのDockerイメージを使った時に、デフォルトではpsやmpstatなど、調べものをする際に
使いたいコマンドが入っていません。

$ docker container run -it --rm --name debian debian:stretch
root@f28f50fe47ca:/# ps
bash: ps: command not found
root@f28f50fe47ca:/# wget
bash: wget: command not found
root@f28f50fe47ca:/# mpstat
bash: mpstat: command not found

もちろん、「docker container exec」でコンテナ内に入り、aptなどでインストールするのもありです。

$ docker container exec -it debian bash
# apt update -y
# apt install sysstat -y

実行可能なコマンドを見つけてきて、「docker container cp」でコンテナ内に放り込むのも良いでしょう。

しかし、Distrolessのようなシェルすら入っていないDockerイメージの場合は、それも困難です。

GitHub - GoogleContainerTools/distroless: 🥑 Language focused docker images, minus the operating system.

こういうケースでは、BusyBoxを覚えておくと役に立ちそうだな、と。

BusyBox

BusyBoxとは、Aboutページによると「多くの一般的なUnixユーティリティを小さな実行可能ファイルにまとめたもの」だそうです。

BusyBox

About BusyBox

BusyBoxを使うと、単独で実行可能なコマンド、もしくはコマンドをまとめたバイナリを単独で使うことができます。

Aboutページを見ると、「組み込みLinuxのスイスアーミーナイフ」だとか。

BusyBox: The Swiss Army Knife of Embedded Linux

ちなみに、Dockerイメージとして提供されているのと

busybox / DockerHub

Alpine Linuxでも利用されているようです。

index | Alpine Linux

about | Alpine Linux

BusyBoxを使ってみる

それでは、試してみましょう。

今回利用するBusyBoxは、1.30.0とします。

ダウンロードは、こちらから対象のバージョン、必要なバイナリをダウンロードします。

Index of /downloads/binaries

まずは、対象としてDebianのコンテナを起動しておきます。

$ docker container run -it --rm --name debian debian:stretch

ここに、BusyBoxからPSコマンドをダウンロードして、実行権限を付与します。

$ wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox_PS
$ chmod a+x busybox_PS

あとはこちらを、コンテナ内の「/usr/local/bin」にでも放り込んであげましょう。このあたりに置けば、PATHが通っているので
便利かなと。

$ docker container cp busybox_PS debian:/usr/local/bin

すると、コンテナ内でこのコマンドが利用できるようになります。

root@eeab426fb585:/# busybox_PS 
PID   USER     TIME  COMMAND
    1 root      0:00 bash
    6 root      0:00 busybox_PS

wgetの場合。

$ wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox_WGET
$ chmod a+x busybox_WGET
$ docker container cp busybox_WGET debian:/usr/local/bin

wgetを使って、コンテナ内でBusyBoxの他のコマンドをダウンロード。

# busybox_WGET -q https://busybox.net/downloads/binaries/1.30.0-i686/busybox_CHMOD
Connecting to busybox.net (140.211.167.122:443)
wget: note: TLS certificate validation not implemented
busybox_CHMOD        100% |***********************************************************************************************************************************| 36780  0:00:00 ETA

対象のDockerイメージ内にシェルすらない場合は、ashを使えば良いでしょう。

$ wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox_ASH
$ chmod a+x busybox_ASH
$ docker container cp busybox_ASH debian:/usr/local/bin

これで、シェルがないコンテナでもashで入れるようになります。

$ docker container exec -it debian busybox_ASH
/ # 

良さそうですが、通常のコマンドと比べるとオプションが少なかったりするので、それなりに制限はありそうです。

# busybox_WGET -h
Usage: wget [-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE]
    [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]
    [-S|--server-response] [-U|--user-agent AGENT] [-T SEC] URL...

Retrieve files via HTTP or FTP

    --spider    Only check URL existence: $? is 0 if exists
    -c      Continue retrieval of aborted transfer
    -q      Quiet
    -P DIR      Save to DIR (default .)
    -S          Show server response
    -T SEC      Network read timeout is SEC seconds
    -O FILE     Save to FILE ('-' for stdout)
    -U STR      Use STR for User-Agent header
    -Y on/off   Use proxy

とはいえ、即席としてはやはり便利ですね。

全部入りのバイナリを使う

ここまでは、単一のコマンドを使用してきましたが、「busybox」というバイナリを使えば、BusyBoxで使えるコマンドが
全部入りのものとして利用することができます。

$ wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox
$ chmod a+x busybox
$ docker container cp busybox debian:/usr/local/bin

コマンドを実行すると、利用できるコマンドの一覧が表示されます。

# busybox
BusyBox v1.30.0 (2018-12-30 22:25:27 CET) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list[-full]
   or: busybox --show SCRIPT
   or: busybox --install [-s] [DIR]
   or: function [arguments]...

    BusyBox is a multi-call binary that combines many common Unix
    utilities into a single executable.  Most people will create a
    link to busybox for each function they wish to use and BusyBox
    will act like whatever it was invoked as.

Currently defined functions:
    [, [[, acpid, add-shell, addgroup, adduser, adjtimex, ar, arch, arp, arping, ash, awk, base64, basename, bc, blkdiscard, blkid, blockdev, bootchartd, brctl, bunzip2,
    bzcat, bzip2, cal, cat, chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm, conspy, cp, cpio, crond, crontab, cryptpw,
    cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df, dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, dpkg, dpkg-deb, du,
    dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, expand, expr, factor, fakeidentd, false, fatattr, fbset, fbsplash, fdflush, fdformat, fdisk,
    fgconsole, fgrep, find, findfs, flash_eraseall, flash_lock, flash_unlock, flashcp, flock, fold, free, freeramdisk, fsck, fsck.minix, fsfreeze, fstrim, fsync, ftpd,
    ftpget, ftpput, fuser, getopt, getty, grep, groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hexedit, hostid, hostname, httpd, hush, hwclock, i2cdetect, i2cdump,
    i2cget, i2cset, id, ifconfig, ifenslave, ifplugd, inetd, init, inotifyd, insmod, install, ionice, iostat, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, ipneigh, iproute,
    iprule, iptunnel, kbd_mode, kill, killall, killall5, klogd, last, less, link, linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login, logname, losetup, lpd,
    lpq, lpr, ls, lsattr, lsmod, lsof, lspci, lsscsi, lsusb, lzcat, lzma, lzop, lzopcat, makedevs, makemime, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs,
    mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mountpoint, mpstat, mt, mv, nameif, nbd-client, nc, netstat,
    nice, nl, nmeter, nohup, nologin, nproc, ntpd, nuke, od, openvt, partprobe, passwd, paste, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap,
    popmaildir, poweroff, powertop, printenv, printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, rdev, readlink, readprofile, realpath, reboot, reformime,
    remove-shell, renice, reset, resize, resume, rev, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run-init, run-parts, runlevel, runsv, runsvdir, rx, script,
    scriptreplay, sed, sendmail, seq, setarch, setconsole, setfattr, setfont, setkeycodes, setlogcons, setpriv, setserial, setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum,
    sha512sum, showkey, shred, shuf, slattach, sleep, smemcap, softlimit, sort, split, ssl_client, start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svc, svlogd,
    svok, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr,
    traceroute, traceroute6, true, truncate, tty, ttysize, tunctl, tune2fs, ubiattach, ubidetach, ubimkvol, ubirename, ubirmvol, ubirsvol, ubiupdatevol, udhcpc, udhcpd,
    udpsvd, uevent, umount, uname, uncompress, unexpand, uniq, unix2dos, unlink, unlzma, unlzop, unxz, unzip, uptime, users, usleep, uudecode, uuencode, vconfig, vi, vlock,
    volname, w, wall, watch, watchdog, wc, wget, which, who, whoami, whois, xargs, xxd, xz, xzcat, yes, zcat, zcip

この場合、利用したいコマンドは「busybox」コマンドのサブコマンドとして実行します。

# busybox ps
PID   USER     TIME  COMMAND
    1 root      0:00 bash
   58 root      0:00 busybox ps



# busybox wget   
BusyBox v1.30.0 (2018-12-30 22:25:27 CET) multi-call binary.

Usage: wget [-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE]
    [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]
    [-S|--server-response] [-U|--user-agent AGENT] [-T SEC] URL...

Retrieve files via HTTP or FTP

    --spider    Only check URL existence: $? is 0 if exists
    -c      Continue retrieval of aborted transfer
    -q      Quiet
    -P DIR      Save to DIR (default .)
    -S          Show server response
    -T SEC      Network read timeout is SEC seconds
    -O FILE     Save to FILE ('-' for stdout)
    -U STR      Use STR for User-Agent header
    -Y on/off   Use proxy


# busybox mpstat
Linux 4.15.0-48-generic (eeab426fb585)  04/27/19    _x86_64_    (8 CPU)

14:11:18     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
14:11:18     all   10.29    0.02    1.48    2.32    0.00    0.05    0.00    0.00   85.85

ashでコンテナに入る場合。

$ docker container exec -it debian busybox ash
/ # 

Dockerコンテナ内の調査時で困った時に知っておくと、便利そうですね。

覚えておきましょう。