kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Automator と say コマンドを組み合わせた簡単な音声テスト

「リモート研修」「リモート会議」をするときに,機材としては Blue Microphones YeticasterBeats Studio(有線)の組み合わせを使っている.特に「リモート研修」のように1日中配信を行う場合は遅延と充電の観点から意図的に有線を選びつつ,カジュアルな場であれば Bluetooth でも問題なく AirPods Pro を使っている.

オーディオ設定の確認 🎧

そのときに「オーディオ設定(特に出力側)はちゃんと機能している?相手の声をちゃんと聞ける状態になっている?」という個人的な不安があり,休憩時間など定期的に YouTube の適当なビデオを流して,音声テストをする癖がある.特に「リモート研修」では,なぜか BlackHole に設定されてしまう場面もあったりして「お客様の声をちゃんと聞ける状態になっている?」という確認を怠らないように意識している.

「Automator」+ say コマンド 🎧

繰り返し行うこともあり,毎回 YouTube を開きたくないし,最初に流れる広告で音声テストをすることになる場面も多いし(笑)もっと簡単な手順に移行したいと考えていた.現在は Mac (macOS) で使える「Automator」say コマンドを組み合わせた手順に移行して,数ヶ月使っている.個人的には便利で満足している!他にも実現方法はあると思うけど,特に配信中は Mac の負荷も高くなるため,不要なツールを常駐させたくなく,シンプルに実現したかった.今回は簡単に設定を紹介する!

できること 🎧

  1. アプリケーションの「サービス」メニューから「音声テスト(say コマンド)」を実行できる
  2. 任意のショートカットから「音声テスト(say コマンド)」を実行できる

f:id:kakku22:20210224181007p:plain

Automator を使う 🎧

まず「Automator」を開いたら「クイックアクション」を選択する.

f:id:kakku22:20210224181319p:plain

次に「アクション」「ライブラリ」「ユーティリティ」「シェルスクリプトを実行」を選択する.特に他サービスと連携する必要はなく「ワークフローが受け取る項目」「入力なし」にしておく.「検索対象」はデフォルトのまま「すべてのアプリケーション」にしておく.シェルスクリプトは以下のように say コマンドを実行する.文章は普通すぎて避難訓練のようになってしまった...!

$ say '音声テストです!聞こえますか?'

最後に「クイックアクション名」「音声テスト」と設定したら終了!簡単!

f:id:kakku22:20210224181455p:plain

ちなみに「クイックアクション」~/Library/Services に保存されている.最初すぐに見つけられなくて困った!

$ ls -1 ~/Library/Services
音声テスト.workflow

サービスを確認する 🎧

「クイックアクション」はすぐに使える.ChromeiTerm2 など,任意のアプリケーションを開いた状態から「サービス」「音声テスト」を選択すると say コマンドを実行できる.便利!うおおおおお!

f:id:kakku22:20210224182219p:plain

ショートカットを設定する

ショートカット経由で「クイックアクション」を実行することもできる.今のところ特に競合することのなさそうな「option + command + z」に割り当てて問題なく使えている.便利!ついつい押したくなってしまう!

f:id:kakku22:20210224183012p:plain

まとめ 🎧

Mac (macOS) で使える「Automator」say コマンドを組み合わせて気軽に「音声テスト」を実行できるようにした.今まで YouTube を使っていた手順をシンプルに移行できて満足している.なお,今まで「Automator」はほとんど使ったことがなかったけど,実はイロイロと使える便利なツールかも?と思った.他にも使えそうな場面があれば検討してみよう.

おまけ : say コマンド + Rubicure

なお,今回は最終的に「音声テストです!聞こえますか?」という普通すぎる文章になってしまったけど,検証段階では id:sue445 さんの Rubicure を使って,プリキュアの必殺技を読ませていたんだけど,say コマンドの声優さんとの相性が悪かったのと,間違って「リモート研修」中に配信してしまうとヤバイため,個人利用に留めている(笑)スクリプトは雑に書き捨てたからもっとシンプルに書けるはず!

require 'rubicure'
system("say #{Precure.healingood.girls.sample.attack_messages.first.gsub(/[\r\n]/,'')}")

github.com

潜水艦の操縦士になろう / ドットインストール「Scratch で潜水艦ゲームを作ろう」を受講した

