あんパン

こしあん派

デスクトップ環境をdisposableに保つ

もう5年以上続けている取り組みのひとつにデスクトップ環境をdisposableに保つというのがある。いつでも何があっても即座に環境を捨てて作り直せるようにするということ。EC2やVPSのインスタンスに対してAnsibleでプロビジョニングできる状態にしておけば即座に新しいホストを立てて古いホストを捨てられる、そんな状態を目指すということ。具体的には以下のようなことを心がけている。

書類のマスターデータを端末上に置かない

デスクトップ環境をdisposableに保つ第一歩は、とにかく手元になんらかのデータのマスターを置かないことにつきる。端末上にマスターデータを置いていると当然新しい環境を用意する際にデータ移行が必要になる。移行をしないためにはこれらを手元に置かないようにする。書類はGoogle DriveやNASに入れる、ソースコードは全てGitHubに上げておく、などなど。現代では機密情報はブラウザやら1Passwordやらに入れておけばだいたいなんとかなるということもあり手元に置きたいデータは少なかろう。もちろん即座に読みたいデータは手元にあっても良いけどマスターは別の場所に置いておく。これを徹底する。

また、複数の場所に置いておくことで耐障害性を高めることもできる。自分はデータをQNAPのNASに入れておくと定時バッチでAmazon S3に上がり、翌日にはGlacierに入るようにしている。

アプリケーションのインストールや設定をコードで管理する

冒頭で出したように、何らかの方法でプロビジョニングできる状態を目指す。自分は全ての設定をdotfilesに置いていて、2,3コマンド走らせて1,2時間くらい放置するだけで慣れたデスクトップ環境が仕上がるようにしている。

github.com

これを利用すればArch Linuxのインストールはいくつか環境変数を設定して1コマンドで終わるし、ツール類のインストールも1コマンドで終わる。日本語環境もウィンドウマネージャもなにもかもが自分の好みの状態で立ち上がる。このあたりは以前も書いた。このころからあんまり変わっていないけど、3年くらい経ってどうなったかはそのうち書きたい。

masawada.hatenablog.jp

なおLinuxデスクトップを使い始める以前はmacOSを利用していて、brewやbrew caskで対応していた。brewのインストールからシェルスクリプトで書いておいて、一発実行すればOKという要領。設定はdefaultsで対応。しかしやや大変ではある。Linuxの場合は全てがファイルなので、大抵の場合ファイルを適当に配置して回ればOKなのがありがたい。

一定期間おきにクリーンインストールする

つまり全ての設定を吹っ飛ばしてOSからインストールしなおすということ。disposableに保っておけば定期的にこれができるし、これができるということはdisposableといえる。なぜこれをやるかというと

  • 構成管理のコードを一切変えてなかったとしても長期間適用しないと動かない可能性があるため
    • コードを変えなくても周辺のツールのバージョンは上がっていくわけで、いざ必要になったときに動かないということがある
      • 手元環境のバージョン固定とか極力やりたくないと思う
    • これを防ぐために定期的に実行して壊れる箇所がないかを確認する
  • 長期間リセットしないまま使うと、どうしても手元にマスターデータが溜まりやすいため
    • 消すリズムを持っておかないと、まああとでGoogle Driveに上げるから……みたいな怠惰な気持ちになりマスターデータが手元環境に溜まりやすい(人による)
    • マジで消えてはいけないものを消してしまってもダメージが少なくなるということもある
      • 消えたら勉強代ということで…
  • リセットする手順を記憶しておくため
    • ある程度は自動化するしドキュメントも書くけれど、放置しているとリセットの方法が記憶から抜けていってだんだんと手順に自信がなくなっていく
    • 手順を覚えておくことで一連の動作を躊躇なく素早く行うことができる
    • つまりは避難訓練

などなどいろんな理由がある。

