2019年1月31日木曜日

kubeless 超入門

概要

kubelsss は k8s 上でサーバレスアーキテクチャを実現できるツールです
今回は minikube を使って kubeless に入門してみました

環境

  • macOS 10.14.2
  • minikube v0.28.2
  • kubeless 1.0.1

minikube 起動

minikube の環境は構築済みを想定しています
minikube に関してはこちらの記事を参照してください

  • minikube start

うまく起動しない場合は一旦キャッシュを削除してイメージの再取得から行ってください

  • rm -rf ~/.minikube

kubeless インストール

今回は homebrew を使ってインストールしました
公式だと Github から zip をダウンロードしてそこに含まれるバイナリを PATH に通す手順になっています
その手順でも全然 OK です

  • brew install kubeless

リソースファイルの取得

YAML ファイルなどが含まれている zip ファイルをダウンロードしておきます
ちなみにこの中に kubeless のバイナリファイルも含まれています

  • wget https://github.com/kubeless/kubeless/archive/v1.0.1.zip
  • unzip v1.0.1.zip

namespace 作成

  • kubectl create ns kubeless
  • kubectl get ns
NAME          STATUS   AGE
default       Active   1h
kube-public   Active   1h
kube-system   Active   1h
kubeless      Active   6s

kubeless 環境のデプロイ

k8s 上に kubelss を実行するために必要なコンテナをデプロイしていきます

  • kubectl create -f https://github.com/kubeless/kubeless/releases/download/v1.0.1/kubeless-v1.0.1.yaml
configmap/kubeless-config created
deployment.apps/kubeless-controller-manager created
serviceaccount/controller-acct created
clusterrole.rbac.authorization.k8s.io/kubeless-controller-deployer created
clusterrolebinding.rbac.authorization.k8s.io/kubeless-controller-deployer created
customresourcedefinition.apiextensions.k8s.io/functions.kubeless.io created
customresourcedefinition.apiextensions.k8s.io/httptriggers.kubeless.io created
customresourcedefinition.apiextensions.k8s.io/cronjobtriggers.kubeless.io created

いろいろなコンポーネントが作成されています
デプロイされたら pods を確認してみます

  • kubectl get all --namespace kubeless
NAME                                               READY   STATUS    RESTARTS   AGE
pod/kubeless-controller-manager-568b578f78-vkgd5   3/3     Running   0          4m

NAME                                          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kubeless-controller-manager   1         1         1            1           4m

NAME                                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/kubeless-controller-manager-568b578f78   1         1         1       4m

deployment, replicaSet, pod がデプロイされています
またそれ以外では configmap もデプロイされています

  • kubectl get configmap --namespace kubeless
NAME              DATA   AGE
kubeless-config   10     8m

dashboard で確認しても良いと思います

関数を作成、デプロイ

とりあえずサンプルにある通り素直に python でやってみたいと思います

  • vim city-bikes.py
import urllib2
import json

def find(event, context):
    term = event["data"]["term"]
    url = "https://feeds.capitalbikeshare.com/stations/stations.json"
    response = urllib2.urlopen(url)
    stations = json.loads(response.read())

    hits = []

    for station in stations["stationBeanList"]:
        if station["stAddress1"].find(term) > -1:
            hits.append(station)

    return json.dumps(hits)

サンプルをそのまま使っています
一部修正しています (引数を event と context の 2 つに修正しています)
JSON を取得してそれを出力しています
この関数を kubeless deploy コマンドでデプロイします

  • kubeless function deploy bikesearch --runtime python2.7 --handler city-bikes.find --from-file city-bikes.py
INFO[0000] Deploying function...                        
INFO[0000] Function bikesearch submitted for deployment 
INFO[0000] Check the deployment status executing 'kubeless function ls bikesearch' 

--runtimepython2.7 を使います
--handler は実行する関数のメソッドを指定します
今回は city-bikes.py の find というメソッドを登録しています
function ls サブコマンドで確認できます

  • kubeless function ls
NAME            NAMESPACE       HANDLER         RUNTIME         DEPENDENCIES    STATUS   
bikesearch      default         city-bikes.find python2.7                       1/1 READY

pods としても動作しているのが確認できます
namespace は default でデプロイされるようです

  • kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
bikesearch-fcb99cd8-5mvdl   1/1     Running   0          3m

http trigger を作成

関数を http 経由で実行してみましょう
minikube の場合 ingress アドオンを有効にする必要があります

  • minikube addons enable ingress

少し時間がかかるので待ちましょう

  • kubectl get pod -n kube-system -l app=nginx-ingress-controller
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-5984b97644-4v86w   1/1     Running   0          1m

Running になれば OK です
ではトリガー「http」を作成します

  • kubeless trigger http create bikesearch-trigger --function-name bikesearch
INFO[0000] HTTP trigger bikesearch-trigger created in namespace default successfully! 

function 同様に ls コマンドがあるのでこれで確認しましょう

  • kubeless trigger http ls
NAME                    NAMESPACE       FUNCTION NAME
bikesearch-trigger      default         bikesearch

関数実行

では関数を実行してみます
ingress が新たに作成されているので確認してみます

  • kubectl get ing
NAME                 HOSTS                              ADDRESS     PORTS   AGE
bikesearch-trigger   bikesearch.192.168.99.100.nip.io   10.0.2.15   80      1m

このエンドポイントに対して curl でコールしてみます

  • curl --data '{"term":"Eastern"}' -H "Host: bikesearch.192.168.99.100.nip.io" -H "Content-Type:application/json" 192.168.99.100

minikube の ingress 場合 VirtualHost で振り分けを行っているため Host の指定を忘れないようにしましょう
これで JSON の結果が返ってくれば OK です
ちなみに関数の挙動を確認するのにはログを見るのが良いと思います

  • kubeless function logs -f bikesearch

Ruby でもやってみる