ドットインストールには昨日紹介したScratch 3.0 入門以外にもう1個「Scratch で潜水艦ゲームを作ろう」というコンテンツがある.Scratch の基本的な操作を理解した上で「より高度な操作」を学びながらゲームを作っていくことができる.とても楽しく,僕も使ったことがないブロックがあったりして,素晴らしいコンテンツだった!今回も「良さ」を紹介したいと思う.以下に載せた「全21個」の動画があり,全て3分以内で終わるので,流し見をするだけなら1時間もあれば十分!

  • 01 : 潜水艦ゲームを作ってみよう
  • 02 : 潜水艦の素材をアップロードしよう
  • 03 : コスチュームを切り替えてみよう
  • 04 : スプライトをスムーズに動かそう
  • 05 : 潜水艦を矢印キーで動かそう
  • 06 : 背景を作り込んでいこう
  • 07 : 壁と衝突したか判定しよう
  • 08 : 他のスクリプトを止めてみよう
  • 09 : メッセージを送ってみよう
  • 10 : ブロックを整理していこう
  • 11 : レベルごとに背景を作っていこう
  • 12 : ゲームクリア画面を作ろう
  • 13 : 背景が切り替わる条件を設定しよう
  • 14 : レベルアップで背景を切り替えよう
  • 15 : ゲームクリアできるようにしよう
  • 16 : 敵を作っていこう
  • 17 : 敵を上下に動かそう
  • 18 : 敵との衝突判定をしよう
  • 19 : レベル 3 だったら敵を表示しよう
  • 20 : BGM を追加しよう
  • 21 : 効果音を追加しよう

dotinstall.com

作るもの 🚢

「Scratch で潜水艦ゲームを作ろう」では,名前の通り「潜水艦ゲーム 🚢」を作る.以下に埋め込んだ Scratch プロジェクトの完成版が公開されている.簡単に言えば「潜水艦を上下に動かしながら壁にぶつからないように進んでいくゲーム」になっている.潜水艦が重力により沈んだり,ステージによってコースが違ったり,当たると爆発してしまう敵が出てきたりもする.よくでてきて普通に楽しい!わいわい!

良いところ 1 : 自作の背景と色を使った衝突判定を学べる 🚢

序盤で Scratch のペイントエディタを使って「背景」を自作する.重要なのは「壁」の部分で実はオレンジ色のペンで手描きをしている.手描きをしてしまうとスプライトにすることができず,衝突判定はどうやるんだろう?と考えていたら「もし < オレンジ色に触れた > なら」という制御で実現していた!色を衝突判定に使うアイデアは使ったことがなくて,なるほどー!と思った.以下は自分で作った「背景 : LEVEL 4」でカスタマイズして楽しむこともできる(頑張って進んでいるところww)!

f:id:kakku22:20210225165848p:plain

良いところ 2 : メッセージを学べる 🚢

Scratch で別のスプライトやステージを同期的に(実際に同期しているかどうかは別として)制御する場合「メッセージ」という機能を使う必要がある.メッセージを送る側とメッセージを受信する側で独立してワークフローを作るイメージになり,今回のコンテンツでは「リセットメッセージ」「レベルアップメッセージ」を使う.「メッセージ」を使うとより高度なワークフローを作ることができるため実際に学べるのはとても良いと思う.「変数」と組み合わせた送信先の制限など実践的な Tips は Japanese Scratch-Wiki にも載っている.

ja.scratch-wiki.info

良いところ 3 : リファクタリングを学べる 🚢

「10 : ブロックを整理していこう」では,簡単ではあるけど,重複したブロックを整理するリファクタリングを学べる.動くなら良いじゃん!と娘に言われてしまうかもしれないけど,修正箇所が増えてきたら教えてあげる良いタイミングかもしれない!「リファクタリング(整理)」という観点を学べるのも素晴らしい!今回のコンテンツでは Scratch「ブロック定義」までは使わないけど,より複雑化するなら検討すると良いと思う.

ja.scratch-wiki.info

良いところ 4 : 背景番号を使った Tips を学べる 🚢

全ての背景をクリアしたら「背景 : GAME CLEAR」を表示して,ワークフローを止める必要がある.仕組みとしては「レベルアップメッセージ」を受信したら「次の背景にする」ブロックを実行しているため,そのままだと「背景 : GAME CLEAR」で右に進むと,また「背景 : LEVEL 1」に戻ってしまう.

そこで「もし < ステージの背景 # = 4 > なら」という背景番号を使った条件でクリアを判定している.マジックナンバーに依存してしまうので,ベストプラクティスではないかもしれないけど「添字」を使うという Tips を学べるのは参考になると思う.正確には以下のように「スプライトの他のスクリプトを止める」「すべてを止める」も組み合わせてゲームを止めている.

f:id:kakku22:20210225174952p:plain

まとめ

ドットインストールで学べる「Scratch で潜水艦ゲームを作ろう」Scratch の基本的な操作を理解した上で「より高度な操作」を学びながらゲームを作れる素晴らしいコンテンツだった!是非受講してみて欲しい!今回紹介した「良いところ」以外にもいろいろと工夫されているぞ!

dotinstall.com

関連記事

Scratch に入門するならまず以下を読んでもらえると良いかと!

kakakakakku.hatenablog.com

親子で楽しめる Scratch 超入門 / ドットインストール「Scratch 3.0 入門」を受講した

ドットインストールで学べる「Scratch 3.0 入門」を受講してみたら「Scratch 初学者」「親子で Scratch を楽しみたいとき」にピッタリで素晴らしいコンテンツだった!とてもわかりやすく,楽しく,ステップバイステップに学べる.今回の記事では,コンテンツの「良さ」を紹介したいと思う.以下に載せた「全19個」の動画があり,全て3分以内で終わるので,流し見をするだけなら1時間もあれば十分!

  • 01 : Scratch を使ってみよう
  • 02 : 画面の見方を確認しよう
  • 03 : 猫を動かしてみよう
  • 04 : スプライトの状態を確認しよう
  • 05 : ブロックを組み合わせてみよう
  • 06 : 猫をずっと動かしてみよう
  • 07 : コスチュームを変えてみよう
  • 08 : 矢印キーで動かせるようにしよう
  • 09 : 緑の旗でゲームをスタートさせよう
  • 10 : 上から卵を落としてみよう
  • 11 : 乱数を使ってみよう
  • 12 : 卵のクローンを作ってみよう
  • 13 : 猫に卵をキャッチさせてみよう
  • 14 : スコアを導入してみよう
  • 15 : ゲームを止めてみよう
  • 16 : ゲームオーバー画面を作ろう
  • 17 : 背景を切り替えてみよう
  • 18 : ゲームに BGM をつけてみよう
  • 19 : ゲームを共有してみよう

dotinstall.com

作るもの 😺

「Scratch 3.0 入門」では「ねこゲーム😺」を作る.以下に埋め込んだ Scratch プロジェクトの完成版が公開されているため,まずは遊んでみると良いと思う!簡単に言えば「猫を左右に動かしながら上から落ちてくる卵を拾うゲーム」になっている.実際に遊んでみると,結構楽しいし,猫と卵の位置関係によっては確実に拾えない場面があって笑ってしまうww

良いところ 1 : 基本的な操作を学べる 😺

最初に「画面レイアウトの説明」「用語の説明」「ブロック操作の説明」など基本的なところから学べる.Scratch を使うのに最低限必要な操作を学べるため,特に初学者に最適だと思う.より詳細な説明は Japanese Scratch-Wiki などにも載っている.

  • 言語設定(日本語/にほんご)
  • スプライト(名前/座標/大きさ/向き)
  • ステージ
  • ブロック
  • プロジェクト共有設定
  • etc

ja.scratch-wiki.info

良いところ 2 : よく使うブロックを学べる 😺

以下に載せたよく使うブロックを使って動かしながら学べる.特に猫を左右に動かしたり,コスチュームを変えてトコトコ歩いているように見せたり,BGM を鳴らしたりすると,本当にゲームを作っている気持ちになるし,子供たちにも飽きずに楽しんでもらえる.

  • 10 歩動かす
  • こんにちは!2 秒言う
  • ニャー の音を鳴らす
  • 次のコスチュームにする
  • 背景を PLAYING にする
  • 終わるまで Elec Piano Loop の音を鳴らす
  • etc

良いところ 3 : 便利な制御を学べる 😺

以下に載せた便利な制御を組み合わせて作っていく.特に制御を理解することは Scratch で重要なので,トライアンドエラー(動いた!動かない!何かがおかしい!)を繰り返しながらステップバイステップに改善できるのはとても良いと思う.また「猫と卵の衝突判定」として「もし < ねこに触れた > なら」を使ったり,他にも「卵と地面の衝突判定」として「もし < y座標 < -180 > なら」を使ったり,少し複雑だけど実践的な制御も学べるのも良い!

  • ずっと 〜
  • もし < > なら 〜
  • etc

最終的に「卵」に設定したワークフローは以下のようになる.初学者には少し複雑だけど読み解けるようになるはず👍

f:id:kakku22:20210225114217p:plain

良いところ 4 : クローンを学べる 😺

特に Scratch 初学者だと「卵を上からどんどん落とすワークフロー」ってどうやって作るんだろう?と悩んでしまうこともあると思う.数個ならスプライトを増やしても良いけど,今回は自分自身 のクローンを作る」ブロックを使ったワークフローを作っていく.

「隠す」と組み合わせたり1 秒待つ」と組み合わせながらクローンを増やせるため,難易度によって待ち時間を変えるなどカスタマイズできる要素もある.また上に載せたワークフローを見てもらうとわかる通り,「クローンされたとき」という制御ブロックを使ってトリガーしているところも理解しておくべきポイントと言える.

まとめ

ドットインストールで学べる「Scratch 3.0 入門」「Scratch 初学者」「親子で Scratch を楽しみたいとき」にピッタリで素晴らしいコンテンツだった!是非受講してみて欲しい!

1点気を付けると良さそうな点は,コンテンツとしては事前にゲームの完成版がイメージできているので「こういう動きを作りたい!」という課題に対して「じゃあこの制御を使ってみよう!」とすぐに解決しているけど,実際にやろうとすると「どの制御を使うべきなのか」などの設計に頭を悩ませることが多いと思う.特に僕自身は娘に Scratch を教えたり,小学生に教える機会もあるけど「なんで ずっと 〜 を使うの?」「なんで もし 〜 を使うの?」など,思考的な疑問が出てくることが多くて教えるのが楽しい!そういった「プログラミング的思考」も吟味しながら楽しめるのもドットインストール良いところだと思う!

dotinstall.com

関連記事

2年ほど前に紹介した小学生向けのドリル「たのしいプログラミング」Scratch で学びながら合わせて解いてみるとワークフロー(フローチャート)の理解がしやすくなって相乗効果があると思う.

kakakakakku.hatenablog.com

GitHub リポジトリのスター数を時系列グラフとして取得できる「starcharts」

「starcharts」を使うと GitHub リポジトリの「スター数⭐」を時系列グラフ(SVG フォーマット)として取得できる.GitHub リポジトリの README.md に載せることもできて便利!

github.com

kakakakakku/redash-hands-on を例にすると

「starcharts」の URL (starchart.cc) に kakakakakku/redash-hands-on のようにリポジトリ情報を追加すれば OK!以下に載せたような時系列グラフを取得できる.少しずつ増えてて 250 スター⭐までもう少し!

https://starchart.cc/kakakakakku/redash-hands-on.svg

関連サービス

時系列グラフは必要なく現在のスター数⭐を表示するだけで良いなら「Shields.io」も使える!関連サービスとして載せておく.

kakakakakku.hatenablog.com

PodDisruptionBudget (PDB) と kubectl drain --timeout オプションを組み合わせる

Kubernetes で PodDisruptionBudget (PDB) を使うと,kubectl drain コマンドでノードをドレインするときなどに Kubernetes クラスター内に起動しておく「最低限必要な Pod 数」を設定できる.よって,Kubernetes を使ったサービスの可用性を高める戦略としてよく使われる.

以下のドキュメントを読むと「自発的な混乱 (Voluntary Disruptions)」「非自発的な混乱 (Involuntary Disruptions)」という表現があり,既に紹介した「ノードをドレインするとき」は,管理者が運用として「自発的に」行うため「自発的な混乱 (Voluntary Disruptions)」に該当する.例えば「カーネルパニック (a kernel panic)」は突発的に発生するため「非自発的な混乱 (Involuntary Disruptions)」に該当する.

kubernetes.io

前提 : kubectl drain コマンド

今回使う kubectl drain コマンドの基本的な流れは以下の記事にまとめてある.前提として合わせて読んでもらえると良いかと!

kakakakakku.hatenablog.com

検証内容 : kubectl drain コマンド + PDB + リソース不足

今回はkubectl drain コマンドでノードをドレインしたときに PodDisruptionBudget (PDB) に設定した最低限必要な Pod 数を満たすリソースがノードに不足していた場合」という少し複雑な状況での挙動を検証する.検証する前の予想としては「デッドロック的な挙動になる?」もしくは「タイムアウト的な挙動になる?」と考えていた.

検証環境

今回は kind を使って,Mac 上に検証用の Kubernetes クラスター(複数ノード構成)を構築する.バージョンは v1.19.1 を使う.各ノードは「1 GiB メモリ」を使えるようにしてある.

$ kubectl get nodes
NAME                 STATUS   ROLES    AGE     VERSION
kind-control-plane   Ready    master   4m      v1.19.1
kind-worker          Ready    <none>   3m30s   v1.19.1
kind-worker2         Ready    <none>   3m30s   v1.19.1

$ kubectl describe nodes kind-worker | grep -A 6 Allocatable:
Allocatable:
  cpu:                2
  ephemeral-storage:  41021664Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             989764Ki
  pods:               110
  
$ kubectl describe nodes kind-worker2 | grep -A 6 Allocatable:
Allocatable:
  cpu:                2
  ephemeral-storage:  41021664Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             989764Ki
  pods:               110

そして「メモリ 300 MiB (requests.memory: 300Mi)」を要求する Pod「6個」Deployment 経由で作る.以下の kubectl get pods コマンドの結果からもわかる通り,各ノードに「3 Pod ずつ」デプロイされている.

$ kubectl apply -f deployment.yaml
deployment.apps/sandbox-drain-timeout-nginx created

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-94z9s   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-gcvh8   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-kxw2l   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-8cxxt   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-vksh8   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-z5f6n   Running   kind-worker2

構成をザッと図解すると以下のようになる.

f:id:kakku22:20210224003614p:plain

検証 1 : PDB なしで kubectl drain コマンドを実行する

まずは PodDisruptionBudget (PDB) なしで kubectl drain コマンドを実行して kind-worker ノードをドレインする.すると kind-worker ノードで起動していた Pod「3個」が削除 (eviction) される.そして kind-worker ノードのステータスは SchedulingDisabled になり,新しく Pod をスケジューリングしないようになる.今回 kind-worker2 ノードにリソース(メモリ)が不足しているため,スケジューリングされている Pod は全て Pending になっている.

$ kubectl drain kind-worker --ignore-daemonsets
node/kind-worker cordoned
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-94z9s
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-kxw2l
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-gcvh8
pod/sandbox-drain-timeout-nginx-f57cbc6cb-gcvh8 evicted
pod/sandbox-drain-timeout-nginx-f57cbc6cb-kxw2l evicted
pod/sandbox-drain-timeout-nginx-f57cbc6cb-94z9s evicted
node/kind-worker evicted

$ kubectl get nodes
NAME                 STATUS                     ROLES    AGE   VERSION
kind-control-plane   Ready                      master   12m   v1.19.1
kind-worker          Ready,SchedulingDisabled   <none>   11m   v1.19.1
kind-worker2         Ready                      <none>   11m   v1.19.1

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-f6qth   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-nvlkf   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-nzpbt   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-8cxxt   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-vksh8   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-z5f6n   Running   kind-worker2

構成をザッと図解すると以下のようになる.

f:id:kakku22:20210224003647p:plain

次の検証をするためにノードと Deployment を同じ構成に戻しておく.

$ kubectl uncordon kind-worker

$ kubectl delete -f deployment.yaml

$ kubectl apply -f deployment.yaml

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-hxz7h   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-xdvc9   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-2kq98   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-m9cbb   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-vcwjv   Running   kind-worker2

検証 2 : PDB ありで kubectl drain コマンドを実行する

次は PodDisruptionBudget (PDB) ありで kubectl drain コマンドを実行して kind-worker ノードをドレインする.まず,PodDisruptionBudget (PDB) のマニフェストを作る.今回は Deployment 経由で作られる Pod「6個」に対して「最低限必要な Pod 数 (minAvailable)」「4」に設定している.他には maxUnavailable という設定値も使える.

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: sandbox-drain-timeout-pdb
spec:
  minAvailable: 4
  selector:
    matchLabels:
      app: nginx

