Created
March 28, 2019 22:01
-
-
Save akatrevorjay/14e6ab8802281abe39f5c019f3ce4646 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -eo pipefail | |
usage() { | |
cat <<-'EOF' | |
# Container exec | |
A method for exporting commands for transparent docker-compose usage from your shell, | |
letting you forget that you're even using commands across different containers. | |
## Come again? | |
There are several scripts in the `bin/` folder that are part of `container-exec`, which as it's name may suggest can be | |
useful for running commands easily inside of a given container. | |
This includes bringing a command that's *inside* of a specific container *outside* to your local environment in a | |
mostly transparent fashion that may help your wrists from the pain of typing `docker-compose exec -u postgres postgres | |
psql` just to get to a postgresql prompt. | |
In other words, this is magic that allows you to: | |
```sh | |
# Run psql as the postgres user in the postgres container | |
# equivalent to: docker-compose exec -u postgres postgres psql | |
./bin/psql | |
``` | |
As you normally would, but it will actually be running transparently inside of the `postgres` container. | |
Return values and arguments are preserved as you should expect as well. | |
Other examples: | |
```sh | |
# Start a shell in the web container | |
# equivalent to: docker-compose exec web bash | |
./bin/web bash | |
``` | |
```sh | |
# These also run in the web container as if you were inside of it just fine: | |
./bin/manage.py shell | |
./bin/runtests.py -vv | |
``` | |
## How does this work? | |
```sh | |
./bin | |
├── container-exec # ~30 lines of mostly voodoo. | |
├── postgres # shim that sources container-exec above, named the same as the container. | |
└── psql -> postgres # symlink to postgres above, specifying a command to run in the destination container. | |
``` | |
Via a one line shim *file* named the same as the container (the line is just sourcing `container-exec`). | |
Commands are then made by just symlinking to said shim. | |
* Commands can be optionally prefixed by `{container_name}-`. | |
This should be the go to unless it's absolutely obvious what container a command will intuitively run in, such as | |
`psql` or `manage.py`. (Definitely not ambiguities like `bash` and such.) | |
Take a look at the comments below if you want to *go deeper*, it's not large. | |
## What's in a shim? | |
Just a line to `source` this script: | |
```sh | |
#!/bin/bash | |
source "${0%/*}/container-exec" | |
``` | |
Optionally (and rarely) you'll want a set of commands to be executed as a specific user (looking at you, postgres): | |
```sh | |
#!/bin/bash | |
username=$(readlink "$0") # optional; just sets the user to run commands as in the container | |
source "${0%/*}/container-exec" | |
``` | |
## Source | |
Part of boilerplate: https://github.com/akatrevorjay/boilerplate | |
EOF | |
} | |
main() { | |
# Get the basename of what was executed to get here. | |
name="${0##*/}" | |
# If we're running from a symlink, we're a command to run inside of that container, so we'll need that name. | |
# If not, we are the container shim, and our arguments contain the command to run. | |
realname=$(readlink "$0" || echo "$name") | |
container="$realname" | |
# If our name is prefixed with the container name and a dash, strip. | |
name="${name#$realname-}" | |
case "$realname" in | |
$name) | |
[ $# -gt 0 ] || set -- --help | |
case "$1" in | |
-h|--help|help) | |
usage | |
exit 0 | |
;; | |
esac | |
;; | |
esac | |
cmd=( | |
docker-compose | |
exec | |
) | |
# Allow specifying the username to run as in the shim | |
[[ -z "$username" ]] || cmd+=(--user "$username") | |
cmd+=("$container") | |
# If we're running from a symlink, we're a command to run inside of that container. | |
[[ "$name" == "$realname" ]] || cmd+=("$name") | |
exec "${cmd[@]}" "$@" | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment