kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Redis で特定のコマンドを無効化できる設定「rename-command」

最近 Redis の公式ドキュメント「Redis Security」を読んでいたら「Disabling of specific commands」というトピックを発見した.簡単に表現すると redis.conf に rename-command という設定を定義すると,特定のコマンドを無効化したり,別名のコマンドに変更することができる機能と言える.例えば FLUSHALL や FLUSHDB など,もし運用上不要なコマンドがあれば,誤って実行してしまうことを防止することができる.rename-command は今まで使ったことがなく,試してみることにした.

redis.io

検証環境

今回は Mac に brew でインストールした Redis 5.0.5 を使う.

$ redis-server --version
Redis server v=5.0.5 sha=00000000:0 malloc=libc bits=64 build=31cd6e21ec924b46

$ redis-cli --version
redis-cli 5.0.5

CONFIG GET コマンドを実行する

まず,設定値を取得する CONFIG GET コマンドを通常通りに実行する.以下のように port と save の設定値を取得できた.

127.0.0.1:6379> CONFIG GET port
1) "port"
2) "6379"

127.0.0.1:6379> CONFIG GET save
1) "save"
2) "3600 1 300 100 60 10000"

CONFIG コマンドを無効化する

次に,公式ドキュメントに書いてある通りに redis.conf を修正する.

rename-command CONFIG ""

すると,CONFIG GET を実行しても unknown command となり,無効化されていた.

127.0.0.1:6379> CONFIG GET port
(error) ERR unknown command `CONFIG`, with args beginning with: `GET`, `port`,

127.0.0.1:6379> CONFIG GET save
(error) ERR unknown command `CONFIG`, with args beginning with: `GET`, `save`,

CONFIG コマンドを別名に変更する

次も,公式ドキュメントに書いてある通りに redis.conf を修正する.今度は CONFIG コマンドを推測不可能な別名に変更している.

rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52

すると,今度は b840fc02d524045429941cc15f59e41cb7be6c52 コマンドを使って,設定値を取得できた.

127.0.0.1:6379> b840fc02d524045429941cc15f59e41cb7be6c52 GET port
1) "port"
2) "6379"

127.0.0.1:6379> b840fc02d524045429941cc15f59e41cb7be6c52 GET save
1) "save"
2) "900 1 300 10 60 10000"

KAKKUSET コマンドと KAKKUGET コマンドを作る

運用上使うことはないけど,例えば KAKKU というプレフィックスを付けたコマンドを作ることもできる.同様に redis.conf を修正する.

rename-command SET KAKKUSET
rename-command GET KAKKUGET

すると,KAKKUSET コマンドと KAKKUGET コマンドを使えるようになる.

127.0.0.1:6379> KAKKUSET mykey "Hello"
OK
127.0.0.1:6379> KAKKUGET mykey
"Hello"

まとめ

  • Redis の公式ドキュメント「Redis Security」を読んでいたら「Disabling of specific commands」というトピックを発見した
  • redis.conf に rename-command という設定を定義すると,特定のコマンドを無効化したり,別名のコマンドに変更することができる

Shell で「テンプレートエンジン」のような仕組みを実現できる envsubst コマンド

少し前に envsubst コマンドの存在を知った.envsubst コマンドを使うと,変数展開など,Shell で「テンプレートエンジン」のような仕組みを実現できる.例えば,設定ファイルを生成するときなどに使える.なぜ今まで知らなかったんだろう!と思うけど,今回は envsubst の紹介記事を書きたいと思う.

準備

例えば Amazon Linux 2 など,環境によって,最初から envsubst コマンドが使える場合もある.もしインストールする場合は gettext パッケージに含まれているため,yum などを使ってインストールする.

$ yum install -y gettext
$ which envsubst
/usr/bin/envsubst

Mac なら brew を使ってインストールできる.インストール後に brew link を実行することを忘れずに!

$ brew install gettext
$ brew link --force gettext
$ which envsubst
/usr/local/bin/envsubst

なお envsubst コマンドの help を確認すると「環境変数の値を代入する」と記載されていた.

$ envsubst --help
Usage: envsubst [OPTION] [SHELL-FORMAT]

Substitutes the values of environment variables.

echo と envsubst を組み合わせる

まず,以下のように名前を ${NAME} として環境変数にした文字列を作成し,echo で標準出力をすると,そのまま出力される.

$ echo 'Hello ${NAME}'
Hello ${NAME}

次に,export で環境変数を設定して,標準出力を envsubst に流すと,${NAME} の部分が変数展開される.これは便利!