kubeless は runtime に Ruby (ruby2.3, ruby2.4, ruby2.5) もサポートしています
今度は Ruby の関数を試してみたいと思います

  • touch handler.rb
  • vim handler.rb
require 'json'

def handle(event, context)
  {body: event[:data]["body"]}.to_json
end

関数をデプロイして

  • kubeless function deploy rfunc --runtime ruby2.5 --handler handler.handle --from-file handler.rb

http トリガーを関数に紐づけして

  • kubeless trigger http create rfunc-trigger --function-name rfunc

コールします

  • curl -v --data "hoge" -H "Host: rfunc.192.168.99.100.nip.io" -H "Content-Type:application/json" 192.168.99.100

{"body":"hoge"} こんな感じです
関数のレスポンスが JSON でない場合はエラーになりました

Rubygems を使っている場合

例えば以下のような場合は

  • vim Gemfile
gem "slack-ruby-client"
  • vim handler.rb
require 'json'
require 'slack-ruby-client'

def handle(event, context)
  {body: 'ok'}.to_json
end

デプロイ時に --dependencies を付与することで対応できます

  • kubeless function deploy rfunc --runtime ruby2.5 --handler handler.handle --from-file handler.rb --dependencies Gemfile

内部的には bundle install が走っているので pod の起動には少し時間がかかります
あとは同じです

  • kubeless trigger http create rfunc-trigger --function-name rfunc
  • curl -v -H "Host: rfunc.192.168.99.100.nip.io" 192.168.99.100

Tips

関数削除

  • kubeless function delete bikesearch

最後に

minikube で kubeless に入門してみました
関数は AWS lambda と同様に書けます (おそらく使い回すこともできると思います)
仕組み的にも lambda に近いので lambda に慣れている人は導入障壁は低いと思います
k8s の仕組みを知らなくても何とかなりそうですが kubectl を使ったオペレーションも若干発生するので覚えておいて損はないと思います

runtime は今回 python2.7 と ruby2.5 を使いましたが他にも JVM や Golang も使えます

また今回は公式のチュートリアルを元に進めましたがかなり情報が古いのでそのままだと動きません
Github にあるドキュメントがかなり充実しているのでそちらを見ながら進めると良いと思います

参考サイト

2019年1月30日水曜日

AWS lambda を curl で実行する

概要

lambda にはトリガー機能があり様々なトリガーを元に lambda を実行することができます
今回は curl でエンドポイントにアクセスして lambda を実行してみたいと思います

環境

  • AWS lambda 2019/01/25 時点
  • Ruby 2.5

API Gateway の作成

まずはトリガーとなる API Gateway を関数に紐づけます
関数を選択して左メニューのトリガー一覧から「API Gateway」を選択します

すると下に設定画面が開くので必要な情報を入力します

ポイントはセキュリティの部分です
今回は「API キー使用でのオープン」にしました
リクエストヘッダに API をコールするためのキーを指定することで実行することができます
設定できたら「追加」して関数の設定を「保存」しましょう

API Gateway のトリガーが作成できると以下のようになります

curl を叩く

あとはこのエンドポイントに対して curl するだけです

  • curl -H 'x-api-key: SUxNxpRcYiadKY1juNSiz5XraV9T2EVa608tKmIl' https://7xt0qcg5ya.execute-api.ap-southeast-2.amazonaws.com/default/layers_test_func

リクエストヘッダに x-api-key を指定するだけです
関数のログ (Cloud Watch) を確認するとちゃんと関数が実行されているのが確認できると思います

トラブルシューティング

API Gateway からのレスポンスが 502 {"message": "Internal server error"} で返ってくる場合は lambda のレスポンスがちゃんと JSON になっているか確認しましょう

require 'json'

def lambda_handler(event:, context:)
    { "statusCode": 200, "body": "hello" }
end

こんな感じのレスポンスにすればちゃんと curl のレスポンスも 200 になります

最後に

API Gateway と lambda を組み合わせて lambda 関数を curl で実行できるようにしてみました
lambda にトリガーを設定するだけなのでかなり簡単に実現できます

lambda のトリガーには他にもいろいろなトリガーがあります

2019年1月29日火曜日

AWS lambda の Layers 機能を試す (Ruby 編)

概要

AWS lambda の layers は共有で使えるライブラリの機能です
関数で参照する共通処理をライブラリに登録しておくことでコードの記述量を減らすことができます
今回は Ruby を使った簡単な layers の使い方を紹介します

環境

  • AWS lambda 2019/01/25 時点
  • Ruby 2.5

簡単なレイヤー作成

まずはレイヤーを作成します
ローカルで準備します

  • mkdir -p ruby/lib/
  • touch ruby/lib/my_func.rb
  • vim ruby/lib/my_func.rb
def str_now
  Time.now.strftime("%Y/%m/%d %H:%M:%S")
end
  • zip -r my_ruby_gems.zip ./ruby/

ここで作成した zip をレイヤーとしてアップロードします

レイヤーを作成すると以下のようになります

アップロードできたら関数からレイヤーが参照できるようにレイヤーを追加します

レイヤーを使う関数を準備

あとは lambda に普通に関数を記述しましょう
今回レイヤーをデプロイしたパスは ruby/lib/ になります
この配下は lambda 上ですでに RUBY_LIB に登録されているのでファイル名だけで require することができます (フルパスで参照しなくて OK)

require 'json'
require 'my_func'

def lambda_handler(event:, context:)
    p str_now
end

テスト

あとはイベントを作成して実行してみましょう
以下のようにレイヤーに登録したライブラリを参照することができると思います

gem を使ったレイヤーを作成

lambda 上の関数で gem を使う場合に SAM を使った方法を紹介しました
その方法ではなくレイヤーに使いたい gem を登録することで lambda から gem を参照することもできます

まずローカルで準備します

  • mkdir -p ruby
  • bundle init
  • vim Gemfile
gem "aws-sdk"
  • bundle install --path=.

これで ruby/2.5.0/gems 配下に gem が配置されます
あとはこれを zip にして再度レイヤーとして登録します

  • zip -r my_ruby_gems.zip ./ruby/

今回は同じレイヤーにバージョン2 として登録しました
別のレイヤーとして登録しても OK です

バージョン2 のレイヤーを関数から参照しましょう
(同一レイヤーの別バージョンは参照できないかもしれません、、、エラーになる場合は最新のバージョンだけ参照するようにしてください、もしくは別レイヤーを作成して参照してください)

GEM_PATH の修正

lambda のデフォルトだと gem は /opt/ruby/gems/2.5.0 のパスを参照しています
今回は /opt/ruby/2.5.0 なのでこれを追加します

関数修正

今回はテストなのでとりあえず gem が参照できるかだけ確認します

require 'json'

def lambda_handler(event:, context:)
    p require 'aws-sdk'
end

テスト

イベントを適当に作成して実行しましょう
true になれば OK です

Tips

デフォルトだと lambda の実行時間は 3 秒以内でなければなりません
もしタイムアウトでエラーになる場合は設定を変更できるので少し伸ばしてあげましょう

最後に

lambda の Layers 機能を Ruby で試してみました
基本はライブラリ化したコードを zip にして lambda にアップロードすれば OK です

GEM_PATH を上書きして自分で追加した gem を lambda 上で参照する方法も紹介しました
gem を参照した共通ライブラリを作成する場合は gem は GEM_PATH に配置してそこを参照するライブラリを ruby/lib に配置する感じがベストプラクティスかなと思います
ローカルの環境と lambda 上の環境を合わせるのが少し大変そうですが bundler や rake を使ってうまくタスク化すれば何とかなると思います

参考サイト

2019年1月28日月曜日

KVM 入門

概要

Ubuntu 16.04 上で KVM を試してみました
インストール方法から CentOS のイメージで VM を作成するところまでやってみました

環境

  • Ubuntu 16.04
  • libvirt 1.3.1-1ubuntu10.24

KVM インストール

  • sudo apt -y install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils virtinst
  • systemctl status libvirt-bin

ステータスがアクティブになっていれば OK です
また kvm-ok コマンドで

CentOS7 VM 起動

ISO ファイルを取得してそこから qemu で動作するイメージを作成して VM を起動します

イメージ作成

qemu-img コマンドを使ってイメージを作成します

  • wget 'http://ftp.riken.jp/Linux/centos/7.6.1810/isos/x86_64/CentOS-7-x86_64-Minimal-1810.iso'
  • cd /var/lib/libvirt/images
  • sudo qemu-img create -f qcow2 centos7.qcow2 10G

VM 起動

virt-install コマンドで VM を作成、起動します
少し長いので区切っています
1 行で実行しても OK です

sudo virt-install \
  --name centos7.qcow2 \
  --disk path=/var/lib/libvirt/images/centos7.qcow2,size=10 \
  --vcpus 1 \
  --ram 512 \
  --os-type linux \
  --graphics none \
  --console pty,target_type=serial \
  --network bridge:virbr0 \
  --location '/home/user_name/CentOS-7-x86_64-Minimal-1810.iso' \
  --extra-args 'console=ttyS0,115200n8 serial'

コンソールへの接続はシリアル通信を使います (最後の 1 行)

CentOS7 のインストール

起動するとまずは CentOS7 のインストールが始まります
今回の場合、インストールイメージから VM を作成したのでそうなります
すでに OS インストール済みの qemu イメージを作成すればこの作業は不要になります

今回はターミナルで virt-install から起動しているので CUI 環境で進めます
ISO からインストーラが起動すると以下のような画面になります

ここで表示されているのはインストール時に設定が必要な項目になります
「!」になっている部分は設定が必須になるので数字を入力して設定を進めます
例えば「2」を押すとタイムゾーンの設定になります
設定方法も必要な数字を押して「c」で次の設定へみたいな感じで CUI 上だけで進めることができます
あとは root パスワードやインストールディスクの設定をすれば OK です
すべてが「x」になったら「b」でインストールを開始することができます

ログイン

30 分ほどするとインストールが完了します
今回はシリアル接続で VM との通信を行います
インストールが完了すると以下の画面になるので設定した ID/PW でログインできるか確認してみましょう

VM 停止、削除

CentOS7 上で shutdown コマンドを実行しても OK です
virsh を使う場合は以下の通りです

  • virsh shutdown centos7.qcow2

or

  • virsh destory centos7.qcow2

shutdown で停止できない場合は destory してください
停止できたら削除します

  • virsh undefine centos7.qcow2

list コマンドで表示されなければ削除が完了しています

  • virtsh list --all

ネットワーク設定

実は上記の方法で起動すると外部のネットワークに通信することができません
KVM のプロセス (libvirtd) が自動で作成してくれている NAT 用のネットワークがあります
それを VM にアタッチすることで外部通信できるようになります

  • sudo virsh attach-interface centos7.qcow2 network default

これで ping 8.8.8.8 などを実行すると VM -> ホストマシンを経由して外部に接続できます
当然ですがホストマシン自体が外部に接続できる必要はあります

最後に

KVM に入門してみました
いわゆる仮想化ソフト (ハイパーバイザ) なので VirtualBox や VMware と同じように使えると思います
今回は CUI ベースで進めましたがデスクトップ Ubuntu にすれば virt-manager を使って GUI で VM の作成や削除を行うことがもできます

Windows や Mac を使っている環境で仮想化するのに LVM は使わないと思いますが、Linux を使っているのであればありかなと思います

大規模に KVM を利用する場合は OpenStack と組み合わせて使うと良いと思います
OpenStack も過去に構築しているので興味があれば見てください

参考サイト

2019年1月25日金曜日

AWS lambda 超入門 (Ruby 編)

概要

今更ながら AWS lambda に入門してみました
Ruby が動かせるようになっているので Ruby を使っています

環境

  • AWS lambda 2019/01/25 時点
  • Ruby 2.5

Hello World

まずは Hello World を出力してみます
lambda は何かしらのイベントをトリガーにして作成した関数を実行することができます

なのでまずは関数を作成します
UI 的には作成するための導線がたくさんあるので以下からでなくても OK えす
lambda1.png

「1 から作成」で必要な内容を入力していきます

  • 名前・・・hello_world_func
  • ランタイム・・・Ruby 2.5
  • ロール・・・「1 つ以上のテンプレートから新しいロールを作成します。」 
  • ロール名・・・hello_world_func_role
  • ポリシーテンプレート・・・「Amazon S3 オブジェクトの読み取り専用アクセス権限」

lambda2.png

ロールは作成した関数がどのリソースにアクセス可能なのかを指定します
とりあえず S3 にしておきます
問題なければ「関数の作成」を選択します

関数が作成されるとすでに Ruby のコードがあることがわかります
これを実行してみましょう
lambda3.png

「テスト」を選択します
するとイベントを作成する画面になると思います
冒頭に述べましたが lambda は何かしらのイベントを元にコードが実行されます
lambda4.png

上記のスクリーンショット上にはありませんが下の方に「作成」があるのでこれでテストイベントを作成します
イベントを作成したら「テスト」を再度押しましょう
これでイベントから関数が実行され結果が画面上に表示されます
lambda5.png

これが lambda の超基本的な流れと操作方法になります
あとはイベントや関数をカスタマイズしていく感じです

Rubygems と連携してみる

Ruby を使っているなら Rubygems で公開されているライブラリを lambda でも使いたくなります
結論から言うと使うことは可能ですが、先程とは違いかなりやり方が変わります

ローカルで環境を作成する

まずはローカルで環境と関数を作成します
適当に作業用のディレクトリを作成して移動しましょう

  • bundle init
  • vim Gemfile
gem "aws-sdk"
  • bundle install --deployment

今回は S3 にアクセスして指定のバケット配下にあるオブジェクトの一覧を取得したいと思います
事前に S3 にアクセスできるユーザの作成とバケットの作成を行っておきましょう
今回は「アジアパシフィック (シドニー) (ap-southeast-2)」に作成しました
lambda6.png

これらを取得するスクリプトを作成します

  • vim s3_test.rb
require 'aws-sdk'

$client = Aws::S3::Client.new(
  :region => 'ap-southeast-2',
  :access_key_id => 'xxxxxxxxx',
  :secret_access_key => 'xxxxxxxxxxx',
)

def list_objects(event:, context:)
  $client.list_objects(:bucket => 'lambda-test-12345').contents.map do |object|
    {:key => object.key }
  end
end

# p list_objects(event: nil, context: nil)

list_objects をコールして、一度ローカルで動作するか確認すると良いと思います
event および context の引数は必須になります
使わなくても宣言時には指定しましょう
また 2 つはイベント発生時に指定した JSON 情報になります
Ruby 内ではハッシュとして扱えるのでイベントから値を取得する場合などに参照してましょう

AWS SAM を使って関数を登録する

AWS SAM は Serverless Application Model の略でサーバレスアプリを YAML で記述することができるツールです
Cloud Formation の拡張で Cloud Formation と同じように定義します

sam コマンドのインストール

まず SAM コマンドをインストールします
awscli に依存しているので awscli もインストールします

  • brew install awscli
  • brew tap aws/tap
  • brew install aws-sam-cli

aws configure コマンドを使って初期化しましょう

sam テンプレートファイルの作成

次に今回の lambda 用の SAM テンプレートファイルを作成します

  • vim template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'sample s3 access ruby application'

Resources:
  S3TestFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: s3_test.list_objects
      Runtime: ruby2.5
      Policies:
      - S3ReadPolicy:
          BucketName: lambda-test-12345

Outputs:
  S3TestFunction:
    Description: Objects list
    Value:
      Fn::GetAtt:
      - S3TestFunction
      - Arn

Policies は SAM 用に定義されています
ここ に指定可能なポリシーの一覧を確認することができます
またポリシーを YAML で使うサンプルもあります
Outputs で指定している Fn::GetAtt では他の属性も指定できます
ここに指定可能な属性の一覧があります

S3 に関数を配置

このテンプレートファイルを使って一旦 S3 にローカルで作成したスクリプトを配置します

  • sam package --template-file template.yaml --output-template-file packaged-template.yaml --s3-bucket lambda-test-12345

lambda7.png

こんな感じでローカルで作成したスクリプトとライブラリが S3 にアップロードされています
今回はバケットは 1 つで行っていますがリソースファイルを配置するバケットと関数を配置するバケットは別でも問題ないです

関数を登録する 

そしてローカルに packaged-template.yaml という新しいテンプレートが作成されています
これを使って lambda に関数を登録します

  • sam deploy --template-file packaged-template.yaml --stack-name s3Test --capabilities CAPABILITY_IAM

以下のようになれば関数の登録が完了しています

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - s3Test

コンソールで確認してみましょう
lambda8.png

実行

あとは先程同様テスト用のイベントを作成して実行してみましょう
以下のようにちゃんとオブジェクトの一覧が取得できるのが確認できるはずです
lambda9.png

ちなみに関数を削除した場合は Cloud Formation 側に Stack も残っているのでそれも削除しましょう

Sinatra アプリをデプロイする

サンプルに API Gateway と lambda を連携して API サーバを構築する方法もあったのでやってみました
template.yaml などはすでにあるサンプルを使っています
AWS::Serverless::Api などが定義されているので興味があれば確認してみてください

  • git clone https://github.com/aws-samples/serverless-sinatra-sample.git
  • cd serverless-sinatra-sample
  • bundle install --deployment
  • sam package --template-file template.yaml --output-template-file packaged-template.yaml --s3-bucket lambda-test-12345
  • sam deploy --template-file packaged-template.yaml --stack-name LambdaSinatra --capabilities CAPABILITY_IAM

これで関数がデプロイされます
lambda10.png

左メニューからアプリケーションを選択すると API Gateway などの他のリソースの情報が確認できます
lambda11.png

API エンドポイントにアクセスすると Sinatra アプリが表示されます
/Prod/feedback でフィードバックアプリが /Prod/hello-world{"Output":"Hello World!"} という JSON が返ってきます

ちなみに SinatraApp 関数のログは CloudWatch に自動的に格納されています
lambda12.png

最後に

Ruby で AWS lambda に入門してみました
Rubygems を使う場合には一旦 S3 に関数を配置し SAM (Serverless Application Model) を使うことで関数を登録することができました

AWS の他のリソース (API Gateway や DynamoDB など) と連携する場合は SAM が必須なので実際のユースケースを考えると SAM の習得も必須かなと思います

参考サイト

2019年1月21日月曜日

firecracker 超入門

概要

firecracker は Amazon がオープンソースで開発しているサーバレスアーキテクチャを実現するための軽量 VM です
firecracker 上で動作する microVM を使ってサーバレスアーキテクチャを実現します
今回は firecracker のインストールから microVM の起動まで試してみました

環境設定

  • Ubuntu 16.04.2 LTS (kernel 4.4.0-62-generic)
  • libvirt 1.3.1-1ubuntu10.24
  • firecracker 0.13.0

VM 設定変更

今回は Ubuntu16.04 上に KVM をインストールして KVM を使って firecracker を動作させます
本来であれば物理サーバ上にインストールした Ubuntu が必要なのですが、なかったので ESXi 上に構築した Ubuntu を使いました
仮想化の上に仮想化環境を構築するので Nested Virtulazation の設定が必要になります
ESXi であれば作成した Ubuntu の VM の設定から「Expose hardware assisted virtualization to the guest」のチェックをオンにすれば OK です
この設定は VM が停止している状態でないとできないのでご注意ください
firecracker1.png

KVM インストール

まずは KVM をインストールします
すでに KVM が動作する環境がある方は飛ばしてもらって OK です

  • sudo apt -y install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
  • sudo setfacl -m u:${USER}:rw /dev/kvm
  • grep -c '(vmx|svm)' /proc/cpuinfo

0 以上になっていることを確認しましょう

  • kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

最終的に kvm-ok の結果が上記のようになっていれば OK です

firecracker インストール

