Running containers
Before your container can be started, you'll first need to build an image defined in the Dockerfile. You can build the image using the following command:
docker build -t <name> <path>
The -t <name> argument allows us to name the image with a readable identifier. It is totally optional, but without it you won't be able to easily reference a newly created image. The <path> argument specifies the path to the directory where your Dockerfile is located. Let's assume that we were already running the command from the root of the project we presented in the previous section, and we want to tag our image with the name webserver. The docker build command invocation will be following, and its output may be as follows:
$ docker build -t webserver .
Sending build context to Docker daemon 4.608kB
Step 1/5 : FROM python:3.7-slim
3.7-slim: Pulling from library/python
802b00ed6f79: Pull complete
cf9573ca9503: Pull complete
b2182f7db2fb: Pull complete
37c0dde21a8c: Pull complete
a6c85c69b6b4: Pull complete
Digest: sha256:b73537137f740733ef0af985d5d7e5ac5054aadebfa2b6691df5efa793f9fd6d
Status: Downloaded newer image for python:3.7-slim
---> a3aec6c4b7c4
Step 2/5 : WORKDIR /app/
---> Running in 648a5bb2d9ab
Removing intermediate container 648a5bb2d9ab
---> a2489d084377
Step 3/5 : COPY static/ static/
---> 958a04fa5fa8
Step 4/5 : ENTRYPOINT ["python3.7", "-m", "http.server", "--bind", "80"]
---> Running in ec9f2a63c472
Removing intermediate container ec9f2a63c472
---> 991f46cf010a
Step 5/5 : CMD ["--directory", "static/"]
---> Running in 60322d5a9e9e
Removing intermediate container 60322d5a9e9e
---> 40c606a39f7a
Successfully built 40c606a39f7a
Successfully tagged webserver:latest
Once created, you can inspect the list of available images using the docker images command:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver latest 40c606a39f7a 2 minutes ago 143MB
python 3.7-slim a3aec6c4b7c4 2 weeks ago 143MB
The 143 MB of image for a simple Python image may seem like a lot, but it isn't really anything to worry about. For the sake of brevity, we have used a base image that is simple to use. There are other images that have been crafted specially to minimize this size, but these are usually dedicated to more experienced Docker users. Also, thanks to the layered structure of Docker images, if you're using many containers, the base layers can be cached and reused, so an eventual space overhead is rarely an issue.
Once your image is built and tagged, you can run a container using the docker run command. Our container is an example of a web service, so we will have to additionally tell Docker that we want to publish the container's ports by binding them locally:
docker run -it --rm -p 80:80 webserver
Here is an explanation of the specific arguments of the preceding command:
- -it: These are actually two concatenated options: -i and -t. -i (like interactive) keeps STDIN open, even if the container process is detached, and -t (like tty) allocates pseudo-TTY for the container. In short, thanks to these two options, we will be able to see live logs from http.server and ensure that the keyboard interrupt will cause the process to exit. It will simply behave the same way as we would start Python, straight from the command line.
--rm: Tells Docker to automatically remove container when it exits.
- -p 80:80: Tells Docker to publish the container's port 80 by binding port 80 on the host's interface.