Use of Docker

Learn why, when, and how to use Docker on the Educative platform.

Why use Docker?

Educative widgets allow authors to teach various technologies to readers with the help of executable code within the platform. The widgets natively support some technologies. If you want to extend or add execution environments, you will need to use Docker.

Docker is a container management service that allows you to create your own custom environments, which can include a variety of Operating Systems and developing frameworks.

If this is the first time you are hearing about docker, then have a look at the following resources to get an introduction:

You can find many pre-built official images at Docker HubDocker Hub is a hosted repository service provided by Docker for finding and sharing container images with your team. that can be used as a base image A base image is the image that is used to create all of your container images. Your base image can be an official Docker image, such as Centos, or you can modify an official Docker image to suit your needs, or you can create your own base image from scratch. in the dockerfile.

Docker useage on Educative
Docker useage on Educative

In a nutshell, we create a Dockerfile that has instructions on setting up the environment required for our code to run. We create a docker image from this Dockerfile which is a compiled version of the Dockerfile along with the code. Next, we build a Docker container from the image which is its running instance. This container serves as the execution environment behind the Educative widget. Keep on reading to learn more!

When and how to use Docker?

Let's take an example of a scenario where we would require Docker. Suppose we were writing an answer on creating a smart contract using Solidity.

For this purpose, we would use the code widget and select the language "Solidity". This will rename the code file in the left panel of the widget to helloworld.sol. You can now write your code in this file.

Select Solidity language in code widget (edit mode)
Select Solidity language in code widget (edit mode)

You can see a working example below.

pragma solidity ^0.5.0;
contract HelloWorld { // creating the Helloworld contract
bytes32 message; // define a variable message
constructor (bytes32 myMessage) public { // define a constructor
message = myMessage;
}
function getMessage() public view returns(bytes32) { //define a function that will return the state (message)
return message;
}
}

The pragma directive tells the compiler which version of Solidity the source code can run on. ^0.5.0 means the file will compile with 0.5.0 and higher versions in the 0.5.x branch up to version 0.6.0, where 0.6.0 is not included. This ensures that the smart contract does not behave abnormally due to a newer compiler version.

The current compiler version for solidity in the code widget is 0.5.12. Now suppose we want to change the compiler version to ^0.8.0. This can be done in the widget above and will result in an error due to a version mismatch. This situation calls for docker!

Steps to make a docker environment

Let's look at the steps we need to follow to make our own custom environment to run the specific compiler version. A similar approach will be followed for other scenarios!

  1. Explore the widget's docker guide: We will look at the guide for setting up docker in the code widget (or any other that we require) that will educate us on how to make the environment.

  2. Explore Answers' docker repository: Next, we will explore the Answer docker repository to see if a docker setup exists that we can use or modify for our specific requirements. In this case, we have a solidity docker setup available in the repository that will allow us to run our desired compiler version.

  3. Create/modify the Docker tarball: We will create the docker tarball or use an existing one from the repository. The tarballTAR archive - a group of files collected together as one is a collection of the Dockerfile and the required project/code files.

🐳 Dockerfile: The docker file is a text file that contains instructions for building a Docker image. The instructions in a Dockerfile include which base image to use (specifies the OS as well), which packages and libraries to install, and any other configuration settings or custom commands needed to run the code.

🐳 Docker image: The Dockerfile is used to make a docker image. It is a lightweight, stand-alone, and executable package that includes everything needed to run a piece of software, including the application code, libraries, dependencies, and runtime. It will form the environment behind the widget.

The command docker build is used to create a docker image from a Dockerfile. This will be done for you on the platform automatically once you upload the docker tarball containing the Dockerfile.

Let's look at the Dockerfile from the repository that we will be using in this case:

# base image
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y wget
RUN wget https://github.com/ethereum/solidity/releases/download/v0.8.0/solc-static-linux
RUN mv solc-static-linux /usr/local/bin/solc
RUN chmod +x /usr/local/bin/solc

Explanation

  • Line 2: This instruction specifies the base image for the Docker image. In this case, the base image is ubuntu:20.04, which is a version of Ubuntu Linux.

  • Line 4: This instruction runs the apt-get update command to update the package manager's package index and then installs the wget package, which is a utility for downloading files from the web.

  • Line 6: This instruction uses wget to download the Solc v0.8.0 binary from the specified URL.

  • Line 8: This instruction moves the Solc binary to the /usr/local/bin directory, which is a directory on the system's PATH, so that it can be easily accessed from the command line.

  • Line 10: This instruction changes the permissions on the Solc binary to make it executable.

Now that our Dockerfile is made, we can open a terminal on our computer/laptop and navigate to the folder containing the Dockerfile. With the following command, our tarball will be made:

tar -czvf solc8.tar.gz Dockerfile
In case we had project files that we had copied inside our Dockerfile, we can use the following command:

tar -czvf solc8.tar.gz .

There might be cases where we would have a big project but only a few files that concern the learner. For example, when we are running a React application in SPA widget. In this case, we can copy the project inside the Dockerfile.

To copy files and directories inside a Docker Container from our Local machine, we can use the COPY instruction inside the Dockerfile. Also if the project is present on githib, we can git clone it inside the Dockerfile. Then in the widget we can only place files that the user would want to see or change. All files in the widget are automatically placed in a directory called the "usercode" inside the docker container. In the run script we can copy the files from the usercode to our project directory in the container and run the code from there so that the user can see their changes.

📚 Have a look at SPA widget's docker guide to see how the above mentioned scenario is handled.

  1. Upload the docker tarball: Scroll to the end of the Answer editor towards the docker setting button and click on it. It will allow you to upload the tarball, as shown below. You can then click on the save button to build your docker image.

In case of an error during the build you can look at the build log to see the cause of failure.

  1. Create the docker job: Go ahead and create a docker job. Give it a descriptive name, such as solc0.8.0. The docker job allows us to specify the commands that we require to run our code. For the current use case, we would have the following docker job to run our solidity code:

Docker job for running solidity code in code widget
Docker job for running solidity code in code widget

For the code widget, the docker job type would be "default". We can name the code file in the input file name field. In the Run script, we have the command solc --bin contract.sol. It will compile the Solidity contract in the file "contract.sol" and output the resulting bytecode in binary form.

A Docker job is not required when using docker with the Terminal widget. In the case of a terminal widget, it has a start script field that is used to run commands to setup the enviroment for the user.

  1. Setup the widget: Now, in the code widget, we need to select the docker job. Next, we will add the code in the file present in the code widget. We can create multiple files too.

All the files made in the widgets are automatically sent to a directory inside the docker container called the usercode.

  1. Then, we save the lesson, and we are good to go. When the user runs the code widget, a container will be spun up based on the docker image that was built. Inside the container, the commands written in the run script will compile the contract and display the binary to the user. Try it out below.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract StringComparison {
function compare(string memory str1, string memory str2) public pure returns (bool) {
if (bytes(str1).length != bytes(str2).length) {
return false;
}
return keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2));
}
}

This example showed a specific scenario to develop an understanding of the steps we need to follow to make our code executable when a native supportive environment is not sufficient.

💡 Go through the previous lesson to see which widget to use for different use cases.

💡 Go through the Answer docker repository to see how to add interactivity for different technologies.