5

I have a docker-compose.yml file, and in that a build context for a given service with a Dockerfile.

Sample docker-compose:

version: '3'

services:

  scd-service:
    build:
      context: ./cmd/some-service/
      dockerfile: Dockerfile
      args:
        broker: redis:6379
        queue: somequeue
    depends_on:
      - redis
    networks:
      - backend

  redis:
    image: "redis:alpine"
    restart: unless-stopped
    networks:
      - backend

It can find the Dockerfile and build it with: docker-compose up --build some-service

However, this will fail. The broker and queue args are never passed to the given Dockerfile.

Sample Dockerfile:

FROM golang:1.11

// stuff...

ARG broker
ARG queue

CMD ["go", "run", "/go/src/github.com/org/project/cmd/some-service/some-service.go", "--broker $broker", "--queue $queue"]

As evident in the build stage, these are never parsed:

Step 7/7 : CMD ["go", "run", "/go/src/github.com/org/project/cmd/some-service/some-service.go", "--broker $broker", "--queue $queue"]

Whereafter the Go program crashes as the command line parameters are invalid.

How does one parse args from docker-compose to a Dockerfile?

Edit: Weirdly, I can echo the correct value?

Example:

ARG broker
ARG queue

RUN echo ${broker}

Outputs:

Step 7/8 : RUN echo ${broker}
 ---> Running in c84828847d9a
redis:6379

How is this not parsed onto the CMD?

cbll
  • 6,499
  • 26
  • 74
  • 117
  • 2
    Build-args are only available at build-time, but `CMD` entry executes at run-time. Here's a reference and a possible solution: https://stackoverflow.com/questions/35560894/is-docker-arg-allowed-within-cmd-instruction – Wintermute Jun 11 '19 at 13:07

2 Answers2

10

There are two problems here. ARG is only used at build time, when creating the image, and CMD defines a step at run time, when running your container. ARG gets implemented as an environment variable for RUN steps, so it is up to the shell to expand the environment variable. And the json syntax doesn't run a shell. So to do this with CMD, you need to make two changes.

First, you need to save your ARG as an ENV value that gets saved to the image metadata and used to setup the environment when creating the container.

And second, you need to switch from an exec/json syntax for running CMD to run a shell that will expand these variables. Docker does this for you with the string syntax.

The end result looks like:

FROM golang:1.11

// stuff...

ARG broker
ENV broker=${broker}
ARG queue
ENV queue=${queue}

CMD go run /go/src/github.com/org/project/cmd/some-service/some-service.go --broker "$broker" --queue "$queue"

As an aside, you should also note that every argument in exec syntax needs to be a separate array entry, e.g.:

CMD ["go", "run", "/go/src/github.com/org/project/cmd/some-service/some-service.go", "--broker $broker", "--queue $queue"]

is similar to running:

go run /go/src/github.com/org/project/cmd/some-service/some-service.go "--broker $broker" "--queue $queue"

when you really wanted to run:

CMD ["go", "run", "/go/src/github.com/org/project/cmd/some-service/some-service.go", "--broker", "your_broker", "--queue", "your_queue"]

which would be similar to:

go run /go/src/github.com/org/project/cmd/some-service/some-service.go --broker "your_broker" --queue "your_queue"

(Note I removed the variables from my example because they do not work in the exec syntax.)

BMitch
  • 231,797
  • 42
  • 475
  • 450
  • 1
    Thanks for your help. Seems like the container cannot see the redis container otherwise specified now, but one problem at a time. Cheers, it worked. – cbll Jun 11 '19 at 13:19
  • 1
    ARG can be used during BUILD time as well as during RUN time but it needs to be declared as mentioned in the docs: https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact – Ashish Singh Oct 10 '20 at 07:27
  • @AshishSingh the RUN step is performed at build time, when you create the image. The CMD step is executed at runtime, when you create the container. Yes the terminology is a bit confusing. – BMitch Oct 10 '20 at 09:52
4

You should set them as ENV, if you want them to be avaliable on containers based on the image (running-side). Something like:

ENV broker $broker   //assign your env broker value to container
ENV queue  $queue

ARG

These are avaliable when you create the image, but not when you want to run a container based on that.

ENV

ENV values are available to containers and also RUN-style commands. If you want the arguments to be avaliable during runtime, these are the good ones.

You also may find useful info about env values here.

Edit. In order to avoid [Warning] One or more build-args [] were not consumed message, you should do something like:

ARG broker=your.broker.value
ENV broker=${broker}

The error is telling that you have unused ARGS (altough you may be ok without setting them now that you have ENVs). More info here as well.

aran
  • 10,978
  • 5
  • 39
  • 69
  • Can you provide an example? Just swapping out `ARG` with `ENV` appears to be invalid syntax. – cbll Jun 11 '19 at 13:08
  • 1
    sure! it's a silly example, but the provided link may guide you better : ) – aran Jun 11 '19 at 13:09
  • With your example, I get: `[Warning] One or more build-args [queue broker] were not consumed` – cbll Jun 11 '19 at 13:09
  • Edited, that seems to be related to not-using the args you provide (*silly docker*) – aran Jun 11 '19 at 13:16
  • What is `your.broker.value` referring to? This is what should be passed on from docker-compose, presumably? – cbll Jun 11 '19 at 13:16