Docker Tip #60: What Really Happens When You Run docker-compose up?
In this tip you'll learn how to look under the hood of what Docker Compose is doing whenever you run any of its commands.
Without looking at Docker Compose’s source code, it would be reasonable to
think that Docker Compose might just parse your docker-compose.yml
file and
then transform things like services, volumes and networks into various docker
commands.
And that’s not far from the truth, but Docker Compose isn’t directly calling
the docker
binary to run these commands. Instead, it’s using Docker’s API.
Using --verbose
to Take a Peek at What’s Happening
You can attach the --verbose
flag to any docker-compose
command, such as
running docker-compose --verbose up
to get the full view of what’s happening.
High level overview of running the up
command:
- Try to load any custom Docker config files
- Connect to the configured Docker daemon
- Attempt to inspect or create your project’s networks
- Attempt to inspect or create your project’s volumes
- Search for any containers already created for your project
- Search for any images already built for your project
- Create your project’s containers
- Start your project’s containers
- Periodically inspect your project’s running containers
- When you press
CTRL+C
, then stop your project’s containers
The raw verbose output:
This is the output of running docker-compose --verbose up
when running an
example Flask application that is part of the
Docker best practices project on GitHub.
nick@workstation:/e/src/github/docker-web-framework-examples/flask$ docker-compose --verbose up
compose.config.config.find: Using configuration files: ./docker-compose.yml
docker.utils.config.find_config_file: Trying paths: ['/home/nick/.docker/config.json', '/home/nick/.dockercfg']
docker.utils.config.find_config_file: No config file found
docker.utils.config.find_config_file: Trying paths: ['/home/nick/.docker/config.json', '/home/nick/.dockercfg']
docker.utils.config.find_config_file: No config file found
urllib3.connectionpool._new_conn: Starting new HTTP connection (1): 0.0.0.0
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/version HTTP/1.1" 200 568
compose.cli.command.get_client: docker-compose version 1.21.2, build a133471
docker-py version: 3.3.0
CPython version: 3.6.5
OpenSSL version: OpenSSL 1.0.1t 3 May 2016
compose.cli.command.get_client: Docker base_url: http://0.0.0.0:2375
compose.cli.command.get_client: Docker version: Platform={'Name': ''}, Components=[{'Name': 'Engine', 'Version': '18.05.0-ce', 'Details': {'ApiVersion': '1.37', 'Arch': 'amd64', 'BuildTime': '2018-05-09T22:20:16.000000000+00:00', 'Experimental': 'true', 'GitCommit': 'f150324', 'GoVersion': 'go1.10.1', 'KernelVersion': '4.9.87-linuxkit-aufs', 'MinAPIVersion': '1.12', 'Os': 'linux'}}], Version=18.05.0-ce, ApiVersion=1.37, MinAPIVersion=1.12, GitCommit=f150324, GoVersion=go1.10.1, Os=linux, Arch=amd64, KernelVersion=4.9.87-linuxkit-aufs, Experimental=True, BuildTime=2018-05-09T22:20:16.000000000+00:00
compose.cli.verbose_proxy.proxy_callable: docker inspect_network <- ('flaskhello_default')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/networks/flaskhello_default HTTP/1.1" 200 557
compose.cli.verbose_proxy.proxy_callable: docker inspect_network -> {'Attachable': True,
'ConfigFrom': {'Network': ''},
'ConfigOnly': False,
'Containers': {},
'Created': '2018-06-21T13:42:50.1357015Z',
'Driver': 'bridge',
'EnableIPv6': False,
'IPAM': {'Config': [{'Gateway': '172.18.0.1', 'Subnet': '172.18.0.0/16'}],
'Driver': 'default',
'Options': None},
...
compose.cli.verbose_proxy.proxy_callable: docker info <- ()
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/info HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker info -> {'Architecture': 'x86_64',
'BridgeNfIp6tables': True,
'BridgeNfIptables': True,
'CPUSet': True,
'CPUShares': True,
'CgroupDriver': 'cgroupfs',
'ClusterAdvertise': '',
'ClusterStore': '',
'ContainerdCommit': {'Expected': '773c489c9c1b21a6d78b5c538cd395416ec50f88',
'ID': '773c489c9c1b21a6d78b5c538cd395416ec50f88'},
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_network <- ('flaskhello_default')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/networks/flaskhello_default HTTP/1.1" 200 557
compose.cli.verbose_proxy.proxy_callable: docker inspect_network -> {'Attachable': True,
'ConfigFrom': {'Network': ''},
'ConfigOnly': False,
'Containers': {},
'Created': '2018-06-21T13:42:50.1357015Z',
'Driver': 'bridge',
'EnableIPv6': False,
'IPAM': {'Config': [{'Gateway': '172.18.0.1', 'Subnet': '172.18.0.0/16'}],
'Driver': 'default',
'Options': None},
...
compose.cli.verbose_proxy.proxy_callable: docker containers <- (all=False, filters={'label': ['com.docker.compose.project=flaskhello', 'com.docker.compose.oneoff=False']})
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/json?limit=-1&all=0&size=0&trunc_cmd=0&filters=%7B%22label%22%3A+%5B%22com.docker.compose.project%3Dflaskhello%22%2C+%22com.docker.compose.oneoff%3DFalse%22%5D%7D HTTP/1.1" 200 3
compose.cli.verbose_proxy.proxy_callable: docker containers -> (list with 0 items)
compose.cli.verbose_proxy.proxy_callable: docker containers <- (all=True, filters={'label': ['com.docker.compose.project=flaskhello', 'com.docker.compose.service=web', 'com.docker.compose.oneoff=False']})
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/json?limit=-1&all=1&size=0&trunc_cmd=0&filters=%7B%22label%22%3A+%5B%22com.docker.compose.project%3Dflaskhello%22%2C+%22com.docker.compose.service%3Dweb%22%2C+%22com.docker.compose.oneoff%3DFalse%22%5D%7D HTTP/1.1" 200 1305
compose.cli.verbose_proxy.proxy_callable: docker containers -> (list with 1 items)
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_image <- ('flaskhello_web')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/images/flaskhello_web/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_image -> {'Architecture': 'amd64',
'Author': '',
'Comment': '',
'Config': {'ArgsEscaped': True,
'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'-c',
'python:config.gunicorn',
...
compose.cli.verbose_proxy.proxy_callable: docker containers <- (all=True, filters={'label': ['com.docker.compose.project=flaskhello', 'com.docker.compose.service=web', 'com.docker.compose.oneoff=False']})
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/json?limit=-1&all=1&size=0&trunc_cmd=0&filters=%7B%22label%22%3A+%5B%22com.docker.compose.project%3Dflaskhello%22%2C+%22com.docker.compose.service%3Dweb%22%2C+%22com.docker.compose.oneoff%3DFalse%22%5D%7D HTTP/1.1" 200 1305
compose.cli.verbose_proxy.proxy_callable: docker containers -> (list with 1 items)
compose.cli.verbose_proxy.proxy_callable: docker inspect_image <- ('flaskhello_web')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/images/flaskhello_web/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_image -> {'Architecture': 'amd64',
'Author': '',
'Comment': '',
'Config': {'ArgsEscaped': True,
'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'-c',
'python:config.gunicorn',
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.parallel.feed_queue: Pending: {<Service: web>}
compose.parallel.feed_queue: Starting producer thread for <Service: web>
Starting flaskhello_web_1 ...
compose.parallel.feed_queue: Pending: {<Container: flaskhello_web_1 (c79799)>}
compose.parallel.feed_queue: Starting producer thread for <Container: flaskhello_web_1 (c79799)>
compose.cli.verbose_proxy.proxy_callable: docker attach <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9', stdout=True, stderr=True, stream=True)
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "POST /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/attach?logs=0&stdout=1&stderr=1&stream=1 HTTP/1.1" 101 0
urllib3.connectionpool._new_conn: Starting new HTTP connection (2): 0.0.0.0
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker attach -> <docker.types.daemon.CancellableStream object at 0x7fc9cc552cf8>
compose.cli.verbose_proxy.proxy_callable: docker start <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "POST /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/start HTTP/1.1" 204 0
compose.cli.verbose_proxy.proxy_callable: docker start -> None
Starting flaskhello_web_1 ... done
compose.parallel.feed_queue: Pending: set()
compose.parallel.parallel_execute_iter: Finished processing: <Service: web>
compose.parallel.feed_queue: Pending: set()
Attaching to flaskhello_web_1
compose.cli.verbose_proxy.proxy_callable: docker events <- (filters={'label': ['com.docker.compose.project=flaskhello', 'com.docker.compose.oneoff=False']}, decode=True)
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/events?filters=%7B%22label%22%3A+%5B%22com.docker.compose.project%3Dflaskhello%22%2C+%22com.docker.compose.oneoff%3DFalse%22%5D%7D HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker events -> <docker.types.daemon.CancellableStream object at 0x7fc9cc5bd2e8>
web_1 | [2018-06-21 13:54:07 +0000] [1] [INFO] Starting gunicorn 19.8.1
web_1 | [2018-06-21 13:54:07 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
web_1 | [2018-06-21 13:54:07 +0000] [1] [INFO] Using worker: sync
web_1 | [2018-06-21 13:54:07 +0000] [15] [INFO] Booting worker with pid: 15
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._new_conn: Starting new HTTP connection (3): 0.0.0.0
web_1 | /usr/local/lib/python2.7/site-packages/flask/sessions.py:208: UserWarning: "localhost" is not a valid cookie domain, it must contain a ".". Add an entry to your hosts file, for example "localhost.localdomain", and use that instead.web_1 | ' "{rv}.localdomain", and use that instead.'.format(rv=rv)
web_1 | 127.0.0.1 - - [21/Jun/2018:13:54:37 +0000] "GET /healthy HTTP/1.1" 200 - "-" "Wget" in 951µs
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
^CGracefully stopping... (press Ctrl+C again to force)
compose.cli.verbose_proxy.proxy_callable: docker containers <- (all=False, filters={'label': ['com.docker.compose.project=flaskhello', 'com.docker.compose.oneoff=False']})
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/json?limit=-1&all=0&size=0&trunc_cmd=0&filters=%7B%22label%22%3A+%5B%22com.docker.compose.project%3Dflaskhello%22%2C+%22com.docker.compose.oneoff%3DFalse%22%5D%7D HTTP/1.1" 200 1472
compose.cli.verbose_proxy.proxy_callable: docker containers -> (list with 1 items)
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
Stopping flaskhello_web_1 ...
compose.parallel.feed_queue: Pending: {<Container: flaskhello_web_1 (c79799)>}
compose.parallel.feed_queue: Starting producer thread for <Container: flaskhello_web_1 (c79799)>
compose.cli.verbose_proxy.proxy_callable: docker stop <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9', timeout=10)
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._new_conn: Starting new HTTP connection (4): 0.0.0.0
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],
...
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.cli.verbose_proxy.proxy_callable: docker wait <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
compose.cli.verbose_proxy.proxy_callable: docker inspect_container <- ('c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9')
urllib3.connectionpool._new_conn: Starting new HTTP connection (5): 0.0.0.0
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
compose.parallel.feed_queue: Pending: set()
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "POST /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/wait HTTP/1.1" 200 None
compose.cli.verbose_proxy.proxy_callable: docker wait -> {'Error': None, 'StatusCode': 0}
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "POST /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/stop?t=10 HTTP/1.1" 204 0
compose.cli.verbose_proxy.proxy_callable: docker stop -> None
Stopping flaskhello_web_1 ... done
urllib3.connectionpool._make_request: http://0.0.0.0:2375 "GET /v1.36/containers/c797998210352cb9596bbd2927133bc8f8cecc25021ee918e8c8802e4e753cd9/json HTTP/1.1" 200 None
compose.parallel.feed_queue: Pending: set()
compose.cli.verbose_proxy.proxy_callable: docker inspect_container -> {'AppArmorProfile': '',
'Args': ['--reload', '-c', 'python:config.gunicorn', 'hello.app:create_app()'],
'Config': {'AttachStderr': False,
'AttachStdin': False,
'AttachStdout': False,
'Cmd': ['gunicorn',
'--reload',
'-c',
'python:config.gunicorn',
'hello.app:create_app()'],