Few Things Need to be Noted — My Experience Using Docker

Muhammad Ryan
6 min readMay 7, 2020

Before using something, you must know what really that thing is. For me, Docker is a lightweight virtual machine rather than using a word like containerization. When you really need to use docker? W̶h̶e̶n̶ ̶y̶o̶u̶ ̶r̶e̶a̶l̶l̶y̶ ̶c̶u̶r̶i̶o̶u̶s̶ ̶a̶b̶o̶u̶t̶ ̶d̶o̶c̶k̶e̶r̶ ̶b̶e̶c̶a̶u̶s̶e̶ ̶e̶v̶e̶r̶y̶o̶n̶e̶ ̶t̶a̶l̶k̶i̶n̶g̶ ̶a̶b̶o̶u̶t̶ ̶i̶t̶ When you want to build an application that running exactly same in everywhere and don't need to reconfigure anything like environment variables, library, even OS of the running machine. An application that running the same everywhere? I think that is the main jargon of Java or why we use an interpreted programming language like Python, PHP, etc. But in most cases, you must do reconfigure and install various libraries before running that application in different machines. Convenience like don’t need to reconfigure (of course you still need to reconfigure when your app needs a parameter like a host address of the database server etc) or install anything is the main reason why we use docker.

Ok, so here I write down things that I wish to know when I start using docker. I will update this post when I found something interesting during my adventure with docker.

3 Main Object of Docker

Docker has a 3 main object that must be understood to make your life easier, namely:

  • Volume, the virtual partition for the docker.
  • Container, An active virtual machine.
  • Image, An image of the virtual machine (like an iso file, but this is not an iso file).

Those were 3 main components of a typical virtual machine, right? You can check the existences of these 3 components with

docker volume ls
docker container ls
docker image ls

For me, I have 1 volume, no active container (there is no running docker virtual machine at this time), and many images.

To run 1 of these images is with

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

For example, I want to run bash in docker_rekap_metar_web, so the command is

docker run -t -i docker_rekap_metar_web bash

here the options are -t and -i. It’s just to make sure the bash command returns tty and we can get feedback from the command coming trough tty. With this, now there is 1 active container. You can check it with ls command in another terminal.

Dockerfile A.K.A The Recipe to Build an Image

Docker has 1 file that dictates what to do to build the image of the virtual machine, namely Dockerfile. A typical example of Dockerfile is like this:

FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/

FROM in line 1 mean we need an image template namely python with tag 3 a.k.a python3. The image template is a base image to make sure we don't need to build the app from scratch. ENV to set an environment variable, in this case, we set PYTHONUNBUFFERED as 1 (proportional to export PYTHONUNBUFFERED=1). What the effect of this variable is to make sure the output of the python command sent straight to the terminal. RUN is to do a command. Inline 3 we do

mkdir /code

It will create /code directory in the virtual machine. WORKDIR inline 4 is to set a working directory of the virtual machine. next in line 5, we do COPY to copy requirements.txt in the real machine directory to the /code in the virtual machine directory. Next, we do

pip install -r requirements.txt

in /code in the virtual machine. How come we can do pip in the virtual machine? Remember we use the python3 image template (using the FROM command) so the python3 is already installed. This is possible too because we already copy requirements.txt file to the /code directory in the virtual machine. And last we do COPY to copy all files in the current directory to the /code directory in the virtual machine. And that’s all the step by step to build an image of our app that we tell to docker. Every time you want to build a new one, the docker will do all of this.

How to Connect Your Docker App to The External Server

Remember, our docker app is in the virtual machine. So the “localhost” of our real machine and “localhost” of our app is different. For example, you have a MySQL server in your localhost and want to connect your docker app to the server. Even you set localhost to the localhost like this in your pseudo code

mydb = mysql.connector.connect(
host = "localhost",
user = "root",
passwd = "password",
database = "db_name"
)

It will not work. The easiest way is to virtually make your docker app in the “localhost” of the real machine. To do this, when you do a docker run, set

--network=host

For example, using image docker_rekap_metar_web, you want to run the Django application (in this case, actually our docker app is Django app) and want to connect with localhost of the real machine, do this

docker run --network=host docker_rekap_metar_web python3 manage.py runserver

How to Build Complex App or Build More Than 1 App Simultaneous

Use docker-compose. If you use docker-compose, you will need 1 more file, namely docker-compose.yml. docker will read the file when you do

docker-compose up

to start a container of the app. An example of contents of docker-compose.yml is like this

version: '3'

services:
db:
image: postgres
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db

Line 1 we define the version number. Line 3, we define a list of services or apps we want to build. In this case, we have 2 apps, namely db and web.

in db app, we using postgres image template and set 3 environment variables that is POSTGRES_DB , POSTGRES_USER , and POSTGRES_PASSWORD . Next in web app, we set

build: .

It’s mean we tell docker that our Dockerfile is in the current directory. next line is command: python manage.py runserver 0.0.0.0:8000 it’s the command we will execute when the container is started. Next is we set the directory in the real machine we want to mount to the virtual machine using

volumes:
- .:/code

Next, we set port we want to open and forward to the real machine with

ports:
- "8000:8000"

n"8000:8000" means our app listen in port 8000. When our real machine gets accessed in port 8000, it will be forwarded to the virtual machine with port 8000 too. The real format for this configuration is

HOST:CONTAINER

For example, in case port 8000 in real machine is already used. We can change the ports configuration to

ports:
- "5656:8000"

So in order to access our app in the virtual machine, the user (for example, the user in localhost) must access 127.0.0.1:5656 (localhost is the alias of 127.0.0.1).

And the last is depends_on: . It tells docker that our web app need db app to run properly.

How to Connect Our docker-compose App to The External Server

Docker-compose doesn’t have options --network like vanilla docker instead, you can set it in docker-compose.yml. To keep using this easiest way (some source say, this method is not secure but right now this is the only method I know and understand), we set --network=host in the docker-compose.yml.

So we change the file from this

version: '3'

services:
db:
image: postgres
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db

to this

version: '3'

services:
db:
image: postgres
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
web:
build: .
networks:
- host
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
networks:
host:
external: true

How to Export Image to The Real Machine and Import It in Another Machine

This is the main reason why we use docker. We want to move our app from the development machine to the production machine easily. Because my current app is not yet finished so I have never tried this step before.

We can save our app image in tar file with docker save

docker save image_file > image_file.tar

and to load it with docker load in another machine

docker load < image_file.tar

After you load it, you can run it like usual with dockeror docker-compose .

References:

https://docs.docker.com/compose/django/, accessed on 7 May 2020

https://stackoverflow.com/questions/59812009/what-is-the-use-of-pythonunbuffered-in-docker-file, accessed on 7 May 2020

--

--

Muhammad Ryan

Meteorologist | Coder | Problem Solver | Writer | Daydreamer