Quit Virtualenv and use Docker
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 git@github.com: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
python main.py
-
Try to access our application from outside the container by opening a new terminal
curl http://127.0.0.1:8080/
It should return a Hello
6. 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
exit
to exit the container -
You can check that the container is no longer running by typing
docker ps
Here are the videos for these steps
Creating a custom docker image
Let's build a custom image for our application.
Why?
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
The -t
flag tells docker to build an image with the name myDockerImage
, the :
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
curl http://127.0.0.1:8080/
-
Go to the terminal where the
docker logs -f myPythonContainer
is 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:
- Kubernetes
https://kubernetes.io/
https://www.tutorialspoint.com/kubernetes/index.htm - Docker Swarm
https://docs.docker.com/engine/swarm/
Photo Credits: https://instagram.com/hikaique