Github Actions上とローカルMac上のmakeタスクの挙動が異なっていてプチハマりした件
タスクランナーとしてmakeタスクをよく利用しています。
その際、ローカルのMacで問題なく動くのに、GitHub Actions上で異なる動作になっていてプチハマりしてたのでメモします。
なお、GitHub Actionsで利用しているDocker Imageは ubuntu-latest
です。
makeタスクの内容
docker composeのサービス起動待ちのために以下のようなワンライナーのタスクを作ることがあります。 [1]
以下は localhost:8080の疎通ができるまで1秒スリープしながら 600回繰り返す(おおよそ最大10分待つ)
という何のことはないタスクです。
waiting-for-service:
@echo "waiting for service ..."
@for i in {0..600}; do if [ `curl -fs http://localhost:8080/` ]; then echo 'complete!'; break; fi; sleep 1; done;
ローカルPC環境で動かすと想定通り、サービスの起動を待つ動作になります。
ところがGitHub Actions上ではうんともすんとも言わずスルッと抜けてしまいます。 なんで?
というわけで、一つ一つ検証しながら原因を探ってみたいと思います。
検証その1:判定の仕方を変えてみる
あまり問題はあるとは思えないのですが、 curlの判定を終了ステータスで確認するようにしてみました。
waiting-for-service:
@echo "waiting for service ..."
@for i in {0..600}; do _=`curl -fs http://localhost:8080/`; if [ "$$?" = "0" ]; then echo 'complete!'; break; fi; sleep 1; done;
しかし、特に改善は見られませんでした。
検証その2:makeバージョンを疑ってみる
ローカルのmakeバージョンとGitHub Actions上のmakeバージョンを表示してみて、差分を確認しました。
ローカルPC: makeバージョン
% make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
GitHub Actions: makeバージョン
% make --version
GNU Make 4.3
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
お、差分があるようです。これかな?と思いローカルPCのmakeを 4.x系にしてみることにしました。
brewでインストールし、PATH変数に追加すればOKです。
% brew install make
Running `brew update --auto-update`...
(中略)
GNU "make" has been installed as "gmake".
If you need to use it as "make", you can add a "gnubin" directory
to your PATH from your bashrc like:
PATH="/opt/homebrew/opt/make/libexec/gnubin:$PATH"
==> Summary
🍺 /opt/homebrew/Cellar/make/4.4: 16 files, 1.2MB
==> Running `brew cleanup make`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Warning: Use postgresql@14 instead of deprecated postgresql
表示内容に則ってPATHを指定し、makeを実行してみると問題なくupgradeされたようです。
% export PATH="/opt/homebrew/opt/make/libexec/gnubin:$PATH"
% make -v
GNU Make 4.4
Built for aarch64-apple-darwin21.6.0
Copyright (C) 1988-2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
これが原因であればローカル実行すると再現するはずですが、このmakeバージョンで実行しても特に再現せず問題なく wait出来てしまいました😢
検証その3:ループ内でデバッグしてみる
もっと早くやれよというお話もありますが、forループがそもそもきちんと動いているかを確認してみます。
最初のスクリプトにechoを仕込んでみます。また、curlのsilentも外して詳細に表示してみます。
waiting-for-service:
@echo "waiting for service ..."
@for i in {0..600}; do echo "i=$$i"; _=`curl -f http://localhost:8080/`; if [ "$$?" = "0" ]; then echo 'complete!'; break; fi; sleep 1; done;
ローカル動作結果
ローカルでは以下のような表示になりました。
きちんと、何度かwaitしたのちにbreakしています。
% make waiting-for-service
waiting for service ....
i=0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
i=1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
(中略)
complete!
GitHub Actions 動作結果
GitHub Actions上では以下のような表示になりました。
おや、iの値がおかしいですね…!?
またcompleteも表示されずにすぐに終わっています。なるほど、きちんとループ変数が展開されていないことが原因のようです。
% make waiting-for-service
waiting for service ....
i={0..600}
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
検証その4:SHELLを指定してみる
ループ変数に使われている以下の記述が問題のようです。
for i in {0..600};
ここまでくると、確信はないですがおそらくshとbashの違いかなーという想像がついたのでmakefile内で指定するようにしてみました。
試す方針としては
- 「ローカルでは
sh指定
」 - 「GitHubActionsでは
bash指定
」
するようにしてみます。
ローカル動作結果
以下を追加した結果です。
SHELL=/bin/sh
以下実行結果です。あれ、sh指定でも問題なく動作してしまった😓
若干雲行きが…
% make waiting-for-service
waiting for service ....
i=0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
i=1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
(中略)
complete!
GitHub Actions 動作結果
以下を追加した結果です。
SHELL=/bin/bash
以下実行結果です。おお、想定通りの正しい動作になったようです! 🎉
やはり、原因としては実行シェルの違いだったようですね。
% make waiting-for-service
waiting for service ....
i=0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
i=1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (52) Empty reply from server
(中略)
complete!
最終的なスクリプト
あまり書く意味もないと思いますが、最終的には以下のようなタスクになっています
SHELL=/bin/bash
waiting-for-service:
@echo "waiting for service ..."
@for i in {0..600}; do if [ `curl -fs http://localhost:8080/` ]; then echo 'complete!'; break; fi; sleep 1; done;
まとめ
わかってみればなんのことはない原因でした。
SHELL変数は知っていたのですが、場合によって設定したり設定しなかったりしていました。
今後は確実にSHELL指定してmakeタスクを書いていこうと思います!
-
make内では改行するの若干面倒なのでワンライナーで書きたくなりますよね ↩︎
Discussion