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/