In part 1 of this series, we saw how to pull Docker images from Docker Hub and launch Docker containers. We interacted with a running Docker container by running some bash commands, in this tutorial we will see how to use Dockerfile to automate image building for quicker deployment of applications in a container.
Dockerfile is a text file containing a set of instructions or commands in order to build a Docker image.
Prerequisites
1. Complete the tutorial on part 1 before proceeding. You will need a Docker engine running and the latest official Ubuntu Docker images locally hosted.
2. Create directories
$mkdir ~/docker-flask
$cd ~/docker-flask
3. Add Dockerfile : ~/docker-flask/Dockerfile
The commands below will be used to create the Docker image. It will pull the latest Ubuntu official Docker image as a first layer or base. Then it will resynchronize the apt package index files from their sources.
A /flask directory will be created in the image, followed by installing Flask and running our Flask app, which we will write in next step.
FROM ubuntu:latest
RUN apt-get update && apt-get install -y python-pip python-dev
COPY . /flask
WORKDIR /flask
RUN pip install -r requirements.txt
EXPOSE 80
ENTRYPOINT ["python"]
CMD ["app.py"]
4. Write flask app : ~/docker-flask/app.py
Let us write a practical app, rather than just printing hello world. The flask app will return the user agent information of the visitor if the index page is visited.
We will also have a URL under /status/ followed by a valid HTTP status code. Given this HTTP status code by the visitor, the flask web server will generate the same HTTP status code header. For instance, if the user visits http://localhost/status/502, the flask server will respond with ‘502 BAD GATEWAY’ HTTP header.
Let us write it under ~/docker-flask/app.py
from flask import Flask
from flask import request, jsonify
app = Flask(__name__)
@app.route('/')
def user_agent():
user_agent = request.headers.get('User-Agent')
return 'Your browser is %s.' % user_agent
@app.route('/status/<int:httpcode>')
def get_status(httpcode):
httpcode = int(httpcode)
if httpcode < 100 or httpcode >= 600:
return jsonify({'Status': 'Invalid HTTP status code'})
elif httpcode >= 100 and httpcode < 500:
return jsonify({'Status': 'UP'}) , httpcode
else:
return jsonify({'Status': 'DOWN'}) , httpcode
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=80)
5. requirements.txt : ~/docker-flask/requirements.txt
cat ~/docker-flask/requirements.txt
Flask==0.12
By now, your directory structure should look similar to this –
daniel@lindell:~/docker-flask$ pwd
/home/daniel/docker-flask
daniel@lindell:~/docker-flask$ ls
app.py Dockerfile requirements.txt
Time to build the Docker image –
sudo docker build -t flaskweb:latest .
This will execute the series of commands under Dockerfile. If successful, you will end up with a Docker image named flaskweb and tagged latest –
root@lindell:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flaskweb latest 6b45443b6380 22 minutes ago 440.4 MB
ubuntu latest 104bec311bcd 2 weeks ago 129 MB
If you encounter any errors, validate you don’t have any syntax errors on Dockerfile.
It is time to run the container –
daniel@lindell:~/docker-flask$ sudo docker run -d -p 80:80 flaskweb
d9af9a1c92bff45b56fc97d13935972b65e3554bfe22ec2f3c102fd26bd20e4c
daniel@lindell:~/docker-flask$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9af9a1c92bf flaskweb "python app.py" About a minute ago Up About a minute 0.0.0.0:80->80/tcp drunk_mcnulty
In this case, both the host and container will be listening on port 80, feel free to modify this according to your setup.
Test it, we will use httpie to query the web server, if you don’t have httpie installed, you can use ‘curl -I’ to get the full header –
daniel@lindell:~/blog/docker-flask$ http http://localhost/
HTTP/1.0 200 OK
Content-Length: 29
Content-Type: text/html; charset=utf-8
Date: Fri, 30 Dec 2016 14:35:53 GMT
Server: Werkzeug/0.11.13 Python/2.7.12
Your browser is HTTPie/0.9.2.
daniel@lindell:~/blog/docker-flask$ http http://localhost/status/404
HTTP/1.0 404 NOT FOUND
Content-Length: 21
Content-Type: application/json
Date: Fri, 30 Dec 2016 14:35:56 GMT
Server: Werkzeug/0.11.13 Python/2.7.12
{
"Status": "UP"
}
daniel@lindell:~/blog/docker-flask$ http http://localhost/status/502
HTTP/1.0 502 BAD GATEWAY
Content-Length: 23
Content-Type: application/json
Date: Fri, 30 Dec 2016 14:35:58 GMT
Server: Werkzeug/0.11.13 Python/2.7.12
{
"Status": "DOWN"
}
Full clean up – if you want to start all over again or want to delete the container and images we have created, i have outlined the steps below. The first step is to stop the running container using ‘docker stop’ command, pass it the first few digits of the container ID.
Once the container is stopped, use ‘docker rm’ to delete the container. At this point, we can proceed with deleting the image as the image is not attached to any running container. Use ‘docker rmi’ to delete the image. We will keep the base Ubuntu image for future use.
daniel@lindell:/tmp$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9af9a1c92bf flaskweb "python app.py" 12 minutes ago Up 12 minutes 0.0.0.0:80->80/tcp drunk_mcnulty
daniel@lindell:/tmp$ sudo docker stop d9a
d9a
daniel@lindell:/tmp$ sudo docker rm d9a
d9a
daniel@lindell:/tmp$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
daniel@lindell:/tmp$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flaskweb latest 6b45443b6380 39 minutes ago 440.4 MB
ubuntu latest 104bec311bcd 2 weeks ago 129 MB
daniel@lindell:/tmp$ sudo docker rmi 6b45
Untagged: flaskweb:latest
Deleted: sha256:6b45443b63805583f41fbf60aaf5cf746b871fdcfa8fe1c6d5adfb52870e7c89
Deleted: sha256:02062a8ea251d993f54e15f9e5654e40894449430acd045476000cd9ebbdf459
Deleted: sha256:fa2439cd5bc8a53152877c1dc3b12a60ab808bcfe5078549ea5e945f462330da
Deleted: sha256:3bac38b223d80a4db6c4283fd56275fe05ceeab6a1dfd81871aa14c6cda387df
Deleted: sha256:d97357dc5d7454e3b7757f2c348323c84d1902dd806792c53d1fd0ca7813b091
Deleted: sha256:b55dd5bd3326ec4657dc389f4aae69c34a7ba222872f7b868eb8de69d7f69dab
Deleted: sha256:eab59ae84eb136339d08fbacd2905a1ee80a0c875e8e14a4d5184fac30445714
Deleted: sha256:588253a9066c49786fcd0121353e7f0f2cea05cebbc6b9cef67f0c823d23dce8
Deleted: sha256:fe9f27a1cb9165531a1f5149c16ebcd522422e4ac2610035bbbcada7fd0b7551
Deleted: sha256:18ca1bc40895f6f97cae28fa5707bde537ac27023762303f98912c11549431ae
daniel@lindell:/tmp$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 104bec311bcd 2 weeks ago 129 MB
References –
https://docs.docker.com/engine/reference/builder/
https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
http://flask.pocoo.org/docs/0.12/quickstart/