Why args passed to script through ENTRYPOINT is not received properly? - bash

The startup.sh script for my node.js project is:
#!bin/sh
echo "Starting with ENV: $ENV"
cd /app
export PORT=8080
export NODE_ENV=$ENV
node main.js $ENV
The Dockerfile looks like:
FROM ...
LABLE ..
ARG env
ENV ENV=${env}
RUN mkdir /app
# COPY required files
COPY ...
RUN cd /app && npm install --silent
EXPOSE 8080
ENTRYPOINT ["/bin/sh", "/app/startup.sh"]
I'm building the image using Jenkins with command:
docker build --build-arg ENV=test -t "tag" .
The script is failing to receive the value "test".
What I tried:
Updating startup.sh to use $1(positional arg) instead of $ENV and pass the value through ENTRYPOINT:
ENTRYPOINT ["/bin/sh", "/app/startup.sh", ${ENV}]
This gives error: file or directory not found: /bin/sh /bin/sh,]
ENTRYPOINT ["/bin/sh", "/app/startup.sh", "${ENV}"]
Doesn't give error but value of $1 is "${ENV}"
Use combination of ENTRYPOINT and CMD:
ENTRYPOINT ["/bin/sh", "/app/startup.sh"] and CMD[${ENV}]
The value of $1 is coming as "-c".

I think it's because of the use of ARG env
ARG ENV
ENV ENV=${ENV}

Related

pass arguments in dockerfile?

