When I set an env var and run:
#! /bin/sh
cat << EOF > foo.txt
this is ${TEMPVAR} and maybe this is too? $TEMPVAR
and that's all folks!
EOF
It generates foo.txt
with the right values.
But when I try to use a similar method for dockerfile RUN command, it doesn't work?
FROM --platform=linux/amd64 postgres:16-alpine AS base
RUN cat << EOSQL > /docker-entrypoint-initdb.d/start.sql \
create role ${ROLE1} with login password '${ROLE1PWD}'; \
create role ${ROLE2} with login password '${ROLE2PWD}'; \
EOSQL
When the image is being built, it fails, with the error:
1.188 cat: can't open 'create': No such file or directory
1.188 cat: can't open 'role': No such file or directory
1.188 cat: can't open 'with': No such file or directory
1.188 cat: can't open 'login': No such file or directory
1.188 cat: can't open 'password': No such file or directory
1.188 cat: can't open '${ROLE1PWD}': No such file or directory
1.207 /bin/sh: create: not found
What's wrong with the RUN command? Dockerfile is being invoked by docker compose which picks up .env
values automatically so not sure what else to try?
The suggested questions are irrelevant because I'm no longer struggling to pass build args to the dockerfile. I'm struggling to understand why heredocs don't work in dockerfile. I've evolved the code to:
RUN /bin/bash -c "cat <<-EOSQL > /docker-entrypoint-initdb.d/start.sql \
create role ${ROLE1} with login password '${ROLE1PWD}'; \
create role ${ROLE2} with login password '${ROLE2PWD}'; \
EOSQL\
"
... and edited with vi to circumvent the docker formatter constantly indenting the EOSQL
. I also added an extra line at the end. Still no joy.
This...
RUN cat << EOSQL > /docker-entrypoint-initdb.d/start.sql \
create role ${ROLE1} with login password '${ROLE1PWD}'; \
create role ${ROLE2} with login password '${ROLE2PWD}'; \
EOSQL
Isn't going to work because it's delivered to the shell as a single line (the \
at the end of each line means "turn this into a single virtual line"). Here documents only work when there are actual line breaks in your script, and there's no easy way to get that with this form of a RUN
statement.
Why not just put your script in a file and COPY
it into the image?
COPY start.sql /docker-entrypoint-initdb.d/start.sql
With recent versions of Docker (where "recent" actually seems to mean post-2021) there is actually support for heredocs in the Dockerfile, so you can write:
COPY <<EOSQL /docker-entrypoint-initdb.d/start.sql
create role ${ROLE1} with login password '${ROLE1PWD}';
create role ${ROLE2} with login password '${ROLE2PWD}';
EOSQL