Skip to content

Create a private Git Server, using latest git sources, as a Docker Container

License

Notifications You must be signed in to change notification settings

mwczapski/private_gitserver_docker_container

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Git Server Docker Container

Introduction

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).

Top

Assumed host environment

  • 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.

Top

Assumed execution environment

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.

Fictitious directory hierarchy and actual artifacts

Top

Installation

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"

Top

Create Git Server Docker Image: 01_create_gitserver_image.sh

Customisation

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"

Top

Script invocation

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.

Top

High-level build logic

  1. Set environment variables
  2. Create docker-entrypoint.sh
  3. Create Dockerfile
  4. if (Image Does not exist) OR (Dockerfile changed since last time) => Build the Docker Image using the Dockerfile from 3
  5. if (container that uses the image exists) => stop AND/OR remove the container
  6. Create and Start the container
  7. Give non-root user's ownership of its home directory and resources
  8. Create and deploy custom Git Shell commands (help, list, backup)
  9. Commit continer changes to the image
  10. Stop the container
  11. Tag the image (DockerRemoteRepositoryName/ImageName:Version)
  12. if (user requested push to remote docer repository) => Push the image to the defined remote docker repository

Top

Bill of Materials (of sorts)

  1. bitnami/minideb:jessie
  2. See output of docker image inspect gitserver once the image is built or inspect the Dockerfile.gitserver in the parent of the _commonUtils directory to see what actually went on.
  3. The build script adds the following to the bitnami/minideb:jessie image:
    1. tzdata
    2. net-tools
    3. iputils-ping
    4. openssh-client
    5. openssh-server
    6. nano
    7. less
  4. The build script adds the following to enable git to be built from sources, then removes them once build is done:
    1. wget
    2. unzip
    3. build-essential
    4. libssl-dev
    5. libcurl4-openssl-dev
    6. libexpat1-dev
    7. gettext
  5. Perhaps needless to say, the build process also adds:
    1. git

Top

Create and Run Docker Container: 02_create_gitserver_container

Customisation

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.

Top

Script invocation

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.

Top

High-level logic

  1. Set local environment variables
  2. Prompt whether user wants to have Windows Shortcuts created
  3. Confirm Artefact location
  4. Create docker-compose.yml file
  5. If (docker image does not exists) => Pull image from remote repository and abort if can't pull the image
  6. If container exists but is not running => start container
  7. If container does not exist => create container and start it
  8. Start ssh service in the container
  9. If user asked for windows shortcuts => create windows shortcuts

Top

Extras

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.

Windows Shortcuts and commands they execute
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

Top

Host-Guest-Shared "backups" directory

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.

Top

Custom Git commands accepted by the server over SSH

Custom Git Server commands
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

Top

Create Remote Git Repository: 03_create_named_repo_in_private_gitserver.sh

Customisation

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.

Top

Script invocation

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.

Script 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

Top

High-level logic

  1. Get repository name and location of id_rsa.pub from the command line, or substitiute defaults.
  2. Validate repository name and existence and content of the file => abort if invalid
  3. Authorise client to ssh into the server by adding the id_rsa.pub to server's authorized_hosts store
  4. Determine whether repository already exists and abort if it does or the existence cannot be established
  5. Create the repository (as --bare) => abort if failed to create the repository

Top

Delete Empty Remote Repository: 04_DeleteRemoteRepoIfEmpty

Customisation

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.

Top

Script invocation

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.

Script Arguments
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
[Top](#Git-Server-Docker-Container)

High-level logic

  1. Get repository name from the command line, or substitiute default.
  2. Validate repository name => abort if invalid
  3. Verify that client running the script is authorised to ssh into the server
  4. Determine whether repository already exists and abort if it does not or the existence cannot be established
  5. Determine whether repository is empty and abort if it is not empty or the command triggered an error
  6. Delete the repository (exisiting and empty) => abort if failed to delete the repository
  7. Verify that repository was deleted

Top

Unit Tests

Unit tests are provided for functions in

  1. fn__GitserverGeneric.sh (50%)
  2. fn__UtilityGeneric.sh (100%)
  3. 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.

Top

Dependencies

This scripts have hard dependencies on a number of constants and functions whose sources are in the _commonUtils/utils directory. Specifically:

  1. __env_devcicd_net.sh
  2. __env_gitserverConstants.sh
  3. __env_YesNoSuccessFailureContants.sh
  4. fn__ConfirmYN.sh
  5. fn__CreateWindowsShortcut.sh
  6. fn__DockerGeneric.sh
  7. fn__GitserverGeneric.sh
  8. fn__UtilityGeneric.sh
  9. fn__WSLPathToDOSandWSDPaths.sh

Top

To-Do

  1. Better customisation experience (externally-defined customisation variables AND/OR configuration script)
  2. Add "Create a remote repository" functionality
  3. Add automatic repository backup on push functionality
  4. Add recover repository from selected backup functionality

Top

Licensing

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.

Top

Note

Top

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.

Top

2020/05 MCz

About

Create a private Git Server, using latest git sources, as a Docker Container

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages