Sometimes while working on the command line, you want to take a quick look inside a running container, then get on with other things without much distraction.
Using “docker ps
” is the usual way to start this process and is simple, but when working with Kubernetes (particularly without kubectl), cleaning up the output of “docker ps” to find the right ID became irritating.
Of course, kubectl exists, and ameliorates this significantly, but I wanted to take the guesswork/checking out of the process when working with multiple setups and get myself into the container I am interested in without delay, using only docker.
So this started out as a basic way to clean up the “docker ps” output for my use cases while working with Kubernetes, but has gradually expanded (as they do) to become my preferred way to briefly pull up the cli of a container for a look, even on systems just running docker alone.
For example, if I want to check the contents or permission of a mounted volume in, say, WordPress, I can issue the command; dcs word
The command line comes straight up. I can stay focused on my plans, complete the task, and get on with things without delay. It pays for itself.
Though I call it “dcs” in my ecosystem, you can rename it at your convenience without modifying anything else for functionality. However, you should probably also update the “–help” section to suit.
Full script
#!/bin/sh set -e # "pod" is used throughout the vars. # It's just easer than "container" or abbreviations thereof option_output(){ # ${1} passed in from main, not cli. We already know it starts with "--". case "${1}" in --help) cat <<HELPTEXT Quick container console startup dcs takes a single option. "dcs --help" provides this help screen "dcs --list" tries to list only your userspace containers (Some may not have a terminal, so YMMV) "dcs <substring>" will try to put you in a unique matching container. When there are multiple matching containers they will be listed with highlighting With only two matching containers you are given a choice. Substring matches on unique container name and/or ID substring. Try not to use single-character strings. Prioritizes /bin/bash in the container. Fallback to /bin/sh. HELPTEXT ;; --list) list_containers ;; *) echo "Option ${1} is not supported" ;; esac } get_pod_list(){ # The check for whether docker is available is already done in main. # Belt and suspenders, even though stakes are low. # Produces a table of 12 digit ID, image name, container name # Depending on what you are running the exclusions list can be adjusted. if [ -n "${docker_bin}" ]; then # Sanity check. "${docker_bin}" ps | \ awk '!/CONTAINER|fleetagent|ingress|rancher|cattle|kube/ {print $1"_"$2"_"$(NF)}' |\ cut -d"_" -f1,2,4 | sed 's/_/\ /g' |\ awk '{printf "%-15s%-35s%-35s\n", $1, $2, $3}' else error_feedback no_docker # Should never happen fi } list_header(){ printf "\033[93m%-15s%-35s%-35s\033[0m\n" "ID" "IMAGE NAME" "CONTAINER NAME" } list_containers(){ # For presentation printf "\033[96m%s\033[0m\n" "Running user containers:"; list_header get_pod_list } error_feedback(){ case ${1} in no_name) printf "\033[93m%s\n%s\n\033[0m" \ "You did not supply the container name as the first parameter" \ "(Or you are lazily getting the list)" list_containers ;; no_unique) printf "\033[96m%s %s\033[0m\n" \ "The following list matches your string:" \ "'${req_pod_string}'" list_header ## We like grep color highlighting. echo "${match_list}" | grep --color -- "${req_pod_string}" printf "\033[91m%s\033[0m\n" \ "The string you used is not unique, try being more specific" ;; no_pod) list_containers printf "\033[91m%s %s\n\033[0m" \ "There are no matches for the supplied string" \ "'${req_pod_string}'" ;; invalid_id) printf "%s %s\n" "An ID with invalid length was seen." \ "Something unexpected happened" ;; no_docker) printf "\033[91m%s\033[0m\n" \ "This script requires docker, which does not seem to be installed" ;; *) printf "%s\n" "Something went wrong"; list_containers ;; esac } ## MAIN ## # Checks docker_bin="$(command -v docker)" # Used later if [ -z "${docker_bin}" ]; then error_feedback no_docker # Exit with error message no docker exit 1 fi # No name, ID or option. if [ -z "${1}" ]; then error_feedback no_name; exit 1 # Message and list then exit fi # We have docker and a string. Lets see what the string is for. if [ "${1%"${1#??}"}" = "--" ]; then # Option starts with "--".. option_output "${1}"; exit 0 fi # Treat as string/substring of a name or ID. Following vars are reused later req_pod_string="${1}" # Take only the first option, ignore anything after space # Following grep handles possible expected fail case with "true" # Prepending search string with "--" to handle when string begins with "-" match_list="$(echo "$(get_pod_list)" | grep -- "${req_pod_string}" || true )" possible_id="$(echo "${match_list}" | cut -d " " -f1)" # Needs echo here and above id_length=12 # Docker IDs are 12 chars long. This may change in the future. id_length_double=$((1+2*${id_length})) possible_id_length="${#possible_id}" # Create rangegaps in the subsequent switch/case. Probably never used. if [ "${possible_id_length}" -gt 0 ] \ && [ "${possible_id_length}" -lt "${id_length}" ]; then error_feedback invalid_id exit 1 elif [ "${possible_id_length}" -gt "${id_length}" ] \ && [ "${possible_id_length}" -lt "${id_length_double}" ]; then error_feedback invalid_id exit 1 fi case "${possible_id_length}" in 0) error_feedback no_pod; exit 1 ;; # case: Passed tests and has single ID length, assume it is a valid ID. ${id_length}) # So go into the container. I sometimes prefer a clear screen, you may not. # clear pod_name="$(echo "${match_list}" | awk '{print $3}')" printf "\n\033[93m%s %s\033[0m\n" "Connecting to" "${pod_name}" printf "\033[93m%s\033[0m\n" "(control-d to exit)" # Notify on entry # Set up cli for the matching container - bash if available, sh otherwise. # We give it a nice PS1 prompt if possible. connection_script=' export PS1="\033[93m\h \033[92m\s \033[95m\u \033[96m[\w]\033[0m\$\040" bash_bin="$(command -v bash)" sh_bin="$(command -v sh)" if [ -n "${bash_bin}" ]; then "${bash_bin}" else "${sh_bin}" fi ' # Enter the container "${docker_bin}" exec -it "${possible_id}" /bin/sh -c "${connection_script}" printf "\n\033[93m%s %s\033[0m\n" "Exiting" "${pod_name}" # Notify on exit exit 0 ;; # case: Passed tests and matches [2x ID length + 1]. Make it an easy choice. # Specified ID is passed back into the script. ${id_length_double}) error_feedback no_unique first_option_line="$(echo "${match_list}" | head -1 | sed 's/\ \ */\ /g')" printf "\n\033[93m%s \033[96m%s \033[93m%s\033[0m" \ "Selecting"\ "${first_option_line}"\ "[Y/n]: " read -r select_first # n|N, or anything else for yes # Recurse back into this script definitively with selected full ID. script_myname="${0}" # Not assuming this script will be called "dcs" case "${select_first}" in n|N) # specific no second_option_id="$(echo "${match_list}" | tail -1 | cut -d " " -f1)" "${script_myname}" "${second_option_id}" exit 0 # Assumed success. "set -e" takes care of exit on failure though. ;; *) # assumed yes first_option_id="$( echo "${first_option_line}" | cut -d " " -f1)" "${script_myname}" "${first_option_id}"; exit 0 # Assumed success ;; esac ;; *) # case: Catchall. ID length is more than double+1. Multiple (> 2) matches error_feedback no_unique; exit 1 # Just notify and exit with failure ;; esac
Examples
Specify by ID
$ dcs --list Running user containers: ID IMAGE NAME CONTAINER NAME b1f97805ce10 searx/searx searx 67c50f1fbd73 qmcgaw/gluetun vpn-gluetun-usa ec444ac4af84 qmcgaw/gluetun vpn-gluetun-overseas ee6daaa57386 qmcgaw/gluetun vpn-gluetun-au d9191e86f544 qmcgaw/gluetun vpn-gluetun-au-searx 4d7151ceabbe tkrs/maxmind-geoipupdate geoip ade6a3e10fb3 bitnami/wordpress wordpress 92fdd9565c52 mariadb mariadb 9a7c48dcbe1f linuxserver/nextcloud nextcloud b6da179fd580 onlyoffice/documentserver onlyoffice $ dcs 9a7 Connecting to nextcloud (control-d to exit) nextcloud-7d5df7676c-gqktc bash root [/]$
An ID substring can be used to specify which container you wish to use. This is the same as using the docker command but with less typing.
Specify by name, single result
$ dcs word Connecting to wordpress (control-d to exit) I have no name!@wordpress-7d69f4fc5-p6bmb:/$
The simplest use case. Specify a unique name substring which matches the container you want.
Specify by name, two results
$ dcs -au The following list matches your string: '-au' ID IMAGE NAME CONTAINER NAME ee6daaa57386 qmcgaw/gluetun vpn-gluetun-au d9191e86f544 qmcgaw/gluetun vpn-gluetun-au-searx The string you used is not unique, try being more specific Selecting ee6daaa57386 qmcgaw/gluetun vpn-gluetun-au [Y/n]: n Connecting to vpn-gluetun-au-searx (control-d to exit) vpn-gluetun-au-searx-579974847c-4gdxb s root [/]$
In this case the -au
is the search term. It is not an option.
When there are only two results, you can choose which you want. The script captures the full ID and recurses back into itself. This example demonstrates the correct handling of a substring starting with a hyphen.
Specify by name, multiple results
$ dcs glue The following list matches your string: 'glue' ID IMAGE NAME CONTAINER NAME 67c50f1fbd73 qmcgaw/gluetun vpn-gluetun-usa ec444ac4af84 qmcgaw/gluetun vpn-gluetun-overseas ee6daaa57386 qmcgaw/gluetun vpn-gluetun-au d9191e86f544 qmcgaw/gluetun vpn-gluetun-au-searx The string you used is not unique, try being more specific $ dcs ee6 Connecting to vpn-gluetun-au (control-d to exit) vpn-gluetun-au-5c76f8bd84-qbgzh s root [/]$
When multiple results are returned for matching containers, a list of matching containers is shown, allowing the user to use a more specific string, either ID or name, to enter the CLI.
Conclusion
In this post, we’ve explored a shell script designed to streamline the process of accessing the command line interface of a running Docker container. This tool is particularly beneficial when working with Kubernetes without kubectl, allowing you to quickly and efficiently interact with your containers. We’ve delved into the script’s functionality, dissected its code, and provided practical examples of its usage.
Whether checking the contents of a mounted volume in WordPress or managing multiple container setups, this script can significantly enhance your productivity by reducing the guesswork and time spent on routine tasks. Remember, you can customize the script to suit your needs and working environment.
We hope you find this script useful in your Docker and Kubernetes operations. As always, we encourage you to experiment with the script, adapt it to your needs, and share your experiences and feedback. Happy Dockering!