├── .gitignore ├── bootstrap-debug ├── Dockerfile └── debug ├── kitchen-sink-debug ├── simple-server.go ├── sources.list ├── Dockerfile └── .bashrc ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .idea_modules 3 | *.iml 4 | *.swp 5 | .DS_Store 6 | 7 | kitchen-sink-debug/simple-server 8 | -------------------------------------------------------------------------------- /bootstrap-debug/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | MAINTAINER Mark Eijsermans 3 | ADD debug /bin/debug 4 | ADD https://raw.githubusercontent.com/markeijsermans/docker-debug/master/.bashrc /root/.bashrc 5 | -------------------------------------------------------------------------------- /kitchen-sink-debug/simple-server.go: -------------------------------------------------------------------------------- 1 | // Credit: Luke Kysow https://github.com/lkysow 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "github.com/valyala/fasthttp" 7 | ) 8 | 9 | func main() { 10 | fasthttp.ListenAndServe(":8080", fastHandler) 11 | } 12 | 13 | func fastHandler(ctx *fasthttp.RequestCtx) { 14 | fmt.Fprint(ctx, "OK") 15 | } 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IMG := markeijsermans/debug 2 | 3 | all: build-kitchen-sink build-bootstrap 4 | 5 | build-bootstrap: 6 | cd bootstrap-debug && docker build -t $(IMG):alpine . 7 | 8 | build-kitchen-sink: 9 | cd kitchen-sink-debug && docker build -t $(IMG):kitchen-sink . 10 | docker tag $(IMG):kitchen-sink $(IMG):latest 11 | 12 | push: 13 | docker push $(IMG):alpine 14 | docker push $(IMG):kitchen-sink 15 | docker push $(IMG):latest 16 | -------------------------------------------------------------------------------- /kitchen-sink-debug/sources.list: -------------------------------------------------------------------------------- 1 | deb http://archive.ubuntu.com/ubuntu/ xenial main restricted 2 | deb-src http://archive.ubuntu.com/ubuntu/ xenial main restricted 3 | 4 | deb http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted 5 | deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted 6 | 7 | deb http://archive.ubuntu.com/ubuntu/ xenial universe 8 | deb-src http://archive.ubuntu.com/ubuntu/ xenial universe 9 | deb http://archive.ubuntu.com/ubuntu/ xenial-updates universe 10 | deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates universe 11 | 12 | deb http://archive.ubuntu.com/ubuntu/ xenial multiverse 13 | deb-src http://archive.ubuntu.com/ubuntu/ xenial multiverse 14 | deb http://archive.ubuntu.com/ubuntu/ xenial-updates multiverse 15 | deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates multiverse 16 | 17 | deb http://archive.ubuntu.com/ubuntu/ xenial-backports main restricted universe multiverse 18 | deb-src http://archive.ubuntu.com/ubuntu/ xenial-backports main restricted universe multiverse 19 | 20 | deb http://security.ubuntu.com/ubuntu xenial-security main restricted 21 | deb-src http://security.ubuntu.com/ubuntu xenial-security main restricted 22 | deb http://security.ubuntu.com/ubuntu xenial-security universe 23 | deb-src http://security.ubuntu.com/ubuntu xenial-security universe 24 | deb http://security.ubuntu.com/ubuntu xenial-security multiverse 25 | deb-src http://security.ubuntu.com/ubuntu xenial-security multiverse 26 | -------------------------------------------------------------------------------- /bootstrap-debug/debug: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TOOLS="bash vim curl bind-tools tree jq" 4 | TMPDIR= 5 | NEW_PKGS= 6 | 7 | main() { 8 | if [ -n "$1" ]; then 9 | TOOLS="$@" 10 | fi 11 | 12 | # ensure bash gets installed 13 | if echo $TOOLS | grep -vw "bash" > /dev/null; then 14 | TOOLS="$TOOLS bash" 15 | fi 16 | 17 | echo -e "Installing: \033[38;5;003m$TOOLS\033[0m" 18 | echo "These will be uninstalled on shell exit" 19 | 20 | TMPDIR=$(mktemp -d) 21 | trap clean SIGTERM SIGINT SIGHUP 22 | 23 | # install apps 24 | apk info --update -q | sort > $TMPDIR/installed 25 | echo $TOOLS | tr ' ' "\n" | sort > $TMPDIR/desired 26 | NEW_PKGS=$(comm -13 $TMPDIR/installed $TMPDIR/desired) 27 | apk add $NEW_PKGS 28 | 29 | export TERM=xterm-256color # exec'ing into a container usually gives you an unset or dumb $TERM 30 | 31 | local rcArg="" 32 | if [ ! -e "~/.bashrc" ]; then 33 | rcArg="--rcfile $(bashrc)" 34 | fi 35 | 36 | bash $rcArg 37 | 38 | clean 39 | } 40 | 41 | clean() { 42 | if [ -d $TMPDIR ]; then 43 | rm -rf $TMPDIR 44 | fi 45 | apk del $NEW_PKGS 46 | } 47 | 48 | bashrc() { 49 | local file="$TMPDIR/.bashrc" 50 | cat <<- 'EOF' > $file 51 | [ -z "$PS1" ] && return # bail if not running interactively 52 | 53 | HISTCONTROL=ignoredups:ignorespace 54 | shopt -s histappend 55 | HISTSIZE=1000 56 | HISTFILESIZE=2000 57 | shopt -s checkwinsize 58 | 59 | if [ -f ~/.bash_aliases ]; then 60 | . ~/.bash_aliases 61 | fi 62 | if [ -f /etc/bash_completion ] && ! shopt -oq posix; then 63 | . /etc/bash_completion 64 | fi 65 | # ( error-code time hostname pwd ) 66 | export PS1="\[\033[38;5;007m\](\[\033[38;5;196m\]\$(rc=\$?; if [[ \$rc != 0 ]]; then echo -n \"\$rc \"; fi)\[\033[38;5;201m\]\A\[\033[38;5;15m\] \[\033[38;5;93m\]\h\[\033[38;5;7m\]:\[\033[38;5;21m\]\w\[\033[38;5;7m\]) " 67 | EOF 68 | echo "$file" 69 | } 70 | 71 | main "$@" 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Docker Debug Containers 2 | ======================= 3 | 4 | ## Kitchen Sink 5 | 6 | `docker pull markeijsermans/debug:kitchen-sink` 7 | 8 | An image meant for debugging. Includes the kitchen sink (548MB+ image). Very often production containers are minimal in contents or even built from `scratch`. It is very tricky to diagnose issues (especially when scheduled on k8s/Mesos) without basic tools like netcat/ping/dig etc. 9 | 10 | This image is built from `ubuntu:16.04` and contains common networking and other system tools. See `Dockerfile` for current list of tools. This is the default image and is tagged as `latest`. 11 | 12 | #### Tips 13 | ```sh 14 | # running in privileged+host mode can be useful 15 | docker run --privileged --net=host --rm -ti markeijsermans/debug 16 | 17 | # start a performant simple http server - only prints our "OK". Useful for load testing 18 | docker run --rm -ti -p 8080:8080 markeijsermans/debug simple-server 19 | 20 | # start a python http server that hosts files 21 | docker run --rm -ti -p 8080:8080 markeijsermans/debug python3 -m http.server 22 | ``` 23 | 24 | #### Todo 25 | * vet packages and remove those that are never used 26 | 27 | 28 | ## Bootstrap 29 | 30 | `docker pull markeijsermans/debug:alpine` 31 | 32 | Alpine is a great ~5MB bare-bones image. The advantage of alpine over an even more stripped image (like [distroless](https://github.com/GoogleCloudPlatform/distroless) images) is that you get a package management system. 33 | 34 | But, when you exec into a container to debug it's nice to have some basic tools. When you run `debug` it will add basic tools (see [bootstrap-debug/debug](bootstrap-debug/debug) for current list), add a `~/.bashrc`, and throws you into a bash sub-shell. On exit any new packages that were installed will be removed leaving the container in the original state. This approach keeps your images small, but gives you easy debug ergonomics for your most common tasks. 35 | 36 | You can optionally specify which packages are installed. Bash is automatically installed as it is required to put you into a sub-shell: 37 | 38 | ```sh 39 | debug vim tcpdump 40 | ``` 41 | 42 | #### Tips 43 | 44 | Alpine has wget installed by default, so you can also run: 45 | 46 | ```sh 47 | wget https://git.io/vAKxa -O - | sh 48 | ``` 49 | 50 | You can include the `debug` script directly into your Dockerfile: 51 | 52 | ```dockerfile 53 | FROM alpine 54 | ADD https://raw.githubusercontent.com/markeijsermans/docker-debug/master/bootstrap-debug/debug /bin/debug 55 | ``` 56 | 57 | It's probably not a good idea to make this the entrypoint or cmd for an image. 58 | -------------------------------------------------------------------------------- /kitchen-sink-debug/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.10 as builder 2 | WORKDIR /go/src/github.com/markeijsermans/docker-debug/kitchen-sink-debug 3 | COPY simple-server.go . 4 | RUN go get -v . 5 | RUN CGO_ENABLED=0 GOOS=linux go build -a -o simple-server . 6 | 7 | 8 | FROM ubuntu:16.04 9 | MAINTAINER Mark Eijsermans 10 | 11 | ADD sources.list /etc/apt/sources.list 12 | 13 | RUN apt-get update && \ 14 | apt-get install -y \ 15 | bind9utils \ 16 | build-essential \ 17 | bzip2 \ 18 | coreutils \ 19 | cpustat \ 20 | curl \ 21 | diffutils \ 22 | dnsutils \ 23 | ethtool \ 24 | findutils \ 25 | gcc \ 26 | git \ 27 | gzip \ 28 | htop \ 29 | ifstat \ 30 | iftop \ 31 | iperf \ 32 | iproute2 \ 33 | iptables \ 34 | iptstate \ 35 | iputils-ping \ 36 | iputils-tracepath \ 37 | jq \ 38 | libbind-dev \ 39 | libcap-dev \ 40 | libgeoip-dev \ 41 | libkrb5-dev \ 42 | libnghttp2-dev \ 43 | libssl-dev \ 44 | libxml2-dev \ 45 | lsb-release \ 46 | lsof \ 47 | lynx \ 48 | make \ 49 | net-tools \ 50 | netcat-openbsd \ 51 | netperf \ 52 | nghttp2 \ 53 | openssh-client \ 54 | openssl \ 55 | procps \ 56 | socat \ 57 | strace \ 58 | sysstat \ 59 | tcpdump \ 60 | tree \ 61 | unzip \ 62 | vim \ 63 | wget \ 64 | xxdiff \ 65 | && apt-get clean 66 | 67 | # install slow_cooker 68 | RUN wget -q -O /usr/local/bin/slow_cooker https://github.com/BuoyantIO/slow_cooker/releases/download/1.1.0/slow_cooker_linux_amd64 && \ 69 | chmod 755 /usr/local/bin/slow_cooker 70 | 71 | # install wrk 72 | RUN git clone https://github.com/wg/wrk.git /tmp/wrk && \ 73 | cd /tmp/wrk && \ 74 | make && \ 75 | mv wrk /usr/local/bin/wrk && \ 76 | cd / && \ 77 | rm -rf /tmp/wrk 78 | 79 | # install dnsperf 80 | RUN cd /tmp && \ 81 | curl ftp://ftp.nominum.com/pub/nominum/dnsperf/2.1.0.0/dnsperf-src-2.1.0.0-1.tar.gz -O && \ 82 | tar -xzf dnsperf-src-2.1.0.0-1.tar.gz && \ 83 | cd dnsperf-src-2.1.0.0-1 && \ 84 | ./configure && \ 85 | make && \ 86 | make install && \ 87 | cd / && \ 88 | rm -rf /tmp/dnsperf-src-2.1.0.0-1 89 | 90 | # install curl with HTTP/2 support 91 | RUN cd /tmp && \ 92 | wget https://curl.haxx.se/download/curl-7.54.1.tar.bz2 && \ 93 | tar -xjf curl-7.54.1.tar.bz2 && \ 94 | cd curl-7.54.1 && \ 95 | make && \ 96 | make install && \ 97 | ldconfig && \ 98 | cd / && \ 99 | rm -rf /tmp/curl-7.54.1 100 | 101 | # add simple server 102 | COPY --from=builder /go/src/github.com/markeijsermans/docker-debug/kitchen-sink-debug/simple-server . 103 | 104 | # lets just set the TERM for `exec`ing into a container 105 | ENV TERM=xterm 106 | ADD .bashrc /root/.bashrc 107 | -------------------------------------------------------------------------------- /kitchen-sink-debug/.bashrc: -------------------------------------------------------------------------------- 1 | # ~/.bashrc: executed by bash(1) for non-login shells. 2 | # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) 3 | # for examples 4 | 5 | # If not running interactively, don't do anything 6 | [ -z "$PS1" ] && return 7 | 8 | # don't put duplicate lines in the history. See bash(1) for more options 9 | # ... or force ignoredups and ignorespace 10 | HISTCONTROL=ignoredups:ignorespace 11 | 12 | # append to the history file, don't overwrite it 13 | shopt -s histappend 14 | 15 | # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) 16 | HISTSIZE=10000 17 | HISTFILESIZE=20000 18 | 19 | # check the window size after each command and, if necessary, 20 | # update the values of LINES and COLUMNS. 21 | shopt -s checkwinsize 22 | 23 | # make less more friendly for non-text input files, see lesspipe(1) 24 | [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" 25 | 26 | # set variable identifying the chroot you work in (used in the prompt below) 27 | if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then 28 | debian_chroot=$(cat /etc/debian_chroot) 29 | fi 30 | 31 | # set a fancy prompt (non-color, unless we know we "want" color) 32 | case "$TERM" in 33 | xterm-color) color_prompt=yes;; 34 | esac 35 | 36 | # uncomment for a colored prompt, if the terminal has the capability; turned 37 | # off by default to not distract the user: the focus in a terminal window 38 | # should be on the output of commands, not on the prompt 39 | #force_color_prompt=yes 40 | 41 | if [ -n "$force_color_prompt" ]; then 42 | if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then 43 | # We have color support; assume it's compliant with Ecma-48 44 | # (ISO/IEC-6429). (Lack of such support is extremely rare, and such 45 | # a case would tend to support setf rather than setaf.) 46 | color_prompt=yes 47 | else 48 | color_prompt= 49 | fi 50 | fi 51 | 52 | if [ "$color_prompt" = yes ]; then 53 | PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' 54 | else 55 | PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' 56 | fi 57 | unset color_prompt force_color_prompt 58 | 59 | # If this is an xterm set the title to user@host:dir 60 | case "$TERM" in 61 | xterm*|rxvt*) 62 | PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" 63 | ;; 64 | *) 65 | ;; 66 | esac 67 | 68 | # enable color support of ls and also add handy aliases 69 | if [ -x /usr/bin/dircolors ]; then 70 | test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" 71 | alias ls='ls --color=auto' 72 | #alias dir='dir --color=auto' 73 | #alias vdir='vdir --color=auto' 74 | 75 | alias grep='grep --color=auto' 76 | alias fgrep='fgrep --color=auto' 77 | alias egrep='egrep --color=auto' 78 | fi 79 | 80 | # some more ls aliases 81 | alias ll='ls -alF' 82 | alias la='ls -A' 83 | alias l='ls -CF' 84 | 85 | # Alias definitions. 86 | # You may want to put all your additions into a separate file like 87 | # ~/.bash_aliases, instead of adding them here directly. 88 | # See /usr/share/doc/bash-doc/examples in the bash-doc package. 89 | 90 | if [ -f ~/.bash_aliases ]; then 91 | . ~/.bash_aliases 92 | fi 93 | 94 | # enable programmable completion features (you don't need to enable 95 | # this, if it's already enabled in /etc/bash.bashrc and /etc/profile 96 | # sources /etc/bash.bashrc). 97 | if [ -f /etc/bash_completion ] && ! shopt -oq posix; then 98 | . /etc/bash_completion 99 | fi 100 | 101 | # ( error-code time hostname pwd ) 102 | export PS1="\[\033[38;5;007m\](\[$(tput sgr0)\]\[\033[38;5;196m\]\$(rc=\$?; if [[ \$rc != 0 ]]; then echo -n \"\$rc \"; fi)\[$(tput sgr0)\]\[\033[38;5;201m\]\A\[$(tput sgr0)\]\[\033[38;5;15m\] \[$(tput sgr0)\]\[$(tput bold)\]\[\033[38;5;93m\]\h\[$(tput sgr0)\]\[\033[38;5;7m\]:\[$(tput sgr0)\]\[\033[38;5;21m\]\w\[$(tput sgr0)\]\[\033[38;5;7m\])\[$(tput sgr0)\] " 103 | export EDITOR=vim 104 | --------------------------------------------------------------------------------