2021年10月29日金曜日

iOS アプリのレビューを curl で取得する方法

iOS アプリのレビューを curl で取得する方法

概要

公開している iOS アプリにレビューが評価があっても通知されません

基本的には自分で定期的にチェックするしかありません
公開しているアプリであれば公式で評価とレビューを取得するためのフィードが準備されているのでそれを使うと楽です

XML と JSON のメディアタイプで取得できます

環境

  • macOS 11.6
  • フィード 2021/10/04 時点

アプリID の取得

App Store Connect などで取得できます

App Store Connect -> アプリ選択 -> 一般 -> App 情報 -> AppleID

URL にも表示されているのでそこから取得しても OK です

xml

1234567890 の部分は取得したアプリID に変更してください

json

1234567890 の部分は取得したアプリID に変更してください
json の場合は一番後ろのパスを json に変更するだけです

2021年10月28日木曜日

golang でパスワードの強度をチェックする方法

golang でパスワードの強度をチェックする方法

概要

hesahesa/pwdbro を使います

環境

  • macOS 11.6
  • golang 1.17

インストール

サンプルコード

package main

import (
	"fmt"
	"github.com/hesahesa/pwdbro"
)

func main() {
	pass := ""
	pwdbro := pwdbro.NewDefaultPwdBro()
	// パスワードの強度のチェック結果は status に配列で格納されています
	// pwnedpasswords と zxcvbn とパスワードが空かの 3 つのチェック方法の結果が格納されています
	status, err := pwdbro.RunChecks(pass)
	if err != nil {
		panic(err)
	}
	// 3 回ループします 
	for _, resp := range status {
		// Safe は true or false が返ってきます
		// true の場合はパスワードが強度チェックをパスしています 
		fmt.Println("*******************Safe")
		fmt.Println(resp.Safe)
		// Method は各パスワードのチェック方法が文字列で格納されています
		fmt.Println("*******************Method")
		fmt.Println(resp.Method)
		// Message は各パスワードチェックの結果が文字列で含まれています
		fmt.Println("*******************Message")
		fmt.Println(resp.Message)
		// Error はもしエラーだった場合に nil 以外のエラー情報が含まれています
		fmt.Println("*******************Error")
		fmt.Println(resp.Error)
	}
}

ポイント

pwnedpasswords というサービスの API を使っているのでオフラインだと pwnedpasswords の結果は必ず false になります

オフラインの場合は zxcvbn の結果を見て判断すると良いかなと思います

2021年10月27日水曜日

Ubuntu18.04 で podman を使ってみる

Ubuntu18.04 で podman を使ってみる

概要

podman は docker のようにコンテナを動作するためのランタイムです
docker のようにデーモンが不要で root レスで動作します

今回は Ubuntu18.04 にインストールする方法を紹介します

環境

  • Ubuntu18.04
  • podman 1.6.2

準備

  • apt -y update
  • apt -y install software-properties-common

apt リポジトリの追加

  • add-apt-repository -y ppa:projectatomic/ppa

podman のインストール

  • apt -y install podman

podman 用のレジストリの設定

  • echo -e "[registries.search]\nregistries = ['docker.io']" | sudo tee /etc/containers/registries.conf

動作確認: コンテナ起動

  • podman run --rm hello-world

最後に

あとは docker と同じ用に

  • podman ps
  • podman images

などが使えます

docker-compose も使えるようですが socket 用のデーモンの起動などが必要なようです
また swarm のようなクラスタ機能には対応していないようです

k8s を操作することもできるようですが今回は紹介しません
機会があれば試してみたいと思います

2021年10月26日火曜日

golang で WebAssembly 超入門

golang で WebAssembly 超入門

概要

WebAssembly は主にブラウザで動作する言語でバイトコードを使うため JavaScript よりも高速に動作します
また golang や Rust などサーバサイドのコードから .wasm と呼ばれるコンパイルされた WebAssembly コードを吐き出すことができこれがブラウザで動作します
つまり golang や Rust のコードがブラウザで動かせるような技術になります

今回は HelloWorld をやってみました

環境

  • macOS 11.6
  • golang 1.17
  • Chrome 94.0.4606.71

golang のコード

まずは普通に golang のコードを書いてみます
とりあえず「Hello」と出力するだけのコードを記載します

  • vim main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, WebAssembly!")
}

.wasm ファイルを作成する

go build する際にいくつかのオプションを指定するだけで OK です

  • GOOS=js GOARCH=wasm go build -o main.wasm

これで main.wasm というファイルが作成されています

% ls -l main.wasm 
-rwxr-xr-x  1 hawk  staff  2020036 10 14 16:22 main.was

index.html の作成

