Using Gitolite Hook Points with Docker

These days as a developer you spend a great part of your day on github.com. Git is the most powerful version control we have right now and github added an easy to use UI on top of it where with a couple of clicks you can add your repository and start to have a versioned control data.

But still there are some scenarios in which you don't want to use github (or any other hosted git service). What if you don't want to push your source code into cloud? What if you want a versioned data as part of your data-model? Of course there are solutions like Github Enterprise available, but they all come at a relatively high cost.

Gitolite is an open-source project that allows you to setup git hosting on a central server. Setup and installation is straightforward and there is a good cookbook at hand.

For me, the most interesting point of Gitolite is its hook points. With a little plumbing you can connect it to your other backend services and make it part of your application stack. These hooks are called by Gitolite when certain event happen in your code repository, like pull or code push of commits.

Let's see how we can call an endpoint to update some model data on backend server:

There is a post-receive hook you can configure which will be called after each push to a repository.

This is a one-line script I need to call my backend server every time someone pushes code into the repository.

#!/bin/sh

wget http://my-backend-server-address/git --post-data "user=$GL_USER&repo=$GL_REPO"

First I need to change the /home/git/.gitolite.rc file and add follwing line to it :

LOCAL_CODE => "/home/git/local"  

Now we should copy above script into a specific folder on Gitolite server :

$ mkdir -p /home/git/local/hooks/common
$ cp my-post-receive-hook /home/git/local/hooks/common/post-receive
$ chmod +x /home/git/local/hooks/common/post-receive

At the end run following commend to update Gitolite server settings:

$ gitolite setup --hooks-only

It is ready and we will start to get some post calls on backend server after each push to repositories.
There are more hook points you can play with. As an example there is a pre-receive hook, you may use to add an authorization step before user can push to a repository.

Unfortunately there is no official Docker Image for Gitolite yet but you can find several unofficial one in Docker hub. I tried couple of them and they do the job. The Gitolite docker container can be setup very easy and I can push and pull my repositories without any issue.

https://hub.docker.com/r/elsdoerfer/gitolite/ is one of the good ones which supports hooks points as well. You need to pass the address of your script in $LOCAL_CODE environment variable.

If you are a fan of small Alpine images like me , this is a good and easy to use image: https://hub.docker.com/r/jgiannuzzi/gitolite/
This image however does not support hook points. But this is not going to stop us from trying to add them ourselves!

Following the previous steps on configuring a real server, first we need to have our script inside the image, then we should change the .rc file and at last we need to run the gitolite setup.

The script can be part of image so it can be added in Dockerfile but changes in .rc file should happen on a running server which in container world means running inside a container.

jgiannuzzi/gitolite uses a docker-entrypoint.sh to setup Gitolite container in runtime we can add our setup steps to it.

#!/bin/sh

# if command is sshd, set it up correctly
if [ "${1}" = 'sshd' ]; then  
  set -- /usr/sbin/sshd -D

  # Setup SSH HostKeys if needed
  for algorithm in rsa dsa ecdsa ed25519
  do
    keyfile=/etc/ssh/keys/ssh_host_${algorithm}_key
    [ -f $keyfile ] || ssh-keygen -q -N '' -f $keyfile -t $algorithm
    grep -q "HostKey $keyfile" /etc/ssh/sshd_config || echo "HostKey $keyfile" >> /etc/ssh/sshd_config
  done
fi

# Fix permissions at every startup
chown -R git:git ~git

# Setup gitolite admin
if [ ! -f ~git/.ssh/authorized_keys ]; then  
  if [ -n "$SSH_KEY" ]; then
    [ -n "$SSH_KEY_NAME" ] || SSH_KEY_NAME=admin
    echo "$SSH_KEY" > "/tmp/$SSH_KEY_NAME.pub"
    su - git -c "gitolite setup -pk \"/tmp/$SSH_KEY_NAME.pub\""
    rm "/tmp/$SSH_KEY_NAME.pub"
    ##########################################
    ############START OF HOOK SETUP###########
    ##########################################    
    ######CHANGING .gitolite.rc
    sed -i "s|# LOCAL_CODE.*=>.*$|LOCAL_CODE => \"/var/lib/git/local\",|" /var/lib/git/.gitolite.rc
    ######give the script run access
    chmod +x  /var/lib/git/local/hooks/common/post-receive
    ######run gitolite setup
    su - git -c "gitolite setup --hooks-only"
    ##########################################
    ############END OF HOOK SETUP#############
    ##########################################
  else
    echo "You need to specify SSH_KEY on first run to setup gitolite"
    echo "You can also use SSH_KEY_NAME to specify the key name (optional)"
    echo 'Example: docker run -e SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" -e SSH_KEY_NAME="$(whoami)" jgiannuzzi/gitolite'
    exit 1
  fi
# Check setup at every startup
else  
  su - git -c "gitolite setup"
fi

exec "$@"

And this is the docker file to add our script :

FROM jgiannuzzi/gitolite  
MAINTAINER ShaB

USER git  
RUN mkdir -p /var/lib/git/.gitolite/logs  
RUN mkdir -p /var/lib/git/local/hooks/common  
ADD post-receive /var/lib/git/local/hooks/common/

USER root  
COPY docker-entrypoint.sh /  
RUN chown root:root /docker-entrypoint.sh  
RUN chmod +x /docker-entrypoint.sh  

Create a script file called post-receive and copy the contents of above oneline script into it. Copy the above docker-entrypoint.sh and Dockerfile in the same folder and build a new image:

docker build -t gitolite-alpine-hook .  

The result is a hook enabled gitolite alpnie image can be used in your docker stack.

ShaB

ShaB is a full stack developer at Cloud 66.

London, UK
Subscribe and get updates

Have feedback? Please get in touch @cloud66 on Twitter.

Everything you need to build, manage and maintain containers in production on your own servers and any cloud

Try Cloud 66 — 14 Days Free Trial, No credit card required