Tutorials

Configure a Docker Container to Automatically Pull from GitHub Using OAuth

Table of Contents

Introduction

One common situation I have run into on different projects is how to instruct my Docker containers to automatically clone or pull from a private GitHub repository when they're built. The goal of this tutorial is to pull together various references I found into a single document for what I needed to do which is to spin up a rails app using code in a private repo on GitHub.

In this tutorial we will go through how to acquire an OAuth token from GitHub to access your repositories in an automated fashion and then use that in a Dockerfile to bring up a basic Ruby-on-Rails application using the Phusion Passenger 3.0 webserver.

Create GitHub OAuth Token

Developers have a few methods they can use to access their repositories on GitHub. Using personal access tokens allows you to forgo having to provide a username and password when making a request. This is the recommended approach to automating the synchronization of your code. It is also an easier method than hacking together one of the many SSH key solutions you might find elsewhere on the web.

These instructions assume that you host your repos with GitHub and that you have private repos you would like to pull or clone automatically. While being logged into your GitHub account you can obtain an OAuth token by navigating to Settings --> Applications --> Generate New Token.

Be aware that when GitHub generates the token it will only show it to you once. When you browse away from the page you will not be able to view the token again therefore it's a good idea to make note of what it is before proceeding onto the Dockerfile steps. If you lose the token you will need to regenerate it. You can also use this interface to revoke tokens.

Create the token so that it has the appropriate scope for what you require. The defaults should be fine for this example.

Dockerfile

Now that you have an OAuth token it's relatively easy to construct the HTTPS URL to pull or clone from your private repo(s). This can be done in the following fashion:

git clone -b docker https://<token>:x-oauth-basic@github.com/StackPointCloud/myapp.git /myapp/

The <token>:x-oauth-basic is where the magic happens. It should be noted that we are using personal access tokens which are a bit different than registered application tokens.

Now, let's turn to our Dockerfile:

# Let's use the official Passenger container.
FROM phusion/passenger-ruby19:latest
MAINTAINER Matt Baldwin "baldwin@spc"

# Clone our private GitHub Repository
RUN git clone -b docker https://<token>:x-oauth-basic@github.com/StackPointCloud/myapp.git /myapp/
RUN cp -R /myapp/* /home/app/
RUN chown app:app -R /home/app/

# Setup Gems
RUN bundle install --gemfile=/home/app/Gemfile

# Setup Nginx
ENV HOME /root
RUN rm -f /etc/service/nginx/down
ADD myapp /etc/nginx/sites-enabled/
RUN rm /etc/nginx/sites-enabled/default

# Setup Database Configuration. Since we use both we'll add both here.
# This is done to preserve Docker linking of environment variables within Nginx.
ADD postgres-env.conf /etc/nginx/main.d/postgres-env.conf
ADD mongodb-env.conf /etc/nginx/main.d/mongodb-env.conf

# Clean-up
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /myapp/

CMD ["/sbin/my_init"]
EXPOSE 80 443

In the first section we're instructing Docker to use Phusion's Ruby 1.9.3 image. If you don't have it locally it will be pulled down.

We then clone our desired branch -- in our case docker -- to a new directory myapp at the root of the file system. All content is then copied over to the default /home/app location for the Passenger 3.0 container. The bundle install installs any required gems we may need.

Our Nginx configuration is taken from Passenger's Docker documentation, but looks like this:

server {
    listen 80;
    server_name www.myapp.com;
    root /home/app/public;

    passenger_enabled on;
    passenger_user app;

    # For Ruby 1.9.3 (you can ignore the "1.9.1" suffix)
    passenger_ruby /usr/bin/ruby1.9.1;
}

We also add a few environment configuration files to ensure our Docker link names are exposed in Nginx, too.

Once all that is done my_init is ran when the container spins up with 80 and 443 exposed.

Conclusion

Hopefully this short tutorial helped you setup automatic GitHub repo pulls or clones using OAuth tokens. In future articles we will dive deeper into connecting our Ruby-on-Rails container to our two DB containers and connecting the DB containers to persistent storage volume containers.

 
  • Thanks, very helpful. Been search this for the last hour.

    Whats in the /sbin/my_init please?

  • @molinto

    The Dockerfile from my repo is based upon Phusion's Passenger ubuntu base image. This is what they have to say on my_init:

    According to the Unix process model, the init process -- PID 1 -- inherits all orphaned child processes and must reap them. Most Docker containers do not have an init process that does this correctly, and as a result their containers become filled with zombie processes over time.

    Furthermore, docker stop sends SIGTERM to the init process, which is then supposed to stop all services. Unfortunately most init systems don't do this correctly within Docker since they're built for hardware shutdowns instead. This causes processes to be hard killed with SIGKILL, which doesn't give them a chance to correctly deinitialize things. This can cause file corruption.

    Baseimage-docker comes with an init process /sbin/my_init that performs both of these tasks correctly.

    You can read more on that here.

  • Thanks for writing this up.

    My understanding is that the Dockerfile (which in this case includes the github token) gets commited to the repo with the rest of the code.

    Is there a way to have the token come from an environment variable? I wonder how this would work on Shippable.com.

  • Actually, Shippable supports deploy keys, so it would have the code local and not need to clone.

  • Hello Matt, this is a really good guide [which I followed to the letter :] ] . I was just wondering...is there a way to avoid having that token hardcoded in the dockerfile? I implemented a solution where I ask for the token as an ARG, but when I started using docker-compose I no longer can. I would like to give the token directly to the dev in order to setup the containers.

  • Thanks for the write up. This was very helpful!

  • Through your pen I found the problem up interesting! I believe there are many other people who are interested in them just like me! How long does it take to complete this article? I hope you continue to have such quality articles to share with everyone! spanish dictionary

Log In, Add a Comment