Skip to content

Deploying Autolab with Docker (DEPRECATED)

Aatish Nayak edited this page Feb 22, 2017 · 1 revision

These are the instructions for setting up Autolab for production usage using Docker. It's the recommended way to deploy an instance of Autolab for real-world usage.

It is a bit opinionated, though. If you're more interested in the essential setup instructions for deploying in production, see Deploying Autolab on Ubuntu. Alternatively, if you're interested in contributing to Autolab, it's easier to just set up a development environment. See Installing Autolab on Ubuntu for these instructions.

Table of Contents

0. Overview

Here's a list of some of the technologies that are going to be involved in this installation, as well as quick overview of the game plan going forwards:

  • Phusion Passenger for serving the core Rails app
  • Nginx for serving the static files and playing host to Passenger
  • MySQL as required by the Rails app
  • Mandrill for sending transactional emails
  • Docker for lightweight containerization and reproducible builds
  • Docker Compose to orchestrate the whole deal

We'll cover installing Docker, move a few config files into place, and finally use Docker Compose to build and run the application.

This guide starts all the way from the beginning with a bare bones server; if you already have a box that you know you'll be running the installation on, feel free to skip to Step 3.

Unfortunately, we don't have documentation on how to get a domain name registered. You'll need a custom domain or subdomain to set up Autolab. If you're doing this for your school, there's a chance you can ask them to give you access to a subdomain. Otherwise, you can look into DNS registrars like Namecheap or Gandi to acquire your own domain name. You might be able to get away with using localhost or a hard-coded IP address, but this hasn't been tested.

1. Provision a Server

If you don't already have a server, we recommend a VPS (virtual private server). There are plenty of VPS providers online, so pick your favorite. If you're looking for a recommendation, Digital Ocean is probably the most popular VPS provider right now (and if you sign up with this referral link, you can get enough credit to set up and try out Autolab for for a month for free).

I'll be assuming you're on a standard Ubuntu droplet, but apart from installing Docker there should be no reason why any of the setup instructions are too different.

Once you have a box that you can SSH into, you'll want to do a few simple maintenance tasks to lock it down and prevent spammers from harassing you. These tasks only take 5 minutes, and are all documented in Bryan Kennedy's My First 5 Minutes on a Server. There's only one hiccup with these instructions, and the solution is detailed here.

Now would be a good idea to set up some DNS records that you can use to SSH into your server.

Summary:

2. Prep the Development Environment

