253

I am unable to specify CPU and memory limitation for services specified in version 3.

With version 2 it works fine with mem_limit & cpu_shares parameters under the services. But it fails while using version 3, putting them under deploy section doesn't seem worthy unless I am using swarm mode.

Can somebody help?

    version: "3"
    services:
      node:
        build:
         context: .
          dockerfile: ./docker-build/Dockerfile.node
        restart: always
        environment:
          - VIRTUAL_HOST=localhost
        volumes:
          - logs:/app/out/
        expose:
          - 8083
        command: ["npm","start"]
        cap_drop:
          - NET_ADMIN
          - SYS_ADMIN
saw303
  • 8,051
  • 7
  • 50
  • 90
vivekyad4v
  • 13,321
  • 4
  • 55
  • 63

6 Answers6

251

I know the topic is a bit old and seems stale, but anyway I was able to use these options:

deploy:
  resources:
    limits:
      cpus: '0.001'
      memory: 50M

when using 3.7 version of docker-compose

What helped in my case, was using this command:

docker-compose --compatibility up

--compatibility flag stands for (taken from the documentation):

If set, Compose will attempt to convert deploy keys in v3 files to their non-Swarm equivalent

Think it's great, that I don't have to revert my docker-compose file back to v2.

Denys Kurochkin
  • 1,360
  • 1
  • 18
  • 34
Rigi
  • 2,870
  • 1
  • 9
  • 18
  • 17
    It's interesting that this option has a [note](https://github.com/docker/compose/pull/5684): "The conversion is a "best effort" attempt and shouldn't be relied on for production deployments." – bartolo-otrit Aug 27 '19 at 11:56
  • 25
    This is a great fix for a poorly designed program, docker-compose. docker-compose is trying too hard to be what it isn't, a production grade orchestrator: https://github.com/docker/compose/issues/4513 – four43 Nov 05 '19 at 23:01
  • 2
    Your resource constrains will not take effect if container RAM/CPU > Docker for Windows/Mac has available. To change this go to Docker for Mac/Windows preferences->resources and adjust accordingly. – 8bitme Feb 10 '20 at 08:42
  • 3
    Why using non-integer _cpus: '0.001'_ here? Is it something like “one or none”? – Павле Sep 21 '20 at 12:33
  • 3
    Thank link from @four43 is still golden: https://github.com/docker/compose/issues/4513 – – gies0r Mar 06 '21 at 22:32
  • Hi, want to ask something with the `cpus` key. I am using version 2, can someone explain what is that key means? is it the CPU cores? or is it just a ratio from my Host CPU? thank you – Evan Gunawan Apr 04 '21 at 14:18
  • 1
    @EvanGunawan per documentation, it's the absolute number of CPUs of your host system. If you have 2 CPUs and set the value to 1, you'll cap your container to 1 CPU. If you have 4, and you set it to 0.5, your container will get 50% of _one_ CPU of your system (or, in other words, 12.5% of the whole system CPU capacity). – Gian Segato Apr 13 '21 at 07:03
  • It is worth pointing here that the `--compatibility` option was introduced in version 1.20.0 of Docker Compose. I'm mentioning here because I was testing with compose 1.17 and didn't work. Source: https://docs.docker.com/compose/compose-file/compose-versioning/#compatibility-mode – Ruben Alves Jul 05 '21 at 17:52
  • 1
    It's notable that compatibility mode doesn't support CPU reservation, but it does support CPU limits. `WARNING: The following deploy sub-keys are not supported in compatibility mode and have been ignored: resources.reservations.cpus` – Paul Oct 11 '21 at 15:11
  • 1
    in my case, upgrade docker-compose to 1.29.2, I don't need to add `--compatibility` , just `docker-compose up` is enough – Jackiexiao Oct 11 '22 at 09:45
  • How to auto restart the Docker compose container during reboot when container using `--compatibility` flag? I'm using `restart_policy`, but maybe I shouldn't? Or should I use a process manager?? https://docs.docker.com/config/containers/start-containers-automatically/#restart-policy-details – Melroy van den Berg Apr 02 '23 at 16:12
  • 1
    You don't need `--compatibility` anymore: https://github.com/docker/compose/issues/4513#issuecomment-1357633037 – Thore Jul 10 '23 at 10:43
132
deploy:
  resources:
    limits:
      cpus: '0.001'
      memory: 50M
    reservations:
      cpus: '0.0001'
      memory: 20M

More: https://docs.docker.com/compose/compose-file/compose-file-v3/#resources

In you specific case:

version: "3"
services:
  node:
    image: USER/Your-Pre-Built-Image
    environment:
      - VIRTUAL_HOST=localhost
    volumes:
      - logs:/app/out/
    command: ["npm","start"]
    cap_drop:
      - NET_ADMIN
      - SYS_ADMIN
    deploy:
      resources:
        limits:
          cpus: '0.001'
          memory: 50M
        reservations:
          cpus: '0.0001'
          memory: 20M

volumes:
  - logs

networks:
  default:
    driver: overlay

Note:

  • Expose is not necessary, it will be exposed per default on your stack network.
  • Images have to be pre-built. Build within v3 is not possible
  • "Restart" is also deprecated. You can use restart under deploy with on-failure action
  • You can use a standalone one node "swarm", v3 most improvements (if not all) are for swarm

Also Note: Networks in Swarm mode do not bridge. If you would like to connect internally only, you have to attach to the network. You can 1) specify an external network within an other compose file, or have to create the network with --attachable parameter (docker network create -d overlay My-Network --attachable) Otherwise you have to publish the port like this:

ports:
  - 80:80
kenny_k
  • 3,831
  • 5
  • 30
  • 41
Berndinox
  • 1,874
  • 2
  • 11
  • 11
  • 8
    1. I am able to build images using version 3 .
    2. It seems like approach for v3 is completely different from v2 , not like an upgrade .
    3. Deploy seems to be working only in swarm mode . I am getting warnings -
    "WARNING: Some services (node) use the 'deploy' key, which will be ignored. Compose does not support deploy configuration - use `docker stack deploy` to deploy to a swarm. "
    – vivekyad4v Feb 20 '17 at 14:02
  • 43
    @viveky4d4v As the Compose format v3 doc states, `deploy` is ignored if you aren't using Swarm. There's really no reason to use v3 format unless you are using Swarm. – Dan Lowe Feb 20 '17 at 14:48
  • @DanLowe we wanted to provide healthcheck in the compose itself which is supported only in v3. But i think i can survive without that . I agree that it doesn't make sense to move to v3 now . – vivekyad4v Feb 20 '17 at 15:11
  • 2
    If starting a new deployment, i would start with v3. Even if i just have one host. So you got the posibility to scale later and it's the same amount of time wou will need, once u understand the concept. – Berndinox Feb 20 '17 at 15:21
  • @Berndinox : Perfectly said :) . – vivekyad4v Mar 27 '17 at 13:55
  • @DanLowe you as well as the warning message state that `deploy` is ignored if you aren't using Swarm. How do you use Swarm so the warning message will go away? – A. Wentzel Dec 30 '17 at 01:37
  • docker swarm init – Berndinox Jan 19 '18 at 08:05
  • Build within v3 is indeed possible. See https://docs.docker.com/compose/compose-file/#build Tested w/ `docker-compose` 1.18.0 – helvete Jan 23 '18 at 10:31
  • @JayTaylor What do you mean by connecting "internally only"? How does that differ from a standard connection? – Connor Jun 14 '18 at 16:57
  • 1
    Hi @Connor, when I edited the answer all I did was correct a broken link. Like you, I'm unable to decipher what "internally only" means here. – Jay Taylor Jun 14 '18 at 22:38
  • To clearify: Per Default each service specified within one docker-compose.yml can communicate with each other service within the yml. (If not changed network settings to connect to another network) If you would like to connect a network from another compose-yml you have to explicit specifie it. – Berndinox Jun 19 '18 at 09:01
  • 6
    @Berndinox Do you happen to know how to set the `memory-swap` option mentioned at https://docs.docker.com/v17.12/config/containers/resource_constraints/#limit-a-containers-access-to-memory? I don't see an example of how to set it in `docker-compose.yml` (https://docs.docker.com/v17.12/compose/compose-file/#resources). Thanks so much. – Ryan Jul 14 '18 at 16:05
  • @DanLowe The only reason I see is providing network during build, which seems not possible in v2: https://stackoverflow.com/a/47545276/3276634 – Lion Sep 21 '19 at 21:51
