If you've ever worked with Docker, you'll know that creating Dockerfiles is an iterative process that is hard to debug. Developing a Dockerfile reminds me of writing Batch programs in college. It was a long time ago, don't ask. Suffice to say, writing a Dockerfile is a lot like getting a C program to compile. Write some code, compile, hope it creates a program that acutally works. If it doesn't add print statements or use the debugger.
Fun huh? Except docker doesn't have a debugger. Containers are also ephemeral, so their contents go away when the container stops. So, it's really hard to run a shell in a running container to debug a Dockerfile.
Problems with Dockerfiles come in these flavors:
- Dockerfile syntax errors
- Installing the right packages using the right package installation command, such as yum, apk or apt.
- Using the correct syntax for running the program in the docker container
The simplest solution is to get a basic docker container to run and use the shell to execute commands interactively. This is best accomplished by running a program that doesn't exit. It's not obvious how to do this however. The following Dockerfile runs a date command continuously. This allows using
docker exec to run a shell and perform commands interactively. If you map the local filesystem into the docker container, you can save files which are picked up when the container is re-run (otherwise local files are lost).
Here's the Dockerfile:
FROM alpine RUN apk update CMD [ "/bin/sh", "-c", "while sleep 5; do date; done" ]
Let's run the container and run a shell in it:
% docker rm -f test % docker build -t test . % docker run -d --name test -v $(pwd)/root:/root test % docker exec -it test sh -li # ps ax PID USER TIME COMMAND 1 root 0:00 /bin/sh -c while sleep 5; do date; done 6 root 0:00 sleep 5 7 root 0:00 sh -li 12 root 0:00 ps ax
At this point, you can use the container to install packages and configure the container interactively. When things are working properly, you can update the Dockerfile and you'll be good to go.