firecracker は Github 上でバイナリで配布されています
ダウンロードして PATH 上に配置すれば完了です
バージョンの部分は適宜変更して最新版をインストールしてください

  • curl -LOJ https://github.com/firecracker-microvm/firecracker/releases/download/v0.13.0/firecracker-v0.13.0
  • `mv firecracker-v0.13.0 firecracker
  • chmod +x firecracker
  • sudo mv firecracker /usr/local/bin/
  • firecracker --version

firecracker API 起動

それでは起動してみましょう
firecracker は socket 通信を使って API サーバを起動させることで使えるようになります

  • rm -f /tmp/firecracker.socket
  • firecracker --api-sock /tmp/firecracker.socket

microVM 起動

API サーバが起動したらコールしてみます
作成された socker ファイルを使って API サーバと通信します
その前に firecracker で microVM を起動するのに必要なイメージファイルとディスクファイルをダウンロードします
Getting started 用のイメージファイルとディスクファイルがすでに準備されているのでそれを使います (中身は Alpine Linux)

  • curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin
  • curl -fsSL -o hello-rootfs.ext4 https://s3.amazonaws.com/spec.ccfc.min/img/hello/fsfiles/hello-rootfs.ext4

これを使って API をコールします
まずはイメージを使って boot-source を作成します

curl --unix-socket /tmp/firecracker.socket -i \
-X PUT 'http://localhost/boot-source' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
  "kernel_image_path": "./hello-vmlinux.bin",
  "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
}'

次にディスクファイルを使って rootfs を作成します

curl --unix-socket /tmp/firecracker.socket -i \
-X PUT 'http://localhost/drives/rootfs' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
  "drive_id": "rootfs",
  "path_on_host": "./hello-rootfs.ext4",
  "is_root_device": true,
  "is_read_only": false
}'

最後にマシンのスペックを決定します
CPU およびメモリサイズを指定します

curl --unix-socket /tmp/firecracker.socket -i \
-X PUT 'http://localhost/machine-config' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
  "vcpu_count": 1,
  "mem_size_mib": 512
}'

あとは InstanceStart アクションを使って microVM を起動するだけです
さらっとやっていますが firecracker はこんな感じで REST API を使って microVM を操作します

curl --unix-socket /tmp/firecracker.socket -i \
-X PUT 'http://localhost/actions' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
  "action_type": "InstanceStart"
}'

各 API のレスポンスですが基本 204 No Content が返ってきました
何もしていないかと思うくらいレスポンスが早いですが大丈夫です
InstanceStart すると firecracker API を動作させていたターミナルでログインプロンプトが動作します
root/root で microVM の Alpine Linux にログインすることができます
firecracker2.png

作成した各リソースは以下のように GET をコールすることで取得できます (以下は machine-config を取得しています)

curl -s --unix-socket /tmp/firecracker.socket  \
-X GET 'http://localhost/machine-config' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json'

microVM 停止

これがよくわかりませんでした
API でできるらしいのですがやり方がわからず断念しました
InstanceStop というアクションがあるかなーと思いコールしてみたのですがそんなアクションはないと言ってエラーとなりました
テストだったので自分は firecracker のプロセスを kill して socker ファイルを削除することで microVM も停止しました

firectl という専用の CLI があるのでこれでできないかなーと思ったのですがコマンドがなくダメでした

最後に

KVM 上で firecracker を試してみました
KVM 環境があればサクッと試すことはできるようです
同じレイヤーのソフトウェアとしては Virtualbox や VMware Fusion などがあります
特徴としては高速かつセキュアに軽量な VM が起動できる点かなと思います

firecracker は起動したい microVM ごとに firecracker プロセスを起動させます
そしてアクセスする場合にはそれぞれのプロセスごとに作成された socker ファイルを使うので microVM ごとにサンドボックスになっているのでセキュアなのかなと思います

これからの成長と具体的なユースケースの登場に期待かなと思います

参考サイト

2019年1月19日土曜日

ダーツライブ 200s キーボードマップ一覧

ハックする際にご利用ください
(もしかすると個体差があるかもしれません)

200s_keyboard_map.png

英字小文字

  • a・・・double12
  • b・・・triple19
  • c・・・isingle2
  • d・・・osingle13
  • e・・・osingle18
  • f・・・triple12
  • g・・・osingle1
  • h・・・osingle8
  • i・・・osingle9
  • j・・・osingle4
  • k・・・osingle3
  • l・・・doubleBull
  • m・・・double3
  • n・・・isingle6
  • o・・・isingle13
  • p・・・double17
  • q・・・isingle5
  • r・・・triple9
  • s・・・double9
  • t・・・double4

英字大文字

  • A・・・osingle10
  • B・・・osingle6
  • C・・・isingle11
  • D・・・double10
  • E・・・triple20
  • F・・・osingle14
  • G・・・isingle4
  • H・・・isingle20
  • I・・・double16
  • J・・・triple2
  • K・・・triple4
  • L・・・osingle17
  • M・・・isingle8
  • N・・・triple1
  • O・・・double2
  • P・・・osingle15
  • Q・・・triple10
  • R・・・isingle7
  • S・・・triple8
  • T・・・isingle1
  • U・・・osingle16
  • V・・・isingle14
  • W・・・double8
  • X・・・triple17
  • Y・・・isingle17
  • Z・・・triple7

数字

  • 1・・・double1
  • 2・・・osingle12
  • 3・・・isingle16
  • 4・・・double14
  • 5・・・triple18
  • 6・・・double5
  • 7・・・triple13
  • 8・・・osingle19
  • 9・・・triple15
  • 0・・・osingle11

記号

  • - (ハイフン) ・・・double18
  • = (イコール) ・・・osingle2
  • [ (レフトスクエアブラケット) ・・・triple5
  • ] (ライトスクエアブラケット) ・・・double19
  • \ (バックスラッシュ) ・・・triple14
  • ; (セミコロン) ・・・triple11
  • ' (シングルクオート) ・・・double13
  • , (コロン) ・・・osingle7
  • . (ピリオド) ・・・triple16
  • / (シュラッシュ) ・・・double15
  • ! (エクスクラメーションマーク) ・・・isingle18
  • @ (アットマーク) ・・・double11
  • # (シャープ) ・・・double20
  • $ (ダラー) ・・・osingle20
  • % (パーセント) ・・・isingle19
  • ^ (キャレット) ・・・isingle9
  • & (アンド) ・・・double6
  • * (アスタリスク) ・・・double7
  • ( (レフトパーレン) ・・・singleBull
  • _ (アンダースコア) ・・・triple6
  • + (プラス) ・・・isingle15
  • : (コロン) ・・・osingle5
  • " (ダブルクオート) ・・・isingle3
  • < (レフトアングルブラケット) ・・・triple3(sender:))),
  • > (ライトアングルブラケット) ・・・isingle10(sender:))),
  • ? (クエスチョンマーク) ・・・isingle12(sender:))),

エスケープ文字

  • \r (キャリッジリターン) ・・・change
  • \t (タブ) ・・・start

2019年1月18日金曜日

fastlane 入門 (スクリーンショットを自動で取得してみる)

概要

fastlane は iOS/Android 用に作られたワークフローツールです
アプリのビルドからリリースまでを一貫して行えます
今回はインストールと簡単な動作確認を行ってみました

環境

  • macOS 10.14.2
  • fastlane

fastlane インストール

  • brew cask install fastlane
  • export PATH="$HOME/.fastlane/bin:$PATH"

他にも rubygems でインストールしたり xcode-select でもインストールできます
お好きな方法でインストールしてください
brew インストールの場合は PATH に fastlane コマンドを追加します

初期化

  • cd /path/to/project
  • fastlane init

で対話式の初期化が始まります
今回はスクリーンショットを自動で取得するレーンを作成しました
以下はログです

[11:27:24]: Created new folder './fastlane'.
[11:27:24]: Detected an iOS/macOS project in the current directory: 'ios-200s-games.xcodeproj'
[11:27:24]: -----------------------------
[11:27:24]: --- Welcome to fastlane  ---
[11:27:24]: -----------------------------
[11:27:24]: fastlane can help you with all kinds of automation for your mobile app
[11:27:24]: We recommend automating one task first, and then gradually automating more over time
[11:27:24]: What would you like to use fastlane for?
1. Automate screenshots
2. Automate beta distribution to TestFlight
3. Automate App Store distribution
4. Manual setup - manually setup your project to automate your tasks
?  1
[11:27:32]: -------------------------------------------------------                                                            
[11:27:32]: --- Setting up fastlane to automate iOS screenshots ---                                                            
[11:27:32]: -------------------------------------------------------                                                            
[11:27:32]: fastlane uses UI Tests to automate generating localized screenshots of your iOS app                                
[11:27:32]: fastlane will now create 2 helper files that are needed to get the setup running                                   
[11:27:32]: For more information on how this works and best practices, check out                                               
[11:27:32]:     https://docs.fastlane.tools/getting-started/ios/screenshots/                                                   
[11:27:32]: Continue by pressing Enter
[11:28:46]: Parsing your local Xcode project to find the available schemes and the app identifier
[11:28:46]: $ xcodebuild -showBuildSettings -project ios-200s-games.xcodeproj
   Successfully created SnapshotHelper.swift './fastlane/SnapshotHelper.swift'
   Successfully created new Snapfile at './fastlane/Snapfile'
-------------------------------------------------------
Open your Xcode project and make sure to do the following:
1) Add a new UI Test target to your project
2) Add the ./fastlane/SnapshotHelper.swift to your UI Test target
   You can move the file anywhere you want
3) Call `setupSnapshot(app)` when launching your app

  let app = XCUIApplication()
  setupSnapshot(app)
  app.launch()

4) Add `snapshot("0Launch")` to wherever you want to trigger screenshots
5) Add a new Xcode scheme for the newly created UITest target
6) Add a Check to enable the `Shared` box of the newly created scheme

More information: https://docs.fastlane.tools/getting-started/ios/screenshots/
[11:28:48]: If you want more details on how to setup automatic screenshots, check out
[11:28:48]:     https://docs.fastlane.tools/getting-started/ios/screenshots/#setting-up-snapshot
[11:28:48]: Continue by pressing Enter
[11:29:14]: Which is your UI Testing scheme? If you can't find it in this list, make sure it's marked as `Shared` in the Xcode scheme list
1. ios-200s-games
?  1
[11:29:37]: ------------------------------------
[11:29:37]: --- Automatically upload to iTC? ---
[11:29:37]: ------------------------------------
[11:29:37]: Would you like fastlane to automatically upload all generated screenshots to App Store Connect
[11:29:37]: after generating them?
[11:29:37]: If you enable this feature you'll need to provide your App Store Connect credentials so fastlane can upload the screenshots to App Store Connect
[11:29:37]: Enable automatic upload of localized screenshots to App Store Connect? (y/n)
n
[11:35:46]: It looks like your project isn't set up to do automatic version incrementing
[11:35:46]: To enable fastlane to handle automatic version incrementing for you, please follow this guide:
[11:35:46]:     https://developer.apple.com/library/content/qa/qa1827/_index.html
[11:35:46]: Afterwards check out the fastlane docs on how to set up automatic build increments
[11:35:46]:     https://docs.fastlane.tools/getting-started/ios/beta-deployment/#best-practices
[11:35:46]: --------------------------------------------------------
[11:35:46]: ---    Successfully generated fastlane configuration ---
[11:35:46]: --------------------------------------------------------
[11:35:46]: Generated Fastfile at path `./fastlane/Fastfile`
[11:35:46]: Generated Appfile at path `./fastlane/Appfile`
[11:35:46]: Gemfile and Gemfile.lock at path `Gemfile`
[11:35:46]: Please check the newly generated configuration files into git along with your project
[11:35:46]: This way everyone in your team can benefit from your fastlane setup
[11:35:46]: Continue by pressing Enter
[11:36:06]: fastlane will collect the number of errors for each action to detect integration issues
[11:36:06]: No sensitive/private information will be uploaded, more information: https://docs.fastlane.tools/#metrics
[11:36:06]: ----------------------
[11:36:06]: --- fastlane lanes ---
[11:36:06]: ----------------------
[11:36:06]: fastlane uses a `Fastfile` to store the automation configuration
[11:36:06]: Within that, you'll see different lanes.
[11:36:06]: Each is there to automate a different task, like screenshots, code signing, or pushing new releases
[11:36:06]: Continue by pressing Enter
[11:36:18]: --------------------------------------
[11:36:18]: --- How to customize your Fastfile ---
[11:36:18]: --------------------------------------
[11:36:18]: Use a text editor of your choice to open the newly created Fastfile and take a look
[11:36:18]: You can now edit the available lanes and actions to customize the setup to fit your needs
[11:36:18]: To get a list of all the available actions, open https://docs.fastlane.tools/actions
[11:36:18]: Continue by pressing Enter
[11:36:25]: ------------------------------
[11:36:25]: --- Where to go from here? ---
[11:36:25]: ------------------------------
[11:36:25]: Learn more about how to automatically generate localized App Store screenshots:
[11:36:25]:             https://docs.fastlane.tools/getting-started/ios/screenshots/
[11:36:25]: Learn more about distribution to beta testing services:
[11:36:25]:             https://docs.fastlane.tools/getting-started/ios/beta-deployment/
[11:36:25]: Learn more about how to automate the App Store release process:
[11:36:25]:             https://docs.fastlane.tools/getting-started/ios/appstore-deployment/
[11:36:25]: Learn more about how to setup code signing with fastlane
[11:36:25]:             https://docs.fastlane.tools/codesigning/getting-started/
[11:36:25]: 
[11:36:25]: To try your new fastlane setup, just enter and run
[11:36:25]: $ fastlane screenshots

途中で iTunesConnect にアップロードするか聞かれますがそれは NO にしました

Xcode 側の準備

init 時にコード側で設定してほしいことが表示されているのでそれを設定するだけです
必要なファイルを配置したりコードを変更します

まず UITests のグループ配下に生成された fastlane/SnapshotHelper.swift を配置します
fastlane1.png

そして UITests のテストコード setup を以下のように変更します

override func setUp() {
    continueAfterFailure = false
    let app = XCUIApplication()
    setupSnapshot(app)
    app.launch()
}

更にテスト実行時にスクリーンショットを取得したい箇所で screenshot メソッドをコールします
スクリーンショットを取得した画面分挿入してあげると良いでしょう
0Launch の部分は好きな名前を入力することができます

func testExample() {
    snapshot("0Launch")
}

fastlane2.png

これでスクリーンショットを取得するための準備は完了です

実行

  • fastlane screenshots

でスクリーンショットの取得が開始されます
デフォルトでは以下のデバイスのスクリーンショットが取得されます

  • iPhone 7
  • iPhone 7 Plus
  • iPhone 8
  • iPhone 8 Plus
  • iPhone X
  • iPhone XS
  • iPhone XS Max
  • iPhone XR
  • iPad (5th generation)
  • iPad Pro (9.7-inch)
  • iPad Pro (12.9-inch)
  • iPad Pro (10.5-inch)
  • iPad (6th generation)
  • iPad Pro (11-inch)
  • iPad Pro (12.9-inch) (3rd generation)

実行中はヘッドレスでシミュレーターが起動するのでマシンに結構な負荷がかかるのでご注意ください

かなりログが表示されるので省略しますが以下のように時間が表示されれば完了です

[11:19:32]: fastlane.tools just saved you 14 minutes!

HTML ファイルとスクリーンショットは fastlane/screenshots/en-US/ に保存されブラウザで結果を表示してくれます

レーンを独自に定義する

fastlane/ ディレクトリ配下に各種設定ファイルがあります

Appfile
Fastfile
Snapfile
SnapshotHelper.swif

これをカスタマイズすることでスクリーンショットを取得する以外のことができるようになります
ちなみに今回は fastlane screenshots コマンドを定義しまし実行しましたが実行可能なコマンドの一覧を表示するには

  • fastlane list

を実行します
また DSL として実際に使えるアクションの一覧を表示する方法は

  • fastlane actions

で表示できます
この一覧に capture_screenshots というアクションがありこれを fastlane/Fastfile で使って lane: screenshots として DSL で定義することでコマンドが使えるようになります

最後に

fastlane でスクリーンショットを自動取得してみました
init コマンドを使えば雛形は作成してくれるので簡単に始められます

あとはドキュメントとアクションを見ながら自分で Fastfile をカスタマイズすれば好きなビルドフローを作成することができます
slack というアクションもあるのでフロー終了後に通知したりすることもできます

Xcode Server などを個別で立ててやるよりも fastlane 対応すれば Travis CI や Circle CI でも動かすことができるので将来的にも幸せになれると思います

参考サイト

2019年1月17日木曜日

Xcode10 で Xcode Server を使ってみた

概要

Xcode 9 以上から macOS Server なしで Xcode Server が使えるようになりました
今回は Xcode 10 で Server 機能を使ってみました

環境

  • macOS 10.14.2
  • Xcode 10.1 (10B61)

Xcode Server を有効にする

まずは Xcode Server を有効にします
メニューバーから「Xcode」->「Preferences」を選択します
そしてタブから「Server & Bots」を選択しトグルボタンで ON に変更します
管理者権限のパスワードを入力します
「Select Integration User」でユーザを選択
xcode_server1.png

以下のようになれば有効化完了です
xcode_server2.png

ツールバーにもトンカチのようなアイコンが出現します
xcode_server4.png

アイコンを選択すると Server 機能が ON になっていることを確認できます
xcode_server3.png

使ってみる

せっかく Server を有効にしたので使ってみます

Xcode Server を追加する

「Xcode」->「Preferences」を開きます
「Accounts」タブを選択して「+」ボタンを押して追加します
タイプの一覧に Xcode Server があるのでそれを選択します
xcode_server5.png

追加した Xcode Server を選択します
xcode_server6.png

追加した Xcode Server の Integration User の情報を入力して Add します
xcode_server7.png

以下のように一覧に追加されれば OK です
xcode_server8.png

Bot を作成する

Bot を作成することで push したら自動で Xcode Server 上でビルドが走るようにできます

Xcode に戻り左ペインから一番右のタブを選択します
すると追加した Xcode Server があるので右クリックして「Create Bot」を選択します
xcode_server9.png

xcode_server10.png

Bot の名前を決定し動作させる Xcode Server を選択します
xcode_server11.png

プロジェクトとリモートリポジトリの情報を確認し次にいきます
ここで指定したリモートリポジトリから pull してビルドする感じです
xcode_server12.png

ボットのビルド設定をします (今回はそのまま)
xcode_server13.png

ビルドのスケジュールを設定します (今回はそのまま)
xcode_server14.png

テスト対象のデバイスを設定します (今回はそのまま)
xcode_server15.png

証明書の設定をします (今回はそのまま)
xcode_server16.png

ビルドパラメータを設定します (今回はそのまま)
xcode_server17.png

ビルドのトリガーを設定します (今回はそのまま)
xcode_server18.png

これでボットの作成は完了です
integrate が始まっているので Xcode に戻って確認するとビルドが開始されていることが確認できます
xcode_server19.png

完了すると以下のようになります
選択したデバイス上でテストが実行されていることも確認できると思います (結構ビルドが失敗しました、自分が遭遇したエラーは以下のトラブルシューティングを参照してください)
xcode_server21.png

ビルドにかかった時間はだいたい 20 分程度でした
ビルドマシンも Mac Book Air だったので Mac Pro などを使えばもっと速くなると思います
またビルド設定も調整すればもっと速くなると思います
例えばビルドするデバイスを 1 台にすればかなり速くなります

トラブルシューティング

「Creating a bot requires that the project be under source control that is accessible by the server.」という警告が出る場合は git remote add でリモートリポジトリを追加してください
どうやらリモートリポジトリがないと上記の警告が表示されるようです

「Bot Issue for ios-200s-games Bot (error)
Integration #1 of ios-200s-games Bot on xcode-server
Open Integration in Xcode: xcbot://xcode-server/botID/f549b44a3bc6a69d9d3ec2703b012997/integrationID/f549b44a3bc6a69d9d3ec2703b013c9d
Error: ios-200s-games.app encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted. (Underlying error: Lost connection to testmanagerd))
Potentially resolvable by user」が出てビルドが失敗する場合は Bot の証明書がちゃんと設定されているか確認しましょう
xcode_server20.png

最後に

Xcode10 の Server 機能を試してみました
リモートリポジトリの push をトリガーにテストが勝手に走る感じです
いわゆる CI ができるようになります
ビルド+テストを実行するのでテストをしっかりと書いておく必要があります

今回は localhost でサーバもクライアントもやりましたが本来は別々のマシンが好ましいです
サーバでのビルドは結構な負荷になるので注意してください

参考サイト