Goole Cloud Build上でシェルを実行した結果、エラーが発生しても正常終了してしまう問題に対処
はじめに
開発効率化、品質向上のために現在のシステム開発に CI/CD パイプラインの構築は必須だと思います。
Github Action / CircleCI / Cloud Build など、CI/CD を構築するためのサービスがありますが、Cloud Build を多用させていただいています。
その "Cloud Build" でシェルコマンドを実行したところ、エラーが発生したにもかかわらずなぜか正常終了してしまい原因特定までに多少時間がかかってしまいました。
わかってしまえば当然なのですが、ついつい「シェルを実行している」ことを忘れてしまったことが原因でした。
検証環境
Google Cloud Platform ( GCP ) の Cloud Build を利用しました。
再現方法
Cloud Build でビルドステップを構築する方法として、ちょっと複雑なものを構築しようとした場合は Git リポジトリに cloudbuild.yaml
という YAML ファイルを配置してやります。
ここで、以下のような cloudbuild.yaml
というファイルを用意としましょう。
steps:
- name: "bash"
entrypoint: "bash"
args:
- "-c"
- |
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
処理概要は以下のとおりです。
name: "bash"
: DockerHub で公開されている bash イメージを利用するentrypoint: "bash"
:bash
コマンドを実行するargs:
:bash
の引数を指定する
以下の docker
コマンドを実行したのと同義になるわけです。
docker run --rm bash -c '
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
'
設定ページは以下のようになっています。
この cloudbuild.yaml
の設定を元にビルドを実行します。
このビルドは エラー終了 となる想定でした。
なぜなら、実行しているコマンドのうち ls -la /nothing
がエラーになるからです。
( 試しに読者の PC で実行していただければわかります。 /nothing
というディレクトリが存在しないため、エラーとなりますね。 )
しかし、結果は正常終了してしまいます。
実行ログを見ると、たしかに ls -la /nothing
というコマンドではエラーが発生しているのですが、 ビルドステップ全体は 正常終了 となっています。
原因
シェルコマンドの特性であるのにすっかり忘れていました。
話をさかのぼりますが、 Cloud Build で実行しているコマンドは以下のコマンドと同義です。
docker run --rm bash -c '
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
'
こちらのコマンドをローカル PC などで実行してみましょう。
begin
total 8
drwxrwxrwt 1 root root 4096 Mar 26 02:14 .
drwxr-xr-x 1 root root 4096 May 12 02:47 ..
ls: /nothing: No such file or directory
end
2 つめの ls
コマンドでエラーが発生していますが、最後の echo "end"
まで実行が行われています。
上記コマンド実行後にステータスを確認してみます。
$ echo $?
0
正常終了扱いですね。
bash -c "..."
コマンドは、 -c
で渡した複数コマンドのうち、最後のコマンドの合否で実行ステータスが決まります。
最後の echo
を消してみましょう。
$ docker run --rm bash -c '
echo "begin"
ls -la /tmp
ls -la /nothing
'
begin
total 8
drwxrwxrwt 1 root root 4096 Mar 26 02:14 .
drwxr-xr-x 1 root root 4096 May 12 02:47 ..
ls: /nothing: No such file or directory
$ echo $?
1
では、最後の echo
を削除せずに、問題を解決するにはどうしたら良いでしょう?
対処法 1
実行時のコマンドラインオプションを追加してやります。 -e
オプションを追加します。
$ docker run --rm bash -e -c '
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
'
begin
total 8
drwxrwxrwt 1 root root 4096 Mar 26 02:14 .
drwxr-xr-x 1 root root 4096 May 12 02:48 ..
ls: /nothing: No such file or directory
$ echo $?
1
Cloud Build の YAML ファイルを修正します。
steps:
- name: "bash"
entrypoint: "bash"
args:
- "-e"
- "-c"
- |
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
対処法 2
実行される複数コマンドの戦闘で、 set -o errexit
を実行し、エラー発生時に強制的にシェル実行をエラー停止させるようにします。
$ docker run --rm bash -e -c '
set -o errexit
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
'
begin
total 8
drwxrwxrwt 1 root root 4096 Mar 26 02:14 .
drwxr-xr-x 1 root root 4096 May 12 02:51 ..
ls: /nothing: No such file or directory
$ echo $?
1
Cloud Build の YAML ファイルを修正します。
steps:
- name: "bash"
entrypoint: "bash"
args:
- "-c"
- |
set -o errexit
echo "begin"
ls -la /tmp
ls -la /nothing
echo "end"
ひとこと
どちらの方法でも問題は解決できます。
結局問題は "Cloud Build" の設定などではなく、Bash実行時のオプションや設定でした。
いつものシェルに関するブログ記事になりましたね。
ディスカッション
コメント一覧
まだ、コメントがありません