作成した .wasm ファイルをブラウザ上で動かします
main.wasm と index.html は同じディレクトリ上に配置してください

  • vim index.html
<html>
  <head>
    <meta charset="utf-8">
    <script src="wasm_exec.js"></script>
    <script>
      const go = new Go();
      WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
          go.run(result.instance);
      });
    </script>
  </head>
  <body></body>
</html>

wasm_exec.js の配置

golang を brew でインストールしているのであれば以下のようなパスにあるはずです
コピーして同じディレクトリに配置します

  • cp /usr/local/Cellar/go/1.17/libexec/misc/wasm/wasm_exec.js .

動作確認

サーバを立てましょう
なんでも OK です
今回は Python を使います

  • python3.9 -m http.server 8000

これでブラウザで localhost:8000 にアクセスしブラウザのコンソール情報を見ると以下のようにメッセージが表示されているのが確認できると思います

DOM を操作する

syscall/js を使うと golang から dom を操作できます
DOM は Get/Set で取得、設定ができます
DOM のメソッドをコールしたい場合は Call() を使います

DOM から取得できる値はすべて js パッケージの型として取得できるので golang で扱う場合には型の変換が必要です

main では WebAssembly 上で golang が終了しないようにチャネルを作成しています

HTML 側で作成したボタンがクリックされたときにコールされるメソッドを golang 側に実装します
今回は countup というメソッドが呼ばれるようにしかつその結果は id=counter の div タグに設定するようにしています

  • vim main.go
package main

import (
	"strconv"
	"syscall/js"
)

func countup(this js.Value, i []js.Value) interface{} {
	c := js.Global().Get("document").Call("getElementById", "counter").Get("textContent")
	current, _ := strconv.Atoi(c.String())
	js.Global().Get("document").Call("getElementById", "counter").Set("textContent", current+1)
	return 0
}

func registerCallbacks() {
	js.Global().Set("countup", js.FuncOf(countup))
}

func main() {
	c := make(chan struct{}, 0)
	registerCallbacks()
	<-c
}

HTML 側も少しだけ修正します
ボタンと結果を表示する div を追加するだけです

  • vim index.html
<html>
  <head>
    <meta charset="utf-8">
    <script src="wasm_exec.js"></script>
    <script>
      const go = new Go();
      WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
          go.run(result.instance);
      });
    </script>
  </head>
  <body>
    <div id="counter">0</div>
    <button onClick="countup()">up</button>
  </body>
</html>

これで再度ビルドして python で動作確認するとちゃんとカウントアップボタンが動作することが確認できると思います

  • GOOS=js GOARCH=wasm go build -o main.wasm
  • python3.9 -m http.server 8000

最後に

golang で WebAssembly に入門してみました
現在だと開発もかなり進んでおりドキュメントも豊富なので簡単に開発できると思います

WebAssembly を直接書くのは面倒なので golang に慣れている人はこの方法を使うと簡単に WebAssembly を使うことができると思います

WebAssembly で有名な Rust も同じような感じだと思います

参考サイト

2021年10月25日月曜日

golang で bcrypt を使う方法

golang で bcrypt を使う方法

概要

Ruby で使う方法はこちら
Python で使う方法はこちら

今回は golang で使う方法を紹介します

環境

  • macOS 11.6
  • golang 1.17

パスワードのハッシュ化

package main

import (
	"fmt"
	"golang.org/x/crypto/bcrypt"
)

func main() {
	pass := "hoge"
	hash, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(hash))
}

ハッシュ化パスワードとの比較

package main

import (
	"golang.org/x/crypto/bcrypt"
)

func main() {
	hash := "$2a$08$vQc70PtoxLTdIc4qi/nlZ.Qjfps150pJzrn6J3oRf4pkOY0uQ5BTO"
	pass := "hoge"
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(pass))
	if err != nil {
		panic(err)
	}
}

参考サイト

2021年10月22日金曜日

FitText.js を使っていい感じに文字列を画面最大に表示する方法

FitText.js を使っていい感じに文字列を画面最大に表示する方法

概要

画面いっぱいに大きな文字を表示したい場合に便利です

環境

  • macOS 11.6
  • chrome
  • FitText.js 1.2.0

サンプルコード

index.html の作成だけで動作します

  • index.html
<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
  <style type="text/css">
    #counter {
      color: #40e0d0
    }
    .container {
      width: 100%;
      margin: 0 auto;
    }
    h1 {
      text-align: center;
    }
  </style>
  </head>
  <body>
    <div class="container">
      <header>
        <h1 id="msg">Count: <span id="counter">0</span></h1>
      </header>
    </div>
  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FitText.js/1.2.0/jquery.fittext.min.js" integrity="sha512-e2WVdoOGqKU97DHH6tYamn+eAwLDpyHKqPy4uSv0aGlwDXZKGwyS27sfiIUT8gpZ88/Lr4UZpbRt93QkGRgpug==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script>
    $("#msg").fitText(1.2);
  </script>
