My last PHP update broke Spress, the static site generator I use for this blog. I decided to move my blog generation to a more stable and portable environment - a Docker container. I’ve documented what I did and what I learned with this blog post. This is my first attempt to do something with Docker, please excuse any bad practices.
You can find the finished Dockerfile at https://github.com/gbirke/spress-docker.
Writing the Dockerfile
FROM php:alpine
As the base image I’m using the alpine variant of the official PHP Docker image to keep the storage space for the image as small as possible.
Since the docker container will only run on my local machine and is not intended to be deployed, I don’t bother setting up an extra user account. Everything will be run as root
inside the container.
RUN curl -L -o /usr/local/bin/spress https://github.com/spress/Spress/releases/download/v2.1.3/spress.phar && \
chmod +x /usr/local/bin/spress
The installation of Spress is fairly simple: Download the Spress PHAR file and make it executable. The commands are chained with &&
instead of being individual RUN
commands, because Docker internally creates a new image for every RUN
command and I don’t want to clutter my hard disk with too many intermediary images.
WORKDIR /var/www
ENTRYPOINT [ "/usr/local/bin/spress" ]
CMD [ "site:build", "--watch", "--server" ]
WORKDIR
is pretty self-explanatory: It’s the directory where all the following commands will be run.
ENTRYPOINT
specifies the command that will always be run when the container is started.
CMD
specifies what parameters will be passed to the command in ENTRYPOINT
. They can be overwritten when starting the container. By default, a development server is started.
The Dockerfile is complete. Now a Docker image needs to be built with the command
docker build -t gbirke/spress .
The option -t gbirke/spress
tags it for later submission to DockerHub. This will allow me to skip the build step when using it on other machines.
Runnning Spress
The docker run
command takes a Docker image and runs it in a Docker container.
The full command is
docker run -v $(pwd):/var/www -p 4000 --name serve_my_blog -t gbirke/spress
Let’s have a look at all the parameters
-v $(pwd):/var/www
mounts the current directory as a volume inside the running container.-p 4000
exposes port 4000 of the container to my host computer so I can reach the blog at http://localhost:4000/ from my browser.--name serve_my_blog
applies the nameserve_my_blog
to the image. If this parameter is missing, Docker will generate an arbitrary name likeoptimistic_payne
ormodest_agnesi
.-t
assigns the running process a “pseudo-tty”. If I left this parameter out, I wouldn’t be able to detach myself from the docker image with Control-C. Using a pseudo-tty also means that Spress can use its colored output.
While the image is running, I can go to localhost:4000/
and browse my blog.
Stopping and restarting
If I want to detach myself from the running Spress web server, I can press Control-C. The image will still be running, but in a detached state.
With the command docker ps
I can see a list of images, their names and their status. To attach my console back to the process to see its output I can use docker attach serve_my_blog
(for full console access which is not needed here) or docker logs -f serve_my_blog
for just reading the output.
A running image can be stopped the command docker stop serve_my_blog
which will wait for 10 seconds an then stop the image. To stop immediately, I use docker stop -t 0 serve_my_blog
.
When I’ve stopped a container, docker ps
will not show it anymore. But it still exists, in a stopped state. I can see that with docker ps -a
, which will show all containers. If I try to start the container again with docker run
and the same name, I will get the error message the container name "/serve_my_blog" is already in use by container
.
To restart the container with the same parameters, I could use the command docker restart serve_my_blog
.
To start the image with different parameters, I’d first have to remove the stopped image. Removing all stopped images can be done with the command
docker rm $(docker ps -q -f "status=exited")
By adding the --rm
parameter to the docker run
command, the image will be removed automatically when the container stops.
By adding the -d
parameter to the docker run
command, the image will start in a detached state.
Usage without the web server
When I just want to build my blog with Spress, without having a web server or watching for file changes, I append the Spress command line options to the docker run
command:
docker run -v $(pwd):/var/www --rm -t gbirke/spress site:build
Here is how I run it with my production configuration:
docker run -v $(pwd):/var/www --rm -t gbirke/spress site:build --env=prod
Conclusion
This was a fun little project. I’ve long dreaded looking into Docker, especially on macOS, my primary work OK. Now I’ve boarded the Docker hype train and will continue exploring the possibilities. I’ve already experimented with running MySQL in a Docker image for running tests for my “Remember me” library …