kubectlをcronから起動するときの注意
はじめに
こんにちは。インフラエンジニアの北野です。
kubectlは、kubernetesを管理するためのコマンドラインツールですが、
運用の中でcronからkubectlを含むスクリプトを定期実行したいときってありますよね。
今回は、kubectlを含むShellスクリプトをcronから起動したとき、想定外のエラーが出たので、 その原因と対策を共有したいと思います。
前提となる環境
コンテナ基盤:EKS
OS:amazon linux2
忙しい人の為に先に結論
kubectl含むスクリプトをcronから実行する場合、 /etc/crontabのPATH定義を以下のように設定することを推奨します。
PATH=/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
PATHに/usr/local/binを追加する
追加する/usr/local/binは先頭(一番左)に定義する
この2点がエラーを回避するポイントとなります。
cronから起動したスクリプトからkubectlを実行すると「command not found」が発生。
とある要件で、EKSのコンテナの監視スクリプトを作成することに。 起動方法はお手軽なcron、言語はshellを採用しました。
スクリプトを作成し、単体テストでは正常に動作することを確認しました。 続いて結合テストでcron実行したところ、異常終了してしまいました。
出力されたエラーは以下のとおりです。
xxxx.sh: line xx: kubectl: command not found
「command not found」の発生原因。
shellログインして実行した場合は、正常に動作するのに、cron実行の場合はコマンドが見つからないのは何故でしょうか。
/etc/crontab内には下記のように実行シェルとパス等の環境変数が設定されています。
# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
cronから起動するスクリプトのコマンドがパスのどれかに含まれている場合は問題ないのですが、 kubectlは/usr/local/bin/内に置かれるので、コマンドが見つかりません。
PATHに追加設定してみると、amazonlinuxの場合は想定外のエラーが発生
対応として、まずは単純にスクリプトの初期処理で以下のようにPATHを追加設定しました。
PATH=$PATH:/usr/local/bin
よしこれでkubectlのPATHが通ったので、うまくいくだろうとcron実行すると、エラーで異常終了しました。。
出力されたエラーは以下のとおりです。
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:
aws help
aws <command> help
aws <command> <subcommand> help
aws: error: argument operation: Invalid choice, varid choices are:
create-cluster | delete-cluster
describe-cluster | describe-cluster
list-clusters | list-updates
update-cluster-version | update-kubeconfig
wait | help
Unable to connect to the server: getting credentials: exec: executable aws failed with exit code 2
事象はawscliのコマンドパラメーター誤り??
awscliのコマンドパラメーター誤りの発生原因
これの原因は、PATHの定義順番の誤りと、想定外のawscliコマンドの実行によるものでした。
普通、PATHの定義を追加をするときは以下のようにするかと思います。
PATH=$PATH:追加するディレクトリ名
まずはこれがNGでした。
awscliは公式の手順に沿って導入すると以下のディレクトリに配置されます。
/usr/local/bin/aws
awscliの導入について:https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html
しかし、実はamazon linuxの場合は、デフォルトで/usr/binや/binの配下にもawscliのモジュールが存在していたのです。 そしてこのモジュールはメンテナンスされず、古いバージョンのままとなってしまっていました。
その為、固定観念に囚われてPATH=$PATH:/usr/local/bin などとしてしまうと、もともとのPATHに設定されている/bin配下のawsコマンドが優先して実行されてしまいます。
そして、私の環境の/bin/awsのawscliはバージョン1.16.102で、残念ながらこのバージョンはaws eks get-tokenのコマンドオプションがありませんでした。 その結果、get-tokenのコマンドオプションが無く、configに設定しているEKS認証用のtoken取得コマンドに失敗し、kubectlの実行に失敗しました。
configの設定について:https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-kubeconfig.html
configに記述した認証の記述部分を抜粋します。
ここで設定しているcommandは実行時のPATHの設定に従って、どのディレクトリに配置されたawscliモジュールが実行されるかが決まります。
users:
- name: arn:aws:eks:$region_code:$account_id:cluster/$cluster_name
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args:
- --region
- $region_code
- eks
- get-token
- --cluster-name
- $cluster_name
まとめ
kubectlをcronから起動したときに想定外のエラーを出さないためには、 /etc/crontabのPATH定義を以下のように設定することを推奨します。
PATH=/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
こうしておけば、/usr/local/bin配下のkubectlやawsが優先して実行されます。
すべてのユーザのcron定義にこの変更を反映させたくない場合は、/var/spool/cron/ユーザー名のファイルに 以下を記述しましょう。
PATH=/usr/local/bin:$PATH
さらに影響範囲を極小化した場合は、Shellスクリプト自体や共通環境設定ファイルに記述すると良いですね。
【おわせて読みたい関連記事】
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/