pecoでSSM start sessionの対象を選ぶ

最近踏み台サーバーをやめて、AWS SSM(System Manager)のstart-sessionでノードに入るようにしています。(そもそもノードに入ることが少ないのですが)

でも、CLIでいっぱいノードがある中で一台選ぶのが大変なので、pecoを使って接続するノードを選ぶ簡単なスクリプトを作りました。

#!/bin/bash

# fetch Inventory from SSM
INVENTORY=$(aws ssm get-inventory --output json | jq -r '.Entities[].Id' )

# select with Tag.Name by peco
EC2=$(aws ec2 describe-instances --instance-ids $INVENTORY --output json \
    --query 'Reservations[].Instances[*].{Id:InstanceId,Name:Tags[?Key==`Name`].Value}' | jq -r '.[][0] | (.Id) + "       " + (.Name[0])' | peco)

# parse instance-id
INSTANCE_ID=$(echo ${EC2} | cut -f 1 -d " ")

aws ssm start-session --target ${INSTANCE_ID}

おしまい。

AWS上のkubernetesでGPUを使う

ということで、今日は、AWS上のk8sでGPUを使ってみましょう。

事前に用意するもの

  1. kubernetes cluster (1.9.3で確認)
  2. kops (1.8.1で確認)

AMIの作成

099720109477/ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20180222 (ami-06d9a360)のイメージを使ってEC2を用意します。イメージを作るだけなのでt2.microでもいいのですが、確認のためにp2.xlargeインスタンスを用意しましょう。あ、ストレージは16GBぐらいにしておくと安全です。8GBでは足りません。

ssh ubuntu@<ip address>して、以下のスクリプトを実行します。手作業で実行したのをscript形式にしたので、そのまま実行したらこけるかもしれませんので、適宜修正してください。

注意点は dockerのバージョンです。docker-ceではk8sが対応しておらずkopsがnodeの設定をできないので、docker-engine 1.13.1を指定します。また、nvidia-docker2のバージョン指定も気をつけます。install時に"nvidia-docker2=2.0.3+docker1.13.1-1"とdockerのバージョンも含めて指定してあげる必要があります。

とはいえ、そろそろdocker-ceでも動くようにはなるので、近いうちにバージョンの問題はなくなる可能性が高いです。

#!/usr/bin/bash

sudo apt-get update && sudo apt-get install -y build-essential

# install NVIDIA driver
wget http://jp.download.nvidia.com/XFree86/Linux-x86_64/390.25/NVIDIA-Linux-x86_64-390.25.run
sudo sh NVIDIA-Linux-x86_64-390.25.run --silent

# install CUDA toolkit
wget https://developer.nvidia.com/compute/cuda/9.1/Prod/local_installers/cuda_9.1.85_387.26_linux
sudo sh cuda_9.1.85_387.26_linux --silent --toolkit --no-man-page


# install nvidia-docker and docker-engine 1.13.1
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/debian9/amd64/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update && sudo apt-get install -y \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg2 \
     software-properties-common

echo 'deb https://apt.dockerproject.org/repo ubuntu-xenial main' | sudo tee /etc/apt/sources.list.d/docker.list

sudo apt-get update
sudo apt-get install -y "docker-engine=1.13.1-0~ubuntu-xenial"
sudo apt-get install -y "nvidia-docker2=2.0.3+docker1.13.1-1" "nvidia-container-runtime=2.0.0+docker1.13.1-1"

# add `-s=overlay2` to docker
sudo sed -i -e 's/fd:\/\//fd:\/\/ -s=overlay2/g' /lib/systemd/system/docker.service

# set default docker runtime to default using nvidia runtime
sudo tee /etc/docker/daemon.json <<EOF
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
EOF

# restart
sudo pkill -SIGHUP dockerd
sudo systemctl restart docker.service

最後に

sudo docker run --rm nvidia/cuda nvidia-smi

してnvidia-dockerではなく、dockerコマンドでnvidia-smiが動くかどうか確認しましょう。確認がすんだら、docker pullされたnvidia/cudaのdocker イメージを消してAMIを作成しておきます。

