Blogging with Docker¶
One issue with the previous approach to blogging is the requirement of installing packages to build the blog. Virtual machines can be installed to alleviate this matter, but at the cost of manually installing an OS and the corresponding packages. Furthermore, the virtual machine needs its own hacks and a lot of computational resources to work properly.
Docker CE is the latest solution to this problem. Installing it is very simple and you only need to run
sudo usermod -aG docker ${USER}
afterwards if you would like to use Docker as a non-root user. Make sure to reboot to apply the new permissions.
Docker itself only needs a Dockerfile
, but this post will include
additional items in order to replace the older blogging methods:
# Use an official Python runtime as a parent image
FROM python:3-slim
# Set the working directory to /app
ENV DEV=/workspace/dev
ENV DEV_DATA=/workspace/data
# Copy the current directory contents into the container at ${DEV}
WORKDIR ${DEV}
COPY . .
ENV TMP=/tmp
ENV ANACONDA_VERSION="https://repo.anaconda.com/archive/Anaconda3-2018.12-Linux-x86_64.sh"
ENV ANACONDA_PATH=${TMP}/anaconda.sh
ENV ANACONDA_ROOT=${DEV}/anaconda
ENV ANACONDA_BIN=${ANACONDA_ROOT}/bin
ENV GCLOUD_SDK_VERSION="https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-237.0.0-linux-x86_64.tar.gz"
ENV GCLOUD_SDK_PATH=gcloud_sdk.tar.gz
ENV GCLOUD_SDK_ROOT=google-cloud-sdk
ENV GCLOUD_SDK_BIN=google-cloud-sdk/bin
ENV LILYPOND_VERSION="http://lilypond.org/download/binaries/linux-64/lilypond-2.20.0-1.linux-64.sh"
ENV LILYPOND_PATH=${TMP}/lilypond.sh
ENV LILYPOND_ROOT=${DEV}/lilypond
ENV LILYPOND_BIN=${LILYPOND_ROOT}/bin
RUN apt-get update --fix-missing \
&& apt-get install -y \
wget bzip2 ca-certificates libglib2.0-0 libxext6 libsm6 libxrender1 \
asymptote texlive-font-utils pdf2svg \
silversearcher-ag mercurial less vim \
&& wget --quiet ${ANACONDA_VERSION} -O ${ANACONDA_PATH} \
&& /bin/bash ${ANACONDA_PATH} -b -p ${ANACONDA_ROOT} \
&& rm ${ANACONDA_PATH} \
&& echo "export PATH=${ANACONDA_ROOT}/bin:$PATH" >> ~/.bashrc \
&& wget --quiet ${LILYPOND_VERSION} -O ${LILYPOND_PATH} \
&& /bin/bash ${LILYPOND_PATH} --prefix ${LILYPOND_ROOT} \
&& rm ${LILYPOND_PATH} \
&& rm -rf /var/lib/apt/lists/* \
&& echo "export PATH=${LILYPOND_ROOT}/bin:$PATH" >> ~/.bashrc \
&& wget --quiet ${GCLOUD_SDK_VERSION} -O ${GCLOUD_SDK_PATH} \
&& tar xvf ${GCLOUD_SDK_PATH} \
&& rm -rf ${GCLOUD_SDK_PATH} \
&& ${GCLOUD_SDK_ROOT}/install.sh --quiet --usage-reporting False --command-completion True --path-update True \
&& cp hgrc ~/.hgrc \
&& cp inputrc ~/.inputrc \
&& ${GCLOUD_SDK_BIN}/gcloud components update --quiet
# Install any needed packages specified in requirements.txt
RUN ${ANACONDA_BIN}/pip install --trusted-host pypi.python.org -r ${DEV}/requirements.txt
# Make ports available to the world outside this container
EXPOSE 80 8000 8888
# Run a shell when the container launches
CMD ["/bin/bash"]
The requirements.txt
is to support
data analysis:
sphinx
sphinxcontrib-bibtex
nbsphinx
sphinx_bootstrap_theme
sphinx_sitemap
sphinx-autobuild
pymprog
graphviz
The files .gitconfig
[core]
editor = vi
[user]
name = alphaXomega
email = alpha.x.omega@outlook.com
and .inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward
"\e[C": forward-char
"\e[D": backward-char
and .vimrc
set tabstop=4
set expandtab
are more for convenience.
Copy Data Between Docker Volume and Host¶
Suppose you have a volume created by
docker volume create blog_data
Any data transfer between host and docker volumes must happen via a container. As an example, suppose we need to generate an SSH key to connect to BitBucket:
mkdir .ssh
cd .ssh
ssh-keygen -f id_rsa
docker container create --name dummy --mount source=blog_data,target=/workspace/data python:3-slim
cd ..
docker cp .ssh dummy:/workspace/data/.ssh
docker rm dummy
Running a Docker Container¶
Suppose the blog uses the provided Dockerfile
to build an image as
follows:
docker build -t blogger .
The blog needs three processes to fully operate:
gnome-terminal --tab -- docker run --name sphinx_autobuild --rm -it --mount source=blog_data,target=/workspace/data blogger
echo -e 'Run this for container sphinx_autobuild (1):\n\neval `ssh-agent`; cd ../data/allthingsphi; sphinx-autobuild -b html source/ gae/www\n'
gnome-terminal --tab -- docker run --name python_server --rm -it -p 8000:8000 --mount source=blog_data,target=/workspace/data blogger
echo -e 'Run this for container python_server (2):\n\ncd ../data/allthingsphi; pushd gae/www/; python3 -m http.server\n'
gnome-terminal --tab -- docker run --name jupyter_notebook --rm -it -p 8888:8888 --mount source=blog_data,target=/workspace/data blogger
echo -e 'Run this for container jupyter_notebook (3):\n\ncd ../data/; jupyter notebook --allow-root --ip=0.0.0.0 --no-browser\n'
sphinx_autobuild is responsible for looking at the blog data for changes and rebuilding the site.
Before running the related commands, you should clone the repository.
eval `ssh-agent` hg clone ssh://hg@bitbucket.org/alphaXomega/allthingsphi
python_server tests the blog with a local web server. Remember that this process will push data to Google Cloud, make sure to initialize it.
gcloud init
jupyter_notebook allows editing of blog content. It must use the following settings in order to run inside a container.
jupyter notebook --allow-root --ip=0.0.0.0 --no-browser