昔は1ヶ月おきに私物のMacBook ProのOSを飛ばして設定しなおしていたのだけど、中身を消して売却するときにSSDに異常が発見されて買い取り価格がめちゃくちゃ下がるという事件があり、それ以来同じことがあったら嫌だなと思ってペースを落としている。だいたい半年に1回程度でやっている。いまは昔と違って消すときにディスクに異常に書き込みまくるみたいなことがないのでこのリスクは少ないかもしれない。


インスタンスを建てたり捨てたりする際もこれらと同じようなことをやっているはずで、気をつけるポイントは同じといえる。

さてdisposableに保っておくことでどういうメリットがあるかというと、自分は以下かなと考えている。

  • 新規にPCを購入して素早く慣れた環境で開発できる状態を整えられる
  • 端末の突然死やデータのロストに耐える状態を作れる
  • 不具合がハードウェアの問題かソフトウェアの問題か分からないときに気軽に切り分けることができる
    • なぜかファンが爆音で回るのだが… というときに気軽にOSを入れ直して様子を見ることができる

逆にデメリットとしては

  • この状態を作るのに手間がかかる
  • ミスってデータが消えると痛い

といったことがある。しかし前者は一度整えたらあとは楽だし、後者はバックアップしましょうという感じ。

半ば趣味の領域ではありそうだけれど、個人的にはオススメできるスタンスかなと考えている。

ロールに求められることと名前は一致させたい

いま所属しているチームには相談役というロールがあって、タスクを進めている人とペアにすることで孤立しないような仕組みになっている。もちろんデイリースタンドアップなどで複数人で相互に見ているのだけど、プライマリな相談相手を決めているという状態。相談役がいることで相談する側が誰に相談するか悩む時間だったり相談される側がタスクのコンテキストを把握する時間だったりが減るのが良いところ。相談役も自分のタスクを持っていたりいなかったりする。

もともとジュニアメンバーにメンターがついて相談を受けていたけど、ジュニアメンバーに限らずどんなタスクでもプライマリな相談相手が決まっているといいよね、という話が元になった。これがだいたい4年くらい前の話。

ところがだんだんチームの規模が大きくなって、うまく回りづらくなっていた。具体的には以下のような状態になっていた。

  • メンバーが増えた結果、相対的に相談役になれるエンジニアの割合が減った
    • 複数の相談役を掛け持つケースが出てきた
      • 把握すべきコンテキストが増えたが、相談役という名前だったためかかる工数の見込みを甘くしてしまった
  • 新しく入ってきたメンバーと既存メンバーの相談役として同じような振る舞いをしてしまった
    • 相談が来るまで待ちの姿勢で居続けてしまった
      • 実際は相手によってもうすこし踏み込んで引っ張ることが期待されていた
      • 例えば進め方や考えに漏れがないかのレビューだったり、間に合わなそうだったらヘルプに入ったり

そうしているうちに、これは相談役という名前ではないよねという話がチームメンバーから持ち上がった。どちらかというとリードしてほしいのでは? という話があったものの、リードともちょっと違う気がしていて、伴走とかコーチとかいろいろな名前を考えてみている。


特定の人を何らかのロールに任命する際は、その名が実態に即しているかは気にしておきたい。気にするタイミングは誰かを何かに任命するとき、とりまく状況が変わるときであろう。

普段エンジニアとしての自分は実態に即した変数名をつけているはずで、ロール名をつけるときに深く考えられていないのは一貫性がないなと思う。いまは紅茶キノコにコンブチャと名付けてしまっている状態といえる。

ついでに書いておくと、ロール名だけでなくて会議の名前もその役割によって変更すべきだと思う。デイリースタンドアップでちょっとおもしろい名前がついているのはいいとして、例えばテクノロジーマネジメント会と称しているのに別にテクノロジーをマネジメントしていない、みたいなことがあると困る。会のメンバーは一緒だけど求められることが変わったり、会のメンバーが入れ替わって方向性が変わると容易に発生してしまう。期やメンバーが変わって会の受け持つ管掌範囲が変わるなら名前も変更すべきか気を払うとよさそう。

逆に、期待する役割があるならその名付けをしておくと沿った働きがしやすくなりそう。

