438

According to the Docker Compose's compose-file documentation:

  • depends_on - Express dependency between services.
  • links - Link to containers in another service and also express dependency between services in the same way as depends_on.

I don't understand the purpose of linking to other containers so the difference between two options still seems quite difficult for me.

It would be much easier if there is an example, but I can't find any.

I noticed, when I link container B with container A then container B will be "pingable" inside container A's shell.

I ran ping B inside container A's bash and got result like this (just for reference, image from the Internet)

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
itsjef
  • 4,659
  • 3
  • 13
  • 12
  • 13
    The `--link` flag is now a deprecated legacy feature of Docker and the documentation suggests "It may eventually be removed" [Docker: Legacy container links](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). It is suggested not to use the [Docker networks feature](https://docs.docker.com/engine/userguide/networking/) or the docker compose method. I figured this would be helpful to anyone here learning about this feature. – A Star Sep 30 '17 at 15:39

4 Answers4

268

The post needs an update after the links option is deprecated.

Basically, links is no longer needed because its main purpose, making container reachable by another by adding environment variable, is included implicitly with network. When containers are placed in the same network, they are reachable by each other using their container name and other alias as host.

For docker run, --link is also deprecated and should be replaced by a custom network.

docker network create mynet
docker run -d --net mynet --name container1 my_image
docker run -it --net mynet --name container1 another_image

depends_on expresses start order (and implicitly image pulling order), which was a good side effect of links.

Siyu
  • 11,187
  • 4
  • 43
  • 55
  • 2
    How to do the same thing in docker-compose? I think that with docker compose all services are in the same network already and there is no need to add anything. Still linking between the containers doesn't work if one of the containers is trying to connect to container that is not in the Ready state. – makkasi Mar 27 '19 at 08:44
  • 1
    I can't see information about links being deprecated in docker-compose version 3 docs: https://docs.docker.com/compose/compose-file/#links . I don't see the option too useful, since we have shared networks and depends_on, but it is not deprecated if I read the docs correctly (they only mention --link flag on docker container). – rideronthestorm Jul 02 '19 at 10:29
  • Note: containers (actually services) in the same network are accessible by service name, not container name. Official documentation: https://docs.docker.com/compose/networking/#links – GarryOne Dec 23 '19 at 13:47
  • 1
    @makkasi you can use the depends_on setting in a compose file to change how containers are span up. At worst, you can add a wait script to your image to only let it run the up command when a certain criteria is met. Such as, only starting the server once a script that checks if the database is up and running has finished executing. – dondrzzy Jan 12 '22 at 06:52
265

This answer is for docker-compose version 2 and it also works on version 3

You can still access the data when you use depends_on.

If you look at docker docs Docker Compose and Django, you still can access the database like this:

version: '2'
services:
  db:
    image: postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

What is the difference between links and depends_on?

links:

When you create a container for a database, for example:

docker run -d --name=test-mysql --env="MYSQL_ROOT_PASSWORD=mypassword" -P mysql

docker inspect d54cf8a0fb98 |grep HostPort

And you may find

"HostPort": "32777"

This means you can connect the database from your localhost port 32777 (3306 in container) but this port will change every time you restart or remove the container. So you can use links to make sure you will always connect to the database and don't have to know which port it is.

web:
  links:
   - db

depends_on:

I found a nice blog from Giorgio Ferraris Docker-compose.yml: from V1 to V2

When docker-compose executes V2 files, it will automatically build a network between all of the containers defined in the file, and every container will be immediately able to refer to the others just using the names defined in the docker-compose.yml file.

And

So we don’t need links anymore; links were used to start a network communication between our db container and our web-server container, but this is already done by docker-compose

Update

depends_on

Express dependency between services, which has two effects:

  • docker-compose up will start services in dependency order. In the following example, db and redis will be started before web.
  • docker-compose up SERVICE will automatically include SERVICE’s dependencies. In the following example, docker-compose up web will also create and start db and redis.

Simple example:

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

Note: depends_on will not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.

Community
  • 1
  • 1
Windsooon
  • 6,864
  • 4
  • 31
  • 50
  • I've updated my answer to clarify that the answer was intended for compose file v1. – Xiongbing Jin Sep 23 '16 at 13:36
  • 1
    Is this still valid for version 3? – fabiomaia Mar 20 '17 at 00:03
  • Yes, you may have a look at `https://docs.docker.com/compose/compose-file/compose-versioning/` – Windsooon Mar 20 '17 at 02:36
  • "This means you can connect the database from your localhost port 32777(3306 in container) But this port will change every time you restart or remove the container" not if you specify the port binding in the docker-compose-file, it will not. And since this question is specifically about docker-compose, I feel that the example with `docker run` here is completely irrelevant, that's not how the container will be run anyway. What am I missing? – Andrew Savinykh May 10 '17 at 05:34
  • 1
    Yes, you are right if you specify the port. My `docker run `example wanna point out why we need to use depends_on or links instead of hard-code a port number.just because if you not specify it, it change every time. I think this will let people understand more about depends_on or links. – Windsooon May 10 '17 at 08:01
  • In the [Get started of v3](https://docs.docker.com/compose/gettingstarted/#step-3-define-services-in-a-compose-file), there isn't `depends_on` or `links`. – Cloud Oct 23 '17 at 01:28
  • @SiminJie You can find more on https://docs.docker.com/compose/compose-file/#depends_on – Windsooon Oct 24 '17 at 06:31
  • `depends_on` _is_ still supported in version 3: https://docs.docker.com/compose/compose-file/compose-file-v3/#depends_on – Benissimo Aug 17 '21 at 18:14
  • "you can use links to make sure you will always connect to the database and don't have to know which port it is." I'm sorry, but despite 250 upvotes, this still doesn't make any f*ing sense. ... "every container will be immediately able to refer to the others just using the names defined " which names? (Understand, my frustration is 95% with the silly ambiguity in the docker documentation.) – Otheus Feb 03 '23 at 20:25
57

[Update Sep 2016]: This answer was intended for docker compose file v1 (as shown by the sample compose file below). For v2, see the other answer by @Windsooon.

[Original answer]:

It is pretty clear in the documentation. depends_on decides the dependency and the order of container creation and links not only does these, but also

Containers for the linked service will be reachable at a hostname identical to the alias, or the service name if no alias was specified.

For example, assuming the following docker-compose.yml file:

web:
  image: example/my_web_app:latest
  links:
    - db
    - cache

db:
  image: postgres:latest

cache:
  image: redis:latest

With links, code inside web will be able to access the database using db:5432, assuming port 5432 is exposed in the db image. If depends_on were used, this wouldn't be possible, but the startup order of the containers would be correct.

Xiongbing Jin
  • 11,779
  • 3
  • 47
  • 41
  • Can you give me an example? Because that part is what I'm still unclear about. Maybe there are other compose-file options that may make it more specific. Please provide further details. Thanks! – itsjef Mar 06 '16 at 21:13
  • Thank you very much! I got it. One final question, please. So, in my particular case, i'm deploying my rails app, should i use `links` or `depends_on` or either of them is ok? My current `docker-compose.yml` uses `depends_on` and things seem to work fine. :) – itsjef Mar 07 '16 at 08:36
  • If you don't need to directly access the other container via `name:port` then `depends_on` is ok. – Xiongbing Jin Mar 07 '16 at 15:09
  • 9
    name:port works even without linking when you use expose: – Amit Goldstein Aug 21 '16 at 13:32
  • 9
    "If depends_on were used, this wouldn't be possible, but the startup order of the containers would be correct.". This is not correct. It would work if you just use depends_on. You can still access your `db` in the `web` using databases hostname. – prog.Dusan Sep 22 '16 at 04:08
  • "Links are not required to enable services to communicate - by default, any service can reach any other service at that service’s name." as long as you are not using "networks" or deploying with swarm. – Chris Sattinger Oct 11 '17 at 08:01
6

I think that the answers for this question need updating based on the new Docker compose specification introduced first in v1.27.0, which now allows for a long-form of depends_on:

https://github.com/compose-spec/compose-spec/blob/master/spec.md#long-syntax-1

In this long form, you can specify that you want to wait for a service to be either started, healthy, or completed successfully.

Docker compose knows that a service is healthy if you produce a health_check on that service:

https://github.com/compose-spec/compose-spec/blob/master/spec.md#healthcheck

I'd recommend to read the examples in the documentation for more details, see links above!

For a quick example, this is what I used in a compose file for integration tests:

services:
  cloud-broker:
    image: my.docker.registry/activemq-artemis:latest
    healthcheck:
      test: ["CMD-SHELL", "wget http://localhost:8161/ --delete-after --tries=3 2> /dev/null"]
      interval: 10s
      timeout: 5s
      retries: 5

  postgresql:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      POSTGRES_PASSWORD: "<my-secret>"
      POSTGRES_USER: "postgres"
      POSTGRES_DB: "postgres"
  
  # This service calls a script to create an empty database and the service-user
  postgresql-setup:
    image: postgres
    depends_on:
      postgresql:
        condition: service_healthy
    restart: "no"
    volumes:
      - "./scripts:/scripts"
    environment:
      PGPASSWORD: "<my-secret>"
    entrypoint: "psql -U postgres -d postgres -h postgresql -f /scripts/create-db.sql"

  my-business-service:
    image: my.docker.registry/my-business-service:latest
    depends_on:
      cloud-broker:
        condition: service_healthy
      postgresql-setup:
        condition: service_completed_successfully