Moved blog to jekyll on nginx on docker
After my yearly lease came up for my VPS service, I decided to move providers and ended up going with AWS. I also did not want to use Wordpress anymore and liked the idea of static site generators and with some thought, I chose Jekyll. Since I was not using GitHub pages, I wanted an alternative way to have my site re-generated every time I have a successful git push. This leaded me to my next few choices:
- Run my blog on Docker
To respawn a site after every change, made docker seem like a perfect choice and I had some experience with it already. After I had created my site in Jekyll, I gathered all the dependencies and needs to run it in docker....
- Use nginx for control
Using just Jekyll, leaves you with a working static www root but no control for rewrites/redirects or custom magic. And no offense to Jekyll, it does a great job with static site generation but you should serve it a real web server. Jekyll does support dumping the site content into a folder, which makes it very compatible with nginx or apache
the configuration
I worked with Jekyll locally and created a template I admired, which started from martin308's left-stripe theme and made a handful or modificiations to make it work for me. These modifications included category support, social share buttons, a complete color theme change, and a few others.
After my testing, I had come up with a solid config, my Dockerfile below:
############################################################
# Dockerfile to build Nginx Jekyll blog
# ~ on Ubuntu ~
############################################################
###################################
# Set the base image to Ubuntu
###################################
FROM ubuntu:latest
###################################
# File Author / Maintainer
###################################
MAINTAINER Nick Reese [email protected]
###################################
# Update the repository
###################################
RUN apt-get update
##################################
# Download and Install utilities
###################################
RUN apt-get install -y curl bc apt-transport-https
###################################
# Download and install dev
###################################
RUN apt-get install -y rubygems ruby-dev gcc make
RUN gem install jekyll rouge kramdown git zip
###################################
# Download and Install Services
###################################
RUN apt-get install -y nginx nginx-extras
###################################
# Copy a configuration files
###################################
RUN mkdir /srv/site-repo/
ADD . /srv/site-repo/
####################################
# nginx
####################################
RUN mkdir /etc/nginx/ssl
ADD etc/nginx/nginx.conf /etc/nginx/
ADD etc/nginx/ssl/self-signed.crt /etc/nginx/ssl/
ADD etc/nginx/ssl/self-signed.key /etc/nginx/ssl/
ADD etc/nginx/conf.d/common.conf /etc/nginx/conf.d/
ADD etc/nginx/sites-available/rsty.me /etc/nginx/sites-available/
ADD etc/nginx/sites-available/blog.rsty.me /etc/nginx/sites-available/
RUN ln -s /etc/nginx/sites-available/rsty.me /etc/nginx/sites-enabled/
RUN ln -s /etc/nginx/sites-available/blog.rsty.me /etc/nginx/sites-enabled/
RUN mkdir /var/www/blog.rsty.me
RUN jekyll build -s /srv/site-repo/ -d /var/www/blog.rsty.me/
RUN rm /etc/nginx/sites-enabled/default
###################################
# Expose ports
###################################
RUN rm -rf /usr/share/nginx/html
EXPOSE 80
EXPOSE 443
###################################
# Add build scripts
###################################
ADD run/services /run/
RUN chmod +x /run/services
###################################
# START SERVICES
###################################
CMD /run/services
The above configuration does a few things:
- Sets the base image to Ubuntu 15.10
- Updates the image and installs my dependencies
- Copies my complete repository to the container
- Copies my nginx configs to the container
- Creates the www root and runs Jekyll using my copied repository files as source and www root as destination
- Expose ports 80 and 443
- Start my services script, which basically just start nginx
So this gets my blog up and running but I would need to manually build and run my docker images. I want to push them to my private BitBucket repo and automatically restart my container with the new content. To do this, I need to have BitBucket communicate to the DockerHub and DockerHub relay a successful build notification to my server. This is the fun part :)
the automagical devopsy stuff
After having my docker/nginx/jekyll work completed, I needed to create a workflow for comitting changes and triggering automatic builds. Having all my BitBucket repo pushes trigger a DockerHub build was pretty simple to set up. Now I needed an endpoint for DockerHub to send towards, after a successful build. After some searching, I found captainhook, a nice project by bketelsen which is a web listener that can run scripts based on the URL called, aka "webhook."
However, captainhook does not run over SSL, so I recommend having nginx running to forward requests to captainhook, which is how I set mine up (SSL reverse proxy). Also, run captainhook in cron so that it never dies or alternatively, use supervisord.
* * * * * pidof captainhook || /home/ec2-user/go/bin/captainhook -configdir /home/ec2-user/caphook &
This ensures that if captainhook has a hiccuup and dies, it will start again under a different PID. My configuration for restarting my docker containers looks like this:
update-docker.json
{
"scripts": [
{
"command": "/home/ec2-user/caphook/update-docker.sh",
"args": [
"NULL"
]
}
]
}
update-docker.sh
!/bin/bash
DOCKER_CURRENT=$(docker ps -a | egrep -i 'myrepo\/blog:latest' | awk '{ print $1}')
OLD_IMAGES=$(docker images | egrep -vi '(myrepo\/blog|REPO)' | awk '{ print $3}')
docker pull myrepo/blog
docker kill $DOCKER_CURRENT
docker rm $DOCKER_CURRENT
docker run -d -p 80:80 -p 443:443 myrepo/blog:latest
# cleanup
docker rmi $OLD_IMAGES
My ultimate workflow
- Test my content changes locally with Jekyll using jekyll --serve
- If satisfied, I delete the temp Jekyll _site destination directory and git commit & git push
That sums it up! Let me know what you think!