parallel で k8s の複数 pod にコマンドを「並列」で流して結果を保存する

f:id:kyagi:20180216023000p:plain

k8s の複数 pod を横断してかつ「並列」でコマンドを実行する必要がある場合、どのような手段があるだろうか。例えばパフォーマンス測定のために jstat を複数 pod で実行したい場合、以下のように kubectl に pod を次々と「直列」で渡していっては、各 pod でコマンドの実行時間のズレが生じてしまう。何よりも jstat のように標準出力(stdout)を取られてしまうコマンドを kubectl に渡した場合、ひとつひとつ Ctrl+C していかなければならず、目的を果たすことができない。

複数 pod に「直列」でコマンドを実行する例

  1. pod リストを取得する
    $ kubectl get pods -lapp=myapp -o jsonpath="{.items[*].metadata.name}" | xargs -n 1 echo
    myapp-78ccc84d99-2cr24
    myapp-78ccc84d99-2pmp7
    myapp-78ccc84d99-59f4g
    myapp-78ccc84d99-5bwkc
    myapp-78ccc84d99-5d8wc
    myapp-78ccc84d99-5fzsd
    myapp-78ccc84d99-67qkr
  2. 取得した pod リストを kubectl に渡して date コマンドを実行するものの、最初の pod と最後の pod で実行時間のズレが生じてしまう。ターミナルを pod 数分開いて「せーの」で実施すれば実行時間のズレはある程度是正できるものの、数十から数百 pod ある環境では現実的ではない。
    $ while read p; do kubectl exec -it $p -c myapp -- date; done < <(kubectl get pods -lapp=myapp -o jsonpath="{.items[*].metadata.name}" | xargs -n 1 echo)

複数 pod に「並列」でコマンドを実行する例

  1. pod リストを取得する。parallel に渡すのに適したフォーマットにする。
    $ kubectl get pods -lapp=myapp -o jsonpath="{.items[*].metadata.name}"
    myapp-78ccc84d99-2cr24 myapp-78ccc84d99-2pmp7 myapp-78ccc84d99-59f4g myapp-78ccc84d99-5bwkc myapp-78ccc84d99-5d8wc myapp-78ccc84d99-5fzsd myapp-78ccc84d99-67qkr myapp-78ccc84d99-6glcz myapp-78ccc84d99-6htmf myapp-78ccc84d99-7dchn
  2. parallel を使って並列でコマンドを流す。jstat は標準出力(stdout)に連続して出力しようとするので、ここでは標準出力を out ディレクトリ配下に吐き出すように指定する。
    $ parallel --results out kubectl exec -it {} -c myapp -- /usr/bin/jstat -gcutil -t 1 1000 ::: $(kubectl get pods -lapp=myapp -o jsonpath="{.items[*].metadata.name}")
  3. 適当に時間が経過したところで Ctrl+C で jstat を中止する。out ディレクトリ配下を確認すると pod 名のディレクトリが自動作成され、jstat の標準出力が吐き出されていることが確認できる。
    $ tree out/
    out/
    └── 1
        ├── myapp-78ccc84d99-2cr24
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-2pmp7
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-59f4g
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-5bwkc
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-5d8wc
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-5fzsd
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-67qkr
        │   ├── stderr
        │   └── stdout
        ├── myapp-78ccc84d99-6glcz
        │   ├── stderr
        │   └── stdout
        └── myapp-78ccc84d99-6htmf
            ├── stderr
            └── stdout
    $ cat out/1/myapp-78ccc84d99-*/stdout
    Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
           339412.0  36.71   0.00  33.87  85.15  97.85  96.46 112186 6009.403   232   25.555 6034.958
           339413.1  36.71   0.00  62.38  85.15  97.85  96.46 112186 6009.403   232   25.555 6034.958
           339414.1  36.71   0.00  89.70  85.15  97.85  96.46 112186 6009.403   232   25.555 6034.958
           339415.1   0.00  37.42  24.00  85.20  97.85  96.46 112187 6009.455   232   25.555 6035.011
           339416.1   0.00  37.42  61.76  85.20  97.85  96.46 112187 6009.455   232   25.555 6035.011
           339417.1   0.00  37.42  89.42  85.20  97.85  96.46 112187 6009.455   232   25.555 6035.011
    Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
           339551.1   0.00  39.96  68.38  46.40  97.99  95.55 107987 6136.845   238   49.173 6186.018
           339552.1   0.00  39.96  93.15  46.40  97.99  95.55 107987 6136.845   238   49.173 6186.018
           339553.1  44.37   0.00  32.62  46.43  97.99  95.55 107988 6136.903   238   49.173 6186.075
           339554.1  44.37   0.00  88.96  46.43  97.99  95.55 107988 6136.903   238   49.173 6186.075
           339555.1   0.00  41.82  17.52  46.49  97.99  95.55 107989 6136.963   238   49.173 6186.135
           339556.1   0.00  41.82  64.14  46.49  97.99  95.55 107989 6136.963   238   49.173 6186.135
           339557.1  39.57   0.00   4.16  46.59  97.99  95.55 107990 6137.027   238   49.173 6186.200
    Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
           339522.0   0.00  35.20  92.33  45.48  97.82  96.47 112235 6360.675   236   25.843 6386.519
           339523.0  37.73   0.00  34.98  45.53  97.82  96.47 112236 6360.728   236   25.843 6386.572
           339524.0  37.73   0.00  79.99  45.53  97.82  96.47 112236 6360.728   236   25.843 6386.572
           339525.0   0.00  36.40  20.69  45.58  97.82  96.47 112237 6360.781   236   25.843 6386.624
           339526.0   0.00  36.40  64.99  45.58  97.82  96.47 112237 6360.781   236   25.843 6386.624
           339527.0  35.51   0.00  10.36  45.64  97.82  96.47 112238 6360.835   236   25.843 6386.678
           339528.0  35.51   0.00  55.57  45.64  97.82  96.47 112238 6360.835   236   25.843 6386.678
    Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
           339454.0  38.18   0.00  38.61  44.10  97.78  95.53 114078 6133.794   236   23.938 6157.731
           339455.1  38.18   0.00  82.87  44.10  97.78  95.53 114078 6133.794   236   23.938 6157.731
           339456.1   0.00  41.97  17.91  44.16  97.78  95.53 114079 6133.854   236   23.938 6157.792
           339457.1   0.00  41.97  51.55  44.16  97.78  95.53 114079 6133.854   236   23.938 6157.792
           339458.1   0.00  41.97  82.24  44.16  97.78  95.53 114079 6133.854   236   23.938 6157.792
    (... snip ...)

kubectl と parallel の組み合わせは相性がよいので組み合わせでいろいろなことができそう。(๑•̀ㅂ•́)و✧

※なお、複数 pod を横断してログを tail するには stern という素晴らしいツールがある。