マニフェストを適用しておく.

$ kubectl apply -f pdb.yaml
poddisruptionbudget.policy/sandbox-drain-timeout-pdb created

$ kubectl get poddisruptionbudgets
NAME                        MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
sandbox-drain-timeout-pdb   4               N/A               2                     40s

さっそく kubectl drain コマンドを実行すると,「検証 1」と同じように kind-worker ノードで起動していた Pod「3個」が削除 (eviction) される.しかし PodDisruptionBudget (PDB)minAvailable: 4 と設定しているため,Pod(今回は sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp)を削除 (eviction) することができず,自動的にリトライをしている.以下の結果では Cannot evict pod というメッセージが繰り返し表示されていて,ターミナルも待機状態のままになっている.

$ kubectl drain kind-worker --ignore-daemonsets
node/kind-worker cordoned
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-hxz7h
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-xdvc9
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/sandbox-drain-timeout-nginx-f57cbc6cb-hxz7h evicted
pod/sandbox-drain-timeout-nginx-f57cbc6cb-xdvc9 evicted
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.

(中略)

evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.

(続く...)

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-fr9cq   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-pntw8   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-9d8qp   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-2kq98   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-m9cbb   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-vcwjv   Running   kind-worker2

待っても待ってもリトライが続くため,以下のドキュメントを確認したところ,今回設定しなかった kubectl drain コマンドの --timeout オプションのデフォルト値は 0s となり,無限にリトライを続ける挙動になっていた.なるほど!

The length of time to wait before giving up, zero means infinite

Kubectl Reference Docs

構成をザッと図解すると以下のようになる.

f:id:kakku22:20210224003710p:plain

次の検証をするためにノードと Deployment を同じ構成に戻しておく.

$ kubectl uncordon kind-worker

$ kubectl delete -f deployment.yaml

$ kubectl apply -f deployment.yaml

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-s4btz   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-ssscp   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-cdkcp   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-g6v7p   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-hvgm2   Running   kind-worker2

検証 3 : PDB ありで kubectl drain --timeout コマンドを実行する

kubectl drain コマンドはデフォルトでリトライを続ける挙動になっていることを確認できたため,最後は --timeout オプションを設定して挙動を確認する.今回はサンプルとして「30秒」にする.すると最後に global timeout reached: 30s というメッセージが表示されて kubectl drain コマンドがエラーを返している.結果としては「検証 2」と同じになる.なるほど!

$ kubectl drain kind-worker --ignore-daemonsets --timeout 30s
node/kind-worker cordoned
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-s4btz
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-ssscp
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/sandbox-drain-timeout-nginx-f57cbc6cb-s4btz evicted
pod/sandbox-drain-timeout-nginx-f57cbc6cb-ssscp evicted
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
There are pending pods in node "kind-worker" when an error occurred: error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh": global timeout reached: 30s
pod/sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh
error: unable to drain node "kind-worker", aborting command...

There are pending nodes to be drained:
 kind-worker
error: error when evicting pod "sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh": global timeout reached: 30s

$ kubectl get pods -o custom-columns=Name:metadata.name,STATUS:status.phase,NODE:spec.nodeName | sort -k 3
Name                                          STATUS    NODE
sandbox-drain-timeout-nginx-f57cbc6cb-5xs7k   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-jlckx   Pending   <none>
sandbox-drain-timeout-nginx-f57cbc6cb-tx6xh   Running   kind-worker
sandbox-drain-timeout-nginx-f57cbc6cb-cdkcp   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-g6v7p   Running   kind-worker2
sandbox-drain-timeout-nginx-f57cbc6cb-hvgm2   Running   kind-worker2

まとめ

kubectl drain コマンドを試しているときにふと気になり,今回はkubectl drain コマンドでノードをドレインしたときに PodDisruptionBudget (PDB) に設定した最低限必要な Pod 数を満たすリソースがノードに不足していた場合」という少し複雑な状況での挙動を検証した.ドキュメントに書いてあるとは言え,kubectl drain コマンドのデフォルトはリトライを続けて,--timeout オプションを設定するとタイムアウト時間を決めることができた.今後も積極的に検証していくぞー!