$ export NAME=kakakakakku
$ echo 'Hello ${NAME}' | envsubst
Hello kakakakakku

テンプレートファイルと envsubst を組み合わせる

検証用のテンプレートファイル profile.yaml.template を作成する.name と blog と github を Key とし,Value に環境変数を指定したシンプルな YAML ファイルにする.

name: ${NAME}
blog: ${BLOG_URL}
github: ${GITHUB_URL}

検証用のテンプレートファイルを cat で標準出力をすると,そのまま出力される.

$ cat profile.yaml.template
name: ${NAME}
blog: ${BLOG_URL}
github: ${GITHUB_URL}

次に,先ほどと同様に export で環境変数を設定して,検証用のテンプレートファイルを envsubst に流すと,Value の部分が変数展開される.環境ごとに異なる設定ファイルを生成できるようになった.これは便利!

$ export NAME=kakakakakku
$ export BLOG_URL=https://kakakakakku.hatenablog.com
$ export GITHUB_URL=https://github.com/kakakakakku

$ cat profile.yaml.template | envsubst
name: kakakakakku
blog: https://kakakakakku.hatenablog.com
github: https://github.com/kakakakakku

なお,ファイルと組み合わせる場合は cat を使わずに,直接流し込むこともできる.

$ envsubst < profile.yaml.template
name: kakakakakku
blog: https://kakakakakku.hatenablog.com
github: https://github.com/kakakakakku

まとめ

  • envsubst コマンドを使うと,Shell で「テンプレートエンジン」のような仕組みを実現できる
  • 設定ファイルを生成するときなどに使えて便利!

文化である DevOps の誤解を紐解こう /「Effective DevOps」を読んだ

先週から「Effective DevOps」を読んでいた.去年出版されたときにパラパラと気になる箇所を読んだけど,書評記事を書いていなかったこともあり,改めて読み直すことにした.本書は「DevOps」をテーマにしつつ,その本質としてはサブタイトルにもある「4本柱による持続可能な組織文化の育て方」となる.よって,タイトルだけを見て「DevOps の技術面」を学べるのかなと期待すると,ある意味期待を裏切られる可能性もあり,まず目次を見てみると良いかと.そのためにも目次を載せておく.

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Effective DevOps ―4本柱による持続可能な組織文化の育て方

目次

  • 第 Ⅰ 部 : devopsとは何か
    • 1ç«  : 大局を見る
    • 2ç«  : devopsとは何か
    • 3ç«  : devopsの歴史
    • 4ç«  : 基本的な用語と概念
    • 5ç«  : devopsに対する誤解とアンチパターン
    • 6ç«  : 効果的なdevopsのための4本柱
  • 第 Ⅱ 部 : コラボレーション
    • 7ç«  : コラボレーション:ともに仕事をする個人たち
    • 8ç«  : コラボレーション:誤解と問題解決
  • 第 Ⅲ 部 : アフィニティ
    • 9ç«  : アフィニティ:個人からチームへ
    • 10ç«  : アフィニティ:誤解と問題解決
  • 第 Ⅳ 部 : ツール
    • 11ç«  : ツール :エコシステムの概要
    • 12ç«  : ツール:文化を加速させるもの
    • 13ç«  : ツール:誤解と問題解決
  • 第 Ⅴ 部 : スケーリング
    • 14ç«  : スケーリング:変曲点
    • 15ç«  : スケーリング:誤解と問題解決
  • 第 Ⅵ 部 : devops文化への架け橋
    • 16ç«  : devopsの4本柱を使って架け橋をつくる
    • 17ç«  : devops文化への架け橋:ストーリーから学ぶ
    • 18ç«  : devops文化への架け橋:人と人のつながりを育てる
    • 19ç«  : まとめ
    • 20ç«  : さらに深く学習するために

DevOps と devops

本書のタイトルは「Effective DevOps」だし,僕が今までブログ記事や発表資料に書いてきた表記も「DevOps」だけど,本書(タイトルを除く)では「devops」に統一されている.本書の冒頭に「Dev と Ops の対立ではなく,ビジネスを持続可能に進めていく手法」として,意図的に小文字表記にしたと書かれていた.とは言え,個人的に見慣れた表記は「DevOps」なので,本記事では「DevOps」に統一する.

誤解と問題解決

本書全体を通して興味深いのは,DevOps に対する「誤解」を問題提起し「問題解決」のために「誤解」を紐解くという観点でまとまっているところで,ある意味「アンチパターン集」としても活用できる.逆に言うと「こうすると DevOps である」という明確な定義はなく,そこは組織ごとに考える必要がある.

