サーバの大量構築をした事がある学生を80人養成した

この記事はwhywaitaアドベントカレンダー21日目の記事です。 タイトルは言い過ぎかもしれません。
2年ぶりの参加です。前回は雑すぎてごめんよ (参考)

ICTトラブルシューティングコンテストという参加者も運営も学生が行うインフラ系のコンテストがあります。学生は本戦の問題作成および競技ネットワーク等の設計で忙しいので予選問題はお手伝いをしてる社会人(僕含め)で作りました。9問出題されましたが、この記事はそのうちの1問の紹介です。

ここでサーバを100台構築させる問題を出題させ、何かしらの構築を効率化できる手法を用いたチームが25チーム中16チームいて、1チーム5名なので80人の学生がサーバの大量構築をしたことがあるということになります。(難易度は別として)

問題

問題文は長いのでこちらに貼っておきます。伏せる内容もないので全文公開です。

【公開用】ICTSC9予選 問1 · GitHub

内容を簡単に言うと、

  • sshして、nginxをインストールしてもらうまでのチュートリアル
  • 同じサーバでnginxに固定のJSONを返すための設定を投入してもらう (問 1-1)
  • 同様な構成で100台構築してもらう (問 1-2)

となっていてチュートリアル的にnginxをインストールしつつ、ちょこっと設定等を変えてもらい、それを100台のサーバに対して展開してもらうという問題構成です。 問1として出題したので、Linuxのサーバにsshしてパッケージをインストールするという操作にあまり慣れていない学生でも点数を取れる難易度を目指しました。結果、0点のチームは居ませんでした!

学生のうちに大量のサーバにsshして構築する経験をした学生は居ないだろうという想像のもと、100台構築してもらうことにしました。100台というのはきりがよかったのと、手動でコマンドを打つのは諦めたくなるくらいにしたかったという意図があります。 何かしらの方法で構築を効率化/自動化できたチームは高得点で、手動でやっていたチームは10台くらい構築して時間の無駄だと思ったのか、諦めた形跡がありました。

出題環境

予備も含めるとサーバを3,200ホスト用意しなければなりません。予選環境としてさくらインターネット様にさくらのクラウドを提供して頂いたのですが、流石にこれだけのために3,200ホストを実際に建てるわけにはいきません。ただ大量のホストは欲しい…そこでLXDです!!Dockerじゃないです。LXDですよ。 LXDはLinux Containerを使ってコンテナの中でinitプロセスが立ち上がり、普通のサーバマシンのように振る舞います。Dockerがアプリケーションコンテナであれば、LXDはシステムコンテナです。

Linux Containers - LXD - イントロダクション

LXDで大量のホスト(コンテナ)を運用する上でいろいろつまづきましたがそれは別記事で紹介します。当初はCPU36コア, メモリ224GBの仮想マシンの上で1,500ホスト(コンテナ)稼働させるのにチャレンジするつもりで構築していましたが、本番を見据えた構成でホストを生成していったところ、1,300コンテナあたりでcgroupが壊れてしまいました。各ホストには1CPU, メモリ256MBの環境となるように制限を掛けていたのですが、途中から新しいcgroupが作れなくなりました。ロードアベレージもアイドル状態で600くらいだったのでプロセス数が異常に増えている環境だとかなり厳しい状態になるということがわかりました。

ubuntu@s01:~$ sudo mkdir /sys/fs/cgroup/memory/test
mkdir: cannot create directory '/sys/fs/cgroup/memory/test': Cannot allocate memory

試しに手動でcgroupを作ってみてもこんな感じで、さらにsyslogを見るとよくわからないエラーが…

