Pages

Sunday, June 30, 2019

Docker - Clone Private Github repository into a Container using SSH Keys

We already know there are many ways of getting the source code into the docker image. The COPY|ADD method, Volume way and using the RUN instruction are different ways of getting the source code into the docker container. The first and the last method allows the code to be available during docker build and volume way is available during the container runtime. The changes made will be available live to the running container in the volume way.

To clone a private GitHub repo, we can configure a Github OAuth token and use that with the RUN instruction to get the code during image building but in most organization it will be hard creating tokens to every project. Ssh keys come to our help. 

When working with a GitHub repository, we often need to identify yourself to GitHub using your username and password. An SSH key is an alternate way to identify yourself that doesn't require you to enter username and password every time.

SSH keys come in pairs, a public key that gets shared with services like GitHub, and a private key that is stored only on your computer. If the keys match, you're granted access. 

Docker from version 18 provides us a way to use ssh keys for cloning the code while building the image itself. There are few things that need to be done before using this feature. 

The first thing that needs to be done is enabling the Buildkit backend. Buildkit is opt-in feature in docker version 18 that can be enabled with an environment variable DOCKER_BUILDKIT=1 before running the docker build. Run the 
export DOCKER_BUILDKIT=1 command to set the variable.

The second thing that we need to do to use the buildkit is to enable the support by adding an experimental syntax in Dockerfile. We need to define the syntax directive as the first line of the Dockerfile. This feature is not enabled in the stable version of the Dockerfile so we need to use the experimental release by adding the syntax line as the first line in the Dockerfile. 
e.g. docker/dockerfile:experimentalor docker/dockerfile/1.0.0-experimental.
# syntax=docker/dockerfile:1.0.0-experimental

Before running the build for the above docker image, we need to make sure to configure our host machine with github. 

1. Run the ssh-keygen command and create the id_rsa and id_rsa.pub files.
2. Go to Github -> Repository -> Deploy keys. Create a new key and paste the id_rsa.pub file contents in there and give it a name. Make sure you can clone the repo using the ssh way.
3. The dockerfile looks something like below,
jagadishm@[/Volumes/Work/build]: cat Dockerfile 
# syntax=docker/dockerfile:1.0.0-experimental
FROM centos AS build

# install git 
RUN yum install -y git

RUN mkdir -m 700 /root/.ssh; \
  touch -m 600 /root/.ssh/known_hosts; \
  ssh-keyscan github.com > /root/.ssh/known_hosts

RUN --mount=type=ssh,id=github git clone git@github.com:jagadish12/simple-java-maven-app.git

We are aware of the most instructions. The most important one is the 
RUN --mount=type=ssh,id=github git clone git@github.com:jagadish12/simple-java-maven-app.git

With the new buildkit feature we can use mounts in RUN instruction of the Dockerfile. In the above RUN instruction we are using the mount type as ssh. In the above case, I have defined an id “github” which will be used during the build. The value to the github id will the private key file from our local machine. We will be creating the build image by running the “docker build --ssh github=/Users/jagadishmanchala/.ssh/id_rsa -t buildtest .” . in the command we are running the build by passing the --ssh and passing the location of the private key file to the github id that we used in the Dockerfile.  The ssh key that is mounted is exposed to the single command that defined the mount, not to the other parts of the build. The ssh key mounted will not be available even in the image metadata. If we run the “docker <Image> history” ,we will not be seeing any details regarding the key mounted.

When we run this,
jagadishm@[/Volumes/Work/build]: docker build --ssh github=/Users/jagadishmanchala/.ssh/id_rsa -t buildtest .

[+] Building 7.1s (12/12) FINISHED                                                                                                
 => [internal] load build definition from Dockerfile  0.1s 
 => transferring dockerfile: 617B  0.0s                                                         
 => [internal] load .dockerignore 0.1s
 => => transferring context: 2B 0.0s
 => resolve image config for docker.io/docker/dockerfile:1.0.0-experimental 2.6s
 => CACHED docker-image://docker.io/docker/dockerfile:1.0.0-experimental@sha256:d2d402b6fa1dae752f8c688d72066a912d7042cc172  0.0s
 => [internal] load .dockerignore   0.0s
 => => transferring context: 2B    0.0s
 => [internal] load build definition from Dockerfile  0.1s
 => => transferring dockerfile: 617B   0.0s
 => [internal] load metadata for docker.io/library/centos:latest   0.0s
 => [1/4] FROM docker.io/library/centos  0.0s
 => CACHED [2/4] RUN yum install -y git 0.0s
 => CACHED [3/4] RUN mkdir -m 700 /root/.ssh;   touch -m 600 /root/.ssh/known_hosts; ssh-keyscan github.com > /root/.ssh/  0.0s
 => [4/4] RUN --mount=type=ssh,id=github git clone git@github.com:jagadish12/simple-java-maven-app.git                       3.5s
 => exporting to image  0.1s
 => => exporting layers 0.1s
 => => writing image sha256:7a7c7b6731eccde3e5aa9bc5b186174cb88f19d383524fb67a5cae11fed95888                                 0.0s
 => => naming to docker.io/library/buildtest    0.0s
Once the image is built, we can run the container and see if the repository is cloned,
jagadishm@[/Volumes/Work/build]: docker run -it buildtest /bin/bash
[root@536ee37212ad /]# ls
anaconda-post.log  dev  home  lib64  mnt  proc  run   simple-java-maven-app  sys  usr
bin                etc  lib   media  opt  root  sbin  srv                    tmp  var
[root@536ee37212ad /]# exit

We can see that the project simple-java-maven-app is cloned successfully. 

Note - the buildkit feature also supports forwarding ssh connections. So in the case of cloning the command with a private key, the request is then forwarded to the host machine where the key is already configured. This key should be available and need to be added using the “ssh-add” command. Once the key is available to the agent, the docker build will be using the agent to clone the command. This way we don't need to pass the keys to the builder also.

Hope this helps in cloning the private repos into the docker container.

No comments :

Post a Comment