174

I have the following docker-compose file

version: '3'
services:
    node1:
            build: node1
            image: node1
            container_name: node1

    node2:
            build: node2
            image: node2
            container_name: node2

I can build both images and start them with a single command

docker-compose up -d --build

But I would like to use build-args on the builds. The original build script of the image outside of the scope of compose looks something like this

#!/bin/sh
docker build \
--build-arg ADMIN_USERNNAME_1=weblogic \
--build-arg ADMIN_PASSWORD_1=weblogic1 \
--build-arg ADMIN_NAME_1=admin \
--build-arg ...
--build-arg ... \
-t test/foo .

Both images would use build-args of the same name but different value. Also, as there are dozens of build args, it would be convenient to store them in a compose service specific build-properties file. Is this possible with docker-compose?

Raphael
  • 9,779
  • 5
  • 63
  • 94
Tuomas Toivonen
  • 21,690
  • 47
  • 129
  • 225
  • 10
    Warning for later people: for passwords, you might consider using a secret manager (Vault, k8s secrets, aws sms, docker swarm secrets) instead of a build arg to avoid security breaches. A build-time arg will bake the cred in the image, which means anyone with pull access can read it. Avoid using credentials at build-time. – James Fulford Dec 25 '20 at 20:02
  • 2
    Very important note about security, thanks a lot. Here is a solution: https://pythonspeed.com/articles/build-secrets-docker-compose/ – sekrett May 19 '21 at 09:35
  • @Bira I fail to see what this question has to do with AWS. The question doesn't mention it, and docker-compose is indeed an independent product. – Raphael Apr 24 '23 at 07:05

5 Answers5

178

You can specify the arguments directly in your docker-compose file:

node1:
    build:
        context: node1
        args:
            ADMIN_USERNNAME: weblogic1
            ADMIN_PASSWORD: weblogic1
            ADMIN_NAME: admin1
    image: node1
    container_name: node1

See a full example: MWE

The official docs (legacy v3 here) have all detail.

Raphael
  • 9,779
  • 5
  • 63
  • 94
  • 2
    For some reason `args` in the docker-compose file did not work for me when trying to use a shell var. Instead I had to use `--build-arg VARNAME=$VARNAME` when running the command. – harvzor Apr 15 '21 at 11:10
  • @harvzor Not sure what you mean by that. Do you expect `docker-compose` to have excess to a Bash variable outside of its own runtime? Yeah, that won't work, and it shouldn't. You _can_ use environment variables, though: https://docs.docker.com/compose/environment-variables/ – Raphael Feb 24 '22 at 15:36
  • For multiline `--build-arg`, see https://stackoverflow.com/a/67135826/432903 – prayagupa Dec 08 '22 at 23:35
52

You can define your args with your build command of docker-compose.

Example Dockerfile:

FROM nginx:1.13

RUN apt-get -y update && apt-get install -y \
    apache2-utils && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

ARG username
ARG password

RUN htpasswd -bc /etc/nginx/.htpasswd $username $password

docker-compose file:

version: '3'
services:
  node1:
     build: ./dir

The ./dir contains the Dockerfile and I build with this command:

docker-compose build --build-arg username="my-user" --build-arg password="my-pass"

I see already:

Step 5/5 : RUN htpasswd -bc /etc/nginx/.htpasswd $username $password
 ---> Running in 80735195e35d
Adding password for user my-user
 ---> c52c92556825

I bring my stack up:

docker-compose up -d

Now I can check inside the nginx container and my username and (encrypted) password are there:

docker@default:~/test$ docker exec -it test_node1_1 bash
root@208e4d75e2bd:/# cat /etc/nginx/.htpasswd
my-user:$apr1$qg4I/5RO$KMaOPvjbnKdZH37z2WYfe1

Using this method your able to pass build args to your docker-compose stack.

lvthillo
  • 28,263
  • 13
  • 94
  • 127
  • 1
    Environment variables can be used as you said, but they have to be defined in .env, not inside the compose file – Alejandro Galera Jun 07 '18 at 08:07
  • 3
    This answer is very useful, it actually shows how `docker-compose` can be used with `--build-arg` on command-line, you can define your ARG in `Dockerfile`, `docker-compose.yml` - **the :args array defined** and then finally override it on the command-line. – CvRChameleon Jul 20 '20 at 10:14
  • 1
    Seems correct, but for others, be wary of baking credentials into images like this. Username/password should be done at runtime, so your prod credentials don't show up in your repository – James Fulford Dec 25 '20 at 19:59
  • This is the answer I was looking for, showing that `--build-arg` can be used with `docker-compose` – Gostega Jan 21 '21 at 23:27
47

In your Dockerfile:

ARG CERTBOT_TAG=latest
FROM certbot/certbot:${CERTBOT_TAG}

In your docker-compose.yml file:

version: '3.4'
services:
  certbot:
    build:
      context: .
      args:
        CERTBOT_TAG: v0.40.1

And you can build or up your service:

docker-compose build certbot
michalhosna
  • 7,327
  • 3
  • 21
  • 40
heralight
  • 920
  • 1
  • 7
  • 15
  • 2
    I got an error using this format, `ERROR: The Compose file './docker-compose.yml' is invalid because: services.certbot.build.args contains {"CERTBOT_TAG": "v0.40.1"}, which is an invalid type, it should be a string` My solution was to remove the `-` to turn it into a string instead of an object. – alete Feb 18 '21 at 21:37
  • @heralight please fix the YAML syntax! – Martynas Jusevičius Nov 17 '21 at 15:49
7

As Salek mentioned above, adding context: . helps.

For example:

version: '3.5'
services:
  app:
    build:
      context: .
      args:
        NODE_VERSION: 14.15.4
       

`

PHZ.fi-Pharazon
  • 1,479
  • 14
  • 15
2

Docker File

ARG ACCOUNT_ID

FROM $ACCOUNT_ID.dkr.ecr.ap-southeast-1.amazonaws.com/my-composer:latest as composer
LABEL stage=intermediate

Buildspec or CLI execute the following command.

docker-compose build --build-arg ACCOUNT_ID="23423432423" --no-cache

If you want to print the ACCOUNT_ID in CLI

ARG ACCOUNT_ID

FROM amazonlinux:latest
RUN yum -y install aws-cli 
RUN echo $ACCOUNT_ID

FROM $ACCOUNT_ID.dkr.ecr.ap-southeast-1.amazonaws.com/my-composer:latest as composer
LABEL stage=intermediate

Note: ARG should be on top of all FROM statement, then it will work as global ARG.

Bira
  • 4,531
  • 2
  • 27
  • 42