79

Docker Compose v1 does not support the deploy key. It's only respected when you use your version 3 YAML file in a Docker Stack.

This message is printed when you add the deploy key to you docker-compose.yml file and then run docker-compose up -d

WARNING: Some services (database) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use docker stack deploy to deploy to a swarm.

The documentation (https://docs.docker.com/compose/compose-file/#deploy) says:

Specify configuration related to the deployment and running of services. This only takes effect when deploying to a swarm with docker stack deploy, and is ignored by docker-compose up and docker-compose run.

Nevertheless you can use Docker Compose v2. Given the following Docker composition you can use the deploy key to limit your containers resources.

version: "3.9"
services:
  database:
    image: mariadb:10.10.2-jammy
    container_name: mydb
    environment:
      MYSQL_ROOT_PASSWORD: root_secret
      MYSQL_DATABASE: mydb
      MYSQL_USER: myuser
      MYSQL_PASSWORD: secret
      TZ: "Europe/Zurich"
      MARIADB_AUTO_UPGRADE: "true"
    tmpfs:
      - /var/lib/mysql:rw
    ports:
      - "127.0.0.1:3306:3306"
    deploy:
      resources:
        limits:
          cpus: "4.0"
          memory: 200M
    networks:
      - mynetwork

When you run docker compose up -d (Note: in version 2 of Docker Compose you call the docker binary at not the docker-compose python application) and then inspect the resources you see that the memory is limited to 200 MB. The CPU limit is not exposed by docker stats.

❯ docker stats --no-stream
CONTAINER ID   NAME   CPU %     MEM USAGE / LIMIT   MEM %     NET I/O           BLOCK I/O         PIDS
2c71fb8de607   mydb   0.04%     198MiB / 200MiB     99.02%    2.67MB / 3.77MB   70.6MB / 156MB    18
saw303
  • 8,051
  • 7
  • 50
  • 90
  • 3
    Specifically the docs say if you want to do this, use v2 or deploy to swarm. – ic_fl2 Jul 03 '19 at 08:04
  • 3
    With docker-compose 3.7 you can add the --compatibility flag and it will translate the deploy limits in your 3.x file to your non-swarm execution. e.g. docker-compose --compatibility up – David Thomas Sep 01 '20 at 03:14
  • 4
    Here is the link to the docs for the `--compatibility` flag mentioned by @DavidThomas: https://docs.docker.com/compose/compose-file/compose-versioning/#compatibility-mode – aemaem Nov 08 '20 at 16:39
  • 7
    Thank you for pointing this out... But it still leaves the question open: How to **simply apply a memory limit per container in a docker compose file?** The [Swarm mode overview](https://docs.docker.com/engine/swarm/) may provide some background knowledge... But after all it is definitly not optimal that one need to run another application beside `docker-compose` to simply limit harware resources... – gies0r Mar 06 '21 at 22:20
  • 2
    Contrary to what the docs say, I found a closed related issue [here](https://github.com/docker/compose-cli/issues/1523) to support `deploy.resource.limits`, although I'm not sure if this is v2 or v3. The weird thing is, I can use these res limits without swarm or compatibility mode in v3.8 (docker-compose v1.28.2, docker v20.10.12) and I'm not sure if this is intentional or the doc is somehow outdated. – emrekgn Mar 21 '22 at 12:20
  • 2
    Ps. `cpus: "4.0"` setting means 4 CPU cores that run 100% CPU load Max (if you have hyper threading 4 cores means actually just 2 cores). So `4` are not physical CPUs. In most systems (with HT) this `4.0` means 2 physical cores are running 100%. Which is a lot! Even with a Ryzen 7 with 16 "cores" (8 cores + HT) setting this is `4.0` is very high. – Melroy van den Berg Feb 01 '23 at 22:24
25

This is possible with version >= 3.8. Here is an example using docker-compose >= 1.28.x :

version: '3.9'

services:
  app:
    image: nginx
    cpus: "0.5"
    mem_reservation: "10M"
    mem_limit: "250M"

Proof of it working (see the MEM USAGE) column :

Memory limit set with version 3.9

The expected behavior when reaching memory limit is the container getting killed. In this case, whether set restart: always or adjust your app code.

Limits and restarts settings in Docker compose v3 should now be set using (restart: always is also deprecated):

deploy:
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
    window: 120s
  resources:
    limits:
      cpus: '0.50'
      memory: 50M
    reservations:
      cpus: '0.25'
      memory: 20M
Melroy van den Berg
  • 2,697
  • 28
  • 31
secavfr
  • 628
  • 1
  • 9
  • 24
  • 3
    Note that the official [Compose Specification](https://github.com/compose-spec/compose-spec/blob/master/spec.md) says about: `mem_reservation` DEPRECATED: use deploy.reservations.memory – FireEmerald Dec 06 '22 at 09:04
8

I think there is confusion here over using docker-compose and docker compose (with a space). You can install the compose plugin using https://docs.docker.com/compose/install if you don't already have it.

Here is an example compose file just running Elasticsearch

 version: "3.7"
 services: 
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.15.2
    restart: always
    ports:
      - "9222:9200"
    deploy:
      resources:
        limits:
          cpus: "4"
          memory: "2g"
    environment:
      - "node.name=elasticsearch"
      - "bootstrap.memory_lock=true"
      - "discovery.type=single-node"
      - "xpack.security.enabled=false"
      - "ingest.geoip.downloader.enabled=false"

I have it in a directory called estest the file is called es-compose.yaml. The file sets CPU and memory limits.

If you launch using docker-compose e.g.

docker-compose -f es-compose.yaml up

Then look at docker stats you see

CONTAINER ID   NAME                     CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O        PIDS
e3b6253ee730   estest_elasticsearch_1   342.13%   32.39GiB / 62.49GiB   51.83%    7.7kB / 0B        27.3MB / 381kB   46

so the cpu and memory resource limits are ignored. During the launch you see the warning

WARNING: Some services (elasticsearch) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use `docker stack deploy` to deploy to a swarm.

Which I think is what leads people to look at Docker stack/swarm. However if you just switch to using the newer docker compose now built in to the docker CLI https://docs.docker.com/engine/reference/commandline/compose/ e.g.

docker compose -f es-compose.yaml up

And look again at docker stats you see

CONTAINER ID   NAME                     CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O        PIDS
d062eda10ffe   estest-elasticsearch-1   0.41%     1.383GiB / 2GiB       69.17%    8.6kB / 0B        369MB / 44MB     6

Therefore the limits have been applied.

This is better in my opinion than swarm as it still allows you to build containers as part of the compose project and pass environment easily via a file. I would recommend removing docker-compose and switching over to use the newer docker compose wherever possible.

James Mudd
  • 1,816
  • 1
  • 20
  • 25
4

I have other experiences, maybe somebody can explain this.

Maybe this is bug(i think this is a feature), but, I am able to use deployments limits (memory limits) in docker-compose without swarm, hovever CPU limits doesn't work but replication does.

$> docker-compose --version
docker-compose version 1.29.2
$> docker  --version
Docker version 20.10.12
version: '3.2'

services:
  limits-test:
    image: alexeiled/stress-ng
    command: [
     '--vm', '1', '--vm-bytes', '20%', '--vm-method', 'all', '--verify', '-t', ' 10m', '-v'

    ]
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 1024M

Docker stats

b647e0dad247   dc-limits_limits-test_1   0.01%     547.1MiB / 1GiB     53.43%    942B / 0B   0B / 0B     3

Edited, thx @Jimmix

hannesvdvreken
  • 4,858
  • 1
  • 15
  • 17
doodzio
  • 61
  • 4
  • I think the docs are a little bit confusing on this subject. I can also confirm docker-compose can properly handle these resource limits (without swarm or compatibility mode). Actually, IMHO this should be the up-to-date answer unless there is a reason this works with plain old docker-compose but should not be used that way. – emrekgn Mar 21 '22 at 12:11
  • I'm currently using a Docker Compose 3.9 and I don't need to add --compatibility flag in order to enable the deploy limits and the docker stats command is showing all the declared limits. – Piergiorgio Lucidi Mar 23 '22 at 17:27