From 4f46d262e6967c9c638b40f3b0246d21b7a9b9dc Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 9 Apr 2025 20:29:15 +0900 Subject: feat(blog/nuldoc): rebuild --- .../pipefail-option-in-gitlab-ci-cd/index.html | 81 ++++++++-------------- 1 file changed, 30 insertions(+), 51 deletions(-) (limited to 'vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd') diff --git a/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html b/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html index 3e41bbf7..197c6074 100644 --- a/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html +++ b/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html @@ -68,27 +68,25 @@ NOTE
- この記事は、2022-11-17 にデジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。 +

+ この記事は、2022-11-17 に デジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。 +

-

- ハマったのでメモ。 + ハマったのでメモ。

-
-

前提

+

前提

-

GitLab CI/CD について

+

GitLab CI/CD について

- GitLab CI/CD では、Docker executor を用いて任意の Docker image 上でスクリプトを走らせることができる。 + GitLab CI/CD では、Docker executor を用いて任意の Docker image 上でスクリプトを走らせることができる。

-

- 例: + 例:

- -
+
hello-world:
   stage: test
   image: alpine:latest
@@ -98,16 +96,13 @@
     - if: '$CI_MERGE_REQUEST_IID'
   when: always
-

- ここで、script に指定したコマンドが失敗する (exit status が 0 以外になる) と、即座に実行が停止され、ジョブは失敗する。 + ここで、script に指定したコマンドが失敗する (exit status が 0 以外になる) と、即座に実行が停止され、ジョブは失敗する。

-

- では、次のようなケースだとどうなるか。 + では、次のようなケースだとどうなるか。

- -
+
hello-world:
   stage: test
   image: alpine:latest
@@ -117,38 +112,32 @@
     - if: '$CI_MERGE_REQUEST_IID'
   when: always
-

- 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。 + 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。

-
-

pipefail オプションについて

+

pipefail オプションについて

- 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、pipefail オプションを有効にする。 + 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、pipefail オプションを有効にする。

-
# On にする
 set -o pipefail
 # Off にする
 set +o pipefail
-

- こうすると、パイプ全体が失敗するようになる。この設定は、デフォルトだと off になっている。 + こうすると、パイプ全体が失敗するようになる。 この設定は、デフォルトだと off になっている。

-
-

発生した問題

+

発生した問題

- 次のような GitLab CI/CD ジョブが失敗してしまった。 + 次のような GitLab CI/CD ジョブが失敗してしまった。

- -
+
hoge:
   stage: test
   image: alpine:latest
@@ -158,15 +147,12 @@
     - if: '$CI_MERGE_REQUEST_IID'
   when: always
-

- grep コマンドは、パターンにマッチする行が一行もなかったとき、exit code 1 を返す。よって、pipefail が on になっていると、このジョブは失敗する。現在の pipefail がどうなっているか確かめるため set +o で全オプションを出力させたところ、pipefail が on になっていた。 + grep コマンドは、パターンにマッチする行が一行もなかったとき、exit code 1 を返す。よって、pipefail が on になっていると、このジョブは失敗する。 現在の pipefail がどうなっているか確かめるため set +o で全オプションを出力させたところ、pipefail が on になっていた。

-

- しかし、先述したように Bash における pipefail のデフォルト値は off のはずだ。実際に、ローカルで alpine:latest を動かしてみたところ、 + しかし、先述したように Bash における pipefail のデフォルト値は off のはずだ。 実際に、ローカルで alpine:latest を動かしてみたところ、

-
$ docker run --rm alpine:latest sh -c "set +o"
 set +o errexit
@@ -183,36 +169,30 @@
 set +o vi
 set +o pipefail
-

- 確かに pipefail は無効になっている。 + 確かに pipefail は無効になっている。

-

- なぜスクリプト内で set -o pipefail しているわけでもないのに pipefail が on になっているのか。 + なぜスクリプト内で set -o pipefail しているわけでもないのに pipefail が on になっているのか。

-
-

どこで pipefail が on になるか

+

どこで pipefail が on になるか

- .gitlab-ci.yml で明示的には書いていないので、GitLab Runner (GitLab CI/CD のスクリプトを実行するプログラム) が勝手に追加しているに違いない。そう仮説を立てて GitLab Runner のリポジトリ を調査したところ、ソースコード中の以下の箇所set -o pipefail していることが判明した (コメントは筆者による)。 + .gitlab-ci.yml で明示的には書いていないので、GitLab Runner (GitLab CI/CD のスクリプトを実行するプログラム) が勝手に追加しているに違いない。 そう仮説を立てて GitLab Runner のリポジトリ を調査したところ、 ソースコード中の以下の箇所set -o pipefail していることが判明した (コメントは筆者による)。

-
// pipefail オプションが存在しない環境にも対応するため、
 // 先に set -o でオプション一覧を表示させたあと、set -o pipefail している
 buf.WriteString("if set -o | grep pipefail > /dev/null; then set -o pipefail; fi; set -o errexit\n")
-
-

どのように解決するか

+

どのように解決するか

- 通常の Bash スクリプトを書く場合と同様に、pipefail が on になっていては困る場所だけ off にしてやればよい。 + 通常の Bash スクリプトを書く場合と同様に、pipefail が on になっていては困る場所だけ off にしてやればよい。

- -
+
 hoge:
    stage: test
    image: alpine:latest
@@ -225,11 +205,10 @@
    when: always
-
-

備考

+

備考

- なお、上述した実装ファイルは shells/bash.go だが、alpine:latest の例でもそうであったように、シェルが sh である場合にも適用される。 + なお、上述した実装ファイルは shells/bash.go だが、alpine:latest の例でもそうであったように、シェルが sh である場合にも適用される。

-- cgit v1.2.3-70-g09d2