项目作者: Nachtfeuer

项目描述 :
Docker and docker-compose
高级语言: Python
项目地址: git://github.com/Nachtfeuer/docker-compose-demo.git
创建时间: 2018-09-29T16:47:30Z
项目社区:https://github.com/Nachtfeuer/docker-compose-demo

开源协议:

下载


Welcome to the docker-compose demo

Table Of Contents

Thoughts

  • The images can be built locally but the docker-compose also would work if the images are already uploaded
    to a Docker registry; this idea is essential if you want to run such an environment either in Jenkins or
    Travis CI like system as part of a CI/CD (coded pipeline) or via Kubernetes.
  • The good thing is: if it works for those systems it also works locally which is usually not the case
    if you use such tools (Docker and docker-compose) relying on a concrete setup on your machine.
  • The setup and teardown should always be easy and fast.
  • The example server (written in Python) is very short (below 50 lines of code)

Requirements

  • Please ensure you have at least Docker 18.06.
  • You should have at least docker-compose 1.22.0.
  • You always should be in the root path of this repository when you execute shown commands.

Starting the primes server directly

  1. $ HOSTNAME=demo FLASK_APP=src/primes_server.py flask run
  2. * Serving Flask app "src/primes_server.py"
  3. * Environment: production
  4. WARNING: Do not use the development server in a production environment.
  5. Use a production WSGI server instead.
  6. * Debug mode: off
  7. * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Open another terminal and then:

  1. $ curl http://127.0.0.1:5000/primes/check/3
  2. {"isPrime": true, "hostname": "demo", "number": 3}
  3. $ curl http://127.0.0.1:5000/primes/check/4
  4. {"isPrime": false, "hostname": "demo", "number": 4}

Building the image for the primes server

It’s basically about installing the required Python module Flask, adding the python
server to the image and defining the command on how to run the server when the Docker container
for this image is started.

  1. docker build -t demo/primes-server:latest . -f images/Dockerfile.primes_server

Running the primes server as Docker container

  1. $ docker run --rm --name=primes-server -p 5000:5000 -d demo/primes-server:latest
  2. $ curl http://localhost:5000/primes/check/3
  3. {"isPrime": true, "hostname": "09d6af743a3f", "number": 3}
  4. $ curl http://localhost:5000/primes/check/4
  5. {"isPrime": false, "hostname": "09d6af743a3f", "number": 4}

When stopping the server (docker stop primes-server) the container automatically
goes away because of the --rm option.

Using docker-compose for starting the primes server

  1. $ docker-compose -f compose/docker-compose-server.yml up -d primes-server
  2. $ docker ps
  3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  4. 29177c0471cf demo/primes-server:latest "flask run --host=0.…" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp docker-compose-demo_primes-server_1
  5. $ curl http://localhost:5000/primes/check/3
  6. {"isPrime": true, "hostname": "09d6af743a3f", "number": 3}
  7. $ curl http://localhost:5000/primes/check/4
  8. {"isPrime": false, "hostname": "09d6af743a3f", "number": 4}

The -d is that docker compose starts the process into background.
Avoiding that more services are started the service prime-service is specified.
You can shutdown with docker-compose -f compose/docker-compose-server.yml down.