Dec 14 05:57:38 s01 kernel: [14972.817859] BUG: unable to handle kernel NULL pointer dereference at           (null)
Dec 14 05:57:38 s01 kernel: [14972.819204] IP: [<          (null)>]           (null)
Dec 14 05:57:38 s01 kernel: [14972.820514] PGD 0
Dec 14 05:57:38 s01 kernel: [14972.820584] Oops: 0010 [#2] SMP
[略]
Dec 14 05:57:38 s01 kernel: [14972.836239] Fixing recursive fault but reboot is needed!
Dec 14 08:18:02 s01 kernel: [23396.544849] htb: too many events!

徹夜に近い状態で準備をしていたのであきらめてCPU16コア、メモリ196GBの仮想マシンを4台つかって、1台あたり800ホスト(コンテナ)、4台で3200ホスト(コンテナ)ということになります。

4台分の監視は普段業務で使っていて慣れているのでDatadogを使いました。 f:id:kuro_m88:20171220133022p:plain

CPUとメモリとロードアベレージとiowaitとネットワークトラフィックくらいしか監視していませんでしたが。メモリもだいぶ余裕があったのでZFSの重複排除機能をONにしていました。結果は…

ubuntu@s02:~$ sudo zpool list
NAME       SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
lxd-pool   248G  3.11G   245G         -     5%     1%  63.49x  ONLINE  -

1ホストあたり 256MB x 800ホスト ≒ 200GBのディスク容量消費で見積もっていたのですが、結果的には重複排除が63.49倍効いた結果3.11GBしか消費しませんでした。同じ環境で全員が同じようなことをするので当たり前といえば当たり前ですが、重複排除すごいですね。

CPUとメモリは検証結果からそこまで心配していなくて、ディスクとネットワークを心配していたのですが、実際ネットワークは本番競技中に一瞬ひやっとしました。とあるチームが100台同時に構築するスクリプトを回したようで、一瞬440Mbpsほど帯域を使いました。1Gbpsで張り付いたらどうしようと思っていたのですが、これ以上帯域を使うことはなく、一瞬で落ち着きました。 最終的にトラブルもなく環境を提供できたのは良い経験になりました。

出題してみてどうだったか

無事100台構築できたチームは、1チームを除き、踏み台サーバからシェルスクリプトを使ってsshをして遠隔でコマンドを投入する方式でした。プロビジョニングツールを使うほどの作業内容でもなさそう & コンテストなのでとりあえず動けばいいということでみんなシェルスクリプトかなと想像していました。

一番シンプルだった解答はこんな感じです。

export SSHPASS=password
for (( i=2; $i <= 100; i++ )); do
  target=`printf "teamxx-c%03d" $i`
  sshpass -e ssh -oStrictHostKeyChecking=no $target 'sudo apt install nginx -y && echo "{\"hostname\": \"`hostname`\"}" | sudo tee /var/www/html/hostname.json'
done

ちなみに芸術点があるのではないかという参加者の声を聞きましたが、芸術点とかはなく、機械的に全台に対してリクエストを投げて点数をモニタリングしていました。構築が終わる前に構築が終わったという報告をしてもすぐに分かる状況になっていたということです。(実際にそういうチームがあったかは触れません)常に監視して採点をしていたので、構築完了の報告を受けたらそのホストに入って手順の報告と全く違う構築方法をしていないか調べていました。

1チームだけansibleを使ってplaybookを書いてきちんとプロビジョニングをしているチームがありました。時間がない中ansibleを使ったということは普段から使い慣れていたのでしょう。素晴らしい。

感想

徹夜して急いで作成した問題にしてはいい感じの問題が出題できたのではないかと思っています。 予選なのでトップ層の点差がつかない事は気にしておらず、予選落ちするチームが勉強になる/楽しんで貰える問題を出したいなと思っていました。本戦は順位を決めるための勝負です。優秀なトラコン運営学生が問題と競技ネットワークの設計を練っているので期待です。 競技用ネットワークを設計している学生はこんなことを言っています。

f:id:kuro_m88:20171220133734p:plain

前回はCLOSトポロジやVXLAN、BGP MPLSにチャレンジしていましたね。

www.slideshare.net

今回はどんなネットワークなのでしょうか。クラウドもOpenStackを卒業して自作しているみたいですね。社会人から見ても恐ろしいです。

ということで、予選を突破したチームの皆さんは本戦で日頃の技術研鑽の結果を見せつけて下さい! 予選に落ちてしまったチームはまたの挑戦をお待ちしております!

Slackで寿司を回転させる技術

こんなツイートをしたらいいねが1000件以上ついたのでやり方を紹介します。

きっかけ

以前Slackで絵文字を回転させる方法を紹介しましたが、もっとちゃんと寿司を回転させたくなりました。

kurochan-note.hatenablog.jp

画像生成

今回もImage Magickを使います。Mac上で生成しました。

絵文字を3行3列の9個順番に並べるといい感じに回っているように見えるのですが、中心は冒頭で紹介した記事で絵文字を回転させてください。今回は中心以外の8種類の画像を生成します。

出来上がったものはこちらです。

f:id:kuro_m88:20170918183136g:plainf:id:kuro_m88:20170918183152g:plainf:id:kuro_m88:20170918183156g:plainf:id:kuro_m88:20170918183202g:plainf:id:kuro_m88:20170918183210g:plainf:id:kuro_m88:20170918183214g:plainf:id:kuro_m88:20170918183218g:plainf:id:kuro_m88:20170918183221g:plain

スクリプトはこんな感じです。最後のgifアニメ生成時の -colors 80 -fuzz 11% というオプションはSlackの絵文字のファイルサイズの64KB制限に引っかからないように画質を手でパラメータ調整した結果です。もしオーバーするようであれば値をいじってみてください。

gist.github.com

もちろん寿司以外にも使えます。いろんな絵文字を回していきましょう。寿司を静止させられるように明日から頑張ります。

DataDogの監視設定からTerraformのresourceを生成する

作ったものはこれ。

github.com

やりたいこと

TerraformのDataDog Providerを使って監視ルールをTerraformで管理したい。resource定義さえ書けば監視ルールがTerraformで管理されるようになります。 参考: Datadog: datadog_monitor - Terraform by HashiCorp

ただ、 query = "avg(last_1h):avg:aws.ec2.cpu{environment:foo,host:foo} by {host} > 2" のようなクエリを書くのは厳しいので、テンプレート化する前はDataDogのWeb UIでルールを作成したいですよね。 そこで既存の監視設定を取り込んでTerraformの設定を生成するようにしました。

Terraform importとどう違うのか

Terraformには terrafrom import という便利なコマンドがあり、既存のterraform管理されていないリソースをterraform管理下に置くことができます。しかしながら、以下の記事にも書いてあるとおり、 tfstate ファイルに状態として取り込まれるだけで、 設定を/構成を管理する tf ファイルには反映されません。

dev.classmethod.jp

使い方

詳細はREADMEに書きました。

datadog_monitor2terraform/README.md at master · kurochan/datadog_monitor2terraform · GitHub

ただのrubyスクリプトなので

$ ruby ./monitor-import.rb dynamodb_user_error_count 112233

resource "datadog_monitor" "dynamodb_user_error_count" {
  name               = "DynamoDB UserError count is above the Threshold !!"
  type               = "metric alert"
  message            = <<EOF
@slack-metric-alert DynamoDB UserError count is above the Threshold !!
EOF
  query = "sum(last_5m):sum:aws.dynamodb.user_errors{*} > 10"
  thresholds {
    warning = 5.0
    critical = 10.0
  }
  notify_no_data = false
  no_data_timeframe = 2
  renotify_interval = 0
  timeout_h = 0
  require_full_window = true
  notify_audit = false
  tags = []
}

という感じで引数にterraformで管理するリソースの名前と、DataDog上での対象のIDを指定するとTerraformのresourceが生成されます。 これで監視ルールの生成と管理が楽にできますね!

Slack用に回転するアニメーション絵文字を作れるようにしてみた

きっかけ

某Slackで回転する :thinking_face: を作っている人がいたので、汎用的に作れるようにしたかった。

f:id:kuro_m88:20170520175648g:plain

↑回転する:thinking_face:

スクリプト

ImageMagickを使ってすぐに生成できるようにしてみた。

#!/bin/bash

WORKDIR=`mktemp -d "tmp-image.XXXXXX"`

input=$1
output=$2

convert ${input} -background white -alpha deactivate -flatten ${WORKDIR}/input.png

for i in `seq -f %02g 0 23`; do
  deg=`expr $i \* 15`
  convert -rotate ${deg} ${WORKDIR}/input.png ${WORKDIR}/img-${i}.png
done

convert -layers Optimize -loop 0 -delay 4 ${WORKDIR}/img-*.png ${output}
rm -rf ${WORKDIR}

透過情報を消してから回転するようにしている。透過情報を消さずに回転すると、前のフレームが残ってしまう模様。

使い方

一つ目の引数に入力ファイル(png)、二つ目の引数に出力ファイル(gif)を指定する。二つ目の引数を .gif にしていないと生成失敗するので注意。

bash emoji_rotate.sh input.png output.gif

f:id:kuro_m88:20170520180008g:plain

↑透過情報を消さずにアニメーション生成するとこんな感じ。

スクリプトの流れとしては、15度ずつ回転させた画像を24枚生成して、それを40msごとに変化させるアニメーションGIFを書き出すようにした。