</html>

ポイント

JavaScript で再描画しているので body の最後で呼び出しましょう

fitText 関数の引数の数字はコンプレッサーで値を小さくすると文字が大きくなり値を大きくすると文字のサイズが小さくなります

動作確認

  • open index.html

で以下のように表示されます

参考サイト

2021年10月21日木曜日

Gitlab のヘルスチェックを行う方法

Gitlab のヘルスチェックを行う方法

概要

外形監視などを行う場合に使えます

環境

  • Omnibus Gitlab 14.2.3-ee

monitoring_whitelist の追加

gitlab_rails['monitoring_whitelist'] = ['127.0.0.0/8', '192.168.100.10']

reconfigure

  • gitlab-ctl reconfigure

動作確認

  • curl https://localhost-/health

Not Found

GitLab OK

最後に

monitoring_whitelist に追加された IP からはトークンなしで API をコールできるのでその仕組を使っています

参考サイト

2021年10月20日水曜日

Python の WebAssembly Pydide 超入門

Python の WebAssembly Pydide 超入門

概要

Python のコードをブラウザで動かすことができる Pydide の Getting Started を試してみました
自分でコンパイル等が不要で JS のコードの中に Python を直接書くことができます

特にインストール作業等も不要で使うことができます

環境

  • macOS 11.6
  • Chrome 94.0.4606.71

とりあえず動かすサンプルコード

  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js"></script>
  </head>
  <body>
    Pyodide test page <br>
    Open your browser console to see Pyodide output
    <script type="text/javascript">
      async function main(){
        let pyodide = await loadPyodide({
          indexURL : "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/"
        });
        console.log(pyodide.runPython(`
          import sys
          sys.version
          import os
          os.name
          "HELLO"
        `));
        console.log(pyodide.runPython("print(1 + 2)"));
      }
      main();
    </script>
  </body>
</html>
  • open index.html

これで以下のように動作します

実行してみるとわかりますが Python のコードはベージが読み込まれてから少し時間が経ってから表示されることがわかります

DOM の操作

DOM も操作できます
以下のサンプルでは button に設定された Python のコード sum([1, 2, 3, 4, 5]) をそのまま取得して runPython で実行しその結果を DOM に反映しています

runPython から取得できた値はそのまま js の世界でも使えるようです (ただ逆に js -> Python の世界で使う場合にはコンバートが必要です 参考)

  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js"></script>
  </head>

  <body>
    <p>
      You can execute any Python code. Just enter something in the box below and
      click the button.
    </p>
    <input id="code" value="sum([1, 2, 3, 4, 5])" />
    <button onclick="evaluatePython()">Run</button>
    <br />
    <br />
    <div>Output:</div>
    <textarea id="output" style="width: 100%;" rows="6" disabled></textarea>

    <script>
      const output = document.getElementById("output");
      const code = document.getElementById("code");

      function addToOutput(s) {
        output.value += ">>>" + code.value + "\n" + s + "\n";
      }
      output.value = "Initializing...\n";
      // init Pyodide
      async function main() {
        let pyodide = await loadPyodide({
          indexURL: "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/",
        });
        output.value += "Ready!\n";
        return pyodide;
      }
      let pyodideReadyPromise = main();

      async function evaluatePython() {
        let pyodide = await pyodideReadyPromise;
        try {
          let output = pyodide.runPython(code.value);
          addToOutput(output);
        } catch (err) {
          addToOutput(err);
        }
      }
    </script>
  </body>
</html>
  • open index.html

最後に

コンパイルも不要なのでブラウザさえあれば Python を始めることができます

ちゃんとした Web アプリをこれで作るのであれば HTML, JS, CSS も書けないとダメですが JS の計算処理などを Python で書くことができるので JS をメインで書けない人はそこを Python に置き換えられるので良いかなと思います

コード中に JS と Python が出てくるので書いているとゲシュタルト崩壊しそうなのとエディタが JS も Python も補完してくれなさそうなので書くときは別で書いたほうがいいかもしれません

また Pypi を使うこともできその場合は WebAssembly 専用の「Micropip」というのを使うことになります

参考サイト

2021年10月19日火曜日

uWSGI のパフォーマンスチューニングを ab を使ってやってみる

uWSGI のパフォーマンスチューニングを ab を使ってやってみる

概要

uWSGI のパフォーマンスチューニングを ab を使って実際に試す記事があったので自分も試してみました

最適な数字はこうやって出していくしかないのかもしれません