Running multiple prime servers with a loadbalancer

  1. $ docker-compose --compatibility -f compose/docker-compose-loadbalancer.yml up -d
  2. Starting compose_primes-server_1 ... done
  3. Starting compose_primes-server_2 ... done
  4. Starting compose_primes-server_3 ... done
  5. Starting compose_proxy_1 ... done
  6. $ for n in $(seq 1 12); do echo "$(curl -s http://localhost/primes/check/$n)"; done
  7. {"isPrime": false, "hostname": "99a5669c6fa2", "number": 1}
  8. {"isPrime": true, "hostname": "35eeb727e120", "number": 2}
  9. {"isPrime": true, "hostname": "ffda7cf2c91f", "number": 3}
  10. {"isPrime": false, "hostname": "99a5669c6fa2", "number": 4}
  11. {"isPrime": true, "hostname": "35eeb727e120", "number": 5}
  12. {"isPrime": false, "hostname": "ffda7cf2c91f", "number": 6}
  13. {"isPrime": true, "hostname": "99a5669c6fa2", "number": 7}
  14. {"isPrime": false, "hostname": "35eeb727e120", "number": 8}
  15. {"isPrime": false, "hostname": "ffda7cf2c91f", "number": 9}
  16. {"isPrime": false, "hostname": "99a5669c6fa2", "number": 10}
  17. {"isPrime": true, "hostname": "35eeb727e120", "number": 11}
  18. {"isPrime": false, "hostname": "ffda7cf2c91f", "number": 12}
  • You can see that each response comes from another prime server (hostname).
    Docker usually adjusts the hostname with the id of the container.
  • You also can see that the mechanism used here is round robin.
  • The --compatibility parameter is required otherwise the scale feature
    in the yaml configuration (name: deploy) works for Docker swarm only.
  • It’s also to mention that the concrete Docker image for the haproxy
    seems no longer maintained which does the automatic re-configuration
    depending on current scale. There are other solution with Docker compose
    but I have not yet investigated.
  • You shutdown with docker-compose --compatibility -f compose/docker-compose-loadbalancer.yml down.

Scaling the primes server

  1. docker-compose --compatibility -f compose/docker-compose-loadbalancer.yml up -d --scale=primes-server=10
  2. Starting compose_primes-server_1 ... done
  3. Starting compose_primes-server_2 ... done
  4. Starting compose_primes-server_3 ... done
  5. Creating compose_primes-server_4 ... done
  6. Creating compose_primes-server_5 ... done
  7. Creating compose_primes-server_6 ... done
  8. Creating compose_primes-server_7 ... done
  9. Creating compose_primes-server_8 ... done
  10. Creating compose_primes-server_9 ... done
  11. Creating compose_primes-server_10 ... done
  12. compose_proxy_1 is up-to-date

Health check

The health check can be implemented as REST call of the server.
The server has to tell whether all is fine.

  1. $ docker ps --format="{{.Names}} {{.Status}}"
  2. compose_proxy_1 Up 43 seconds
  3. compose_primes-server_3 Up 45 seconds (healthy)
  4. compose_primes-server_2 Up 45 seconds (healthy)
  5. compose_primes-server_1 Up 46 seconds (healthy)

In the logs of each container you see a record each
10 seconds:

  1. healthcheck:
  2. test: ["CMD", "curl", "-f", "http://localhost:5000/status"]
  3. interval: 10s
  4. timeout: 2s

Using Mongo database

Starting a Mongo database via Docker:

  1. $ docker run --rm --name=mongo -p 27017:27017 -d mongo:latest

Using the previously started Docker container:

  1. $ MONGODB_HOST=localhost HOSTNAME=demo FLASK_APP=src/primes_server_mongo.py flask run

This prime server stores each calculated primes for a given maximum number into
Mongo DB and next time when same list is requested the list is queried in the database
and returnd instead of the calculation.

The docker image can be built with

  1. $ docker build -t demo/primes-server-mongo:latest . -f images/Dockerfile.primes_server_mongo

With this you can also run an environment with Mongo DB, three primes server and
a loadbalance in front of this:

  1. $ docker-compose --compatibility -f compose/docker-compose-mongo.yml up -d

Using curl then only difference now is that (currently) the port is 80 (loadbalancer).

  1. $ curl http://127.0.0.1:80/primes/list/100
  2. {"max_n": 100, "primes": [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97], "hostname": "383ac2648957"}

You also can verify it changing into the Mongo DB Docker container:

  1. $ docker exec -it compose_mongodb_1 bash
  2. $ mongo
  3. $ use primes
  4. switched to db primes
  5. $ db.Primes.find({max_n: 100})
  6. { "_id" : ObjectId("5bb4aa1a667cd800012a95d0"), "max_n" : 100, "values" : [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,71, 73, 79, 83, 89, 97 ] }