Passing env variables to RUN in Dockerfile - docker

How to pass environment variables to RUN command in Dockerfile? In my scenario, I want to pass env variables to RUN command which runs a script & uses these variables?
.env
NAME=John
script.sh
#!/bin/sh
echo $NAME
Dockerfile
FROM alpine:3.14
COPY . .
RUN chmod +x script.sh
RUN ./script.sh
docker-compose.yml
version: "3.1"
services:
foo:
container_name: foo
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
How can I pass the NAME env variable to the last RUN command in Dockerfile (to be used by the script executable)?
I am aware of --build-arg but it is inconvenient when there are 100s of env variables. Even then how can I format the docker compose command to read all arguments from an env file & pass them as build arguments?

Related

Docker How to use environment variables in RUN command, not CMD?

I have:
docker-compose.yml
version: "3.9"
services:
test_name:
image: ${PROJECT_NAME}/test_service
build:
dockerfile: Dockerfile
env_file: .env
Dockerfile
FROM alpine:3.15
RUN echo $TEST >> test1.txt
CMD echo $TEST >> test2.txt
As result:
test1.txt - empty and test2.txt with data.
My problem is that this variables are too much, so can I get environment variables in RUN command from .env file without enumeration all of them in ARG?
To use variables in a RUN instruction, you need to use ARG. ARG are available at build time while ENV is available when the container runs.
FROM alpine:3.15
ARG FOO="you see me on build"
ENV BAR="you see me on run"
RUN echo $FOO >> test1.txt
CMD echo $BAR >> test2.txt
docker build --build-arg FOO="hi" --tag test .
docker run --env BAR="there" test
There is one thing that comes close to using env variables, but you still need to provide the --build-arg flag.
You can define env variable with the same name as the build arg and reference it by its name without setting a value. The value will be taken from the env variable in your shell.
export FOO="bar"
docker build --build-arg FOO --tag test .
This also works in compose.
Additionally, when you use compose you can place a .env file next to your compose file. Variables found there will be read and are available in the build:arg key as well as the environment key, But you still have to name them.
# env file
FOO=bar
BAZ=qux
services:
test_name:
build:
context: ./
args:
FOO:
BAZ:

How to pass ENV arguments in my Dockerfile when using docker-compose

I have a docker-compose.yml that has a section:
myservice:
env_file:
- myvars.env
My env variable file has:
myvars.env:
SOME_VAL=123
And then in my Dockerfile I have this:
..
RUN echo "some_val ${SOME_VAL}"
ENTRYPOINT bash ${APP_BASE}/run.sh SOME_VAL=${SOME_VAL}
When I run docker-compose up, the value of some_val is empty.
Why is SOME_VAL not accessible in my dockerfile?
How do I pass the env variable SOME_VAL to my run.sh script?
You need to declare the variable with ENV in the Dockerfile before using it:
ENV variables are also available during the build, as soon as you introduce them with an ENV instruction.
Dockerfile
ENV SOME_VAL
RUN echo "some_val ${SOME_VAL}"
ENTRYPOINT bash ${APP_BASE}/run.sh SOME_VAL=${SOME_VAL}
When you docker-compose build an image, it only considers the build: sections of the docker-compose.yml file. Nothing else from any other part of the file is considered. environment: and env_file: settings aren't available, nor are volumes: nor networks:. The only way to pass settings in is through the Dockerfile ARG and the corresponding Compose args: settings, and even then, you only want to use this for things you'd "compile in" to the image.
Conveniently, shell scripts can directly access environment variables already, so you don't need to do anything at all; just use the variable.
#!/bin/sh
# run.sh
echo "SOME_VAL is $SOME_VAL"
# Dockerfile
FROM busybox
WORKDIR /app
COPY run.sh .
# RUN chmod +x run.sh
CMD ["./run.sh"]
# docker-compose.yml
version: '3.8'
services:
echoer:
build: .
env_file:
- my_vars.env
# environment:
# SOME_VAL: foo

Setting container PATH with an ENV parameter

I have a docker-compose file which includes the following:
environment:
DOCUMENT_ROOT: /var/some/dir
I would like to add that path to my container.
In my DockerFile I add:
RUN echo "export PATH=$PATH:${DOCUMENT_ROOT}" >> /root/.bashrc
But it doesn't work. It seems the ENV parameter isn't available.
What's the problem ?
Yaron
ARG some_variable_name
RUN echo "export PATH=$PATH:${some_variable_name}" >> /root/.bashrc
You should use ARG in Dockerfile and set arguments in build command:
docker build --build-arg some_variable_name=a_value
ARG is only available during the build of a Docker image (RUN etc),
not after the image is created and containers are started from it
(ENTRYPOINT, CMD). You can use ARG values to set ENV values to work
around that.
or in docker-compose:
version: '3'
services:
somename:
build:
context: ./app
dockerfile: Dockerfile
args:
some_variable_name: a_value
Understanding Docker Build Args, Environment Variables and Docker Compose Variables