DevOps に対する誤解

本書には,よく聞く「DevOps の誤解」がまとまっていて,読みながら何度も頷いてしまった.その一部を以下に紹介する.

  • DevOps はチームである
  • DevOps は肩書だ
  • DevOps はウェブ系のスタートアップだけの問題だ
  • DevOps はツールの問題だ
  • DevOps とは自動化のことだ

確かに最近だと「DevOps = 自動化」というコンテキストの発表も多いけど,正確には「自動化も重要だけど,組織の透明性やコラボレーションを意識しないと,自動化が未知のリスクになる」と書いてあり,考えさせられる.また,僕自身も2017年に一時期「DevOps エンジニア」と自己紹介をしていた時期もあり,恥ずかしくもある.

4本柱

本書では「DevOps とは何か?」という概論と歴史の紹介に続き,サブタイトルにもある「4本柱」の解説があり,以下のように定義されている.記事の冒頭にも書いた通り,文化面の話が中心になっている.それぞれ紹介していこうと思う.

  • コラボレーション
  • アフィニティ
  • ツール
  • スケーリング

4本柱「コラボレーション」

4本柱の1個目「コラボレーション」は,メンバー同士うまく協力することを意味している.協力とは言え,内容は幅広く,コミュニケーションの手段(即時性/負担/コンテキストなど)を適切に選んだり,傾聴を通じて共感と信頼を育てたり,双方向メンタリングを行うなども紹介されている.

特に「人それぞれ異なる目標(モチベーション)を持っている」という話は,今までも意識してきたものの,改めて考えさせられた.具体的には,現在のキャリアを重要視している人もいれば,カンファレンス参加などのネットワーキングを重要視している人もいれば,収入のための仕事であると割り切っている人もいる.エンジニアリングマネージャーやプロジェクトリーダーにも役立つ内容になっている.

なお,コミュニケーションの手段としては,即時性の観点で「雑談」も入っていたらもっと良さそうだなと思う.僕自身は「雑談」を大切にしていて,以下のような内容を発表したこともある.

f:id:kakku22:20190531014953j:plain

kakakakakku.hatenablog.com

4本柱「アフィニティ」

4本柱の2個目「アフィニティ」は,チーム間の関係を築き,チーム目標の違いを乗り越えることで,4本柱の1個目「コラボレーション」の延長線上にあるとも言える.

「アフィニティの誤解」の中に「運用エンジニアは企業にとって開発者ほど役に立たない」という内容があるが,過去の経験として,運用エンジニアに限らず,特定のチームの価値を正しく理解できず,必要性を疑ってしまったこともある.今になって,うまく関係を築けていなかったなと反省している.心理的安全性という言葉でまとめるのが適切かどうかはわからないけど,チーム間の相互理解に悩みがあれば,読んでみるのが良いと思う.

4本柱「ツール」

4本柱の3個目「ツール」で,やっと技術面の話だ!と思うかもしれないけど,文化を改善するために目的意識を持ってツールを選定しようという内容になっている.DevOps を支える技術の詳細に興味があれば,例えば「Infrastructure as Code」などを合わせて読むと良さそう.

Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス

Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス

読み進めていたら「ツールの選定」という内容に興味を持った.ツールを選定するときに,機能の有無や予算だけではなく,以下を考慮するべきと書かれていた.確かに「バージョンアップの頻度」や「プルリクエストの滞留具合」などは気になるし,日本語の解説記事なども,少なければ積極的に書くモチベーションには繋がるけど,ツールを選定する立場になると,コミュニティの健全性もしくは浸透度を考える必要もありそう.

  • 製品の開発状況
  • コミュニティの健全性
  • 内部でのカスタマイズの可能性

また,自動化に対するスタンスとして「残りものの原則」という表現が紹介されている.「自動化に適切ではないタスクもある」という納得できる話なんだけど,引用元の論文タイトルに笑った.「Automation Should Be Like Iron Man, Not Ultron」ってもう.

queue.acm.org

4本柱「スケーリング」

4本柱の4個目「スケーリング」は,もしかしたら「インフラストラクチャのスケーリング」をイメージするかもしれないけど,組織変革など,組織が成長していくことを意味している.育成や採用,報酬やカルチャーフィットなど,どんな組織規模でも悩む内容がまとまっていて,一読の価値がある.

また「スケーリングの誤解」の中には「改革を始めるためには経営陣の全面的な支持が必要だ」という内容もあり,本書にも書いてある通り,裁量を与えてもらうべき場面と経営陣を巻き込むべき場面があり,適材適所に判断するのが良いと思う.個人的にも似た経験があり,以下にリンクを載せておく.全ては組織規模とフェーズによって異なると思う.

developers.cyberagent.co.jp

kakakakakku.hatenablog.com

まとめ

  • 「Effective DevOps」を読んだ
  • 本書は「DevOps」をテーマにしつつ,本質的には「DevOps の文化面」を事例と共に深く学べる内容になっている
  • 特に「誤解」と「問題解決」という観点でまとまっているのは過去の経験を想起しながら読むことができて非常に良かった

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Effective DevOps ―4本柱による持続可能な組織文化の育て方

コマンド失敗時に Mackerel にアラートを通知できる mkr wrap を試した

今年2月頃にリリースされた mkr コマンドの新機能 mkr wrap を試した.mkr wrap を使うと,指定したコマンドの失敗時に Mackerel にアラートを通知できるようになり,Worker プロセスなどのモニタリングに役立つ.詳細は以下の公式ドキュメントに載っている.

mackerel.io

今回は Amazon Linux 2 を検証環境として,最新バージョンの mkr を使う.事前設定が必要な mackerel-agent.conf などは割愛する.

$ mkr --version
mkr version 0.37.0 (rev:5789f43)

サンプルコード

今回はサンプルコードとして,正常時に終了コード 0 を返す,以下の check.sh を使う.

#!/bin/sh

echo 'Success!'

エラー時は終了コード 1 を返す.ブログ記事用にシンプルな実装にした.

#!/bin/sh

echo 'Error!' && exit 1

--name オプション

--name オプションを使うと,任意の監視名を設定できる.デフォルトだと mkrwrap-xxx-yyy というフォーマットの監視名になり,エラー発生時に判別しにくくなる可能性もあるので,--name オプションは基本的に使うと良さそう.今回はサンプルとして shell-checker とした.

$ mkr wrap --name shell-checker -- ~/check.sh
Error!
command exited with code: 1

実際にエラーを発生させると,Mackerel 側にアラートが通知された.監視名も正しく shell-checker になっている.

f:id:kakku22:20190527110044p:plain

--auto-close オプション

実装によっては,次回実行時に正常終了になれば自動復旧と判断できる場合もあると思う.Mackerel の仕様として,通知されたアラートを意図的に終了する必要があるけど,--auto-close オプションを使うと,自動的にアラートを終了できるようになる.必要に応じて,使うと良さそう.実際に試したところ,自動的に終了されていた.

$ mkr wrap --name shell-checker --auto-close -- ~/check.sh
Success!

f:id:kakku22:20190527110157p:plain

なお,公式ドキュメントに記載がある通り,--auto-close オプションを使うと一時領域に実行結果ファイルを保存し,次回実行時に参照する仕組みになっている.今回の検証環境だと /tmp/mkrwrap-shell-checker.json に実行結果ファイルがあった.なお,mkr コマンドの実装を確認したところ,一時領域の取得は os.TempDir() になっていた.

github.com

--notification-interval オプション

通知されたアラートを定期的に再送する場合は --notification-interval オプションを使う.オプション引数としては 10m や 1h など,再送間隔を指定する.個人的にはアラートが通知された後に指定した間隔で自動的に再送されるのかなと予想したけど,実際に動作確認をしてみると,2回目以降のエラーが発生したときに指定した間隔を超えている場合に再送されるようだった.

$ mkr wrap --name shell-checker --auto-close --notification-interval 10m -- ~/check.sh
Error!
command exited with code: 1

なお,試していたら公式ドキュメントに誤記を発見したため,プルリクエストを送っておいた.既に merge してもらっている.

github.com

Mackerel 関連のドキュメントは今年3月頃に OSS 化されている.気になる誤記などがあれば,積極的にプルリクエストを送ると良さそう!

mackerel.io

まとめ

  • mkr wrap を試した
  • 指定したコマンドの失敗時に Mackerel 側にアラートを通知できるようになる
  • 多くのオプションがあり,他にも今回紹介しなかった --detail オプションや --note オプションもある

「Mackerel アンバサダー」として,積極的にアウトプットをしていくぞ!

JMESPath Tutorial と jp コマンドを使って JMESPath を学ぶ

JSON をパース(集計/整形など)するときに,よく使われているのは「jq」だと思う.僕も jq をよく使っている(構文は毎回調べるけど).今回は jq 以外の選択肢となる「JMESPath」の理解を深めることにした.JMESPath も JSON をパースできるクエリ言語(仕様)で,例えば AWS CLI の --query オプションでも採用されている.

