Running a Live Server

The most important use of Docker on the Educative platform is to run a web application on a server. Examples of such apps include React, MEAN, ASP, Ruby on Rails, etc.

The server for your app will be deployed on a live virtual machine. This VM will stay persistently active for a fixed period of time. It gives users the ability to interact with an app/webpage and use a terminal to perform other tasks.

If you wish to include such a running server in your course, you can use the SPA widget.

This guide will take you through all the steps required to set up a live server. We will create a Dockerfile, set up our Docker job, and run the code.

Example - Setting Up a React App

Objective

To demonstrate the LiveVM functionality of our platform, we’ll be running this React App.

Step 1: Create a Dockerfile

As always, the first step is to create a Dockerfile. There are three objectives to consider while making your Dockerfile.

  • Identify your base image.

  • Make all the installations required to run your project.

  • Bring your project code into the container.

FROM ubuntu:20.04
RUN apt update &&\
apt install -y curl git &&\
curl -sL https://deb.nodesource.com/setup_12.x -o nodesource_setup.sh &&\
bash nodesource_setup.sh &&\
apt install -y nodejs
RUN git clone https://github.com/rauhaanrizvi/simple-reactjs-app &&\
cd simple-reactjs-app && npm install
  • FROM ubuntu:20.04: We are using the official base image for Ubuntu 20.04. ubuntu images are officially supported on the platform, and hence, are always recommended.

  • RUN apt update... (lines 3 - 7): This set of commands installs Node 12 in our container. The commands are chained using && to save build time.

  • git clone https://github.com/rauhaanrizvi/simple-reactjs-app: Cloning our project into the container. It is recommended that you upload your code to GitHub and use git to clone it. Alternatively, you could use Docker’s COPY command to move the project into the container, however, the project will have to be included in the tarball along with the Dockerfile.

  • npm install: This is step required to run React app. It installs all the packages specified in your app’s package.json file.

We’ve achieved all three objectives required to make a good Dockerfile!

Step 2: Create a Tarball and Upload It

As done previously, we need to compress our Dockerfile into a tarball.

tar -czvf react.tar.gz Dockerfile

If we were using the COPY command instead of git to import our code, we’d have to include the project in the tarball as well.

tar -czvf react.tar.gz Dockerfile simple-reactjs-app

git clone vs COPY

Sometimes, the project repository may be very large in size. Putting this in your tarball might result in the tarball being larger than 40 MB, which is not supported on the platform. In such a case, simply cloning the project from GitHub makes things much easier than COPY.

Step 3: Create a Docker job

All the fields in this job are similar to those of a job for a regular Docker environment until you change the job type from Default to Live. On selecting the live option, you’ll see a few more fields appear. We’ll discuss these fields in detail later on in this lesson.

This is where the actual set up of your container takes place. So, let’s discuss each component one by one.

Select Docker Job Type

This field will be used to select your docker job type.

Job Name

This name will be used to select the job in a SPA widget.

Input File Name

This field is not applicable when working with LiveVMs. The files in the SPA widget are not linked to your container. Hence, there is no input file for the backend to work with. Instead, we can copy the files from the SPA into our container (more on this shortly).

Application Port

This is the port where your server will be listening. Port 3000 is always open by default and you can listen on one more port. Luckily, React runs on 3000, so we’ll just provide that in the field. However, if we had a Node server that runs on 8080, we’d provide that in the Application Port field.

Remember: If your application has a frontend, backend, etc., provide the frontend port in this field, and deploy the backend on port 3000.

HTTPS Strict Mode

If your server is HTTPS, tick this field.

Force Relaunch On Run

With this option enabled, the entire container shuts down and starts up again whenever Run is pressed in a widget where this job is selected. This is mainly useful for programs that only have a CLI output (C++, Python, etc.) rather than a web application.

Force Relaunch On Widget Switch

With this option enabled, if you use the same job in different widgets, a container will be started on each switch. However, on the same widget, the session won’t restart. For the same job being used in multiple widgets, check this box if you want the container to restart on every widget switch.

Start Script

