최근 GitHub Actions 를 통해 CD 파이프라인을 실행 중, echo
커맨드로 인한 트러블 슈팅을 경험했습니다.
이번 포스팅은 이에 대한 원인과 그 해결법을 공유하고자 합니다.
프로젝트에 구성한 CD 는 다음과 같은 모습을 하고 있습니다.
특히 이 중 build-and-push
는 어플리케이션을 build, 생성된 이미지를 Docker Hub 에 업로드하는 과정으로, 여러 "비밀 처리된" 프로필을 넣어주는 과정이 포함되어 있습니다.
(application-secret.yaml 등)
이에 사용하는 복합 액션은 다음처럼 구성되어 있습니다.
## 주어진 내용을 파일로 저장하는 composite action
name: Save to file
description: 'Save given context to file.'
inputs:
context:
required: true
description: 'A context to be saved as a file'
file_dir:
required: true
description: 'A directory where file will exist'
file_name:
required: true
description: 'Name of the file to be saved'
runs:
using: 'composite'
steps:
- name: Check whether duplicate exists
shell: bash
run: |
if [ -f "${{ inputs.file_dir }}/${{ inputs.file_name }}" ]; then
exit 1
fi
- name: Create directory if not exists
shell: bash
run: |
mkdir -p "${{ inputs.file_dir }}"
- name: Save context to destination
shell: bash
run: |
echo "${{ inputs.context }}" > "${{ inputs.file_dir }}/${{ inputs.file_name }}"
하지만 이를 실행하니 아래와 같은 에러가 발생했습니다.
> Run echo ...
***
***
***
***
***
***
***
***
: bad substitution
Error: Process completed with exit code 1.
실패 원인은 저장하는 내용 중 ${...}
같은 형태가 존재하였기 때문입니다.
저희는 아래와 같은 yaml
프로필을 저장하고 있었습니다.
# application-prod-secret.yaml
# prod server has not been set yet
db:
host:
username:
password:
name:
port:
url: jdbc:mysql://${db.host}:${db.port}/${db.name}
spring.jpa.hibernate.ddl-auto: create
문제는 ${...}
가 Spring 에서도 사용되는 표현 방식이지만 bash 에서도 그러하다는 점입니다.
- name: Save context to destination
shell: bash
run: |
echo "${{ inputs.context }}" > "${{ inputs.file_dir }}/${{ inputs.file_name }}"
즉, bash 가 위 echo "${{ inputs.context }} ..."
를 실행할 때, 아래처럼 실행되며 에러가 발생했던 것 입니다.
> echo "# prod server has not been set yet
db:
host:
username:
password:
name:
port:
url: jdbc:mysql://${db.host}:${db.port}/${db.name} # <--- 이 부분을 이상하게 인식해버려 error
spring.jpa.hibernate.ddl-auto: create"
> : bad substitution
결국 근본적인 원인은 bash 가 ${...}
을 평이한 문자열이 아닌 무언가로 인식했기 때문이었습니다.
따라서 해결방법은 "주어진 내용을 문자 그대로" 저장토록 변경하면 됩니다.
- name: Save context to destination
shell: bash
run: |
cat <<'EOF' > "${{ inputs.file_dir }}/${{ inputs.file_name }}"
${{ inputs.context }}
EOF
이를 위해 cat
, EOF
를 이용하였고 아래처럼 workflow 가 성공하는 것을 확인하였습니다.
Workflow 스크립트를 작성할 땐 echo
보다 cat
을 애용하자.