Don’t get me wrong, I really like virtualenv and it’s pretty useful in some scenarios. But sometimes you have to deal with OS dependencies and that forces you to install new packages and it can get a bit messy in some scenarios.
If you haven’t heard about Docker (containers), you can read more about it at https://www.tutorialspoint.com/docker/index.htm
You can think of docker as a micro vm without all the overhead of a Virtual Machine.
Launching your first Docker container
- Install docker on your system https://docs.docker.com/install/
Clone the repo with the app I created for this
git clone firstname.lastname@example.org:gdi3d/quit-virtualenv-use-docker.git
Spin up a container and access to it using the following command on your terminal
docker run -it --name myPythonContainer --volume $(PWD):/code -p 8080:5000 python:3.6 bash
Install our python application requirements
cd /code pip install -r requirements.txt
Run the application
Try to access our application from outside the container by opening a new terminal
It should return a Hello
You can also check the container is running using
docker ps. This command will list all the container running.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 989f00e4a7fc python:3.6 "bash" 50 seconds ago Up 10 seconds 0.0.0.0:8080->5000/tcp myPythonContainer
- Great!, now go back to the terminal where you have the container and close it. First ctrl+c to shutdown the python process and then type
exitto exit the container
You can check that the container is no longer running by typing
Here are the videos for these steps
Creating a custom docker image
Let’s build a custom image for our application.
By creating a custom image we can have ready-to-go container with all the things that we need for our application to run and also set the command to run when our container start.
First, let’s create a file named Dockerfile in our application folder
# Our custom new image is based on a public image of python 3.6 FROM python:3.6 # create the directory /code and set it as the working directory WORKDIR /code # Copy the files to the docker folder /code COPY . /code # Install the python packages that we need RUN pip install -r requirements.txt # Define what command should be executed when this container starts ENTRYPOINT ["python", "/code/main.py"]
Now we need to build the image:
docker build -t mydockerimage:latest .
It will output something like this:
Sending build context to Docker daemon 4.096kB Step 1/5 : FROM python:3.6 ---> 1daf62e8cab5 Step 2/5 : WORKDIR /code ---> Using cache ---> 246ac5eb5a44 Step 3/5 : COPY . /code ---> Using cache ---> 8ab217175a34 Step 4/5 : RUN pip install -r requirements.txt ---> Using cache ---> ff9500f71963 Step 5/5 : ENTRYPOINT ["python", "/code/main.py"] ---> Using cache ---> 8f765333673a Successfully built 8f765333673a Successfully tagged mydockerimage:latest
-t flag tells docker to build an image with the name
:indicates a version for our image (you could also use v1.1, v1.2,… for ex.) and the
. indicates that the
Dockerfile file is in the current directory.
This image now has everything that we need to keep developing our application.
Let’s run the container again:
First, delete the older container. Although we’ve already exited and it’s not running there’s still a container with the name myPythonContainer and you need to delete it to launch a new one with the same name.
docker ps -a
this command will list all the container, even the ones that are terminated:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 989f00e4a7fc python:3.6 "bash" 20 hours ago Exited (0) 3 seconds ago myPythonContainer
docker rm myPythonContainer
Run our new container
docker run -d --name myPythonContainer --volume $(PWD):/code -p 8080:5000 mydockerimage
Notice the changes in this command compared with the first we used to launch our first container:
- You will see a response with and ID like 5d82484a63134dc911e8d2184a881950817b5d8bd07d7a64e1ee1b8207394ef9 that’s the ID of your container and it indicates that it has been launched.
- Not using -it. We’re using -d, that means that we run the container in the background.
- Not using the image python:3.6, we’re now using our new custom image mydockerimage
- Not using an explicit command anymore. This is because we’ve already set that in our Dockerfile in the line
ENTRYPOINT ["python", "/code/main.py"]
One thing you might notice is that we no longer see what’s happening inside the container. To be able to see what’s going on inside the docker you can always use
docker logs -f myPythonContainer
Open a new terminal and call our endpoint
Go to the terminal where the
docker logs -f myPythonContaineris running and you will see the call you just made.
That’s it!, now you can use Docker while developing and keep your OS untouched.
A bit more about containers
Docker and other containers technologies are based on LXC.
When you launch a container, just like a VM, you can choose what OS you want and you can pre-install software on it or use a public image already created by others.
The good part is that you can spin up a container, do your tests, run your code and then turn it off and forget about it, and you don’t need to install any dependencies on your OS for your code.
There’s a lot of benefits of using containers on a production environment, but I’m not going to get into that in this post. If you want to know more about it:
- Docker Swarm
Photo Credits: https://instagram.com/hikaique