Gitolite + Docker = A GitOps Swiss Army Knife

Welcome to another playground: “Gitolite + Docker”

Lately, we started a new series of blog posts accompanied by ready-to-use Git repositories:

In this post, we present how to run Docker commands from a server-side Git hook.

The git backend itself is a Docker image based on jgiannuzzi/gitolite with a Docker client installed.

FROM jgiannuzzi/gitolite

RUN apk add --no-cache docker
RUN addgroup git docker
…

Prepare the environment - Gitolite

Prepare and build the Gitolite image with an embedded Docker..../build.sh. In essence, the script contains the steps described in the cookbook mentioned below…

gitolite cookbook - (a.k.a. "stop all that rambling and just tell me what I need to do!")

Generate a gitolite-admin key:

ssh-keygen -t rsa -b 4096 -f credentials/gitolite-admin_id_rsa -N "" -C "gitolite-admin@sandbox"

…setup Gitolite

docker run --rm \
    -e SSH_KEY="$(cat credentials/gitolite-admin_id_rsa.pub)" \
    -e SSH_KEY_NAME="admin" \
    -v $(pwd)/docker/gitolite/keys:/etc/ssh/keys \
    -v $(pwd)/docker/gitolite/git:/var/lib/git \
    jgiannuzzi/gitolite true

…fire up the sandbox with up.sh.

Verify the Gitolite set up with a simple ssh command like follows:

$ ssh -T -p 2222 -i credentials/gitolite-admin_id_rsa git@localhost
…
hello admin, this is git@8b85d586c069 running gitolite3 3.6.11 on git 2.22.0

 R W    gitolite-admin
 R W    testing

Congratulations! Your basic Gitolite set up is alive and kicking!

Double-check the Docker environment via

$ docker exec -it gitolite-playground_git-sandbox_1 docker ps --format "{{.Names}}"
gitolite-playground_git-sandbox_1

🎉 - Gitolite + Docker is up and running…

Enable server-side hooks

Edit docker/gitolite/git/.gitolite.rc and uncomment the line containing LOCAL_CODE as shown below:

        LOCAL_CODE                =>  "$rc{GL_ADMIN_BASE}/local",

Check the configuration with

$ docker exec -it --user git --workdir /var/lib/git gitolite-playground_git-sandbox_1 gitolite query-rc LOCAL_CODE
/var/lib/git/.gitolite/local

Install the prepared server-side post-receive hook

Clone the gitolite-admin repo into the prepared workspace.

git clone --config core.sshCommand="ssh -i credentials/gitolite-admin_id_rsa -p 2222" git@localhost:gitolite-admin workspace/gitolite-admin

Add the prepared hook:

cd workspace/gitolite-admin
mkdir -p local/hooks/common
cp ../../hooks/post-receive.sample local/hooks/common/post-receive
git add local
git commit -m "Add post-receive hook"

Note: You might need to update .git/config if you want to run the push command from within the repository itself.

[core]
...
  sshcommand = ssh -i ../../credentials/gitolite-admin_id_rsa -p 2222
...

Use git push to update gitolite.

Git hook in Action

Generate a new user key and add it to the gitolite configuration:

Note: This step is optional - for testing purposes, you could reuse the admin user.

Switch back into the main repository:

ssh-keygen -t rsa -b 4096 -f credentials/gitolite-user_id_rsa -N "" -C "gitolite-user@sandbox"
cp credentials/gitolite-user_id_rsa.pub workspace/gitolite-admin/keydir/user.pub

Again add and commit the changes plus git push to update gitolite.

Check the setup with the freshly created user:

ssh -T -p 2222 -i credentials/gitolite-user_id_rsa git@localhost

Finally…

$ git clone --config core.sshCommand="ssh -i credentials/gitolite-user_id_rsa -p 2222" git@localhost:testing workspace/testing

Do some changes, add, commit and push

[main 8cbdc79] initial commit
 1 file changed, 1 insertion(+)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 319 bytes | 319.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Running 'post-receive' hook...
To localhost:testing
   324be7d..8cbdc79  main -> main

Did you spot the remote: tagged line? The server-side hook was triggered. Yay! 🏆

Hey Olli, many thanks! For carfully testing the setup.

Bonus - Do it yourself

In case you got hooked 🧐 - check out the playground availble on Github datenkollektiv/gitolite-playground and roll up your sleeves.

Bonus - Create a Working Copy

To create a working copy (inside the commit hook script) we create a temporary clone inside /workspace:

HEAD_REF=$(git --git-dir=${GL_REPO_BASE}/${GL_REPO}.git rev-parse --verify HEAD)

sudo mkdir /workspace/${HEAD_REF}
sudo chown git:git /workspace/${HEAD_REF}

git clone ${GL_REPO_BASE}/${GL_REPO}.git /workspace/${HEAD_REF}

Random Resources

In case you ask yourself How to retrieve the hash for the current commit in Git? - git-rev-parse - Pick out and massage parameters is the answer.


Photo by Immo Wegmann on Unsplash