windows docker-compose args not working

I'm trying to use args in a docker compose file.
The docker-compose file:
version: '3'
services:
service1:
image: test
restart: always
build:
context: C:/ProgramData/
dockerfile: Dockerfile
args:
entry: 1
volumes:
- C:/ProgramData/test
The Dockerfile:
FROM microsoft/dotnet-framework:3.5
ARG entry
WORKDIR C:\\test
ADD ["/bin/x86/Release/","C:/test/"]
ENTRYPOINT ["C:\\test\\file.exe", ${entry}]
I don't know how exactly works the syntax in the docker file. How I have to put the arg in the ENTRYPOINT?
You cannot use ARG in ENTRYPOINT (at least not directly). See How to pass ARG value to ENTRYPOINT?:
Both ARG and ENV are not expanded in ENTRYPOINT or CMD. (https://docs.docker.com/engine/reference/builder/#environment-replacement) However, because ENVs are passed in as part of the environment, they are available at run time, so the shell can expand them. (This means you can't use the array form of ENTRYPOINT or CMD.)
I solved this issue by changing the Dockerfile as follows:
FROM microsoft/dotnet-framework:3.5
ARG ENTRY
ENV my_env=$ENTRY
#RUN echo %ENTRY%
#RUN echo %my_env%
WORKDIR C:\\test
ADD ["/bin/x86/Release/","C:/test/"]
ENTRYPOINT C:/test/file.exe %my_env%

Setting build args in docker-compose.yml using env_file

I'm trying to use Docker and Docker Compose to create a containerized app. I have a PubNub account, which allows me to use different API keys for different environments (dev, test, prod). To help me build images for this, I am trying to use build args set with an env_file.
It's not working.
WARNING: The PUB_KEY variable is not set. Defaulting to a blank string.
WARNING: The SUB_KEY variable is not set. Defaulting to a blank string.
Questions:
What mistake am I making in setting the build args?
How do I fix it?
Is this a good way to set ENV variables for the containers scan and flask?
At the very bottom is an IntelliJ IDE screenshot, or the text code is just below.
Here is the docker-compose.yml content:
version: '3.6'
services:
scan:
env_file:
- sample.env
build:
context: .
dockerfile: Dockerfile
args:
pub_key: $PUB_KEY
sub_key: $SUB_KEY
target: scan
image: bt-beacon/scan:v1
flask:
env_file:
- sample.env
build:
context: .
dockerfile: Dockerfile
args:
pub_key: $PUB_KEY
sub_key: $SUB_KEY
target: flask
image: bt-beacon/flask:v1
ports:
- "5000:5000"
And the Dockerfile:
# --- BASE NODE ---
FROM python:3.6-jessie as base
ARG pub_key
ARG sub_key
RUN test -n "$pub_key"
RUN test -n "$sub_key"
# --- SCAN NODE ---
FROM base as scan
ENV PUB_KEY=$pub_key
ENV SUB_KEY=$sub_key
COPY app/requirements.scan.txt /
RUN apt-get update
RUN apt-get -y install bluetooth bluez bluez-hcidump python-bluez python-numpy python3-dev libbluetooth-dev libcap2-bin
RUN pip install -r /requirements.scan.txt
RUN setcap 'cap_net_raw,cap_net_admin+eip' $(readlink -f $(which python))
COPY app/src /app
WORKDIR /app
CMD ["./scan.py", "$pub_key", "$sub_key"]
# -- FLASK APP ---
FROM base as flask
ENV SUB_KEY=$sub_key
COPY app/requirements.flask.txt /
COPY app/src /app
RUN pip install -r /requirements.flask.txt
WORKDIR /app
EXPOSE 5000
CMD ["flask", "run"]
Finally, sample.env:
# PubNub app keys here
PUB_KEY=xyz1
SUB_KEY=xyz2
env_file can only set environment variables inside a service container. Variables from env_file cannot be injected into docker-compose.yml itself.
You have such options (described there in detail):
inject these variables into the shell, from which you run docker-compose up
create .env file containing these variables (syntax identical to your sample.env)
Personally I would separate image building process and container launching process (take away image building responsibility from docker-compose to external script, then building process can be configured easily).

Resources