sitateru tech blog: namespace

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

ラベル namespace の投稿を表示しています。 すべての投稿を表示
ラベル namespace の投稿を表示しています。 すべての投稿を表示

2019年12月19日木曜日

安全にkubectl applyするコマンドを作った

12月 19, 2019
どうも朝野です。
最近 本番環境でやらかしちゃった人 Advent Calendar が話題ですね。 私も楽しく読ませてもらっています。

かくいう私も先日、kubernetes環境で作成中のアプリケーションを間違って別アプリケーション用のnamespaceにデプロイしてしまうという事故をやってしまいました😇

何をどうミスしたかというと、
  • 新しく作るnamespace以下にkubectl applyでアプリケーションをデプロイしようとした
  • 対象のyamlファイルは別プロジェクトのソースファイルをコピーして作ったものだった
  • yaml内に書かれているapply先namespaceが別プロジェクトのnamespaceのままだった
ということだったのです。
普段kubernetes環境へのapplyは原則CircleCI内で行っているのですが、今回は環境構築中なアプリケーションだったので手動で実行しようとしていたのでした。

上書きしてしまったほうもデモ用環境のようなもので利用者もいなかったため、大事には至らなかったのは不幸中の幸いでした。
実行前に確認しなかった私が悪いのですが、これは何とかして防げるようにしたいなあということで、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です。

やっていることは、
  1. 引数がkustomizeディレクトリとして正しいかチェック
  2. kustomize結果内のnamespaceを抽出
  3. 抽出されたnamespaceが{リポジトリ名}-{環境名(=引数のディレクトリ名)}と一致しているか確認
  4. すべて一致していれば kubectl apply -k {引数} を実行
  5. 一致していないものがあればプロンプトを表示、yesと回答したらapplyを実行
というフローとなります。

力技っぽさもある気がしますが、これで同じようなパターンの事故はそうそう再発しなくなるので、一歩前進です🤜🏻

kubernetesはyamlを食わせるだけでアプリケーションに必要なものが一式出来上がるのが便利だなあとずっと思っているのですが、その分気軽に環境を吹き飛ばすこともできてしまうので注意して作業しないといけないですね。