Docker is Object Oriented Programming (OOP) for Systems

Sasank Chilamkurthy | | 4 minutes to read.

I was explaining about docker to my colleagues and I was struck by an epiphany: Docker is essentially object oriented programming (OOP) for systems programming. For the uninitiated Docker is OS-level virtualization that allow you to package softwares and make the installations easy and reproducible across systems. No more but it worked on my computer problems. Follow this tutorial from Keval to get a good idea of how it works. In this post, I’ll quickly review the docker concepts so that we can make the connection to OOP.

In docker, you build an image by specifying instructions in Dockerfile on how to install your application. You can think of an image as packaged file system containing your programs. For example, here’s how you build an image.

# Dockerfile
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip3 install numpy
CMD python3 -m http.server

This Dockerfile starts with FROM ubuntu:18.04 which means you’re using ubuntu 18.04 as base image and RUNs the next two commands in this image. CMD specifies the default command when you run this image. You build the image by running:

$ docker build -t numpy .

Once built, you can use this image to spin up an container in which you can run whatever you want. Let’s spin up a container and run python.

$ docker run -it numpy python3
Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> 

Obviously numpy is already installed in this container. How do we get input and output to this container? We can use file system and/or networking to interact with the container. Here’s an example:

$ mkdir input_dir
$ touch input_dir/hi
$ echo "hello sasank" > input_dir/hi
$ docker run -p 8001:8000 -v `pwd`/input_dir:/root/input numpy 

-p publishes port 8001 from docker and maps it to port number 8000 (the default python server port) inside docker. -v mounts input_dir in the present directory to /root/input of the container. In a different terminal, you can verify that the filesystem and network I/O worked with curl.

$ curl localhost:8001/root/input/hi
hello sasank

Now why am I calling this object oriented programming? Let’s start with clarifying what OOP is. In OOP, we have a class which encapsulates the data and methods of a particular functionality. For example, Human can be class whose data is the name and method is what_is_your_name(). You’ll have to create an instance of the Human class (say sasank) to interact with it. Once instantiated, the only way to interact with this instance is through the method (e.g., sasank.what_is_your_name()). What the class does internally is treated like a black box. A class can inherit data and methods from another class (say Animal)

Docker image is exactly like a class in which you define instructions to install your app. Data of this class is the code to run your app. Methods are what your app does. FROM is inheritance where you can inherit data and methods from a previously built image. You instantiate an image by spinning up a container. You interact with your container through filesystem and networking. What the container does internally is not your problem. I summarized the argument below:

Docker Object Oriented Programming
Image Class
Installed packages and code Data
CMD and what your code does Methods
FROM Inheritance
Container Instance

You usually make different classes interact with each other by composition where each interact with other through methods. This is exactly the use case of docker-compose where you can make different container interact with each other. For example your backend and front end can be two containers which can be composed in the following way:

version: "3"
services:
  backend:
    image: jodogne/orthanc-plugins
    ports:
      - 8042:8042

  frontend:
    image: ohif/viewer
    ports:
      - 3000:80

volumes: 
  orthanc_db:

All in all, docker is just OOP for systems programming. No wonder we all love docker and its abstractions.