ここまで通して読み返すと、つまるところ期待のコントロールをうまくやれという話なので、それはそうということしか書いていない。けれど細かい期待の変化は意外と見落としがちなので気をつけたい。気をつけるだけではなくて、期の変わり目にリマインダーを仕込んでおくとか、ドキュメントに書いておくとかの対策は取れそう。

CDKでEC2を建立するときになんかする

めっちゃ小ネタだし知ってるわって人も多そうな話題なのだけど、CDKでEC2建立するときに addUserData でなんかするのが便利。

例えば、Perlの最新版をインストールしたいときは以下みたいな感じでxbuildを使って達成できる。

const bastion = new ec2.BastionHostLinux(this, 'bastion', { vpc });
bastion.instance.addUserData(
  'yum -y update',
  'yum -y install gcc',
  'wget https://github.com/tagomoris/xbuild/archive/refs/heads/master.zip -P /tmp',
  'unzip /tmp/master.zip -d /tmp',
  '/tmp/xbuild-master/perl-install 5.36.0 /opt/perl-5.36',
);

CDK実行時は addUserData 内のコマンドを待つわけではないので、建立直後は実行完了までしばらく待つ必要がある。

ちなみに BastionHostLinux を使う必要はない。 Instance でOK。SSM agentが入っているとPrivate Subnetに建てたとしてもWebコンソールからシュッと接続できるため自分は便利に使っている。が、(いまのところ)Amazon Linux 2が建つので要注意という感じではある。

ちょっと凝ったことしたいなら、curlで取得して実行する手もある。けどあんまセキュアな行いではないと思う…

const bastion = new ec2.BastionHostLinux(this, 'bastion', { vpc });
bastion.instance.addUserData(
  'sh -c "$(curl -fsSL ...)"',
);

自分の場合はときどきRTMPのプロキシを用意したくて、nginx-rtmp-module入りのNginxをビルドするのに同じようなことをしている。

以上、わざわざプロビジョニングのあれこれを考えたくなくて環境が整ったEC2をシュッと建てたいときに使えるテクでした。

はてなブログで見出しへのリンクを表示する

つい最近、はてなブログの見出し(h1からh6までのタグ)にid属性が付与されるようになった。

staff.hatenablog.com

ということは、見出しへのリンクを作って共有できる。ただ普通に暮らしていると、このリンクを生成するためにDeveloper Toolsを表示して見出しのidを入手してURLにhash fragmentを設定して… という手順になってしまいやや煩雑。GitHubのMarkdownのように、hoverしたらリンクアイコンが表示されて見出しのリンクに飛べる、となっていたい。

hoverすると見出しの横にリンクアイコンが出て見出しに飛べる

ということで、自分のブログで同じことができるようにしてみた。以下の記事で試せる。

masawada.hatenablog.jp

見出しにカーソルをあわせるとリンクアイコンが表示される

以下のコードを 設定 > 詳細設定 > headに要素を追加 に貼って保存することで利用できる。テーマによってデザインなどは変える必要があるかもしれない。各々の環境にあったようにカスタムされたい。あとレスポンシブ環境では試していない。

gist.github.com

リンクアイコンはFont Awesomeから持ってきていて、アイコンSVGのライセンスはCC BY 4.0なので留意されたい。

fontawesome.com

他の部分はMITライセンスとした。

過去(おそらく8月中旬より前?)の記事については再度保存しないとidが挿入されないようなのでこちらも注意されたい。新しく書く記事については問題なく挿入されている。


長い記事を書いて見出しをつけたときに便利です。よければご利用ください。

AWS CLIでSwitch Roleするパターン

AWSアカウントを組織で管理していると複数アカウント利用するケースは多いかと思う。別のアカウントに切り替えるには、WebコンソールからSwitch Roleすればよい。そして以下のように $HOME/.aws/config$HOME/.aws/credentials を設定すればAWS CLIからもSwitch Roleできる。

