Skip to content

Instantly share code, notes, and snippets.

@abn
Last active July 31, 2024 06:26
Show Gist options
  • Save abn/a16e9d799312fb492861 to your computer and use it in GitHub Desktop.
Save abn/a16e9d799312fb492861 to your computer and use it in GitHub Desktop.
Dockerfile alternatives for heredoc
#printf
RUN printf '#!/bin/bash\n\
echo hello world from line 1\n\
echo hello world from line 2'\
>> /tmp/hello
#echo
RUN echo -e '#!/bin/bash\n\
echo hello world from line 1\n\
echo hello world from line 2'\
>> /tmp/hello
@MatrixManAtYrService
Copy link

@Querela agreed, it's not a good solution for persistent Dockerfiles. Later on in the script I pipe the string into docker build - so there's never a Dockerfile for anyone to read and be confused about. heredoc support in buildkit seems even better though.

@Querela
Copy link

Querela commented Jul 31, 2021

Yes, heredoc support is great.
I did some decrypting of data etc in a dockerfile entrypoint and embedded the script so no external files were required. But developing this took longer than expected because of different levels of quote escaping, subshells and parameter substitution or escaping ... It was fun but nothing you would want to revisit later. And a nightmare to debug.
An excerpt below: (DECRYPT_* are docker run environment variables)

RUN printf '%s\n' \
    '#!/bin/bash' \
    '' \
    'DATA_DIR=/mnt/data' \
    'echo "Data dir: ${DATA_DIR} ... $(du -sh ${DATA_DIR} | cut -f1)"' \
    '' \
    'echo "* Decrypt data ..."' \
    ' ( \' \
    '   KEY="${DECRYPT_KEY}" IV="${DECRYPT_IV}" \' \
    '   bash -c " \' \
    '       find ${DATA_DIR} -iname '"'"'*.jsonl.bz2.enc'"'"' -type f -exec \' \
    '       bash -c '"'"' \' \
    '           FILE="\${0%.enc}"; \' \
    '           openssl aes-256-cbc -K \${KEY} -iv \${IV} -d -in \"\${FILE}.enc\" -out \"\${FILE}\"' \
    "       '"' {} \; \' \
    '   " \' \
    ' )' \
    '' \
    'echo "* Decompress data ..."' \
    'find ${DATA_DIR} -iname '"'*.jsonl.bz2'"' -type f -exec bzip2 -d {} \;' \
    '' \
    'echo "* Cleanup data ..."' \
    '# remove encrypted and compressed data' \
    'find ${DATA_DIR} -iname '"'*.jsonl.bz2.enc'"' -type f -exec rm {} \;' \
    'find ${DATA_DIR} -iname '"'*.jsonl.bz2'"' -type f -exec rm {} \;' \
    '' \
    'echo "Data dir (ready): $(du -sh ${DATA_DIR} | cut -f1)"' \
    '' \
    'echo -e "\nDataset list:"' \
    'ls -1shR ${DATA_DIR}/*' \
    '' \
    > prepare_data.sh && \
    chmod +x prepare_data.sh

@maxx27
Copy link

maxx27 commented Sep 2, 2022

Also, there is official way to do it:

# syntax=docker/dockerfile:1.3-labs

RUN <<EOF
echo "Hello" >> /hello
echo "World!" >> /hello
EOF

I use it as the following:

# syntax=docker/dockerfile:1.4
RUN cat <<EOF >> /usr/local/bin/startup.sh
if [ \$# -gt 0 ]; then
    exec "\$@"
else
    /usr/bin/tini -- /usr/local/bin/jenkins.sh
fi
EOF

@daudo
Copy link

daudo commented Jun 16, 2024

kudos @maxx27! I was banging my head why in 2024 it still has to be so difficult to use heredocs in Dockerfiles in a reasonable way. That last snippet of yours is the way to go! Thanks!

@image72
Copy link

image72 commented Jul 31, 2024

FROM debian
RUN <<EOT bash
  set -eux
  to_install=(
    vim
  )
  apt-get update
  failing_command # set -e exit with non-zero status 
  apt-get install -y "\${to_install[@]}"
EOT

# execute list shell
RUN <<EOF
apt-get update
apt-get upgrade -y
apt-get install -y ...
EOF

# run python
RUN <<EOF
#!/usr/bin/env python3
with open("/hello", "w") as f:
    print("Hello", file=f)
    print("World", file=f)
EOF

# create index.html
COPY <<EOF /usr/share/nginx/html/index.html
<html>hello, index</html>
EOF

# create /etc/mysql/my.cnf
RUN <<-EOF > /etc/mysql/my.cnf
[mysqld]
user=root
datadir=/app/mysql
port=3306
log-bin=/app/mysql/mysql-bin
EOF

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment