ECE 473/573 Fall 2024 - Project 1

Virtual Machines and Containers



Report Due: 09/15 (Sun.), by the end of the day (Chicago time)
Late submissions will NOT be graded


I. Objective

In this project, you will learn basic steps to setup environments for software development and deployment using virtual machines (VM) and containers.


II. Virtual Machine Setup

Please make sure your computer is able to run VirtualBox. In particular, since VirtualBox does not fully support Apple silicon platform, we are not able to support the use of M1/M2/M3 MacBook etc. in this course.

Install the most recent version of VirtualBox on your computer. You will need to turn on hardware virtualization if you haven't done so already.

Download the VM Appliance IIT-ECE573.ova and double-click to install/import. Make sure the file is downloaded completely with the size of 1,744,280,576 bytes and verify the integrity if possible.

Please keep this .ova file as we will need to use it throughout the semester for other projects.

Choose the installed VM and click 'Settings'. Choose 'Network' and click 'Advanced' from 'Adapter 1'. Click 'Port Forwarding' to bring up 'Port Forwarding Rules'. You should be able to see a mapping from 'Guest Port' 22 to 'Host Port' 57322. If not, you should setup the rule by yourself.

Start the VM. After a while, it would display the login screen. While you could login here, it is much more convenient to access the VM using SSH as introduced next.


III. Access Remote Instances via SSH

Managing computing resources rented from a cloud provider, e.g. a virtual private server (VPS), is not very different from managing your VM that is currently running on your own computer given you are using a proper set of tools. In this section, we will introduce you to remote access tools that depend on the SSH protocol. These tools provide terminal access to instances where you can execute shell commands. Here are some tutorials that you should go through if you are not familiar with Linux systems:

Visual Studio Code (VS Code) is a code editor that can be extended into a powerful IDE by third-party extensions. Download VS Code and install as necessary.

"Remote - SSH" is a widely used VS Code extension that makes it possible to perform development tasks on a remote instance using your favorite graphical user interface. You can follow this link to install it, or you can start VS Code and search for it in the Extensions panel from the left.

Click the green "><" button at the lower left corner to access remote window options in VS Code. Choose "Connect to Host..." and then enter "ubuntu@127.0.0.1:57322". A new VS Code window will open and asks you for the password. Once you type the password 'ece573', you will be connected to the server. You can now access files by opening a folder and execute commands by opening a terminal. Sometimes you will need to type the password again.


IV. Instance Provisioning

Our VM, like most of the instances rented from cloud, only has a minimal set of software packages installed. It is up to you to install and configure packages as needed.

"Pets vs. Cattle" refers to a methodology shift of server management for cloud computing from more traditional approaches. Traditionally, physical servers are treated as "pets". Each server has a particular role and their specific needs are met by installing and configuring software packages individually. Over the years, many of those packages will be updated so it is possible that one may lose track of what packages and what versions are actually installed. As a consequence, it is critical to ensure the health of these servers as it is very difficult to replace any.

Server management takes the "cattle" approach for cloud computing so that a horde of servers can be easily managed and replaced. In this approach, we no longer have direct access to the physical server. Instead, the underlying computing resources are accessed via VM instances that can be created and destroyed. All provisioning tasks including installing and configuring software packages are automated by scripts. These scripts are further stored in a version control system like Git so that any instance can be reproduced exactly.

Clone the repository on GitHub that holds scripts and source code for Project 1 by git clone https://github.com/wngjia/ece573-prj01.git.

ubuntu@ece573:~$ git clone https://github.com/wngjia/ece573-prj01.git
Cloning into 'ece573-prj01'...
...

Provision the instance with the script setup_vm.sh.

ubuntu@ece573:~$ sudo ece573-prj01/setup_vm.sh
...
It will take a while to complete and you may need to type the password again.

Now two software packages, Docker and Go, should be properly installed and configured, which can be verified by go version and docker version.

