When working with IOTstack, it is useful to automate many common tasks such as:
- Launching a shell inside a container (for general nosing around);
- Launching a specific process inside a container (eg the InfluxDB command line interface);
- Executing common tasks (like "up" and "down") without having to first change your working directory to
~/IOTstack; - Extending commands to fill gaps. For example, terminating a single container instead of taking down your entire stack;
- and so on…
Although you could create a scheme of shell scripts to accomplish most of these goals, aliases and shell functions are usually simpler and, often, the only way to accomplish some goals.
Note:
- This GitHub repository used to be a gist. Unfortunately, the copy-and-paste method of acquiring the aliases would occasionally cause problems when the original Unix
0x0Aline-endings (LF) were replaced with DOS/Windows0x0D 0x0Aline-endings (CR+LF). The alias file would then fail. Providing the alias file via Git should reduce the likelihood of that happening.
Login to your Raspberry Pi and clone this repository. The recommended commands are:
$ mkdir -p "$HOME/.local"
$ git clone https://github.com/Paraphraser/IOTstackAliases.git "$HOME/.local/IOTstackAliases"Make sure your stack is running:
$ cd ~/IOTstack
$ docker-compose up -dYour containers need to be up for the next step.
Test the result like this:
$ . ~/.local/IOTstackAliases/dot_iotstack_aliasesNotes:
-
The
.followed by a space at the start of the command is called a source statement. It tells the shell to process the file in-line, like an#includestatement in a programming language.Sourcing a file is different to executing a file. If you check, you will see that
dot_iotstack_aliasesdoes not have execute permission. Neither does the file start with#!/bin/bash. This is intentional. Although you can add execute permission and then execute the file as a command, it will not produce the correct result. It must be sourced. -
The "dot_" prefix on the filename is intended to remind you that the file should be sourced.
If you have done the first two steps correctly, you should get output like this:
Useful Docker aliases and functions:
Influx: influx
NodeRed: NODERED_DATA
Docker: PRUNE | I | S | T | V
DI {<image> …}
DNET | DPS {<container> …}
BUILD | CONFIG | DOWN | PULL {<container> …}
REBUILD | RECREATE | RESTART | UP {<container> …}
If you get any error messages, go back and check your work.
To apply dot_iotstack_aliases each time you login, add this source statement:
. "$HOME/.local/IOTstackAliases/dot_iotstack_aliases"to one of the following files:
- ~/.bashrc
- ~/.profile
What's the difference? I'm glad you asked:
.profileis called when yousshinto your Raspberry Pi but not when you open a terminal session in VNC..bashrcis called when you open a terminal session in VNC but not when youssh.
You might be thinking, "I access my Raspberry Pi using both ssh and VNC so that means I should add the source statement to both files." Well, yes and no. There is a wrinkle. The .profile that you get by default already sources .bashrc, like this:
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
If you have not removed those lines from .profile then .bashrc is the correct place to add the source statement to apply dot_iotstack_aliases. If you have removed those lines from .profile then you may need to add the source statement to both files.
Here's an example of editing .bashrc using vi:
$ vi ~/.bashrc
G
o
. "$HOME/.local/IOTstackAliases/dot_iotstack_aliases"
[ESC]
:wq
$In words:
-
Launch "vi" with the target file.
-
Press G to jump to the end of the file.
-
Press o to open a new line after the last line in the file, and go into insert mode.
-
Type the source statement as-is and press return at the end of the line. Make sure you pay attention to these key points:
- The line starts with a period (
.) followed by a space; - There are no other spaces on the line; and
- Make sure you match the spelling exactly.Unix is case-sensitive.
- The line starts with a period (
-
Press esc to exit insert mode.
-
Press : to move to command mode, w to write the in-memory buffer to the target file, and q followed by return to leave "vi".
Use the tail command to confirm your editing:
$ tail -1 ~/.bashrc If you add a new container, an alias for its shell will be added to the cache automatically the next time you login.
You can always start over from scratch, like this:
-
Remove the cache:
$ rm ~/.cache/IOTstackAliases/cache -
EITHER logout and login again OR run the following command:
$ . ~/.local/IOTstackAliases/dot_iotstack_aliases
Both approaches will rebuild the alias cache.
I create most of my aliases using all-caps names. I think this makes it easier for auto-completion to do its work but, it's your system, so change it if you don't like it.
The key advantage of these aliases is that they work from anywhere. You don't have to cd ~/IOTstack first.
The general-purpose aliases (and functions) are the ones listed under the "Docker" heading above. They are described here in alphabetical order.
Alias: BUILD {container …}
$ docker-compose up -d --build {CONTAINER …}-
Similar to
UPin that it adds the--buildflag to re-build the local images for containers that are built with aDockerfile. -
Differs from
REBUILDin that no attempt is made to pull down any later base image from DockerHub. -
Without arguments, every service definition in your
docker-compose.ymlthat includes abuilddirective will be re-built by running its Dockerfile. -
With a list of named containers, it restricts itself to just those containers.
-
Should usually be followed by:
$ docker system prune
Alias: CONFIG {container …}
$ docker-compose config {CONTAINER …}-
Merges
docker-compose.ymlanddocker-compose.override.yml(if present), and displays the parsed result as it will be implemented. -
Without arguments, every service definition will be displayed.
-
With a list of named containers, it restricts itself to just those containers.
-
This is good for checking the effect of override files but you need to be aware that the result will:
- usually have both service definitions and clauses in a completely different order that the input files; and
- where a clause supports both a simple and complex structure, this command will display the complex structure.
Function: DI {image …}
$ docker images { | grep -e "^REPOSITORY" { -e "image" … } }When invoked:
- without arguments, is a synonym for
docker images - with arguments, executes
docker imagesand pipes the output togrepto filter the header line plus one wildcard match for each argument.
Function: DNET {container …}
$ docker ps --format "table {{.Names}}\t{{.Ports}}"- The column list provided by the
--formatargument focuses on the container's networking aspects (ports etc). - Has the advantage that the information for each container usually fits on one line in the terminal window.
- Optional arguments limit the display to named containers. Names are interpreted as wildcards.
Alias: DOWN {container …}
$ docker-compose down {CONTAINER …}- Without arguments, takes down your entire stack.
- With a list of named containers, it restricts itself to just those containers.
Function : DPS {container …}
docker ps --format "table {{.Names}}\t{{.RunningFor}}\t{{.Status}}"- The column list provided by the
--formatargument focuses on whether a container is running or in a restart loop. - Has the advantage that the information for each container usually fits on one line in the terminal window.
- Optional arguments limit the display to named containers. Names are interpreted as wildcards.
Alias: I
$ cd ~/IOTstack
$ lsAlias: PRUNE
$ docker system prune -f- Removes stopped containers, unused networks, obsolete images and build caches.
- The
-fmeans "force" but it is closer to a-yin its effect in that it will not remove anything that breaks a dependency chain. - Often useful to call twice. The first
pruneremoves local images, the second removes base images.
Alias: PULL {container …}
$ docker-compose pull {CONTAINER …}-
Tells
docker-composeto check for more-recent images on DockerHub and download any newer images. -
Only applies to service definitions with an
imagedirective. -
Without arguments, it tries to pull everything in your
docker-compose.yml. -
With a list of named containers, it restricts itself to just those containers.
-
Should usually be followed by:
$ UP $ docker system prune
Alias: REBUILD {container …}
$ docker-compose build --no-cache --pull {CONTAINER …}-
Can be thought of as a more powerful form of
BUILD. It forces the download of any newer base image from DockerHub and forces the rebuild of the local image by applying theDockerfile. -
Without arguments, it processes all service definitions with a
builddirective. -
With a list of named containers, it restricts itself to just those containers.
-
Should usually be followed by:
$ UP $ docker system prune $ docker system prune
The first
pruneremoves the older local image, the secondprunethe older base image.
Alias: RECREATE {container …}
$ docker-compose up -d --force-recreate {CONTAINER …}- Does a full tear down and reconstruction of the container. Unlike
RESTART, it guarantees that the container starts the same as the image. - Without arguments, it recreates all running services.
- With a list of named containers, it restricts itself to just those containers.
Alias: RESTART {container …}
$ docker-compose restart {CONTAINER …}- A restart sends a signal to the container to restart itself. It's closer to restarting the process inside the container than tearing down and reconstructing the container. Unlike
RECREATE, any changes made inside the container persist. - Without arguments, it restarts all running services.
- With a list of named containers, it restricts itself to just those containers.
Alias: S
$ cd ~/IOTstack/services
$ lsAlias: T
$ cd ~/IOTstack/.templates
$ lsAlias: UP {container …}
$ docker-compose up -d {CONTAINER …}- Without arguments, it brings up your entire stack.
- With a list of named containers, it restricts itself to just those containers.
Alias: V
$ cd ~/IOTstack/volumes
$ lsAlias: «container»\_SHELL
This opens a shell within the container. For example:
$ INFLUXDB_SHELLexpands to:
$ docker exec -it influxdb /bin/bashOpening a shell within a container means that the next thing you see is a prompt from the shell running inside the container, and with the container's view of the file system. INFLUXDB_SHELL will result in a prompt like this:
root@95b20550cb8a:/#where the "#" indicates "you are running as root" (which is another way of saying "you don't need to use sudo for anything"). To get out of a container shell, either press control+d or type exit and press return.
Another benefit of using an alias scheme for common tasks is that you don't have to remember things like "most containers use bash but some, like Mosquitto, don't have bash so you need to use ash or sh, while others, like Portainer and Portainer-CE don't have any shell at all.
Notes:
-
If you are trying to develop a "«container»_SHELL" alias of your own and find that
bashdoesn't work, try replacingbashwithash, and thensh. -
If you're wondering about the
-itoption on «container»_SHELL aliases, think of it as "interactive terminal". It's really-i(keep STDIN connected) and-t(allocate a pseudo-TTY for output). It is howdocker execknows to wait for human interaction, and why you have to typeexitor press control+d to get out of a container.
Alias: influx { argument …}
The influx alias is an exception to my all-caps naming convention. It expands to:
$ docker exec -it influxdb influx -precision=rfc3339It has the same effect as:
$ docker exec -it influxdb bash
# influx -precision=rfc3339
Or, in words:
- Open a shell into the influxdb container, then
- From inside the influxdb container, execute the
influxcommand.
The influx command is InfluxDB's Command Line Interface.
The -precision=rfc3339 option tells influx to display timestamps in human-readable form rather than nanoseconds since 1/1/1970. The timestamps are in UTC but you can tell influx to convert them to your local time by adding a tz() function to queries, like this:
SELECT * from «measurement» WHERE «criteria» tz('Australia/Sydney') You can append any other arguments supported by the influx CLI to the influx alias and the fact that docker exec is involved becomes entirely transparent. For example, all of these are valid:
$ influx
$ influx -database=«database name»
$ influx -type=flux
$ influx -database=«database name» -type=fluxAlias: NODERED_DATA
This alias expands to:
$ cd ~/IOTstack/volumes/nodered/data
$ lsI often have the need to go into Node-Red's persistent data store to see what's what and you may need to do that as well.