docker
installed.docker run hello-world
To begin building an app the Docker way, we start at the bottom of the hierarchy of the app — container.
To run a python app with Docker, you need just grab a portable Python runtime as an image, no installation necessary. Then, your build can include the base Python image right alongside your app code, ensuring that your app, its dependencies, and the runtime, all travel together.
These portable images are defined by something called a Dockerfile
.
Dockerfile
Dockerfile
defines what goes on in the environment inside your container. Access to resources like networking interfaces and disk drives is virtualized inside this environment, which is isolated from the rest of your system, so you need to map ports to the outside world, and be specific about what files you want to “copy in” to that environment. However, after doing that, you can expect that the build of your app defined in this Dockerfile
behaves exactly the same wherever it runs.
Dockerfile
Do as the commands:
$ mkdir temp
$ cd temp
$ touch Dockerfile
$ vim Dockerfile
Paste the following content into the Dockerfile
and save it. Taking note of the comments.
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
Create two more files, requirements.txt
and app.py
, and put them in the same folder with the Dockerfile
. This completes our app, which as you can see is quite simple. When the above Dockerfile
is built into an image, app.py
and requirements.txt
is present because of that Dockerfile
’s COPY command, and the output from app.py
is accessible over HTTP thanks to the EXPOSE command.
requirements.txt
Flask
Redis
app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "cannot connect to Redis, counter disabled"
html = "Hello {name}!
" \
"Hostname: {hostname}
" \
"Visits: {visits}"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
Now we see that pip install -r requirements.txt
installs the Flask
and Redis
libraries for Python, and the app prints the environment variable NAME
, as well as the output of a call to socket.gethostname()
. Finally, because Redis
isn’t running (as we’ve only installed the Python library, and not Redis itself), we should expect that the attempt to use it here fails and produces the error message.
hat’s it! You don’t need Python
or anything in requirements.txt
on your system, nor does building or running this image install them on your system. It doesn’t seem like you’ve really set up an environment with Python and Flask, but you have.
$ ls
Dockerfile app.py requirements.txt
Run the build command. This creates a Docker image, which we’re going to tag using -t
so it has a friendly name.
docker build -t friendlyhello .
Find the image you built.
$ docker image ls
$ docker run -p 4000:80 friendlyhello
You should see a message that Python is serving your app at http://0.0.0.0:80
. But that message is coming from inside the container, which doesn’t know you mapped port 80 of that container to 4000, making the correct URL http://localhost:4000
.
Go to that URL in a web browser to see the display content served up on a web page.
You can also use the curl command in a shell to view the same content.
$ curl http://localhost:4000
This port remapping of 4000:80
demonstrates the difference between EXPOSE
within the Dockerfile
and what the publish
value is set to when running docker run -p
. In later steps, map port 4000 on the host to port 80 in the container and use http://localhost
. Hit CTRL+C
in your terminal to quit.
Now let’s run the app in the background, in detached mode:
$ docker run -d -p 4000:80 friendlyhello
You get the long container ID for your app and then are kicked back to your terminal. Your container is running in the background. You can also see the abbreviated container ID with docker container ls
(and both work interchangeably when running commands):
$ docker container ls
Now use docker container stop
to end the process, using the CONTAINER ID
, like so:
$ docker container stop 1fa4ab2cf395
The details is on https://docs.docker.com/get-started/part2/#share-your-image