ubuntu@ece573:~$ go version
go version go1.21.0 linux/amd64
ubuntu@ece573:~$ docker version
Client: Docker Engine - Community
 Version:           26.1.2
 API version:       1.45
 Go version:        go1.21.10
 Git commit:        211e74b
 Built:             Wed May  8 13:59:58 2024
 OS/Arch:           linux/amd64
 Context:           default
...


V. Docker and Go

Using scripts to automatically setup VM instances makes it possible to manage many instances efficiently. However, VMs are considered "heavy" as they would need to consume resources and take time to create and destroy. Docker provides access to containers, which can be treated as "lightweight virtual machines", that makes the use of resources more effective.

Very similar to how we setup our VM instance, to use Docker you will need to start with some "docker images" that contain initial container setups. Then, you can create your own images by modifying existing ones, e.g. adding your own software. What is the point of all these complexities instead of just deploying your own software binary? The point is that all these images can be easily distributed to any instances supporting Docker and be executed in containers there reproducing the same behavior without the need to install any other packages your software may be depending on. In addition, once software packages are all deployed using Docker, it is possible to reproduce production environments in development settings, a very preferable approach for software developement and testing.

Let's first obtain a docker image for building Go programs by docker pull

ubuntu@ece573:~$ docker pull golang:1.21
1.21: Pulling from library/golang
...
It will take some time to download and Docker will verify the integrity of the images. You can then inspect the images by docker images
ubuntu@ece573:~$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
golang       1.21      3758cb2c0a6b   6 days ago       814MB
Note that we have installed Go to our VM instance that will be used by VS Code for Go development. This docker image is used to build Go programs as releases for deployment into testing and production environments.

The preferable way to create your own images is to use a special script file named Dockerfile. Similar to VM instances, use of scripts ensures that the images can be reproduced exactly if needed. Build your first Docker image by docker build. You will need to supply a name for the image like "prj01" by the -t prj01 option, and then the directory ece573-prj01 that contains the Dockerfile.

ubuntu@ece573:~$ docker build -t prj01 ece573-prj01
...
 => => writing image sha256:2317a9ea6fc78ded75b8d10198fe593fd383c05a93a22dcbe81b1dac069a9e72      0.0s
 => => naming to docker.io/library/prj01                                                          0.0s
ubuntu@ece573:~$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
prj01        latest    2317a9ea6fc7   33 minutes ago   1.82MB
golang       1.21      3758cb2c0a6b   6 days ago       814MB
The newly built image "prj01" can be seen from docker images now. It has a very small size of 1.82MB, which is about 1/1000 of our VM Appliance.

The Docker image can be executed in a container by the docker run command. This is a complicated command that we will take time to learn, but for now we simply use the --rm option so the container will be removed at the end without consuming any storage resources.

ubuntu@ece573:~$ docker run --rm prj01
Hello world!


VI. Project Requirements and Deliverables

You will need to complete all the steps above to setup the VM instance correctly. You should first complete Basic Linux usage: Chapter 1 to 8 from Linux Tutorial if you are not familiar with basic Linux commands. All commands use similar structures for inputs and outputs so if anything goes wrong, you will need to read the outputs carefully to understand what could be the problem - usually it's a typo or a missing or extra space somewhere in your typing.

Modify the file hello.go to print the date and time now as well as the last four digits of your CWID. Build the docker image and execute it again. The output should be something like follows:

ubuntu@ece573:~$ docker build -t prj01 ece573-prj01
...
 => => writing image sha256:6192b944ea4a53094535695b9e8903b330a634c174ac25009c5b7442ac4159b0      0.0s
 => => naming to docker.io/library/prj01                                                          0.0s
ubuntu@ece573:~$ docker run --rm prj01
Hello world!
It's 2023-08-15 21:15:42 now and my CWID ending in 1111.

Prepare a project report in .doc/.docs or .pdf format and submit it to Canvas before the deadline. Your project report should include the following: