カテゴリー
【CRONコマンド活用講座】AWS-CLIをCRONからシェルコマンドとして利用するときの注意点
※ 当ページには【広告/PR】を含む場合があります。
2022/04/30

以前の記事にてCronでカスタムしたシェルスクリプトなどを定期実行させてみる内容の話をポストしましたことがありました。
cron内部のシステム的な事情で、カスタムスクリプトを定期実行させるときの暗黙的なお約束がいくつか存在しており、例えば前回の内容でチラッと説明させていただいた
ちょっとしたことですが、理解しておかないと突如としてスクリプトが期待通りに動かなかったのに、エラーも何も起こらないというニッチモサッチモいかない状況になってしまいます。
今回は、aws-cliなどの他の実行環境から追加インストールするような類のCLIコマンドなどを、cronに実行させる際につまずかないポイントを説明していきます。
CRONに分かるように自作コマンドは絶対パスを利用する
ズバッと今回の話の要点なのですが、cronスケジューラーから呼び出す外部コマンドは、
#/!bin/bash
#👇cronでは動かない
aws --version
#👇cronで動く
AWS_SHELL_PATH=/home/user/.local/bin
$AWS_SHELL_PATH/aws --version
なお、お手持ちの環境によってaws-cliの実行ファイルのインストール先が異なると思いますので、
$ which aws
/home/user/.local/bin
などで実行ファイルの所在を確認しましょう。
CRONスケジューラーで文字列からコマンド実行するときの注意点
このブログの結論としては先ほどの項目でズバッと書いた内容そのものです。
ブログの尺が余るのも寂しいので、cronで文字列をコマンドとして実行させる技をすこしと語ってみます。
なお手元の環境では主にLinuxOSでcronの動作確認していますが、Windowsなどの他のOSでもcronの扱いはほぼ同等かと思います。
まずはテストのスクリプトをホームディレクトリに
tmp
hoge.sh
$ mkdir ~/tmp
$ cat << EOF > ~/tmp/hoge.sh
#!/bin/bash
echo 'HELLO CRON!' >> ~/tmp/hoge.txt
EOF
$ chmod +x ~/tmp/hoge.sh
$ . ~/tmp/hoge.sh
HELLO CRON!
とりあえずテキストに文字列を追加するだけのテストスクリプトができました。
続いてコレをつかってテストします。
素朴にCronのテストは
crontab -e
#...中略
* * * * * $HOME/tmp/hoge.sh >/dev/null 2>&1
をスケジュールの末尾へ追記して保存し、スクリプトが実行されるのを1分待ちます。
$HOME/tmp/hoge.txt
スクリプト内でevalを使う方式
ではここから先ほどの
hoge.sh
まず
$ MY_CMD='echo "HELLO CRON FROM EVAL!"'
$ eval "$MY_CMD"
HELLO CRON FROM EVAL!
cronで動作するかを確認するために先程の
hoge.sh
#!/bin/bash
echo 'HELLO CRON!' >> ~/tmp/hoge.txt
MY_CMD='echo "HELLO CRON?"'
eval "$MY_CMD" >> ~/tmp/hoge.txt
手元の環境で確認すると、eval方式でもcronスケジュールは問題なく動作するようです。
スクリプト内でbash -cを使う方式
次に
$ MY_CMD='echo "HELLO CRON FROM BASH-C!"'
$ bash -c "$MY_CMD"
HELLO CRON FROM BASH-C!
スクリプトも以下のように修正します。
#!/bin/bash
echo 'HELLO CRON!' >> ~/tmp/hoge.txt
MY_CMD='echo "HELLO CRON!?"'
bash -c "$MY_CMD" >> ~/tmp/hoge.txt
こちらも問題なくcronで動作すると思います。
スクリプト内で「$」を使う方式
さらにダブルクオーテーション無しで文字列を
$ MY_CMD='echo "HELLO CRON FROM DOLLAR!"'
$ $MY_CMD
"HELLO CRON FROM EVAL!"
注目すべきは先程の
eval
bash -c
#!/bin/bash
echo 'HELLO CRON!' >> ~/tmp/hoge.txt
MY_CMD='echo "HELLO CRON!??"'
$MY_CMD >> ~/tmp/hoge.txt
これも正しく動作しますが、書き込む結果に
ひとえに文字からコマンド実行と言っても、出力される結果に微妙な差が付きますので、cron内で利用する前に各作法のクセを押さえておきたいところです。
詳しく解説〜AWS-CLIがCronで動かない場合の対策
改めて本題をより詳しく解説していきましょう。
特にユーザーローカルにインストールして利用するツールコマンドなどでは、cronが実行するプログラムを内部で参照できなくなっている可能性もあります。
たとえばユーザーローカルにpythonからインストールした
aws-cli
最初に一度、aws-cliの実行プログラムの所在と、環境変数を確認しておきます。
$ aws --version
aws-cli/1.18.192 Python/3.7.3 Linux/5.4.51-v7+ botocore/1.19.32
$ which aws
/home/user/.local/bin/aws
$ echo $PATH
/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ echo $HOME
/home/user
crontab -e
#...中略
* * * * * bash $HOME/aws_cron_test.sh
まずは失敗するケースのスクリプトですが、以下の内容にして試してみます。
#!/bin/bash
STORE_DIR=/home/user/aws_cron_result.txt
cp /dev/null $STORE_DIR
echo $PWD >> $STORE_DIR
which aws >> $STORE_DIR
aws --version >> $STORE_DIR
echo $PATH >> $STORE_DIR
cronで適切な設定をしていないと、このログファイル(
aws_cron_result.txt
/home/user
/usr/bin:/bin
となり、
つまり
aws-cli
ちゃんとcronスケジューラーが外部コマンドを探せるようにするためには、環境変数に絶対パスを追加してあげることが一番手っ取り早いので以下のように修正します。
#!/bin/bash
#👇実行ファイルをローカルインストールした場所を環境変数に追加
PATH=$PATH:/home/user/.local/bin
STORE_DIR=/home/user/aws_cron_result.txt
cp /dev/null $STORE_DIR
echo $PWD >> $STORE_DIR
which aws >> $STORE_DIR
aws --version >> $STORE_DIR
echo $PATH >> $STORE_DIR
これによりcronがプログラムを利用することが可能となり、
/home/user
/home/user/.local/bin/aws
aws-cli/1.18.192 Python/3.7.3 Linux/5.4.51-v7+ botocore/1.19.32
/usr/bin:/bin:/home/user/.local/bin
が正しく得られました。
また、cronの実行するルートディレクトリがユーザーデフォルトと異なる場合にもaws-cliのクレデンシャル情報(
$HOME/.aws/config
$HOME/.aws/credentials
$ aws --profile user s3 ls
例えば、上のようなaws-cliコマンドは使用者がコンソールで直接手で叩くと、クレデンシャルが当然問題なく読み出せると思います。
上記の理屈で、このコマンドはcronスケジューラーでそのまま使うことは出来ません。
cronでも認証情報を伴うコマンドを利用するには、$HOMEをユーザーデフォルトの絶対パスへリダイレクトさせるか、クレデンシャル情報の場所をシェルスクリプト内に指定してあげるなど、IAM情報の直書きを行う必要もあるでしょう。
#👇ユーザーのデフォルトのホームディレクトリにする
export HOME=/home/user
#👇クレデンシャルファイルを指定する
export AWS_CONFIG_FILE="/home/user/.aws/config"
#👇IAM情報の直書き
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXX
参考サイト:
まとめ
以上のことをまとめると、cronでスケジュールさせて呼び出すコマンドで使ってみたポイントは以下です。
+ eval は最終手段に使ったほうがよい
+ できるだけ bash -c で組めるかを検討する
+ $ はダブルクォーテーションの有無に注意する
とにかくインストール後の実行ファイルの所在が不明瞭なサードパーティ製のコマンドアプリケーションをcronで利用する際には、
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー