- Git Server Docker Container
- Introduction
- Assumed host environment
- Assumed execution environment
- Installation
- Create Git Server Docker Image: 01_create_gitserver_image.sh
- Create and Run Docker Container: 02_create_gitserver_container
- Create Remote Git Repository: 03_create_named_repo_in_private_gitserver.sh
- Delete Empty Remote Repository: 04_DeleteRemoteRepoIfEmpty
- Unit Tests
- Dependencies
- To-Do
- Licensing
- Note
Scripts in this package facilitate creation of a Docker Image and a Docker Container with a private GIT Server. The image uses the most recent GIT distribution (2.26 at the time of this writing). The container can be used to provide docker-network-wide Git repository for small to medium size teams working on projects whose sources cannot or should not be stored in cloud-hosted Git repositories. Small to medium start-ups or small companies might be examples.
The image is based on bitnami/minideb:jessie image as at early May 2020.
Installing latest Git from sources, and pre-requisites for building Git from sources, blows the image up from about 51MB (bitnami/minideb:jessie
) to about 778MB during the build process, and then shrinks it back to 238MB once the build is finished and build tools are removed.
The image is saved as the gitserver:1.0.0
Docker Image and, if the user invokes the script with the correct argument, also uploaded to a remote docker repository, which must be defined (see later).
- Windows 10
- Docker Desktop for Windows 2.2.0.5
- Windows Subsystem for Linux (WSL)
- git installed in the WSL environment
Scripts (bash) expect to run within the Windows Subsystem for Linux (WSL) Debian host and have access to Windows' docker.exe and docker-compose.exe.
The script expects directory structure like:
/mnt/<drive letter>/dir1/../dirN/<projectNameDir>/_commonUtils/
Top-level scripts, belonging to this package, are expected to be located in the _commonUtils directory and to have that directory as their working directory at the time of invocation.
The scripts source a number of utility scripts, located in its utils
subdirectory
The scripts assume that all projects-specific artifacts which are generated, except the docker image and the docker container, will be created in the parent directory of the _commonUtils directory.
The following diagram depicts the fictitious directory hierarchy and actual artifacts involved. The name gitserver is the 'project' name. The name _commonUtils is the name of the directory in which the main scripts are expected to reside. The utils directory contains common constant and function definitions, many of which are used in the main script.
In a suitable location in the file system create a directory to host the package. You might consider gitserver, since scripts in this package will create an image suitable for running a git servere with latest git, and a container based on that image ready for use.
For example (in WSL bash):
cd <my server's directory's parent>
mkdir -pv gitserver
cd gitserver
Then:
git clone https://github.com/mwczapski/private_gitserver_docker_container _commonUtils
OR
wget https://github.com/mwczapski/private_gitserver_docker_container/archive/master.zip -O private_gitserver_docker_container.zip
cd _commonUtils
unzip -j ../private_gitserver_docker_container.zip
git init
git add .
git commit -m "Manual commit after zip unarchive"
Scripts __env_devcicd_net.sh
, __env_gitserverConstants.sh
and fn__DockerGeneric.sh
, located in the utils subdirectory, contain all environment variables that may need to be reviewed and changed to implement site-specific customisations.
Relevant section of the __env_devcicd_net.sh
is reproduced below. Values that can be changed are highlighted.
__DEVCICD_NET_DC_INTERNAL="devcicd_net"
__DEVCICD_SUBNET_ADDRESS="172.30.0.0/16"
If the external docker network docker_devcicd_net
does not exist, it will be created by this script. Note that 'docker_' is prefixed by the docker-compose to the value defined in __DEVCICD_NET_DC_INTERNAL
. Consequently, the full name of the network will be docker_devcicd_net
in this case.
Relevant bits of the __env_gitserverConstants.sh
are reproduced below. The following variables may need to be changed from the standpoint of externally-visible names and numbers. All other variabkes are either derived from these or are internal.
__GIT_HOST_PORT=52022
__GITSERVER_NAME="gitserver"
__GITSERVER_HOST_NAME="gitserver"
__GITSERVER_CONTAINER_NAME="gitserver"
The container runs the ssh server to provide remote access to the Git repositories. Port 22 in the container is exposed on port _GIT_HOST_PORT_ of the docker host. Change that as required.
Script fn__DockerGeneric.sh
contains the definition of the remote docker repository, which will have to be changed if you want to upload the image to a remote repository. If you run the script without arguments that would request remote repository upload then the scrip will skip the related logic and repository name will be ignored. If you need to, change the value of:
__DOCKER_REPOSITORY_HOST="my.docker.repository.net"
cd /mnt/<driver letter>/dir1/../dirN/gitserver/_commonUtils
./01_create_gitserver_image.sh
OR
./01_create_gitserver_image.sh push|yes|p|y
The first variant (no argument or an argument starting with anything other than Y
, y
, P
or p
will NOT perform tagging and upload of the Docker Image gitserver:1.0.0
to the configured remote Docker Repository.
The second variant (an argument starting with Y
, y
, P
or p
) will perform all actions including uploading the Docker Image gitserver:1.0.0
to the configured remote Docker Repository.
Execution of this script will result in the Dockerfile being generated and used to create the Docker Image.
- Set environment variables
- Create
docker-entrypoint.sh
- Create
Dockerfile
- if (Image Does not exist) OR (
Dockerfile
changed since last time) => Build the Docker Image using theDockerfile
from 3 - if (container that uses the image exists) => stop AND/OR remove the container
- Create and Start the container
- Give non-root user's ownership of its home directory and resources
- Create and deploy custom Git Shell commands (help, list, backup)
- Commit continer changes to the image
- Stop the container
- Tag the image (DockerRemoteRepositoryName/ImageName:Version)
- if (user requested push to remote docer repository) => Push the image to the defined remote docker repository
bitnami/minideb:jessie
- See output of
docker image inspect gitserver
once the image is built or inspect theDockerfile.gitserver
in the parent of the _commonUtils directory to see what actually went on. - The build script adds the following to the
bitnami/minideb:jessie
image: tzdata
net-tools
iputils-ping
openssh-client
openssh-server
nano
less
- The build script adds the following to enable git to be built from sources, then removes them once build is done:
wget
unzip
build-essential
libssl-dev
libcurl4-openssl-dev
libexpat1-dev
gettext
- Perhaps needless to say, the build process also adds:
git
There are no customisable properties / variables that this script uses which would not have already been customised for script 01_create_gitserver_image.sh
. All scripts use the same __env_devcicd_net.sh
, __env_gitserverConstants.sh
and fn__DockerGeneric.sh
, so customisation applied there carries over.
cd /mnt//dir1/../dirN/gitserver/_commonUtils
./02_create_gitserver_container.sh
The script accepts no command line arguments and expects the image produced by 01_create_gitserver_image.sh
to be available.
- Set local environment variables
- Prompt whether user wants to have Windows Shortcuts created
- Confirm Artefact location
- Create docker-compose.yml file
- If (docker image does not exists) => Pull image from remote repository and abort if can't pull the image
- If container exists but is not running => start container
- If container does not exist => create container and start it
- Start ssh service in the container
- If user asked for windows shortcuts => create windows shortcuts
As I run Windows Services for Linux a lot, but use Windows Explorer a fair bit, I like to have handy shortcuts that I can use to, for example, get into the container from Explorer.
The 'extras' that you might get, if you choose to have them by responding Y to the appropriate prompt, are a bunch of windows shortcuts that execute specific commands, see table below. Note that 'dcc' stands for docker.exe container
, 'dco' stands for docker-compose.exe
and that the docker compose configuration file path is included by the script and is based on the location of the docker-compose.yml_xxxxx file.
Shortcut Name | Command |
---|---|
dcc exec -itu git gitserver | C:\Windows\System32\cmd.exe /c wsl -d Debian -- bash -lc "docker.exe container exec -itu git --workdir /home/git gitserver /bin/bash -l" || pause |
dcc exec -itu root gitserver | C:\Windows\System32\cmd.exe /c wsl -d Debian -- bash -lc "docker.exe container exec -itu root --workdir / gitserver /bin/bash -l" || pause |
dco gitserver ps | C:\Windows\System32\cmd.exe /c docker-compose.exe -f d:\gitserver\gitserver\docker-compose.yml_gitserver ps gitserver && pause |
dco gitserver rm -s -v | C:\Windows\System32\cmd.exe /c docker-compose.exe -f d:\gitserver\gitserver\docker-compose.yml_gitserver rm -s -v gitserver || pause |
dco gitserver stop | C:\Windows\System32\cmd.exe /c docker-compose.exe -f d:\gitserver\gitserver\docker-compose.yml_gitserver stop gitserver || pause |
dco gitserver up --detach | C:\Windows\System32\cmd.exe /c docker-compose.exe -f d:\gitserver\gitserver\docker-compose.yml_gitserver up --detach gitserver || pause |
The docker-compose command that creates the docker container also creates the host directory "backups"
, at the same level as _commonUtils
, and mounts it as bound volume in the container.
The "backup" command, available to the user issuing the following command from a client:
ssh git@gitserver backup <reponame>
will tar up the nominated remote git repository and will deposit the archive in that host directory. Just in case.
Command invocation | Description |
---|---|
ssh git@gitserver | Will invoke a "no-login" script, present a help text and permit entry of one of the available commands |
ssh git@gitserver help | Will display help text and exit |
ssh git@gitserver backup <git repo name> | Will validate <git repo name>, to ensure the repo exists, and will create a timestamped zip archive of the rpository in the diectory "backups" shared with the host |
There are no customisable properties / variables that this script uses which would not have already been customised for script 01_create_gitserver_image.sh
. All scripts use the same __env_devcicd_net.sh
, __env_gitserverConstants.sh
and fn__DockerGeneric.sh
, so customisation applied there carry over.
cd /mnt//dir1/../dirN/gitserver/_commonUtils
03_create_named_repo_in_private_gitserver.sh [<Name of New Repository>] [<Path To id_rsa.pub>]
The script expects the container, produced by 02_create_gitserver_container.sh
to be running.
The script accepts two optional arguments.
Argument | Description | Default |
---|---|---|
<Name of New Repository> | Optional. The name of the new remote repository. If the repository already exists the script will abort with a note to that effect. If the repository does not exist it will be created as a "bare" repository. |
gittest |
<Path To id_rsa.pub> | Optional. The script needs to connect to the remote repository using ssh. To accomplish this the git server needs to "know" the client. Providing the path to the client's id_rsa.pub will enable the script to add the public key to the server's authorised_keys store and then add the repository. As a side-effect the client will be able to invoke custom commands the git server offers, for example ssh git@gitserver list or ssh git@localhost -p 50022 list if using WSL in windows on which the docker is installed. |
~/.ssh/id_rsa.pub |
- Get repository name and location of id_rsa.pub from the command line, or substitiute defaults.
- Validate repository name and existence and content of the file => abort if invalid
- Authorise client to ssh into the server by adding the
id_rsa.pub
to server'sauthorized_hosts
store - Determine whether repository already exists and abort if it does or the existence cannot be established
- Create the repository (as
--bare
) => abort if failed to create the repository
There are no customisable properties / variables that this script uses which would not have already been customised for script 01_create_gitserver_image.sh
. All scripts use the same __env_devcicd_net.sh
, __env_gitserverConstants.sh
and fn__DockerGeneric.sh
, so customisation applied there carry over.
cd /mnt/<driver letter>/dir1/../dirN/gitserver/_commonUtils
04_DeleteRemoteRepoIfEmpty [<Name of Existing Empty Repository>]
The script expects the container, produced by 02_create_gitserver_container.sh
to be running.
The script accepts one optional argument.
Argument | Description | Default |
---|---|---|
<Name of Existing Empty Repository> | Optional. The name of the remote repository to delete. If the repository does not exists the script will abort with a note to that effect. If the repository already exists but is not empty the script will abort with a note to that effect. If the repository exist and is empty ( git count-objects returns 0 objects).
|
gittest |
- Get repository name from the command line, or substitiute default.
- Validate repository name => abort if invalid
- Verify that client running the script is authorised to ssh into the server
- Determine whether repository already exists and abort if it does not or the existence cannot be established
- Determine whether repository is empty and abort if it is not empty or the command triggered an error
- Delete the repository (exisiting and empty) => abort if failed to delete the repository
- Verify that repository was deleted
Unit tests are provided for functions in
- fn__GitserverGeneric.sh (50%)
- fn__UtilityGeneric.sh (100%)
- fn__WSLPathToDOSandWSDPaths (100%)
Providing unit tests for functions which manipulate physical enviroment, like creating and manipulating a docker image or a docker container, is too resource intensive and developing mock functionality for mocking physical infrastructure manipulation outcomes would be too time consuming for this project.
I will think about these issues.
This scripts have hard dependencies on a number of constants and functions whose sources are in the _commonUtils/utils
directory. Specifically:
- __env_devcicd_net.sh
- __env_gitserverConstants.sh
- __env_YesNoSuccessFailureContants.sh
- fn__ConfirmYN.sh
- fn__CreateWindowsShortcut.sh
- fn__DockerGeneric.sh
- fn__GitserverGeneric.sh
- fn__UtilityGeneric.sh
- fn__WSLPathToDOSandWSDPaths.sh
- Better customisation experience (externally-defined customisation variables AND/OR configuration script)
- Add "Create a remote repository" functionality
- Add automatic repository backup on push functionality
- Add recover repository from selected backup functionality
The MIT License (MIT)
Copyright © 2020 Michael Czapski
Rights to Docker (and related), Git (and related), Debian, its pakages and libraries, and 3rd party packages and libraries, belong to their respective owners.
If you would like me to consider working for you, working with you on an interesting project, or engaging in specific projects for you, feel free to contact me.
2020/05 MCz