This script runs the first time you click the ‘RUN’ button in a SPA. It runs only once. Typically, this script would be used to ‘start’ the server.

The code present in the SPA widget’s editor is not actually part of our project. This code lives in a directory called /usercode which is present in your container’s root directory by default.

So if the user makes any changes to App.js (which is in /usercode), they will not be reflected in your project’s App.js (which is in your project folder).

That’s why you also need to copy the code from the /usercode to your relevant folder (i.e., simple-reactjs-app in this case). Here, we simply copy the code and use npm start to start the server.

Your container is persistently active for 15 minutes. The Start Script is executed once again after the container times out.

Run Script

The Run Script is something you have seen before, but its behavior is slightly different in a Live job. It runs every time you click the ‘RUN’ button. On the first run, the Run Script is executed before the Start Script and after the first run, every subsequent run will only execute the commands written in this field (not the Start Script). These commands are executed in a new terminal on the back end. This ensures that the Run Script is executed even if the terminal visible to you in the browser is held up by another process.

If you start the server using the Start Script; then the only thing you need to worry about is updating the code in the relevant files/folder as the updated code would lie in the file present in the /usercode as we discussed earlier in the Run Script section. That’s why It is typically used to update your project’s code in the container.

cp -r /usercode/* /simple-reactjs-app/src

Here is the general data flow of a Run Script cycle:

Step 4: Select the Docker Job

Finally, create a new Single Page App widget and select your job from the Docker (Beta) dropdown menu.

Put all your project code in the SPA editor files, so that user can see it.

Before we get to running the server, there are a few extra options in the SPA control panel which you can use to fine-tune how your live server looks. Let’s discuss a few important ones.

  • Hide Code: Hides the code completely on the front end.

  • Hide Output: Hides the output window. Only the terminal will be displayed.

  • Output Height: Can be used to define the height of the output window.

  • Provide GitHub token: Provide a personal token if you are using a private repository.

  • Import code from GitHub: Enter the link to a repository to import it. This is useful for importing large projects automatically. The project size should not exceed 750 kb. If the project is larger, the usercode directory will become empty.

  • Override app entrypoint: You can change the server’s landing page with this option. Clicking on it will allow you to modify the link that is generated for the server.

Live Server in Action

Our live server is ready for use. Try it below!

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

Note: A link to your app will be generated and can be opened in your browser and shared with others. The link will be unique to each account. The server will stay up for 15 minutes.

URL Key

If you want to refer to the URL link generated by the SPA widget, you can use the key {{EDUCATIVE_LIVE_VM_URL}} in code playgrounds (Code widget, SPA, and Code Tabs) and it will be replaced by the application URL.

Hence, instead of having users manually copy the URL of their application, you can write {{EDUCATIVE_LIVE_VM_URL}} in the code playground and it will automatically be replaced for each user with their SPA widget’s application URL.

Note: The key must be added in Edit mode. Once you switch to Preview mode, you will see the key replaced by your app’s URL.

Editor View

User View

print("{{EDUCATIVE_LIVE_VM_URL}}") # Convert to string to make it printable

URL Key in a Docker Job

You may want to use your SPA’s URL in a Docker job. For example, you have the following command in your Start Script and want to replace url with your app’s URL:

 curl -H "Accept: text/event-stream" "url/quotes-reactive-paged?page=0&size=50"

This url is stored in the API key: EDUCATIVE_LIVE_VM_URL which can only be accessed inside a code file in the SPA widget. Hence, we can’t do the following directly inside the Start Script of the Docker job:

curl -H "Accept: text/event-stream" "{{EDUCATIVE_LIVE_VM_URL}}/quotes-reactive-paged?page=0&size=50"

In order to use this API key, we can shift the whole start script of the Docker job to a .sh file inside the SPA widget.

  • Make a .sh file in the SPA Widget and select the Hide File option.
  • When you switch to Preview mode and click on the Run button of the SPA widget, this API key will be replaced with the EDUCATIVE_LIVE_VM_URL.

    Note: This may not work in Edit mode.

  • In the Start Script of your Docker job, change the directory to /usercode where your .sh file resides and run it.

Now, your app’s URL is available in your Docker job!