Docker is Object Oriented Programming (OOP) for Systems
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
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
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|
|Installed packages and code||Data|
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.