👏

ShellScript/Dockerfileの可読性を上げるヒアドキュメントの使い方

2024/09/09に公開

これは何?

shell scriptやDockerfile等を書く時にヒアドキュメントを使うと完結かつ,わかりやすく書くことができます。

例: ヒアドキュメントを使わないDockerfileのRUN

RUN apt-get update -y && \
    apt-get install -y --no-install-recommends sudo && \
    echo 'Creating ${USER_NAME} group.' && \
    addgroup ${USER_NAME} && \
    echo 'Creating ${USER_NAME} user.' && \
    adduser --ingroup ${USER_NAME} --gecos "my_portscanner user" --shell /bin/bash --no-create-home --disabled-password ${USER_NAME} && \
    echo 'using sudo' && \
    usermod -aG sudo ${USER_NAME} && \
    echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    rm -rf /var/lib/apt/lists/*

例: ヒアドキュメントを使ったDockerfileのRUN

RUN <<EOF
apt-get update -y
apt-get install -y --no-install-recommends sudo
echo 'Creating ${USER_NAME} group.'
addgroup ${USER_NAME}
echo 'Creating ${USER_NAME} user.'
adduser --ingroup ${USER_NAME} --gecos "my_portscanner user" --shell /bin/bash --no-create-home --disabled-password ${USER_NAME}
echo 'using sudo'
usermod -aG sudo ${USER_NAME}
echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
rm -rf /var/lib/lists
EOF

見た目がごちゃごちゃしないかつ,\や&&のつけ忘れでエラーになるみたいな事故を防げて便利です。
本記事ではヒアドキュメントの使い方を紹介します。


catコマンドでつかう

最も有名な例はcatコマンドでヒアドキュメントを使うことです。

cat <<EOF
heredoc> hoge
heredoc> fuga
heredoc> EOF
hoge
fuga

こういった形でEOFを入力するまで値を連続して入力することができます。

このヒアドキュメントを使うことでシェルスクリプト中でのファイルを生成して値を書き込む処理が簡潔にかけます。
以下の例はAWSのEC2のUserDataを使って起動時にdocker.httpdを起動するためのserviceファイルを作成しています。

#!/bin/bash
yum install -y docker
cat <<'EOF' > /etc/systemd/system/docker.httpd.service
[Unit]
Description=httpd Container
After=docker.service
Requires=docker.service
[Service]
Environment="CONTAINER_NAME=httpd-container"
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop ${CONTAINER_NAME}
ExecStartPre=-/usr/bin/docker rm ${CONTAINER_NAME}
ExecStartPre=/usr/bin/docker pull httpd
ExecStart=/usr/bin/docker run --rm --name ${CONTAINER_NAME} -p 80:80 httpd
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now docker.httpd
systemctl restart docker.httpd
systemctl daemon-reload

Dockerfileで使う

上記にも示したように,RUNで使えます。

RUN <<EOF
set -ex
apt-get update -y
apt-get install -y --no-install-recommends sudo
echo 'Creating ${USER_NAME} group.'
addgroup ${USER_NAME}
echo 'Creating ${USER_NAME} user.'
adduser --ingroup ${USER_NAME} --gecos "my_portscanner user" --shell /bin/bash --no-create-home --disabled-password ${USER_NAME}
echo 'using sudo'
usermod -aG sudo ${USER_NAME}
echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
rm -rf /var/lib/lists
EOF

Terraformで使う

terraformでuser_dataに対してコマンドを投入する際にヒアドキュメントが使えます。
ヒアドキュメントを入れ子で使う際にはEOF2を使います。

resource "aws_instance" "example" {
  ami           = "ami-00c79d83cf718a893"
  instance_type = "t3.micro"
  # attach IAM Role
  iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name

  tags = {
    Name = "sigma-ec2"
  }

  user_data = <<EOF
#!/bin/bash
yum install -y docker
cat <<'EOF2' > /etc/systemd/system/docker.httpd.service
[Unit]
Description=httpd Container
After=docker.service
Requires=docker.service
[Service]
Environment="CONTAINER_NAME=httpd-container"
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop $${CONTAINER_NAME}
ExecStartPre=-/usr/bin/docker rm $${CONTAINER_NAME}
ExecStartPre=/usr/bin/docker pull httpd
ExecStart=/usr/bin/docker run --rm --name $${CONTAINER_NAME} -p 80:80 httpd
[Install]
WantedBy=multi-user.target
EOF2
systemctl enable --now docker.httpd
systemctl restart docker.httpd
systemctl daemon-reload
EOF
}

総括

  • ヒアドキュメントを使うことで見た目がスタイリッシュで可読性が高くなるのでおすすめ。
  • 他にも使える例を探してみたい。
GitHubで編集を提案

Discussion