GPUインスタンスの立ち上げ

準備したAMIをkops用のspec.imageに記述しつつ、kops用のresourceファイルを用意します。注意して欲しいところはspec.kubelet.featureGates.DevicePluginsを指定することです。これがないと、後のDeviceDriverがGPUを認識してくれません。

(念の為書いておくと、kops get ig nodes -oyamlすると、現在のnode設定をyamlで書き出してくれるのでそれを修正していきます)

apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: null
  labels:
    kops.k8s.io/cluster: gpu.alpaca.k8s.local
  name: gpu
spec:
  image: ami-1234569
  kubelet:
    featureGates:
      DevicePlugins: "true"
  machineType: p2.xlarge
  maxPrice: "1.0"
  maxSize: 1
  minSize: 1
  nodeLabels:
    kops.k8s.io/instancegroup: gpu
  role: Node
  subnets:
  - ap-northeast-1a

その後、

% kops create -f stg-gpu-nodes.yml
% kops update cluster gpu.alpaca.k8s.local --yes

でGPUインスタンスが立ち上がります。

DevicePluginのインストール

さて、次にKubernetesからGPUを扱うようにするために、Device Pluginを入れます。

kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.9/nvidia-device-plugin.yml

daemon set として各nodeにインストールされます。

kubectl get nodes -oyaml | grep gpuとすると、nvidia.com/gpu: "1"と出てきたら成功です。(順番は関係ないとは思いますが、もしかしたら、再度gpu-nodeを作りなおしたほうがいいのかもしれません)

使ってみる

適当なpodを立ち上げてnvidia-smiを実行してみます。

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
  namespace: stg
spec:
  nodeSelector:
    kops.k8s.io/instancegroup: gpu
  containers:
    - name: cuda-container
      image: nvidia/cuda
      resources:
        limits:
          nvidia.com/gpu: 1 # requesting 1 GPUs
      command:
        - "nvidia-smi"

無事実行できれば成功です。

参考文献

Headless ChromeをSeleniumから動かすDockerイメージ

Headless ChromeをSeleniumから動かしたいです。どうせやるならDockerで、と思って作りました。

https://github.com/shirou/selenium-headless-chrome

Docker hubはこちら

https://hub.docker.com/r/shirou/selenium-headless-chrome/

使い方

メインはinit.shです。環境変数で指定したS3_URLから任意のスクリプトをダウンロードし、python3で実行します。

実行するスクリプトはこんな感じです。スクリプトはS3に置くことを想定しています。が、原理的にはどこでもいいので、HTTPSの場合はinit.shaws cpをcurlなどに置き換えてみてください。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import

import time
import requests

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

FILE_NAME = "/tmp/search_results.png"
SLACK_TOKEN = "<SLACK BOT API TOKEN>"
SLACK_CHANNEL = "example"


def screenshot():
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-gpu')
    options.add_argument('--window-size=1920,1280')
    driver = webdriver.Chrome(chrome_options=options)

    driver.get('https://google.co.jp')

    time.sleep(5)

    driver.save_screenshot(FILE_NAME)

    driver.quit()


def upload_slack(path):
    f = {'file': open(path, 'rb')}
    payload = {
        "filename": path,
        "token": SLACK_TOKEN,
        "channels": [SLACK_CHANNEL],
        "title": "screenshot: " + path,
    }
    r = requests.post("https://slack.com/api/files.upload",
                      params=payload, files=f)
    print("slack upload: {}".format(r.text))


if __name__ == '__main__':
    screenshot()
    upload_slack(FILE_NAME)

ECSでの使い方

コンテナで実行できるので、ECSではこのようにS3_URLという環境変数を設定してタスクを実行してあげれば良いわけです。

{
   "environment": [
    {
      "name": "S3_URL",
      "value": "s3://foobar/example.py"
    }
  ],
}

弊社ではECSのスケジュール実行で、任意の時間に画面のスクリーンショットを撮ってSlackに送ったりしています。Seleniumですので、アイデア次第でどんなことも実行可能だと思います。

まとめ

  • Headless ChromeをSeleniumで実行できるDocker Imageを作りました。
  • 環境変数で外部のScriptを指定するだけです。
  • Selenium便利

prometheusをkinesis firehose経由でs3にバックアップ

AlpacaJapanのshirouです。

prometheusは長期保存用ではないため、適当な間隔で消されていきます。本来であればinfluxdbなりに保存するのでしょうが、やはり安全安心のS3に保存しておきたいところです。

手法としてS3バケットに直接書き込むなどの方法が考えられますが、S3は更新には弱いのでがんがん書き込む用途には向いていません。

そこで、2017年7月に東京リージョンに来たkinesis firehoseを使います。kinesisはstream用途ですので、がんがん書き込んでも問題ありませんし、そのデータはfirehoseで自動的にS3に保存されていきます。

ということで、prometheusのremote write機能を利用し、kinesisに送りつけるremote integrationを実装しました。

なお、まだ実稼働はしていないので、問題があるかもしれません。ご了承ください。

prometheus_remote_kinesis

https://github.com/shirou/prometheus_remote_kinesis

使い方

goでのbuildが必要ですが、割愛します。Dockerでのmulti stage buildを使うと簡単です。

$ prometheus_remote_kinesis --stream-name prometheus-backup
-stream-name kinesis stream 名(必須)
-listen-addr listenアドレス。指定しないと:9501となる。

もちろん、AWSのcredentialを設定しておきましょう。

docker hubにも置いておきました。

https://hub.docker.com/r/shirou/prometheus_remote_kinesis/

こんな感じで起動すれば良いと思います。

docker run -d --rm --name remote_kinesis \
   -p 9501:9501 \
   -e STREAM_NAME=backup-prometheus-log \
   shirou/prometheus_remote_kinesis

prometheus側の設定

prometheus.ymlremote write設定を以下のようにします。urlの前に-をつけてSequenceにすることが大事です。

remote_write:
  - url: http://localhost:9501/receive

kinesisおよびkinesis forehoseの設定は割愛します。

以上で設定は終わりです。あとは時間が立てばs3にどんどん溜まっていくはずです。

内部仕様

JSONフォーマット

kinesisに送るデータはこんな感じのJSONフォーマットにしました。

{
  "name": "scrape_duration_seconds",
  "time": 1513264725773,
  "value": 0.004345524,
  "labels": {
    "__name__": "scrape_duration_seconds",
    "instance": "localhost:9090",
    "job": "prometheus",
    "monitor": "monitor"
  }
}

prometheusのTimeseriesではひとつのmetricに対して複数のSampleが保存できるようになっています。しかし、あまり階層を増やしたくないので、flattenして、ひとつのsampleごとにひとつのrecordを作成するようにしています。labelはさすがに無理でしたのでmap上になっています。さらに、AthenaやS3SELECTからの利用も想定し、改行を付与したJSON-LDにしています。さらにgzip圧縮した状態でkinesisに送信しようとしたのですが、t2.smallではCPUを使いすぎてしまったので、外しました。そのうちなんとかしようかな、と。また、500レコードごとにまとめてPutRecordsで送信しています。バッファリングしていることになるので、死ぬと失われる可能性があります。gracefulshutdownは一応しているんですけどね。

prometheusからのwrite requestはsnappy圧縮 + protobufで来るので、そのバイト列のままkinesisに転送すると最速かもしれませんが、さすがにそれは後々の扱いが難しくなるだろうということで今回は避けておきます。

まとめ

prometheusの長期ログ保存用にAWS Kinesis経由でs3に貯めるremote storage integrationを作成しました。

実稼働はまだなので問題はあるかもしれませんが、これでS3に貯めることはできるようになりました。問題は取り出す時ですが、平易なJSON形式ですので、必要になった時にがつっと変換すればいけるのではないかな、と思います。remote readでprometheusから直接読むことも可能ですが、おそらく実用上の速度はでないのではないかと思います。