I want to pass an argument to my dockerfile such that I should be able to use that argument in my run command but it seems I am not able to do so
I am using a simple bash file that will trigger the docker build and docker run
FROM openjdk:8 AS SCRATCH
WORKDIR /
ADD . .
RUN apt install unzip
RUN unzip target/universal/rule_engine-1.0.zip -d target/universal/rule_engine-1.0
COPY target/universal/rule_engine-1.0 .
ENV MONGO_DB_HOST="host.docker.internal"
ENV MONGO_DB_PORT="27017"
EXPOSE 9000
ARG path
CMD target/universal/rule_engine-1.0/bin/rule_engine -Dconfig.file=$path
above is my dockerfile
and below is my bash file which will access this dockerfile
#!/bin/bash
# change the current path to rule engine path
cd /Users/zomato/Documents/Intern_Project/rule_engine
sbt dist
ENVIR=$1
config=""
if [ $ENVIR == "local" ]
then
config=conf/application.conf
elif [ $ENVIR == "staging" ]
then
config=conf/staging.conf
else
config=conf/production.conf
fi
echo $config
docker build --build-arg path=$config -t rule_engine_zip .
docker run -i -t -p 9000:9000 rule_engine_zip
but when i access the dockerfile through bash script which will set config variable I am not able to set path variable in last line of dockerfile to the value of config.
ARG values won't be available after the image is built, so
a running container won’t have access to those values. To dynamically set an env variable, you can combine both ARG and ENV (since ENV can't be overridden):
ARG PATH
ENV P=${PATH}
CMD target/universal/rule_engine-1.0/bin/rule_engine -Dconfig.file=$P
For further explanation, I recommend this article, which explains the difference between ARG and ENV in a clear way:
As you can see from the above image, the ARG values are available only during the image build.

/bin/sh: No such file or directory when setting a docker-compose entrypoint

I have a container that runs a database migration (source):
FROM golang:1.12-alpine3.10 AS downloader
ARG VERSION
RUN apk add --no-cache git gcc musl-dev
WORKDIR /go/src/github.com/golang-migrate/migrate
COPY . ./
ENV GO111MODULE=on
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird"
ENV SOURCES="file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab"
RUN go build -a -o build/migrate.linux-386 -ldflags="-s -w -X main.Version=${VERSION}" -tags "$DATABASES $SOURCES" ./cmd/migrate
FROM alpine:3.10
RUN apk add --no-cache ca-certificates
COPY --from=downloader /go/src/github.com/golang-migrate/migrate/build/migrate.linux-386 /migrate
ENTRYPOINT ["/migrate"]
CMD ["--help"]
I want to integrate it into a docker-compose and make it dependent on the Postgres database service. However, since I have to wait until the database is fully initialised I have to wrap the migrate command in a script and thus replace the entrypoint of the migration container. I'm using the wait-for script to poll the database, which is a pure shell (not bash) script and should thus work in an alpine container.
This is how the service is defined in the docker-compose:
services:
database:
# ...
migration:
depends_on:
- database
image: migrate/migrate:v4.7.0
volumes:
- ./scripts/migrations:/migrations
- ./scripts/wait-for:/wait-for
entrypoint: ["/bin/sh"]
command: ["./wait-for database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test#database:5432/test?sslmode=disable", "-verbose", "up"]
Running docker-compose up on this fails with
migration_1 | /bin/sh: can't open './wait-for database:5432': No such file or directory
Running the migrate container for itself with
docker run -it --entrypoint /bin/sh -v $(pwd)/scripts/wait-for:/wait-for migrate/migrate:v4.7.0
does work flawlessly, the script is there and can be run with /bin/sh ./wait-for.
So why does it fail as part of the docker-compose?
If you read the error message carefully, you will see that the file that cannot be found is not ./waitfor, it is ./wait-for database:5432. This is consistent with your input file, where that whole thing is given as the first element of the command list:
command: ["./wait-for database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test#database:5432/test?sslmode=disable", "-verbose", "up"]
It's unclear to me what you actually want instead, since the working alternatives presented do not seem to be fully analogous, but possibly it's
command: ["./wait-for", "database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test#database:5432/test?sslmode=disable", "-verbose", "up"]
Running the migrate container for itself with does work flawlessly
When you run it like:
docker run -it --entrypoint /bin/sh -v $(pwd)/scripts/wait-for:/wait-for migrate/migrate:v4.7.0
entrypoint /bin/sh is executed.
When you run it using docker-compose:
entrypoint (/bin/sh ) + command (./wait-for database:5432) ...` is executed.
./wait-for database:5432 as whole stands for executable that will run and it can't be found, that's why you get the error No such file or directory
Try to specify an absolute path to wait-for in command: and split ./wait-for database:5432 into "./wait-for", "database:5432".
It's possible that splitting will be enough
As an alternative you can follow CMD syntax docs and use different command syntax without array: command: ./wait-for database:5432 ...
ENTRYPOINT ["/bin/sh"] is not enough, you also need the -c argument.
Example (testing a docker-compose.yml with docker-compose run --rm MYSERVICENAMEFROMTHEDOCKERCOMPOSEFILE bash here):
entrypoint: ["/bin/sh"]
Throws:
/bin/sh: 0: cannot open bash: No such file
ERROR: 2
And some wrong syntax examples like
entrypoint: ["/bin/sh -c"]
(wrong!)
or
entrypoint: ["/bin/sh, -c"]
(wrong!)
throw errors:
starting container process caused: exec: "/bin/sh, -c": stat /bin/sh, -c: no such file or directory: unknown
ERROR: 1
starting container process caused: exec: "/bin/sh -c": stat /bin/sh -c: no such file or directory: unknown
ERROR: 1
In docker-compose or Dockerfile, for an entrypoint, you need the -c argument.
This is right:
entrypoint: "/bin/sh -c"
or:
entrypoint: ["/bin/sh", "-c"]
The -c is to make clear that this is a command executed in the command line, waiting for an additional command to be used in that command line. but not starting the bash /bin/sh just on its own. You can read that between the lines at What is the difference between CMD and ENTRYPOINT in a Dockerfile?.

how to build a bash variable from docker build arguments

I have a docker file which I want to take in two build arguments
...
FROM ubuntu:18.04
ARG user
ARG pass
ENV MY_USERNAME = $USER
ENV MY_PASSWORD = $PASS
RUN echo ${MY_USERNAME}
here is how I execute
λ docker build --no-cache --rm -f "Dockerfile" --build-arg user=someusername --build-arg pass=somepass .... etc etc
this strangely outputs
Step 6/20 : RUN echo ${MY_USERNAME}
---> Running in 969c7da3e416
= someusername
Shouldn't that equal sign not be there?? It's gotten in there somehow but I don't understand how to get rid of it.
According to the official Docker documentation it seems that you don't need the equal sign when assigning an ARG variable to an ENV one.
So your Dockerfile should be:
FROM ubuntu:18.04
ARG user
ARG pass
ENV MY_USERNAME ${user}
ENV MY_PASSWORD ${pass}
RUN echo ${MY_USERNAME}

Dockerfile entrypoint bash file that loads .env not visible in container

I am trying to develop a Dockerfile for my application that loads a large number of environment variables after initialisation. Somehow, these variables are not reachable when I later execute the following commands:
docker exec -it container_name bash
printenv
My environment variables are not visible. If I load the files manually however, they are:
docker exec -it container_name bash
source .env
printenv
... environment variables are shown ...
This is my dockerfile:
Dockerfile
FROM python:3.6
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt
COPY . /usr/src/app/
RUN chmod 755 load_env_variables.sh
ENTRYPOINT ["/bin/bash", "-c", "/usr/src/app/load_env_variables.sh"]
load_env_variables.sh
#!/bin/bash
source .env
python start_application
And my .env file contains lines als follows: 'export name=value'.
The reason for this behavior is that docker exec -it container_name bash starts a new bash. A new bash has only the standard environment variables plus the ones specified in the .bashrc or .bash_profile files.
A proper solution for your problem would be to use the option --env-file with the docker run command. Be aware that the env-file needs to look like this:
test1=test1
test2=test2

Referencing the first argument passed to the docker entrypoint?

I'm trying to obtain the value of the first argument I pass to the Docker Entrypoint. I received an answer earlier on how to do this. Here is the link:
Referencing a dynamic argument in the Docker Entrypoint
So I setup an experiment to see if this works:
Here's my Dockerfile:
FROM alpine:3.3
MAINTAINER ole.ersoy#gmail.com
RUN apk add --update --no-cache --no-progress bash
COPY run.sh .
ENTRYPOINT /run.sh
And the run.sh entrypoint:
#!/bin/sh
echo The first argument is: $1
I then build this:
docker build -t test .
And run the image:
ole#MKI:~/docker-test$ docker run test one
The first argument is:
I was expecting:
ole#MKI:~/docker-test$ docker run test one
The first argument is: one
Thoughts?
TIA,
Ole
Change ENTRYPOINT to next:
ENTRYPOINT ["bash", "run.sh"]
It works for me. Read more about entrypoint args here https://docs.docker.com/engine/reference/builder/#entrypoint

Resources