Building docker images from private git repositories using ssh login

Philipp Lies
ITNEXT

--

Docker is an amazing tool if you want to set up and try out software without having to clutter your operating system or build a clean environment for the app you’re developing. In this post I will show you step by step how to set up a docker file such that you can clone a private github repo and use the content built from that repo in a public image without having to worry about credentials or private files in the public image. As example I use building a vue.js app from a private repo and setting up a web server with the built app.

This tutorial has 3 steps:

  1. Cloning and building docker images from a git repository
  2. Using a builder image to build the app before setting up the lean web server
  3. Importing ssh keys into the builder to clone private repositories

Cloning and building docker images from a git repository

Best case, for example when developing in JS with an open git repository and using npm for building, you can set up your app with as little as 5 lines in a docker file. Take a node base image, clone your repo, install the modules, and run the development server. As example I uploaded a repository which contains the boiler plate app created with vue cli.

However, the npm development server should not be used in production and the image will also be quite large, more than 1 GB for the example above, because all the development dependencies are installed. So we could use an productive webserver (apache, nginx) as base image, install everything we need to build the app, build the app, and then delete everything we installed. But this will not make the image immediately smaller, because docker creates a layer for each executed command and keeps all layers by default. You can manually delete layers, but that’s complicated and can lead to problems. (If you want to read up on layers check for example here.)

Using a builder image to build the app before setting up the lean web server

The correct way to do this as of today (June 2019) is using multi-stage builds. We first build an image which serves as builder where we install all dependencies we need and build the final app, and in a second stage create the productive web server image and copy the files we need from the builder.

We first create almost the same image as before and give it the name builder, but we don’t execute a RUN command in the end but instead build the production release of our app. The && concatenates the commands, so they are executed one after another and only one layer is created. This is not necessary but I prefer grouping commands to create only as little layers as necessary.

Then we create a second image based on nginx and copy the built app from the builder to our web server image. The resulting image has sleek 110 MB and only the app, no trace of the build process. (For apache use httpd as base image and replace the target directory by /usr/local/apache2/htdocs/ ).

Now we can publish the container and users who download that image will only get the productive app and a basic web server. The important part of cloning a private repository (here: github) comes next.

Importing ssh keys into the builder to clone private repositories

When you want to publish an image with an app from a private repository you need some way to pass credentials into the docker build process to allow git to log in to your repo. The direct and very dangerous approach would be to use username and password in the clone command. But you should never ever put credentials in a configuration file, so this is not an option. Passing the credentials as command line arguments into the builder is also not a good idea, as it requires to always pass the credentials and the password might be stored in bash history or some other log. The preferred solution are deploy keys. A set of ssh public-private keys that are specifically for read-only access to certain repositories. You can copy those keys into the builder, register them with the ssh agent, and then clone the repository. As the builder image is deleted after the process the final image does not contain any traces of the keys.

First you need to create an ssh key pair, a public key for github and a private key for you to use in the docker file. On linux just run ssh-keygen -t rsa -f github_key to generate an RSA key pair. Make sure to not use a passphrase. Then copy the github_key and github_key.pub files next to your Dockerfile (for convenience). On Windows, PuTTY/KiTTY can generate key pairs, make sure to export the private key in OpenSSH format.

Next you have to log in to github, navigate to your repository, select Settings, then Deploy keys, and then Add key.

There you can upload the content of your public key github_key.pub and save the changes.

Now we just have to copy the github_key into the builder image, start the ssh-agent (line 4), add the key to the agent (line 5), import the public key from github.com (line 6), and finally clone the image using ssh instead of https.

That’s it. Works with any kind of project and should also work with other git hosts as long as they support ssh logins.

The repository with the docker files can be found here: https://github.com/phillies/vue_example

Have fun!

--

--

Writer for

Machine learning and neuroscience | Coding python (and recently JS and Kotlin) | Building apps you love