あ、AlpacaJapanではこのあたりをしてくれる人を絶賛募集中です。Twitter @r_rudiまでご連絡ください。

X1 CarbonのVirtualBoxでxubuntuを使う

転職直後に家庭内パンデミックに見まわれいろいろやばいことになってましたがようやく回復してきました。

さて、職場が変わったので、Mac Book Proを捨ててThinkpad X1 Carbonに移行しました。ここにメモを残しておきます。

参考

やはり1.18kgという軽量は素晴らしいものですね。特に運用とかやってると常に携帯しないといけないのでちょっとした重さの違いが大きく効いてきます。

買うときに気をつけるべきことは、電源を公式サイトで2つ買うことです。USB-Type Cなので他社のでもいいかなと思っていたのですがいろいろ調べるといろいろ罠があるので、素直に純正のアダプタを買ったほうが良い、ということです。

さて本題。

Windowsの初期設定記録

久しぶりにWindowsユーザーになったわけで、記録のために初期設定で何をしたか残しておきます。

  1. Google Chromeをインストール
    • edgeはgoogleを検索するためにのみ存在します。
  2. Google IME をインストール
    • Ctrl-でトグルにするには、Google IMEの「一般タブ」「キー設定」で
      • 「直接入力」「ctrl-」「IMEを有効化」
      • 「入力文字なし」「ctrl-」「IMEを無効化」
  3. ctrl2cap をインストール、実行
  4. Chocoratyをインストール

スタートメニューのカスタマイズ

設定 -> スタート設定からときどきスタート画面におすすめを表示する -> オフ

あとは邪魔な右の方のアイコンを片っ端から右クリック -> ピン留めを外す

IMEの設定

言語 -> 言語 -> 日本語 -> オプション

キーボードからMicrosoct IMEを「クリックして」削除

フォント

MacTypeをインストール。Noto Sansフォントダウンロードしてインストール。

パスワードマネージャ

keepassXCをDropboxで同期して使っています。Linux側でも使えるので便利。

VirtualBox

Windows用PC上でLinuxを使うためには

  • Dual Boot等ネイティブインストール
  • VirtualBox
  • Hyper-V

あたりがよくある話でしょうか。Dual Bootはいろいろ記事があるので今回は仮想化でVirtualBoxを使います。Hyper-Vにしようかと思ったんですが、情報があまりないのと使い慣れていないので、VirualBoxにしました。

まずはBIOS設定でsecurity -> virtualization ->Intel(R) VirtualizationTechnologyをEnableします。Securityにあるとは予想してなかったので手間取りました。

VirualBoxでGUI付きLinuxを動かす場合、ビデオメモリがネックになります。ビデオメモリに256MBを割り当てるとそこそこ快適になるのですが、普通にやると128MB以上は割り当てらません。一回ディスプレイ数を8にすると256MBまで選択できるようになるので、OKで一回保存してから再度ディスプレイ数を1に戻せば256MBのままになります。

Ubuntuもといxubuntuを入れる

DistributionにはUbuntuを選びました。Archとかでも良かったけれども、業務で使うサーバーがUbuntuなので合わせる感じで。大事なことは、Ubuntu Desktopではなく、xubunutuを選ぶということ。ubuntuそのものだと、VRAMを256MBなど割り当てても、VirtualBox上で動かすには非常に重いし、たまにブラックアウトしたりします。最初ubunutuを入れて失敗しました。

フォント

プログラミング用フォント Myricaをインストール。

emacsで確かめたい場合

(set-frame-font "MyricaM M-13")

サイズ等が決まったら、以下で設定。

