Dockerizing multi-git

In this lesson, we'll demonstrate how to upload our Docker image to DockerHub and then run multi-git via Docker even if git is not available locally.

Uploading the multi-git image to DockerHub

So far, we’ve built a local Docker image, but, if we want to share our work with other users we need to upload our Docker images to an image registry. Every cloud provider has an image registry, but I’ll use the defaultDockerHub from Docker. To upload (or push in docker nomenclature) an image, you need an account. My account name is g1g1. To push an image to the DockerHub registry, it needs to be tagged with the account name. There is no need to rebuild. We can tag the existing image:

(🐙)/multi-git/
$ docker tag multi-git:latest g1g1/multi-git:latest

(🐙)/multi-git/
$ docker images --format "{{.ID}} {{.Repository}}" | grep multi-git$
517c0cc344f3 g1g1/multi-git
517c0cc344f3 multi-git

As you can see, the same image ID has two repositories: multi-git (local) and g1g1/multi-git (DockerHub). Now, we can login and push the image:

(🐙)/multi-git/
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: g1g1
Password: ********
Login Succeeded

(🐙)/multi-git/
$ docker push g1g1/multi-git:latest
The push refers to repository [docker.io/g1g1/multi-git]
4f54530836b8: Pushed
e59e3c4e6328: Mounted from alpine/git
43e73583bb50: Mounted from alpine/git
50644c29ef5a: Mounted from alpine/git
latest: digest: sha256:d75d816c5ed100103623b565d639db04b1e4dbd5421d81f207749f6b819e2877 size: 1158

At this point, anyone can pull the image and run it.

Running multi-git with Docker

Let’s remove all the multi-git images to demonstrate how to run it from scratch:

$ docker rmi -f 517c0cc344f3

Note that multi-git relies on a config file, or environment variables, and it operates a root directory of git repositories. Those files and directories are available locally, but multi-git runs inside the Docker container that has its own isolated file system. The way to handle it is to mount local directories into the container.

Let’s check the status of the multi-git repo itself. It resides on my machine at ~/git/multi-git, but, we can map it to any directory inside the container. Let’s map my ~/git to /git. The repository list should be just "multi-git". Let’s create config file to that effect:

root = "/git"
repos = "multi-git"

Here is the command to make it all happen:

$ docker run -it -v $(pwd):/root/.config  -v ~/git:/git g1g1/multi-git status

Let’s examine the output first and then circle back and explain the command. First, docker can’t find the local image called g1g1/multi-git:latest because we just deleted it. So, it fetches it from DockerHub:

Unable to find image 'g1g1/multi-git:latest' locally
latest: Pulling from g1g1/multi-git
df20fa9351a1: Already exists
05655c7bc012: Already exists
431be4a7cb0f: Already exists
89de374b7226: Pull complete
Digest: sha256:d75d816c5ed100103623b565d639db04b1e4dbd5421d81f207749f6b819e2877
Status: Downloaded newer image for g1g1/multi-git:latest 

Then, it runs multi-git, which is still on version v0.8.20 on its own git repository. You can see that there is a new Dockerfile and there are some changes to go.sum and the README.

version:  v0.8.20
Current version is: 0.8.20
[multi-git]: git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   Dockerfile

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   Dockerfile
	modified:   README.md
	modified:   go.sum

There are also, some untracked files, which are the Dockerfile.big without multi-stage build, the multi-git binary we built locally, and the config file multi-git.toml we just created run multi-git from the container:

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	Dockerfile.big
	multi-git
	multi-git.toml

Now that you have seen multi-git running from a Docker container, let’s return to the command to understand exactly what it does.

$ docker run -it -v $(pwd):/root/.config  -v ~/git:/git g1g1/multi-git status

The -it flags tell Docker to run the command interactively and print the result to standard output on the host.

The -v $(pwd):/root/.config flag tells Docker to mount the current directory into /root/.config inside the container. Since multi-git runs as root, this is equivalent to ~/.config, where multi-git will search for the multi-git.toml config file, which conveniently is available in the current directory.

Here is the config file again:

root = "/git"
repos = "multi-git"

So, multi-git inside the container will search for the git repository “multi-git” under the directory “/git”.

This is where the second -v flag mounts the local ~/git directory to /git inside the -v ~/git:/git g1g1/multi-git container.

Finally, the git command to execute in this repository is status.

Since Docker is always checking if the local version is up to date we can update the g1g1/multi-git:latest, and any user will always pull the latest from DockerHub.

This is an alternative way for auto-update as long as users invoke multi-git using the correct command.

Conclusion

In this lesson, you learned a little about Docker and why it is useful both for cloud-native applications and CLIs. We built a lean statically-linked, multi-git executable and created a multi-stage Dockerfile to package it in a Docker image. Then, we uploaded the image to DockerHub and ran multi-git via Docker.

Quiz

Get hands-on with 1200+ tech skills courses.