$ cat $HOME/.aws/credentials
[main-account]
aws_access_key_id = ACCESS_KEY_ID
aws_secret_access_key = SECRET_ACCESS_KEY

$ cat $HOME/.aws/config
[profile sub-account]
source_profile = main-account
role_arn = ROLE_ARN
mfa_serial = MFA_SERIAL_ARN
region = ap-northeast-1

$ aws s3 ls --profile sub-account
(sub-accountのS3 bucketのリスト)

ただこれだと、 ACCESS_KEY_IDSECRET_ACCESS_KEY を平文で保存することになりやや脆弱なのでenvchainを使いたい。envchainはmacOSのKeychainやLinuxのGNOME Keyring等で暗号化保存したcredentialsを復号して環境変数に設定してくれる。使い方はREADMEの通り。

github.com

envchainを併用する場合 $HOME/.aws/credentials$HOME/.aws/config を以下のように設定すればSwitch Roleできる。

$ cat $HOME/.aws/credentials
(envchainに寄せたのでcredentialsは空)

$ cat $HOME/.aws/config
[profile sub-account]
credential_source=Environment
role_arn = ROLE_ARN
mfa_serial = MFA_SERIAL_ARN
region = ap-northeast-1

$ envchain aws-main-account env
...
AWS_ACCESS_KEY_ID=ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=SECRET_ACCESS_KEY
AWS_DEFAULT_REGION=ap-northeast-1

$ envchain aws-main-account env aws s3 ls --profile sub-account
(sub-accountのS3 bucketのリスト)

$HOME/.aws/configcredential_source=Environment を足しておかないと Partial credentials found in assume-role, missing: source_profile or credential_source というエラーが出るので注意。また、profileの指定は --profile オプションでのみ可能で、環境変数 AWS_PROFILE で指定することはできない。このあたりはドキュメントにも載っている。

awscli.amazonaws.com

ところでこの方法だと $HOME/.aws/cli/cache/*.json に一時的なcredentialが吐き出されてしまい、envchainを使う意図としてはやや片手落ちな感がある。ではどうするかというと、AssumeRoleのコマンドを手で発行して、返ってきたcredentialを環境変数に設定する。具体的な方法は以下の記事が詳しい。

dev.classmethod.jp

自分の場合は以下のようなラッパーを書いて利用している。

github.com

このように使う:

$ cat $HOME/.aws/config
[profile sub-account]
role_arn = ROLE_ARN
mfa_serial = MFA_SERIAL_ARN
region = ap-northeast-1

$ envchain aws-main-account env aws-switch-role sub-account
Enter MFA code for MFA_SERIAL_ARN:
$ (sub-account) aws s3 ls
(sub-accountのS3 bucketのリスト)

やっていることとしては aws sts assume-role で取得したcredentialを環境変数に設定して $SHELL を新しく立ち上げているだけ。一時的なcredentialはこのプロセス内でのみ有効になるので、平文で保存されるよりは幾らかマシということにしている。(2022-08-12 追記: sudo cat /proc/$PID/environ | sed 's/\x00/\n/g' とかすれば読み取れてしまうので気持ちの問題ではある…)

ところでこの方法だとcredentialを環境変数に設定するのでAWS CLIの利用時にprofileを指定する必要がなくなるが、逆に現在どのprofileに対して操作しているのかが分かりづらくなる。そこで自分は $SHELL を立ち上げるときに本来必要ない環境変数 AWS_PROFILE を一緒に設定してあげて、これが設定されていたらプロンプトの表示を変えている。

$ cat $HOME/.zshrc
...
PROMPT="%{${fg[yellow]}%}%(!.#.$) $([[ -n $AWS_PROFILE ]] && echo "($AWS_PROFILE) ")%{$reset_color%}"
...

立ち上がったシェルを終了すれば元に戻れるので、一時的にセッションを張る使用感になる。


現実的にはひとつめのパターンやふたつめのパターンで十分ということもありそう。社のセキュリティーポリシーや自分のセキュアにしたい気持ちと相談して選択されたい。