どうも朝野です。
最近 本番環境でやらかしちゃった人 Advent Calendar が話題ですね。 私も楽しく読ませてもらっています。
かくいう私も先日、kubernetes環境で作成中のアプリケーションを間違って別アプリケーション用のnamespaceにデプロイしてしまうという事故をやってしまいました😇
何をどうミスしたかというと、
普段kubernetes環境へのapplyは原則CircleCI内で行っているのですが、今回は環境構築中なアプリケーションだったので手動で実行しようとしていたのでした。
kubernetes
,
kustomize
,
namespace
最近 本番環境でやらかしちゃった人 Advent Calendar が話題ですね。 私も楽しく読ませてもらっています。
かくいう私も先日、kubernetes環境で作成中のアプリケーションを間違って別アプリケーション用のnamespaceにデプロイしてしまうという事故をやってしまいました😇
何をどうミスしたかというと、
- 新しく作るnamespace以下にkubectl applyでアプリケーションをデプロイしようとした
- 対象のyamlファイルは別プロジェクトのソースファイルをコピーして作ったものだった
- yaml内に書かれているapply先namespaceが別プロジェクトのnamespaceのままだった
普段kubernetes環境へのapplyは原則CircleCI内で行っているのですが、今回は環境構築中なアプリケーションだったので手動で実行しようとしていたのでした。
上書きしてしまったほうもデモ用環境のようなもので利用者もいなかったため、大事には至らなかったのは不幸中の幸いでした。
実行前に確認しなかった私が悪いのですが、これは何とかして防げるようにしたいなあということで、applyする前にyaml内のnamespaceをチェックしておかしかったら止める、というシェルスクリプトを作りました。
作るにあたっては以下のような前提があります。
これを私はkubeapplyという名前にしてPATHが通っているところに置いてます。
やっていることは、
実行前に確認しなかった私が悪いのですが、これは何とかして防げるようにしたいなあということで、applyする前にyaml内のnamespaceをチェックしておかしかったら止める、というシェルスクリプトを作りました。
作るにあたっては以下のような前提があります。
- 環境の切り替え管理にkustomizeを使っている
- 各環境のyamlは k8s/overlays/{環境名} ディレクトリに置いて、
kubectl apply -k k8s/overlays/{環境名}
でデプロイ - デプロイ先namespaceは {リポジトリ名}-{環境名} に統一する
#!/bin/sh
# check whether namespace is {repository}-{env} correctly or not
kubectl kustomize $1 > /dev/null 2> /dev/null
if [ $? != 0 ]; then
/bin/echo 'usage: kubeapply [kustomize_dir]'
exit 1
fi
PROCEED=0
REPOSITORY_NAME=$(git rev-parse --show-toplevel | rev | cut -f1 -d'/' | rev)
NAMESPACES=$(kubectl kustomize $1 | grep namespace | sed -E 's/namespace:(.*)/\1/' | tr -d ' ' | sort | uniq)
OVERLAY_DIR=$(echo $1/ | tr -s '/' | rev | cut -f2 -d'/' | rev)
FOUND=()
for NAMESPACE in $NAMESPACES
do
if [ ${NAMESPACE} != ${REPOSITORY_NAME}-${OVERLAY_DIR} ]; then
FOUND+=("${NAMESPACE}")
PROCEED=0
else
PROCEED=1
fi
done
if [ ${PROCEED} = 0 ]; then
/bin/echo "expected namespace is '${REPOSITORY_NAME}-${OVERLAY_DIR}'"
/bin/echo "but, namaspace '${FOUND[@]}' found in kustomize"
/bin/echo -n "proceed apply? (yes/No): "
read ANSWER
if [ ${ANSWER} = 'yes' ]; then
PROCEED=1
fi
fi
if [ ${PROCEED} = 1 ]; then
kubectl apply -k $@
else
echo "stop applying"
fi
これを私はkubeapplyという名前にしてPATHが通っているところに置いてます。
$ kubeapply k8s/overlays/dev
のように実行すればOKです。やっていることは、
- 引数がkustomizeディレクトリとして正しいかチェック
- kustomize結果内のnamespaceを抽出
- 抽出されたnamespaceが{リポジトリ名}-{環境名(=引数のディレクトリ名)}と一致しているか確認
- すべて一致していれば
kubectl apply -k {引数}
を実行 - 一致していないものがあればプロンプトを表示、yesと回答したらapplyを実行
というフローとなります。
力技っぽさもある気がしますが、これで同じようなパターンの事故はそうそう再発しなくなるので、一歩前進です🤜🏻
kubernetesはyamlを食わせるだけでアプリケーションに必要なものが一式出来上がるのが便利だなあとずっと思っているのですが、その分気軽に環境を吹き飛ばすこともできてしまうので注意して作業しないといけないですね。