docker – adding commands to containers
Introduction
I am fully invested living within docker containers. Utilizing containers makes switching between versions of various applications easy. However, leveraging tools within that container can be frustrating; as many standard commands are missing.
For the sake of this article I’m using a Cassandra docker image. The process can be used with other containers, and the base image I’m using will work with other debian based distros (I have used my same side-car container with the confluent Kafka containers as well).
Examples
- improving the setting of the terminal size
- adding VI (or another editor)
Improving Setting Terminal Size
Have you ever experience issues with terminal sizing differences between your terminal and your container? The shell within the container is usually has a smaller terminal size than your developer machine terminal application. This results in early line wrapping.
21:25:12:buesing:~/workspaces/blog % docker exec -it blog_cassandra_1 bash root@65e2641ff45d:/% cqlsh Connected to Test Cluster at 127.0.0.1:9042. [cqlsh 5.0.1 | Cassandra 3.11.1 | CQL spec 3.4.4 | Native protocol v4] Use HELP for help. pleStr CREATE KEYSPACE IF NOT EXISTS ks0000000000 WITH REPLICATION = { 'class' : Sim #{{line wraps, 'ple' at beginning of line}} CTRL-U cqlsh: exit root@65e2641ff45d:/% stty rows 40 cols 128 root@65e2641ff45d:/% cqlsh Connected to Test Cluster at 127.0.0.1:9042. [cqlsh 5.0.1 | Cassandra 3.11.1 | CQL spec 3.4.4 | Native protocol v4] Use HELP for help. cqlsh: CREATE KEYSPACE IF NOT EXISTS ks0000000000 WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1}; cqlsh: exit root@65e2641ff45d:/% CTRL-D
I tend to forget to run the stty at the shell prompt and have to exit/suspend the application and then apply those settings.
stty rows 40 cols 132
Furthermore, I never remember my terminal size and MacOS iTerm2 doesn’t show the window size within the display (at least without customizations).
Ideally, I would not worry about it; a simple use of X11’s resize command would take care of it for me.
eval `resize`
I have yet to see X11 commands available on any preconfigured docker image (and rightfully so).
Adding VI
The omission of vi from containers makes sense for containers running applications, but for development it is hard to do something without it. Making changes to large configuration files (e.g. /etc/cassandra/cassandra.yaml) is a lot easier if I have vi.
Solutions
Layering the Container
For my example provided here, I could easily layer the Cassandra container with the additional packages added. For a single container, this is probably the preferred way to go. When you are dealing with a many containers (e.g. Kafka) the value here is more apparent. If you are already customizing containers, that could still be the proper/viable solution.
Side-Car Sharing unix commands between containers
My solution to this problem: construct a docker container adding my commands and using a shared volume to access those commands from other containers.
Steps
1. Find the core image of the container you are interested in augmenting and create a Dockerfile using the same image.
debian:stretch-slim
2. Add the needed installation commands to add the software packages you need to your Dockerfile. In my case adding vim and xorg with apt-get as I am using a debian distro.
3. Build the image and tag it.
docker build --tag support:stretch-slim .
4. Add support image to docker-compose.
5. Create a volume (e.g. support) that can be shared between two containers.
6. Mount the share volume to all of your containers.
7. Start the containers.
docker-compose up -d
8. log into the support container and move binaries to the shared /opt shared volume.
docker exec -it blog_support_1 bash
8a. move the needed binaries and needed shared libraries (determining missing libraries by running the command in the other containers and let it tell you what shared library cannot be found); or just copy all the libraries and be done with it.
mkdir /opt/bin mkdir /opt/etc mkdir -p /opt/lib/x86_64-linux-gnu cp /usr/bin/resize /opt/bin cp /usr/bin/vim.basic /opt/bin/vi cp /usr/lib/x86_64-linux-gnu/libgpm.so.2 /opt/lib/x86_64-linux-gnu
8b. create a bash profile screen you can source after logging in; you will need to set LD_LIBRARY_PATH as those shared libraries will not be in a standard location.
cat >/opt/etc/.bashrc
export LD_LIBRARY_PATH=/usr/lib:/usr/lib/x86_64-linux-gnu:/opt/lib:/opt/lib/x86_64-linux-gnu export PATH=/opt/bin:${PATH} eval `resize`
Logging into Containers
docker exec -it blog_cassandra_1 bash --init-file /opt/etc/.bashrc
Next Steps
Add in your must have commands (e.g. curl). You may decide the hassle of finding out what .so files are absolutely necessary and just copy all of /usr/lib/x86_64-linux-gnu/.
cp /usr/lib/x86_64-linux-gnu/* /opt/lib/x86_64-linux-gnu
Also, don’t forget to add your favorite alias and functions to your /opt/etc/.bashrc configuration.
Enjoy your added productivity.