Objective
- Flask web app:
Hello World!
count visit from web URL using Redis - using Dockerfile to auto build docker image, then start container and run flask web app on container
- share image via Docker Hub
1) create docker machine for test
launch msys shell from portabledevops, a portable lightweight devops tool on windows.
$ dm create -d "virtualbox" --virtualbox-hostonly-cidr "10.10.100.1/24" testdocker $ denv testdocker $ dm ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS testdocker * virtualbox Running tcp://10.10.100.100:2376 v17.06.2-ce
2) auto build image by Dockerfile
create work folder flaskhello/, create Dockerfile, app.py and requirements.txt under it.
sample script here are from Docker official get-started guide
Dockerfile
# 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 ADD . /app # Install any needed packages specified in requirements.txt RUN pip install -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"]
app.py
app.py is main loop for Flask web,
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 = "<i>cannot connect to Redis, counter disabled</i>" html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}" \ "<b>Visits:</b> {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)
os.getenv, socket.gethostname will get info from container, not docker host, hostname is container id in fact.
requirements.txt
this is list of python lib to be installed.
Flask Redis
So this demo only install python lib for Redis, not install Redis database itself, it will get exception when connect to Redis in web url.
3) build flaskhello app
$ docker build -t flaskhello . Sending build context to Docker daemon 4.608kB Step 1/7 : FROM python:2.7-slim 2.7-slim: Pulling from library/python aa18ad1a0d33: Pull complete 93d43f82f795: Pull complete c5b84867da0c: Pull complete f3a027f2a2da: Pull complete Digest: sha256:4e1518d4e30d93f3f197195fa3b4a0bcdc185a4501b7c109344cbbd569d1b40e Status: Downloaded newer image for python:2.7-slim ---> 8b88f06b72d7 Step 2/7 : WORKDIR /app ---> b0b179e84988 Removing intermediate container a1ca7c19bc3c Step 3/7 : ADD . /app ---> e73279011bfc Removing intermediate container a2f53e979dee Step 4/7 : RUN pip install -r requirements.txt ---> Running in d4dd1b9b09c2 Collecting Flask (from -r requirements.txt (line 1)) Downloading Flask-0.12.2-py2.py3-none-any.whl (83kB) Collecting Redis (from -r requirements.txt (line 2)) Downloading redis-2.10.6-py2.py3-none-any.whl (64kB) Collecting itsdangerous>=0.21 (from Flask->-r requirements.txt (line 1)) Downloading itsdangerous-0.24.tar.gz (46kB) Collecting Jinja2>=2.4 (from Flask->-r requirements.txt (line 1)) Downloading Jinja2-2.9.6-py2.py3-none-any.whl (340kB) Collecting Werkzeug>=0.7 (from Flask->-r requirements.txt (line 1)) Downloading Werkzeug-0.12.2-py2.py3-none-any.whl (312kB) Collecting click>=2.0 (from Flask->-r requirements.txt (line 1)) Downloading click-6.7-py2.py3-none-any.whl (71kB) Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->Flask->-r requirements.txt (line 1)) Downloading MarkupSafe-1.0.tar.gz Building wheels for collected packages: itsdangerous, MarkupSafe Running setup.py bdist_wheel for itsdangerous: started Running setup.py bdist_wheel for itsdangerous: finished with status 'done' Stored in directory: /root/.cache/pip/wheels/fc/a8/66/24d655233c757e178d45dea2de22a04c6d92766abfb741129a Running setup.py bdist_wheel for MarkupSafe: started Running setup.py bdist_wheel for MarkupSafe: finished with status 'done' Stored in directory: /root/.cache/pip/wheels/88/a7/30/e39a54a87bcbe25308fa3ca64e8ddc75d9b3e5afa21ee32d57 Successfully built itsdangerous MarkupSafe Installing collected packages: itsdangerous, MarkupSafe, Jinja2, Werkzeug, click, Flask, Redis Successfully installed Flask-0.12.2 Jinja2-2.9.6 MarkupSafe-1.0 Redis-2.10.6 Werkzeug-0.12.2 click-6.7 itsdangerous-0.24 ---> 520c80b0d4ee Removing intermediate container d4dd1b9b09c2 Step 5/7 : EXPOSE 80 ---> Running in 400eb60a6273 ---> 2910a96f4894 Removing intermediate container 400eb60a6273 Step 6/7 : ENV NAME World ---> Running in 85109c944baf ---> ef4433dc4c69 Removing intermediate container 85109c944baf Step 7/7 : CMD python app.py ---> Running in 43aed160271a ---> a226dc706f6a Removing intermediate container 43aed160271a Successfully built a226dc706f6a Successfully tagged flaskhello:latest SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
4) run app
check app image just built,
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE flaskhello latest a226dc706f6a 5 mins ago 195MB python 2.7-slim 8b88f06b72d7 15 mins ago 184MB
run flaskhello app in container, mapping localhost:4000 to container port 80,
docker run -it -p 4000:80 flaskhello * Running on http://0.0.0.0:80/ (Press CTRL+C to quit) 10.10.100.1 - - [24/Sep/2017 20:22:32] "GET / HTTP/1.1" 200 -
verify web app running by
http://10.10.100.100:4000/ Hello World! Hostname: 828a15523c37 Visits: cannot connect to Redis, counter disabled
also can verify hostname inside docker vm host,
docker@testdocker:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 828a15523c37 a226dc706f6a "python app.py" 56 seconds ago Up 56 seconds 0.0.0.0:4000->80/tcp mystifying_hopper
5) share app image
login to docker hub
$ docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: dreamcloud Password: Login Succeeded
tag image
Before we upload image to Docker Hub registry, need to tag the image in format: username/repository:tag
in our case,
$ docker tag flaskhello dreamcloud/flaskhello:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dreamcloud/flaskhello latest a226dc706f6a 30 mins ago 195MB python 2.7-slim 8b88f06b72d7 40 mins ago 184MB
push image
$ docker push dreamcloud/flaskhello:latest The push refers to a repository [docker.io/dreamcloud/flaskhello] 26e2e235a7ef: Pushed bceb4698c3a9: Pushed ed658958efb4: Pushed 24b02a08f57d: Mounted from library/python aed9311ebf15: Mounted from library/python 17f9d9d4ce37: Mounted from library/python 18f9b4e2e1bc: Mounted from library/python part2: digest: sha256:e1588720beb9e6acef48f8014166f7cef0a1a59e7527e555b62e1648f4d47972 size: 1787
as test, you can delete image from local, then pull or run uploaded image from Docker Hub.
$ docker rmi a226dc706f6a $ docker run -it -p 4000:80 dreamcloud/flaskhello