jmespath.org

JMESPath Tutorial

JMESPath をすぐに試すなら「JMESPath Tutorial」を使うと便利.

jmespath.org

よく使う構文を画面上で試すことができるし,実際にクエリを更新するとすぐに反映される.JMESPath Tutorial で試せる構文は以下となる.

  • Basic Expressions
  • Slicing
  • Projections
    • List and Slice Projections
    • Object Projections
    • Flatten Projections
    • Filter Projections
  • Pipe Expressions
  • MultiSelect
  • Functions

f:id:kakku22:20190513003424p:plain

JMESPath CLI : jp

CLI として使える JMESPath 実装 jp コマンドもある.良くも悪くも jq と似すぎ!

github.com

今回は brew を使ってインストールしてみた.

$ brew install jmespath/jmespath/jp
$ jp --version
jp version 0.1.3

なお,現在 README.md に書いてある手順だと異なる jp が brew からインストールされてしまうため,直接 Formulae を指定する手順に修正するプルリクエストを送った.確実に必要な修正だから merge してもらえると良いんだけど!

github.com

基本的な jp の使い方として,標準出力をパイプして JSON をパースできる.

$ echo '{"key": "value"}' | jp key
"value"

$ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1]
"b"

既に JSON ファイルがある場合,-f もしくは --filename を使うと,ファイルを読み込んで JSON をパースできる.

$ jp --filename input.json foo.bar[1]
"b"

jq を使う場合,よく -r もしくは --raw-output を使って,パース結果に " を付けないようにすると思う.jp にも同様のオプションがあり,-u もしくは --unquoted を使う.また環境変数 JP_UNQUOTED を使うと,デフォルト設定を変更することもできる.

$ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp --unquoted foo.bar[1]
b

$ export JP_UNQUOTED=true
$ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1]
b

JMESPath Tutorial と jp コマンド

JMESPath Tutorial を一通り試して,気になった構文を jp コマンドを使って整理しておこうと思う.

Slicing

「Slicing」では,例えば [0:5] のように書くと,配列データの一部を刈り取ることができる.また [:5] のように終了のみを指定して刈り取ることもできる.

$ echo '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]' | jp [2:5]
[
  2,
  3,
  4
]

$ echo '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]' | jp [:5]
[
  0,
  1,
  2,
  3,
  4
]

Object Projections

「Object Projections」では,例えば ops.*.numArgs のように中間要素をワイルドカードで指定することができる.

$ echo '{
  "ops": {
    "functionA": {"numArgs": 2},
    "functionB": {"numArgs": 3},
    "functionC": {"variadic": true}
  }
}' | jp ops.*.numArgs
[
  2,
  3
]

Filter Projections

「Filter Projections」では,例えば machines[?state=='running'].name のように要素に対して条件を書くことができる.

$ echo '{
  "machines": [
    {"name": "a", "state": "running"},
    {"name": "b", "state": "stopped"},
    {"name": "b", "state": "running"}
  ]
}' | jp "machines[?state=='running'].name"
[
  "a",
  "b"
]

Functions

「Functions」では,例えば length(people) など,ビルトイン関数を使って集計することもできる.他にも max や merge など,多く用意されている.

$ echo '{
  "people": [
    {
      "name": "b",
      "age": 30,
      "state": {"name": "up"}
    },
    {
      "name": "a",
      "age": 50,
      "state": {"name": "down"}
    },
    {
      "name": "c",
      "age": 40,
      "state": {"name": "up"}
    }
  ]
}' | jp "length(people)"
3

JMESPath Specification

JMESPath の全仕様は「JMESPath Specification」に載っている.ビルトイン関数の一覧も確認できる.

jmespath.org

言語別 JMESPath 実装

多くの言語に JMESPath 実装がある.バックエンド実装で JSON をパースする場面があれば検討しても良さそう.

  • Python
  • PHP
  • JavaScript
  • Ruby
  • Lua
  • Go
  • Java
  • Rust
  • .NET

jmespath.org

まとめ

  • JSON をパース(集計/整形など)するときに「jq」以外の選択肢となる「JMESPath」を試した
  • JMESPath をすぐに試すなら「JMESPath Tutorial」を使うと便利
  • JMESPath CLI として使える jp コマンドもある
  • (慣れの問題もあるけど)個人的には「jq」よりも「JMESPath」の方が構文の可読性が高いように感じた