We're going to need Git installed eventually, so let's just do it now (again, I'm assuming this is an Ubuntu server):

$ sudo apt-get install git

# Configure Git so that it knows who you are
$ git config --global user.name "Your Name"
$ git config --global user.email "your.email@example.com"
$ git config --global color.ui true
$ git config --global credential.helper cache

Be sure to insert your name and your email address where necessary.

Let's also install pip, as it'll make installing Docker Compose easier.

$ sudo apt-get install python-pip

(Installing pip is not strictly required; refer to the Docker Compose documentation for alternative installation instructions).

3. Install Docker & Docker Compose

Docker has some good installation instructions for Ubuntu available on it's web site.

Follow these steps in particular:

4. Get the Autolab source

You can install the Autolab source anywhere on your machine. I'll be using ~/autolab-prod for this example, but you may want to consider putting it in /opt or somewhere where multiple people can access it if there will be multiple system administrators.

First up is to get the docker-compose.yml file:

$ git clone https://github.com/autolab/autolab-docker ~/autolab-prod

Next, you'll need to grab the actual Rails app:

# to make sure we're in the repository we just cloned
$ cd ~/autolab-prod

$ git clone https://github.com/autolab/Autolab

(TODO: also clone the Tango source)

You might be thinking, "Git repositories in Git repositories, why not just use submodules?"

Using submodules requires us to make an additional change to the autolab-docker repository every time we make a release for Autolab, thus creating twice the amount of work for us. To make things go smoother, we've opted not to use submodules here.

More information on how to update your app as releases are made can be found below in the section called Updating.

5. Configure Devise Authentication

Next up we have to configure authentication. There are a couple of steps to this.

First, simply copy the templated config file into place. I'll be giving all the relevant filenames relative to the autolab-prod (i.e. parent) repo:

$ cp Autolab/config/initializers/devise.rb{.template,}

Next, generate a new secret key:

$ python -c "import random; print hex(random.getrandbits(512))[2:-1]"

Use this to update the value of config.secret_key in Autolab/config/initializers/devise.rb.

You'll also want to change the hostname in the email address under config.mailer_sender (shown below) to the domain you plan to use for viewing the site.

...

  # ==> Mailer Configuration
  # Configure the e-mail address which will be shown in Devise::Mailer,
  # note that it will be overwritten if you use your own mailer class
  # with default "from" parameter.
  config.mailer_sender = 'creds@<YOUR_WEBSITE>'

...

The specific value doesn't really matter too much; it's only used as the "From" address when sending out new user and password reset instructions.

(TODO: This file is where we can configure omniauth providers, like Facebook or Google logins. This needs to be documented).

6. Configure Nginx

First, copy the stock Nginx configuration into place:

$ cp Autolab/docker/nginx{.template,}.conf

Next, you will need to edit server_name in Autolab/docker/nginx.conf (snippet shown below) to set the appropriate host name. This should be the host name where users will access your site.

...
  server_name example.com;
...

There are some other settings in this file (currently commented out) relating to SSL that we'll get to a bit later.

7. Configure the Production Rails Environment

Next up we need to configure the production Rails environment; i.e., the settings Rails uses when we have RAILS_ENV=production.

The first step is to copy the template into place:

$ cp Autolab/config/environments/production{.template,}.rb

This is a pretty long step, so we've broken it up into a couple sub-steps. All changes will be done in Autolab/config/environments/production.rb.

7.1. Configure Email with Mandrill

Next up, let's configure email. The Rails app uses email for various features, include sending out user confirmation emails and instructor-to-student bulk emails. We recommend that you use Mandrill. They have a very lenient free tier (12,000 emails/month) and a solid service including analytics. Update: Mandrill appears to have changed their volume provided by their free tier. Some alternative services have larger free tiers (for example Mailgun). Feel free to use any mail provider (including rolling your own mail server); the configuration should be similar to what's described below for Mandrill.

  • Create an account at https://mandrill.com/signup/

  • Go to the settings page and create a new API key

  • In Autolab/config/environments/production.rb, uncomment the config.action_mailer.smtp_settings block (shown below). Update your username to your Mandrill username and your password to one of your API keys that you've created.

    # Use a custom smtp server, like Mandrill
    #config.action_mailer.smtp_settings = {
    #  address:              'smtp.mandrillapp.com',
    #  port:                 25,
    #  enable_starttls_auto: true,
    #  authentication:       'login',
    #  user_name:            'MANDRILL_USERNAME',
    #  password:             'MANDRILL_PASSWORD',
    #  domain:               'example.com',
    #}
  • Change config.action_mailer.delivery_method to use raw SMTP:

    config.action_mailer.delivery_method = :smtp
  • Uncomment config.action_mailer.default_url_options (shown below) and fill in your host appropriately. This is the host that Rails will use when generating URL links in emails it sends.

    # Provide context to the email generator about the host
    #config.action_mailer.default_url_options = {protocol: 'http', host: 'example.com' }
  • From the Mandrill Domains settings page, add your domain and configure the DKIM and SFF settings by creating TXT records with your DNS provider. They link to some instructions for how to do this, but the process will differ depending on which DNS provider you are using.

7.2. Configure Exception Notifications

To be emailed every time an error occurs in the Rails app, fill in all the appropriate information for the ExceptionNotification middleware block, shown below.

...

  config.middleware.use ExceptionNotification::Rack,
    email: {
      email_prefix: "[Autolab Error] ",
      sender_address: "\"NOTIFIER\" <NOTIFICATIONS@YOURAPP.com>",
      exception_recipients: "TEAM@YOURAPP.COM"
    }

...
  • email_prefix and sender_address can be anything, their values will only affect the way things are displayed for the recipient.
  • exception_recipients should be the email where you'd like to receive exception notifications.

8. HTTPS

You can run Autolab with or without HTTPS encryption. We strongly recommend you run it with HTTPS.

8.1 Enable HTTPS

To set up HTTPS, you'll need to get an SSL certificate. There are many ways you can get one. Here are a few options:

  • Go through your school
    • Many universities have a program whereby they'll grant SSL certificates to students for free. Some of these programs require you to be using a school-related domain name, but some don't. You should be able to find out more information from your school's IT department.
    • If possible, we recommend this option.
  • Use StartSSL
    • The online service StartSSL offers free single domain SSL certificates. The catch is that
      • they're only free for a single subdomain (wildcard certs cost money)
      • their website isn't exactly the most intuitive
    • This tutorial offers a pretty comprehensive walkthrough of how to get a free StartSSL certificate
    • If you can't get a cert from your school, we recommend this option.
  • Use a paid service
    • There are plenty of services online that offer paid SSL certificates.
  • Wait for Let's Encrypt, coming mid-2015
    • This is a project that aims to offer free, no-stress SSL certificates for the entire Web.

Take the time now to get yourself a certificate and a key file. The next few steps will show you what to do with them to configure Nginx to use them properly.

In Autolab/docker/nginx.conf, uncomment the three lines referenced below:

...
# Uncomment these settings to use SSL (you may wish to change the filenames
# appropriately)
#listen 443 ssl;
#ssl_certificate /etc/nginx/ssl/unified.crt;
#ssl_certificate_key /etc/nginx/ssl/my-private-decrypted.key;

# EFF recommended SSL settings
#ssl_prefer_server_ciphers on;
#ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:ECDH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5:!DSS;
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
...

Note: You may want to remove includeSubDomains if you experience issues when trying to visit sites on a sister subdomain to the one you've configured Autolab to work with.

At this point, you can rename unified.crt and my-private-decrypted.key to whatever you want (in the nginx.conf file above), corresponding to the certificate and key file that you should have created earlier.

Next up, we need to put the SSL certificate and key file in a place that our Docker build will know about them. In the same level as the docker-compose.yml file, run:

$ mkdir -p ssl

Finally, put your certificate and key file in this folder, making sure to match up the names with the names you provided in your nginx.conf.

8.2 Disable HTTPS

Disabling HTTPS is strongly discouraged. It is documented here only for very special cases. You should exhaust every effort to enable SSL before following these instructions.

To disable HTTPS, just comment out the Rack::SslEnforcer line in your production.rb file (some context given to help you locate it):

...

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true
  config.middleware.use Rack::SslEnforcer, :except => [ /log_submit/, /local_submit/ ]

...

9. Configure the Tango Backend

Currently you have to configure Tango separately from the Dockerized Rails app. (TODO: Add support for Dockerized Tango)

First, copy the configuration file into place:

$ cp Autolab/config/autogradeConfig.rb{.template,}

Then, follow the installation instructions at the Tango Wiki.

10. Make Required Volume Directories

The Autolab app requires a couple data volumes to be created: one to hold course submissions and other configuration files, and another to persist the database across containers.

To create them:

$ mkdir -p db-data
$ mkdir -p Autolab/courses

You might want to consider making one or both of these folders symlinks to folders. Effective use of symlinks can make Autolab management simple. For example, maybe db-data is a symlink to a RAID drive for database storage redundancy, or Autolab/courses is a symlink to a networked location where instructors can access their students' submissions from the command line.

11. Build and Run the Containers

Finally, we've reached the point where we can build and run the containers! If everything's gone according to plan, you should be able to run

$ docker-compose up -d

and view your live site! If you've configured your DNS records appropriately, you can go to your-host.example.com in your browser to see Autolab running.

Notes:

  • If the process fails with an error like Cannot start container: Cannot link to a non running container, see issue #559 for a workaround.

  • If you're unfamiliar with or new to Docker and Docker Compose, I'd recommend that you skim over some best practices for what to expect when dealing with Docker.

  • The first time you run docker-compose up -d it will take a long time. Docker is downloading and building all the images required to serve the app. This will only happen once, at which point build times will get much faster. You may want to read about Docker caching to find out about how how you can minimize your build times.

  • If it hangs after printing "Fetching source index from https://rubygems.org/", just give it time. It's running bundle install, which is really slow. Luckily, we don't have to run this very often.

    • Every time there are changes to the Gemfile (i.e., any time an Autolab developer adds a project dependency), build times will be slow because Docker has to run a bundle install, which is really slow.
    • If this step gives you a warning not to run bundle install as root, just ignore it. It doesn't apply because we're using Docker containers.
  • If the build fails with error ENOMEM, it's probably because the amount of memory available on your system is too low for the build to complete. This is fine: Autolab normally takes a small amount of memory, but Docker builds (and bundle installs) are memory intensive. To get around this, try adding a swapfile to your system.

  • If you get hit by a really big wall of text, it's probably just the log from precompiling the static assets. (The filenames should look like a lot of CSS and JS files.)

12. Create the Database

We'll need to run a one-off command to create the MySQL databases:

$ docker-compose run --rm -e RAILS_ENV=production web rake db:create

This creates a temporary container based of web as specified in the docker-compose.yml file, and uses it to run the rake db:create command, and it cleans up after itself when it's done (--rm).

Similarly, we'll need to migrate the database:

$ docker-compose run --rm -e RAILS_ENV=production web rake db:migrate

Because the docker-compose.yml file mounted db-data/ as a data volume into the mysql container, you'll never have to run db:create again, and you'll only have to run db:migrate if the Autolab developers release an update that they mention requires a migration.

13. Create an Administrator Account

By now, you should be able to view the app in your web browser. Navigate to the deployed app and sign up for a new account. It should ask for your name, email, and password.

If you configured Mandrill correctly, you will shortly receive an account verification email. Follow the verification link back to the deployed app and sign in with your newly verified account. You should see a page telling you that you are not registered for any courses.

Once you have successfully created an account, you can use the admin:promote_user rake task to promote yourself to the admin level (inserting your email where appropriate; make sure to keep the square brackets):

$ docker-compose run --rm -e RAILS_ENV="production" web rake 'admin:promote_user[YOUR_EMAIL@EXAMPLE.COM]'

You are now an administrator of your very own Autolab deployment!

Updating

From time to time, the Autolab team releases updates. When release updates become available, you should be able to follow these steps to redeploy an updated version of the app:

# stop the containers, remove them, and delete associated volumes
# (this doesn't delete the data in your host volumes, like db-data/)
$ docker-compose stop && docker-compose rm -v

# get the updated source
$ cd Autolab
$ git pull origin master
# you may want to substitute master for a specific tagged release
$ cd -

# build a new container based on the new code
# depending on the changes introduced, this could take a while
$ docker-compose build web

# While not strictly necessary, you will probably want to clean
# up your old images, volumes, and possibly containers at this
# point. For more information, see
# http://odino.org/spring-cleaning-of-your-docker-containers/

# Run migrations
# This step is only necessary if the release notes for the
# update mention that this release requires migrations, but it
# should be safe to run it even if there aren't migrations to
# be run
$ docker-compose run --rm -e RAILS_ENV=production web rake db:migrate

# Start up the containers again
$ docker-compose up -d

You'll notice that this process can be completely automated if you want it to be.

Tips

These are some additional tips to help make sure that you have an awesome experience using Autolab:

Keep everything updated

By updating often you'll ensure that you have a smooth Autolab experience because you'll be able to do multiple small updates rather than unweildly, all-encompassing updates.

Consider backing up your config files

All the config files we touched in this process are ignored by version control, so that people don't accidentally commit their config files to the upstream Autolab source repo.

To have your personal config files all backed up and versioned, you should move them to a separate folder, say ~/autolab-configs, make this folder into a Git repository, and create symlinks to config files in this folder where Autolab expects there to be config files. For example, you could have a directory structure that looks like

~
├── autolab-configs
│   ├── config
│   │   └── database.yml
│   └── docker
│       └── nginx.conf
└── autolab-prod
    └── Autolab
        ├── ...
        ├── config
        │   ├── ...
        │   └── database.yml -> ~/autolab-configs/config/database.yml
        ├── ...
        ├── docker
        │   ├── ...
        │   └── nginx.conf -> ~/autolab-configs/docker/nginx.conf
        └── ...

TODO

As you might have noticed, this guide is not entirely complete. This is a list of TODOs for the Autolab developers to remind them what still needs to happen, as well as give the user some insight into what's on deck.

These TODOs will be turned into issues as soon as this pull request lands.

Dockerize Tango

All the instructions to set up Tango on the same host as the local deployment should be just as scripted as the Autolab frontend setup like this was.

Devise Omniauth providers

Documentation for Devise Omniauth providers is lacking. We should document how more providers can be added to devise.rb so that users can enable these if they want.

This includes the documentation in this file as well as other Autolab pages that reference Devise.

We should also figure out a way to remove "Sign in with you CMU account" from the sign in page. This is relevant for the CMU installation of Autolab, but not for anyone else.

Onwards

Now that you've got Autolab set up, you should be sure to check out the rest of the documentation on how to create classes and labs and all in all make your life easier with autograding.

If you ran into issues while setting this up, please open an issue or send us an email to let us know. There shouldn't have been that many gotchas (except for maybe setting up DNS settings and configuring your server). The core Autolab Rails app functionality shouldn't be the issue. If it is, we'd really love to know about it so that we can help fix it.

Clone this wiki locally