環境

  • Ubuntu 18.04
  • Python 3.8.3
  • flask 2.0.2
  • uWSGI 2.0.19.1
  • ApacheBench 2.3

アプリ

記事にもある通りフィボナッチ数列を計算するアプリを使用します
かなり単純なアプリでデータベースへのアクセスや外部サービスへのアクセス、キャッシュへのアクセスがないので ab の値は単純な uWSGI の性能値になります

from flask import Flask
import json
import fib

app = Flask(__name__)

@app.route("/<number>", methods=['GET'])
def get_fib(number):
    return json.dumps(fib.get(int(number))), 200

if __name__ == '__main__':
    app.run(host="0.0.0.0", port="8080")
def get(number):
    sequence = [0, 1]
    while sequence[-1] < number:
        sequence.append(sequence[-2] + sequence[-1])
    return sequence

wsgi.ini は以下のように設定します

  • vim uwsgi.ini
[uwsgi]
http=:80
wsgi-file=app.py
callable=app

動作するか確認してみます

  • pipenv run uwsgi uwsgi.ini
  • curl localhost/9000

で 9000 までのフィボナッチ数列が返却されることを確認します

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946]

現在のパフォーマンスを計算する

ab コマンドを使って現在の uwsgi.ini でどれくらいのパフォーマンスが出るのか計算します

  • ab -c 500 -n 5000 -s 90 192.168.1.2/9000

Requests per second で 643.03 出ています