(add-to-list 'default-frame-alist
                       '(font . "MyricaM M-20"))

Google ChromeというかChromium

UbuntuだとChromiumでCtrl-hが履歴になってしまうので、以下のコマンドでbackspaceに切り替える。

gsettings set org.gnome.desktop.interface gtk-key-theme "Emacs"

xubuntuの場合は以下のように。

xfconf-query -c xsettings -p /Gtk/KeyThemeName -s Emacs

python 3.6

deadsnakesで入れます。

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6
sudo apt-get install python3.6-venv


# update-alternativesでpython3を変更
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1

Go

GoのUbuntu installページにしたがって入れます。

go系ユーティリティ

goを入れて、

あたりをgo instll

zeal

Macではdashをつかっていたが、Linux上ではzealを使う。残してあるWindows上にも同じく入れる。

ちなみに、検索窓にカーソルを動かすのはCtrl-k

open

Macのようにopenでファイルを適切なアプリケーションで開いてくれるのは便利。gnomeだと、gnome-openだけど、xubuntuだとxdg-open。openにaliasしておきましょう。

問題点: 解像度

X1 carbonは 2560x1440のWQHDの解像度が出ます。会社ではLGの34 inch 曲面ディスプレイを使っていてかなり快適なのですが、ディスプレイをはずしても当然WQHDの解像度のままなのです。Windows側ではscaleを切り替えてくれるのか問題ないのですが、Linux側はそういうことはしてくれないのですね。なお、LGにはHDMIでつないだらすぐに出力されました。

VirtualBoxで解像度を落とすといいかと思ったのですが、解像度を落とすと周りに黒い枠がでるだけであまり意味がなかったです。

このあたりの知見を持っている方はいらっしゃらないでしょうか。

まさか解像度が大きすぎて問題になるとは時代は変わったものです。

まとめ

  • X1 carbonを買いました。
  • 開発用のLinuxとして、VirtualBox上でxubuntuを使うことにしました。
  • わりと問題ないですね。というか、普通にLinuxだし。
  • 解像度の問題あり。慣れっちゃ慣れですが

近況

(TODO: ここに例の画像を貼ること)

早いもので、2014年にツキノワに入社してからまる三年が経ちました。その間、MQTTやAnsibleそしてgolangなどに関するたくさんのお仕事をして、たくさんの人のお世話になりました。大変感謝しております。

ぶっちゃけ、

  • GolangによるWebサービス実装
  • Ansibleのコンサルや講師業
  • EnOcean機器のプロトコル実装やBLE制御
  • MQTTサービス Sangoの開発、運用
  • 秒間n千 x m のログの解析基盤実装
  • PHPのWebAPIをGolangでリライト
  • Reactによるフロントエンド実装
  • React-Nativeによるアプリ実装 (Android実装含む)
  • Vue.jsによるフロントエンド実装

という感じ(これでもごく一部)で、上から下までいろいろなことが経験できたのは、ツキノワのおかげです。

んで?

どういうことかというと、Alpaca Japanに9月1日から入社しました。この会社は証券会社や銀行等に対して、為替の取引シグナルを提供したりしています。詳しくはこのあたりのリリースを。

ぼくは、こんな記事を書いたように元々金融とか為替とかには興味があり、今年は機械学習をやってみたいなぁ、と思っていたところ、いろいろな縁が重なり、仕事としてやっていくことになりました。

仕事としてといいつつ、実際の機械学習については他にいい人が複数人いるので、ぼくがやることは今までの経験を活かして、

  • 計算機環境の整備・運用・監視 (必要な時に必要な量を!)
  • データ取得
  • 前処理
  • 結果保存
  • モデル評価・検証に必要なサービスの実装
  • UIや管理画面実装 (Webもネイティブも)

等々をやる予定です。つまり、機械学習エンジニアは機械学習そのものに集中してもらい、それ以外のすべてを巻き取る、というお仕事です。

ですので、機械学習エンジニアを絶賛募集中です。

ところで、以前、 uupaaさんがこんなTweetを出していました。なお、これは引用しただけで、uupaaさんはAlpacaとは関係ないです。 (当初誤解を招くような表現を書いてしまい、申し訳ありません。)


カテゴリー

r_rudi

working at AlpacaJapan

#python, #postgres, #sphinx, #golang, #freebsd