Concurrency Level:      500
Time taken for tests:   7.776 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      880000 bytes
HTML transferred:       485000 bytes
Requests per second:    643.03 [#/sec] (mean)
Time per request:       777.565 [ms] (mean)
Time per request:       1.555 [ms] (mean, across all concurrent requests)
Transfer rate:          110.52 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    9  69.8      0    1023
Processing:    30  434 1310.9     70    7712
Waiting:       24  434 1310.9     70    7712
Total:         48  443 1326.2     70    7746

マルチスレッドをオンにする

processes = 4 を追加してみましょう

  • vim uwsgi.ini
[uwsgi]
http=:80
wsgi-file=app.py
callable=app
processes=4

これで再度 uWSGI を起動するログに以下のようなログが追加されています


spawned uWSGI worker 1 (pid: 60526, cores: 1)
spawned uWSGI worker 2 (pid: 60566, cores: 1)
spawned uWSGI worker 3 (pid: 60567, cores: 1)
spawned uWSGI worker 4 (pid: 60568, cores: 1)

この状態で ab を実行すると以下のような結果になりました
Requests per second が 1250.73 まで上がりました

Concurrency Level:      500
Time taken for tests:   3.998 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      880000 bytes
HTML transferred:       485000 bytes
Requests per second:    1250.73 [#/sec] (mean)
Time per request:       399.768 [ms] (mean)
Time per request:       0.800 [ms] (mean, across all concurrent requests)
Transfer rate:          214.97 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   22 128.7      0    1047
Processing:    15  154 370.7     53    3836
Waiting:       14  152 370.5     52    3836
Total:         22  176 403.6     54    3843

紹介記事にもあるのですが lshw などを使い実行しているマシンの CPU 数やコア数に合わせて値をチューニングしてください

例えば 2コアの CPU の場合には更に threads を有効にするとパフォーマンスが更に向上します

# lshw -short -class cpu
H/W path           Device       Class      Description
======================================================
/0/1                            processor  Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz
/0/2                            processor  Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz
  • vim uwsgi.ini
[uwsgi]
http=:80
wsgi-file=app.py
callable=app
processes=4
threads=2
enable-threads=True

Requests per second が 2309.60 まで上がりました
単純に2倍の性能が出ています

Concurrency Level:      500
Time taken for tests:   2.165 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      880000 bytes
HTML transferred:       485000 bytes
Requests per second:    2309.60 [#/sec] (mean)
Time per request:       216.488 [ms] (mean)
Time per request:       0.433 [ms] (mean, across all concurrent requests)
Transfer rate:          396.96 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   45 182.4     10    1046
Processing:     5  123 231.1     49    1285
Waiting:        5  117 230.9     44    1273
Total:         12  168 313.5     58    1700

ログを無効にする

disable-logging を True にします
ab テストをすると各リクエストごとにログが表示されていましたがこの設定を入れると表示されなくなります

  • vim uwsgi.ini
[uwsgi]
http=:80
wsgi-file=app.py
callable=app
processes=4
threads=2
enable-threads=True
disable-logging=True

再度 ab を流してみましょう
これはそこまでパフォーマンスに影響がありませんでした
先程同様で Requests per second が 2311.59 ほどでした
こんな感じで値を変更してパフォーマンスに影響のある値が何か探っていく感じになります

Concurrency Level:      500
Time taken for tests:   2.163 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      880000 bytes
HTML transferred:       485000 bytes
Requests per second:    2311.59 [#/sec] (mean)
Time per request:       216.301 [ms] (mean)
Time per request:       0.433 [ms] (mean, across all concurrent requests)
Transfer rate:          397.30 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   33 168.8      1    1045
Processing:     2  111 230.4     42    1789
Waiting:        2  109 230.1     40    1789
Total:         14  144 307.3     44    1886

ワーカーのライフタイムを設定する

先程 processes=4 で複数の4つのワーカーが立ち上がるようにしました
これらのワーカーを指定の時間経過後に自動で再起動する設定が max-worker-lifetime になります
今回は 30 で設定してみます

  • vim uwsgi.ini
[uwsgi]
http=:80
wsgi-file=app.py
callable=app
processes=4
threads=2
enable-threads=True
disable-logging=True
max-worker-lifetime=30

Requests per second は 2336.88 になりました
それほどパフォーマンスに影響はないようですが多少の改善が見られる感じです

Concurrency Level:      500
Time taken for tests:   2.140 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      880000 bytes
HTML transferred:       485000 bytes
Requests per second:    2336.88 [#/sec] (mean)
Time per request:       213.960 [ms] (mean)
Time per request:       0.428 [ms] (mean, across all concurrent requests)
Transfer rate:          401.65 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   49 198.0      4    1050
Processing:     7  120 254.4     44    1296
Waiting:        4  117 253.2     40    1292
Total:         11  169 362.1     46    1866

おまけ: Python をコンパイルして動作させる

これも多少はパフォーマンスに影響があるようです
ここでは紹介しませんが Cython を使ってコンパイルしてネイティブで動作させると更にパフォーマンスは向上するようです

最後に

ab を使って uWSGI のパフォーマンスチューニングをする方法を紹介しました
これ以外にもたくさんのパラメータがあるので自身の最適なパラメータを見つける感じになると思います

実際のサービスではデータベースや外部サービスが絡むのでもっと Request per second が落ちるかなと思います
そうなると uWSGI 側のチューニングではなくデータベースやキャッシュのチューニングになるのでそのあたりの感覚も必要になるかなと思います

ab トラブルシューティング

macOS で ab を実行する場合に発生します
いろいろと面倒なので素直に Ubuntu などで実行することをオススメします

  • apr_socket_recv: Connection reset by peer (54)

バージョンを最新にしましょう
macOS に標準でインストールされている ab は 2.3 でこれだと上記のエラーが発生するので brew install httpd で最新版をインストールしこちらを使いましょう

  • socket: Too many open files (24)

macOS の場合デフォルトのファイルディスクリプタが 256 なので -c オプションを 200 にして実行しましょう

  • apr_socket_connect(): Invalid argument (22)

localhost の指定はできないのでローカルの IP アドレスをしていしましょう

参考サイト

2021年10月18日月曜日

RaspberryPi4 で xmring のビルド

RaspberryPi4 で xmring のビルド

概要

そのままだと 32bit しか対応していないので 64bit の仮想完了を構築してからビルドする必要があります

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l

raspbian-nspawn-64 のインストール

  • sudo apt-get update
  • sudo apt-get install -y raspbian-nspawn-64
  • sudo reboot -h now

xmrig のビルド

  • ds64-shell
  • sudo apt-get -y update
  • sudo apt-get -y install git build-essential cmake libuv1-dev libssl-dev libhwloc-dev
  • git clone https://github.com/xmrig/xmrig.git
  • cd xmrig
  • mkdir build
  • cd build
  • cmake … -DCMAKE_BUILD_TYPE=Release -DWITH_OPENCL=OFF -DWITH_CUDA=OFF
  • make

systemd 化

一度 ds64-shell を抜けます

  • chmod +x /home/pi/xmrig/build/xmrig
  • mkdir /home/pi/xmrig/log
  • touch /home/pi/xmrig/log/xmrig.log
  • sudo vim /lib/systemd/system/xmrig.service
[Unit]
Description=cpu-monero-miner
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/ds64-run /home/pi/xmrig/build/xmrig --url=pool.supportxmr.com:5555 --donate-level=1 --user=44pxxx --pass=docker -k --coin=monero --log-file="/home/pi/xmrig/log/xmrig.log" --cpu-max-threads-hint 25

[Install]
WantedBy=multi-user.target

cpu-max-threads-hint は 4コアなので 25, 50, 75, 100 が指定できます
1 コアしか使わない場合は 25, 4 コアすべて使う場合は 100 を指定します

  • sudo systemctl daemon-reload
  • sudo systemctl enable xmrig
  • sudo reboot -h now
  • sudo systemctl start xmrig

Tips

ds64-shell を抜けるには Ctrl + ] を素早く 3 回押します

最後に

armv7 の CPU アーキテクチャに対応していないとこういうことをする必要が出てきます

参考サイト

2021年10月17日日曜日

RaspberryPi4 設定メモ

RaspberryPi4 設定メモ

概要

自分用セットアップメモです

環境

  • RaspberryPi4 ModelB 8GBRAM

必要なもの

  • 最低限
    • microSD (SD カード変換)
  • 任意
    • 5V/3A 電源アダプタ
    • 有線キーボード
    • Bluetooth キーボード (つながらないかも)
    • Bluetooth マウス
    • microHDMI ケーブル

RaspberryPiOS の準備

こちら
Wifi の設定と SSH の有効化はここで済ませる

ssh の有効化

Imager で行う

Wifi のセットアップ

SSID の登録
事前に Imager で済んでいる場合は不要

  • sudo vim /etc/wpa_supplicant/wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
ap_scan=1

update_config=1
network={
        ssid="ssid"
        psk=xxx
}

キーボードのセットアップ

caps lock -> ctrl

  • sudo vim /etc/default/keyboard
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS="ctrl:swapcaps"
BACKSPACE="guess"

Bluetooth キーボードのセットアップ

GUI から行う
CLI で行うことはできるのだろうか

docker のインストール

alpine 3.13 だとネットワークエラーになるので alpine 3.12.3 を使うこと https://github.com/docker/for-linux/issues/1196

raspbian-nspawn-64 のインストール

  • sudo apt-get update
  • sudo apt-get install -y raspbian-nspawn-64
  • ds64-shell

電源電圧が足りているか調べる

  • vcgencmd get_throttled
  • vcgencmd mesure_temp

pi-apps のインストール

各種ツール

apt or linuxbrew でインストールすること

2021年10月16日土曜日

Raspberry Pi Imager を使ってラズパイ用の OS を microSD カードに書き込む方法

Raspberry Pi Imager を使ってラズパイ用の OS を microSD カードに書き込む方法

概要

昔は img ファイルをダウンロードして dd コマンドで SD カードに書き込んでいましたが最近では Imager 経由で簡単に SD カードに書き込めるようです

この段階から OS の設定もいくつかできるので初期設定も Imager に任せることができます

今回はインストール方法を実際の書き込み方法を紹介します

環境

  • macOS 11.6
  • Raspberry Pi Imager 1.6.2

ダウンロード

ここからダウンロードします

imager_1.6.2.dmg というファイルがダウンロードできました

インストール

ダウンロードできた dmg ファイルをダブルクリックし展開しましょう
あとは app ファイルを Applications フォルダ配下に移動するだけで OK です

起動

アプリケーション配下にある「Raspberry Pi Imager.app」を開きます

初回起動の場合は以下のような警告が表示されますが「開く」を押して続けます

Raspberry Pi Imager が起動すれば成功です

SDカードの接続

Mac に SD カードを接続します
自分は microSD -> SDカードの変換を使って接続しました

書き込み先の選択

「CHOOSE STORAGE」から接続した SD カードを選択します

書き込みOSの選択

次に「CHOOSE OS」から書き込む OS を選択します
今回は「Raspberry Pi OS (32-bit)」を選択します

まだフォーマットされていない場合は先に Erase を選択してフォーマットしてもいいかもしれません

オプションの設定

画面にはないのですがいろいろとオプションを設定できます 「Cmd + Shift + x」を入力しましょう

すると以下のようなダイアログが表示されるので好きなオプションを設定していきます

自分は以下を設定するようにしています

  • Enable SSH
  • Configure wifi
  • Set locale settings

ちなみにここで設定した項目は保存することもできるので別の SD カードでも同じ設定を使い回すことができます

書き込み

あとは「Write」で書き込みします
管理者権限のダイアログが表示される場合はパスワードを入力して権限を与えましょう

あとは書き込みが終わるまで待ちます

SD カードの書き込み速度にもよりますがだいたい 20 分ほどで完了すると思います

動作確認

あとは Raspberry Pi に SD カードを挿して起動すれば OK です

ちゃんとオプションで設定した通りに初期化されていることを確認しましょう

最後に

Wifi など起動後に設定する場合はモニタが必要であったりキーボードやマウスの接続が必要だったのですが Imager を使うとその辺りの設定を書き込み時に行えるので起動後は SSH すればいきなり使えるようになっているのはかなり嬉しい点かなと思います

ただ Bluetooth 関連の設定はできなかったのが残念です
Bluetooth キーボードの自動接続などもこの段階でできると更にうれしいかなと思いました

自分で SD カードに直接設定ファイルを配置する方法もあるようですが今回は省略します

参考サイト

2021年10月15日金曜日

Ruby guard 超入門

Ruby guard 超入門

概要

guard は特定のファイルに変更があった場合に任意のコマンドやタスクを実行することができるツールです

よく rspec と一緒に紹介されていますが決して rspec が必須というわけではなく実行しているコマンド (プラグイン) が guard-rspec と呼ばれるプラグインを使用しているだけです
このように guard は好きなプラグインと組み合わせてファイルの監視ルールを設定します

今回は guard-shell というファイルが変更されたらシェルコマンドを実行するプラグインを使って適当なコマンドを実行してみました

環境

  • macOS 11.6
  • Ruby 3.0.2p107
  • guard 2.18.0

準備

  • bundle init
  • vim Gemfile
gem "guard"
gem "guard-shell"
  • bundle install

監視ルールの作成

監視ルールと実行するタスクは Guardfile と呼ばれる DSL ファイルに定義します

  • bundle exec guard init

これで作成できます
今回は txt ファイルを監視して ls コマンドで変更されたファイルの詳細を表示する監視ルールを作成します

  • vim Guardfile
guard :shell do
  watch /(.*\.txt)/ do |m|
    n m[0], 'Changed'
    `ls -l #{m[0]}`
  end
end

guard の後ろの「:shell」はプラグイン名を指定します
この部分がよく :rspec であるのは rspec プラグインをインストールしてテストファイルが更新されたら自動でテストが流れるようにするようなルールがよく使われているからです

動作確認

では監視プロセスを実行して挙動を確認してみましょう

  • bundle exec guard start

これで実行できます
今回は標準出力に表示するのでインタラクティブモードで実行しますがインタラクティブモードが嫌な場合は

  • bundle exec guard start -i

で実行しましょう

あとはファイル更新すると以下のように ls の情報が出力されるのが確認できると思います

% echo 'aaa' > hoge.txt

09:33:57 - INFO - Guard is now watching at '/path/to/dir'
[1] guard(main)> 
-rw-r--r--  1 hawksnowlog  staff  4  9 29 09:33 hoge.txt

最後に

あくまでも開発中のツールとして使う感じかなと思います
(プロダクションのファイル監視デーモンプロセスとして使えなくもなさそうですが)

Rubygems で「guard-」と検索するといろいろとプラグインが表示されるので実行したいコマンドやタスクに合わせて既存のプラグインを見つけましょう

参考サイト

2021年10月14日木曜日

Omnibus Gitlab に付属している Prometheus と Alertmanager を使って Gitlab がダウンした際のアラートを受け取る方法

Omnibus Gitlab に付属している Prometheus と Alertmanager を使って Gitlab がダウンした際のアラートを受け取る方法

概要

Omnibus Gitlab には Prometheus と Alertmanager が付属しています
デフォルトだとどちらも有効にはなっていますが Alertmanager に関してはレシバーが登録されていないので通知はされません

今回は Slack レシバーを追加して Gitlab がダウンした際のアラートを受け取る設定を紹介します

環境

  • Omnibus Gitlab 14.2.3-ee

AlertManager の設定を gitlab.rb にする

gitlab.rb に以下を設定します

docker の場合は GITLAB_OMNIBUS_CONFIG に設定します

紹介しているのは Alertmanager と Prometheus に関する部分だけなので他の設定がある場合はその設定に追記してください

prometheus['listen_address'] = '0.0.0.0:9090'
alertmanager['listen_address'] = '0.0.0.0:9093'
alertmanager['receivers'] = [{'name' => 'slack','slack_configs' => ['api_url' => 'https://hooks.slack.com/services/xxx/xxx/xxx', 'channel' => '#private', 'text' => "{{ .CommonAnnotations.summary }}", 'send_resolved' => true]}]
alertmanager['default_receiver'] = 'slack'

ポイントは receivers と default_receiver の部分です

recievers には Slack レシーバを登録します
この設定は alertmanager.yml に記載する receivers の設定と同じなのでそのまま使えます

default_receiver は使用するレシーバを設定します
今回は「slack」レシーバを設定したのでそのレシーバを使うように default_receiver を設定します

あとは Gitlab を再起動しましょう

  • docker-compose down
  • docker-compose up -d

動作確認

gitlab プロセスを停止してみましょう

  • docker-compose exec gitlab gitlab-ctl stop puma
ok: down: puma: 0s, normally up

これでしばらくすると Prometheus と Alertmanager でアラートが発生しているのが確認できます

Slack にもちゃんと通知が来ることを確認しましょう

なぜか .CommonAnnotations.summary が埋め込まれていませんがこれは default-receiver が残ってしまっているせいです

default-receiver と別のグループとして slack レシーバを登録できればちゃんと表示されるはずです

最後に

メリットとして Omnibus Gitlab の監視設定をそのまま使えるので別途監視ツールを導入する必要はありません

デメリットとしては Prometheus 側のメトリックとアラートの設定は Omnibus Gitlab が用意しているものをそのまま使うので本来監視したくないルールがある場合に無視できません

ただ自分が試してみた感じだとこのあたりのドキュメントが少なくどこをどうやって設定するかは Omnibus gitlab の cookbooks などを眺める必要があるので少し面倒かもしれません

参考サイト

2021年10月13日水曜日

Alertmanager でアラート時にシェルスクリプトを実行する方法

Alertmanager でアラート時にシェルスクリプトを実行する方法

概要

AlertManager はアラートの情報を Slack やメールで通知します
アラート発生時に特定のコマンドを実行したい場合があります
その場合は webhook と組み合わせてコマンドを実行しましょう

Promethues や AlertManager の基本的な設定は前回の記事を確認してください

環境

  • Ubuntu 18.04
  • docker 20.10.7
  • Prometheus 2.30.3
  • Alertmanager 0.23.0
  • Node export 1.2.2
  • webhook 2.5.0

webhook の準備

インストールはこちらを参照してください
webhook を受け取った際に実行するシェルと AlertManager から webhook を受け取りペイロードを変数に格納する設定を準備します

  • vim /tmp/alertmanager_test.sh
#!/bin/bash
echo $STATUS > result_alertmanager_test_shell.log
echo $ANNOTATIONS >> result_alertmanager_test_shell.log
  • chmod +x /tmp/alertmanager_test.sh

AlertManager から送信されるペイロード情報はこちらを参考にしてください

  • vim /tmp/alertmanager_hooks.json
[
  {
    "id": "alertmanager_test",
    "execute-command": "/tmp/alertmanager_test.sh",
    "command-working-directory": "/tmp",
    "include-command-output-in-response": true,
    "pass-environment-to-command":
    [
      {
        "envname": "STATUS",
        "source": "payload",
        "name": "status"
      },
      {
        "envname": "ANNOTATIONS",
        "source": "payload",
        "name": "alerts.0.annotations.summary"
      }
    ]
  }
]

今回はアラート情報の status と annotations.summary を取得してシェルスクリプト側で使うような設定を記載しています

スクリプトと設定ファイルが準備できたら webhook を起動しましょう

  • webhook -hooks /tmp/alertmanager_hooks.json -verbose

alertmanager.yml

アラート発生時に webhook を投げるように alertmanager.yml に記載します
同時に Slack にも通知したい場合など複数のレシバーを定義する場合には routes で発生したアラートに応じてどのレシバーを使用するのかを定義する必要があります

continue: true にすることで次のレシバーも評価してくれます

  • vim alertmanager.yml
route:
  receiver: 'slack'
  routes:
    - receiver: 'slack'
      group_wait: 10s
      match_re:
        job: node1
      continue: true
    - receiver: 'webhook'
      group_wait: 10s
      match_re:
        job: node1
      continue: true

receivers:
  - name: 'slack'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/xxx/xxx/xxx'
        channel: '#private'
        text: "{{ .CommonAnnotations.summary }}"
        send_resolved: true
  - name: 'webhook'
    webhook_configs:
      - url: 'http://192.168.100.10:9000/hooks/alertmanager_test'

webhook_configs に起動した webhook の URL 情報などを記載します

動作確認

  • stress-ng -c 2 -l 100

などで CPU の使用率を上げてみましょう アラートが上がった際に webhook のログを確認して以下のようなログが出ていれば正常に webhook が投げられ届いていることになります

[webhook] 2021/10/08 13:32:10 executing /tmp/alertmanager_test.sh (/tmp/alertmanager_test.sh) with arguments ["/tmp/alertmanager_test.sh"] and environment [STATUS=firing ANNOTATIONS=Node1 cpu usage over 40%] using /tmp as cwd

ちなみに webhook_configs はデフォルトだと resolved 時にもリクエストして来ます

  • cat result_alertmanager_test_shell.log
resolved
Node1 cpu usage over 40%

コマンドを複数回実行されても問題ないようにするか send_resolved: false を設定してアラート発生時のみ webhook が投げられるようにしましょう

最後に

AlertManager でシェルスクリプトを実行する方法を紹介しました

webhook のプロセスを一つ管理する必要があるので面倒な感じもしますが AlertManager 自体にシェルをキックするような機能は現状ないのでこの方法がベストプラクティスになるかなと思います

Jenkins などがあればそこに webhook を投げてジョブを実行する感じでもいいのかもしれません

参考サイト