2022/02/20

gir

gir は GObjectIntrospection Repository の略とのこと。

DebianやUbuntuのパッケージの中に先頭に gir1.2- が付くパッケージが多数あり、このgirとは何だろうということで調べてみたところ、
https://mail.gnome.org/archives/gnome-shell-list/2011-April/msg00101.html
に説明を見つけました。

Introspectionの説明は
https://developer.gnome.org/documentation/guidelines/programming/introspection.html
にあります。C言語のコードからAPI情報を抽出して、C言語以外の言語から呼び出せるようにする仕組みのようです。

2022/02/15

Firefox 97でペンを使う

Windows10環境でFirefox 97にアップデートしてペンでタブを移動させられなくなってしまった場合は、about:configから

dom.w3c_pointer_events.dispatch_by_pointer_messages
をfalseに設定しましょう。これで、ペンでタブを移動させられるようになります。

タッチ操作でできる画面のスクロールがペンではできなくなりますが、マウスと同様にテキストを選択できるようになるので、マウスの代わりに利用したい方にはこちらのほうが都合が良いでしょう(そもそも以前はこちらがデフォルトの動作でした)。

2022/02/08

WiMAX+5Gを4Gのみで使う

1行まとめ


WiMAX+5GをSpeed Wi-Fi 5G X11で利用されていて、頻発する4Gと5Gの切り替えに難儀されている方は、回線がまともになるまでは「エコ」モードを使用しましょう。

発生している現象


WiMAX+5Gを利用してみました。速くていいですね。

しかしながら、利用場所によっては落とし穴があります。 中途半端に5Gが受信できる場所では、5Gと4Gが頻繁に入れ替わる現象が発生します。

これが理由なのかどうか明確にはわからないのですが、通信が引っかかる現象が頻発します。 ブラウザで検索したりどこかのウェブページを表示したり、ゲームで通信が発生したときなど、 全く反応がなく、結局接続できず失敗することが起きます。おそらくタイムアウトしているのでしょう。

不思議なことに、その現象が発生しているときに別の端末で別のウェブページを開くことは普通にでき、 pingにも影響がみられませんでした。

想像ではありますが、通信そのものは常にできているけれど、ときおりパケットが行方不明になってしまっていて、 行方不明になったパケットに依存している処理がずっと止まっているのかもしれません。

切り替え周期を測定してみたところ、おおむね25秒〜35秒で4Gから5Gへ、または、5Gから4Gへの切り替えが発生していました。 だいたい1分でもとに戻ってくるということですね。

アンテナが2本しか立たないところで使ってみると、4Gのみになり、切り替えは発生しないものの、 ダウンロードはともかくアップロード速度が100kbps未満というほぼ使えない状態になりました。

他に事例は?


こちらの方 https://hudetoro.com/life/2019/ が同じような現象にみまわれているようです。記事を読む限り、通信を提供している側ですぐになんらかの対処が実施されることはなさそうです。

対処方法


通信が切れる問題の原因が仮に4Gと5Gとの切り替えにあるとすると、切り替えが頻発しないようにすれば安定すると思われます。 そもそも5Gを利用しなければ問題ないだろうということです。

調べたところAndroidであれば5Gを使わない設定ができるようです。WiMAX+5Gの端末はAndroidではないので同じ方法は使えそうにありません。

そこで、X11の取扱説明書を読んでみたところ、なんとp.64に

省電力モードが「エコ」モードを選択した場合、WAN 側回線「5G」は無効となります。
と記載がありました(最初の「が」は「で」の誤植っぽいですが、原文ママです)。

というわけですので、通信が切れて困っている方、X11であれば「エコ」モードにすればもしかしたら問題がましになるかもしれません。

2021/12/18

zmqの通信の認証と暗号化

目的


ZMQで認証&通信暗号化をしてみます。言語はPythonを使います。

コード


REQ-REPで試してみます。Public keyとSecret keyを作成するコード、サーバーのコード、クライアントのコードが必要になります。

キー作成


次のgen_keys.pyを作成し、pythonで実行します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import os
import zmq
import zmq.auth

def main():
    os.makedirs("cert", exist_ok=True)
    server_public_file, server_secret_file = zmq.auth.create_certificates("cert", "server")
    client_public_file, client_secret_file = zmq.auth.create_certificates("cert", "client")

if __name__ == '__main__':
    main()
すると、certディレクトリに
client.key
client.key_secret
server.key
server.key_secret
の4つのファイルが作成されます。

サーバー


サーバーのコードは以下の通り。サーバー側に認証機能をつけます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import zmq
import zmq.auth
from zmq.auth.thread import ThreadAuthenticator

def main():
    ctx = zmq.Context.instance()
    auth = ThreadAuthenticator(ctx)
    auth.start()
    auth.configure_curve(location="cert") # Need only public keys
    server = ctx.socket(zmq.REP)
    server.curve_publickey, server.curve_secretkey = zmq.auth.load_certificate("cert/server.key_secret")
    server.curve_server = True
    server.bind('tcp://*:9000')

    while True:
        msg = server.recv_pyobj()
        print("server:", msg)
        server.send_pyobj("123")

if __name__ == '__main__':
    main()
無限ループをCtrl+Cで止める前提なので入れていませんが、普通はauth.stop()で認証用スレッドを終了しましょう。

クライアント


クライアントのコードは以下の通り。サーバーのpublic keyが必要です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import zmq
import zmq.auth

def main():
    ctx = zmq.Context.instance()
    client = ctx.socket(zmq.REQ)
    client.curve_publickey, client.curve_secretkey = zmq.auth.load_certificate("cert/client.key_secret")
    client.curve_serverkey, _ = zmq.auth.load_certificate("cert/server.key")
    client.connect('tcp://127.0.0.1:9000')

    client.send_pyobj("abc")
    msg = client.recv_pyobj()
    print("client:", msg)

if __name__ == '__main__':
    main()

サーバーを実行し、その後、クライアントを実行すると、サーバー側に

server: abc
クライアント側に
client: 123
と表示されます。

クライアント側で指定するサーバーのPublic keyを間違えるとサーバーには接続できません。 また、Wiresharkで通信内容を見た限りでは、abcや123は平文では通信されていませんでした。 一方、認証関連のコード(authやcurve関連)を削除して実行すると、abcや123を平文で読むことができました。

参考


https://github.com/zeromq/pyzmq/blob/main/examples/security/generate_certificates.py
https://github.com/zeromq/pyzmq/blob/main/examples/security/ironhouse.py

2021/12/11

bashでN進数表記

整数計算に限りますが、bashで$(( ))による計算をするときに# (ASCIIコードで0x23、シャープ、井桁、番号記号、ナンバーサイン、ハッシュ、どう呼べばよいのか?)を使うとN進数で記載できます。計算結果の表示は10進数になります。

2進数

$ echo $((2#1110))
14

3進数

$ echo $((3#201))
19

4進数

$ echo $((4#123))
27

5進数

$ echo $((5#234))
69

8進数

$ echo $((8#17))
15

10進数

$ echo $((10#17))
17

16進数

$ echo $((16#fe))
254

20進数

$ echo $((20#ji))
398

40進数

$ echo $((40#D))
39

50進数

$ echo $((50#N))
49

60進数

$ echo $((60#X))
59

64進数

$ echo $((64#Z))
61
$ echo $((64#@))
62
$ echo $((64#_))
63

基底の最大値は64で、それより値が大きいと

$ echo $((65#1))
bash: 65#1: 無効な基底の数値です (エラーのあるトークンは "65#1")
とエラーになります。

2021/12/07

OzoneのデータにC++でアクセス

Apache Ozone上にあるデータにC++でアクセスしてみます。Ozoneの準備は、「Ozoneを試す」を参照ください。

ライブラリのビルド


https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/setup-linux.htmlを参考にビルドしていきます。

まず、ダウンロードします。

$ git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp.git
この日の時点では、1.4GBありました。大きいですね。

ビルドにはUbuntuでは libcurl4-openssl-dev, libssl-dev, uuid-dev, zlib1g-dev をインストールしておく必要があるようです。

ビルドします。

$ cd aws-sdk-cpp
$ mkdir sdk_build
$ cd sdk_build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../sdk -DBUILD_ONLY="s3" ..
$ make
$ make install

Ozoneにアクセス


https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/build-cmake.htmlなどを参考に、ビルドしたライブラリを使ってOzoneにアクセスしてみます。

すべてのBucketのすべてのObjectを読み込んで標準出力に出力するソースコードmain.cppは次の通りです。 なお、テキストデータの表示のためヌル終端していますが、単に読み込むだけであれば不要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <aws/core/Aws.h>
#include <aws/core/utils/logging/LogLevel.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/ListObjectsRequest.h>
#include <aws/s3/model/GetObjectRequest.h>
#include <iostream>

class Initializer{
public:
  Initializer(){
    options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
    Aws::InitAPI(options);
  }
  ~Initializer(){
    Aws::ShutdownAPI(options);
  }
private:
  Aws::SDKOptions options;
};

int main(void){
  Initializer initializer;
  Aws::Client::ClientConfiguration config;
  config.endpointOverride = "http://localhost:9878";

  // client cannot access objects if useVirtualAddressing is true
  Aws::S3::S3Client client(config, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false/*useVirtualAddressing*/);
  Aws::S3::Model::ListBucketsOutcome buckets = client.ListBuckets();
  if(!buckets.IsSuccess()){
    std::cout << "Fail to get buckets" << std::endl;
    return 1;
  }
  Aws::S3::Model::ListBucketsResult listBucketsResult = buckets.GetResult();
  for(const Aws::S3::Model::Bucket &bucket : listBucketsResult.GetBuckets()){
    std::cout << "Bucket name: " << bucket.GetName() << std::endl;

    // Get objects
    Aws::S3::Model::ListObjectsRequest request;
    request.WithBucket(bucket.GetName());
    Aws::S3::Model::ListObjectsOutcome listObjectsOutcome = client.ListObjects(request);
    if(!listObjectsOutcome.IsSuccess()){
      std::cout << "Fail to get objects" << std::endl;
      continue;
    }
    Aws::S3::Model::ListObjectsResult listObjectsResult = listObjectsOutcome.GetResult();
    std::cout << "Bucket name: " << listObjectsResult.GetName() << std::endl;
    std::cout << "Max keys: " << listObjectsResult.GetMaxKeys() << std::endl;
    const Aws::Vector<Aws::S3::Model::Object> &objects = listObjectsResult.GetContents();
    std::cout << "# of objects: " << objects.size() << std::endl;
    for(const Aws::S3::Model::Object& object : objects){
      // Get the attributes of the object
      std::cout << "Object key: " << object.GetKey() << std::endl;
      long long size = object.GetSize();
      std::cout << "Object value size: " << size << std::endl;

      // Get the value of the object
      Aws::S3::Model::GetObjectRequest objectRequest;
      objectRequest.SetBucket(listObjectsResult.GetName());
      objectRequest.SetKey(object.GetKey());
      Aws::S3::Model::GetObjectOutcome getObjectOutcome = client.GetObject(objectRequest);
      if(!getObjectOutcome.IsSuccess()){
        std::cout << "Fail to get content" << std::endl;
        continue;
      }
      Aws::S3::Model::GetObjectResult getObjectResult = getObjectOutcome.GetResultWithOwnership();
      long long contentLength = getObjectResult.GetContentLength();
      std::cout << "Object value size: " << contentLength << std::endl;
      Aws::IOStream& stream = getObjectResult.GetBody();
      std::vector<char> buff(contentLength+1); // +1 for null terminator
      stream.read(&buff[0], buff.size());
      std::replace(buff.begin(), buff.end(), '\n', '!');
      std::cout << "Object value: " << &buff[0] << std::endl;
    }
  }
  return 0;
}
CMakeLists.txtは次の通りです。
cmake_minimum_required(VERSION 3.3)
set(CMAKE_CXX_STANDARD 11)
project(s3)

add_executable(s3 main.cpp)
target_include_directories(s3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/include)
target_link_libraries(s3 ${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/lib/libaws-cpp-sdk-s3.so
  ${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/lib/libaws-cpp-sdk-core.so)
最初に準備したaws-sdk-cppが、このファイルのあるディレクトリの親ディレクトリ内にあることを前提としています。
┬ aws-sdk-cpp
└ example
   ├CMakeLists.txt
   └main.cpp

今、exampleディレクトリにいるとして、

$ mkdir build
$ cd build
$ cmake ..
$ make
でビルドし、作成されるs3コマンドを実行すると、
$ ./s3
Bucket name: bucket1
Bucket name: bucket1
Max keys: 1000
# of objects: 1
Object key: test.txt
Object value size: 10
Object value size: 10
Object value: test test!
と表示されます。正しく読み込めました。

参考


https://qiita.com/kai_kou/items/095e409539fbe77f0d59

2021/12/04

Ozoneを試す

Apache Ozoneを試してみます。Dockerを事前に使えるようにしておいてください。

準備


Ozoneの立ち上げは https://ozone.apache.org/docs/1.1.0/start/startfromdockerhub.html に従って進めます。

といっても、

$ docker run -p 9878:9878 -p 9876:9876 apache/ozone
を実行するだけです。

操作にはawsコマンドを使用しますので、Ubuntuの場合であれば、

$ apt install awscli
インストールします。また、設定ファイルを作成する必要があるため、例えば、
$ aws configure
AWS Access Key ID [None]: default
AWS Secret Access Key [None]: default
Default region name [None]: default
Default output format [None]: text
のようにします。今dockerで立ち上げたOzoneは ozone.security.enabled=false となっているため、適当な設定でもアクセスできるようです。今は試したいだけなので、このままで進めます。

バケット作成


最初にデータを保管するためのバケットを作る必要があります。バケットの説明は https://www.ipswitch.com/jp/blog/understanding-how-aws-s3-buckets-work が参考になりました。

以下のコマンドでbucket1という名前のバケットを作成できます。

$ aws s3api --endpoint http://localhost:9878/ create-bucket --bucket=bucket1

オブジェクトの格納


データをバケットに格納します。まずコピーするファイル test.txt を作ります。
$ echo "test test" > test.txt
次に、このファイルをバケット内にコピーします。
$ aws s3 --endpoint http://localhost:9878 cp test.txt  s3://bucket1/test.txt
upload failed: ./test.txt to s3://bucket1/test.txt An error occurred (500) when calling the PutObject operation (reached max retries: 4): Internal Server Error
すると、エラーが発生します。今立ち上げているOzoneがシングルコンテナであるため、エラーが発生するようです。そこで、
$ aws s3 --endpoint http://localhost:9878 cp --storage-class REDUCED_REDUNDANCY test.txt  s3://bucket1/test.txt
upload: ./test.txt to s3://bucket1/test.txt
とすると成功します。
$ aws s3 --endpoint http://localhost:9878 ls s3://bucket1/test.txt
2021-12-04 22:20:53         10 test.txt
でファイルが存在することが確認できました。また、
$ aws s3 --endpoint http://localhost:9878 cp s3://bucket1/test.txt -
test test
でファイルの中身を表示できます。出力ファイル名を-にすることで標準出力に流してくれるようです。 これで正しくコピーできていることが確認できました。

Pythonから利用


boto3というライブラリを用いるとPythonからアクセスできます。
$ pip3 install boto3
でインストールします。

次のコード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import boto3

s3 = boto3.resource('s3', endpoint_url="http://localhost:9878")
for b in s3.buckets.all():
    print(" 1:", b)
    print(" 2:", b.name)
    for obj in b.objects.all():
        print(" 3:", obj.key)
        print(" 4:", obj.size)
        print(" 5:", obj.get()["Body"])
        print(" 6:", obj.get()["Body"].read())
        body = obj.get()["Body"]
        print(" 7:", body.read().decode("utf-8"))
        print(" 8:", body.read())
    print(" 9:", b.Object("test.txt").get()["Body"].read())
print("10:", s3.Object("bucket1", "test.txt").get()["Body"].read())
をpython3で実行すると、
 1: s3.Bucket(name='bucket1')
 2: bucket1
 3: test.txt
 4: 10
 5: <botocore.response.StreamingBody object at 0x7f9ae2a71d00>
 6: b'test test\n'
 7: test test

 8: b''
 9: b'test test\n'
10: b'test test\n'
という結果が出力されます。キーをリストアップしてオブジェクトの中身を表示することも、キーを指定してオブジェクトの中身を表示することもできます。 なお、取得したbodyに対して2回readすると、1回目で読み終わっているため、2回目は空が返ってきます。

参考


https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html
https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html#botocore.response.StreamingBody
https://medium.com/towards-data-engineering/get-keys-inside-an-s3-bucket-at-the-subfolder-level-7be42d858372

2021/11/27

AIのべりすと

「AIのべりすと」が面白いそうなので、試してみた。
https://ai-novel.com/

とりあえずデフォルト設定で以下を入れてみた。使用中の言語モデルには「とりんさま6.8B beta (2021/10/19)」と記載されていた。

吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、
これで「続きの文を書く」を何度かクリックすると、以下のような文章が生成された。
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうした事か? これではまるで吾輩が犬ではないか。
あああぁあああっ! なんたる不覚っ! しかし考えてみればそれも無理はないかもしれぬな。
だって吾輩は昨日人間であったのだもの。それが一晩明けて気がついたら犬になっていたのだから。
何を言っているのか解らないと思うが、吾輩も何をされたのか解らぬ。
催眠術だとか超スピードだとか、そんなチャチなものでは断じて無い。もっと恐ろしいものの片鱗を味わった気分
ジョジョじゃないか!

原文を探してみたところ、

な…
何を言っているのか
わからねーと思うが 
おれも 何をされたのか
わからなかった…
頭がどうにかなりそうだった…
催眠術だとか超スピードだとか
そんなチャチなもんじゃあ
断じてねえ
もっと恐ろしいものの片鱗を
味わったぜ……
であった(この部分は「ジョジョの奇妙な冒険」から引用)。一人称が変わり、口語調でなくなっているくらいの差で、ほぼ同じ。 これはモデルが大きすぎてほぼ原文を覚えてしまっている状態なのではないのだろうか?

再現性があるか試してみたが、出力がランダムに変わるようで再現させることはできなかった。 例えば、

吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうしてこうなったのか? 事の発端は一月ほど前に遡る…… ***
「はい、これ」
学校からの帰り道、幼馴染みで親友でもある沙耶香から差し出された封筒を受け取った。表には達筆な字で『招待状』と書かれている。裏返すと
であったり、
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうしてこうなったのだろう? ことの始まりは1時間前に遡る――
***
「やれやれ……」
朝起きると、そこは見知らぬ部屋だった。
知らない天井だなんて古いギャグを言おうと思ったけど、本当に見覚えのない天井で少し驚いた。
俺の名前は
といった結果が出力された。

既存の文章に近い文章がでてくると、文章のコピペを疑われかねないので、今回のようにお試しならともかく、 自分の小説として書く場合はヒントとして使うくらいにしておいたほうが良いのかもしれない。

ところで、さらに続きを書かせてみたら、

吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうした事か? これではまるで吾輩が犬ではないか。
あああぁあああっ! なんたる不覚っ! しかし考えてみればそれも無理はないかもしれぬな。
だって吾輩は昨日人間であったのだもの。それが一晩明けて気がついたら犬になっていたのだから。
何を言っているのか解らないと思うが、吾輩も何をされたのか解らぬ。
催眠術だとか超スピードだとか、そんなチャチなものでは断じて無い。もっと恐ろしいものの片鱗を味わった気分だ。
とにかく何時の間にやら、吾輩は人間ではなくなっていたらしい。
その証拠にほれこの通り、耳としっぽが付いているではないか。……ふむ、なるほど。これが俗に言う『ケモミミ』という奴か。
これはこれで悪くは無いのう。毛
が出てきた。ジョジョシリーズになるわけではない模様。

[追記 2021/11/28]
ジョジョっぽい単語を入れてみた。

吾輩は猫である。名前はまだない。
そんな吾輩は今、ジョースターになってしまった。しかもエジプトに
すると、
吾輩は猫である。名前はまだない。
そんな吾輩は今、ジョースターになってしまった。しかもエジプトに来ている。何故だか解るか? それはな――」
「まあ待てよ承太郎さんよォ~」
花京院が、何やら長くなりそうな語りを遮った。
「俺もまだ全部の事情を聞いたわけじゃあねえんだぜ。
なんか色々間違っている気もするが、それっぽい文章がでてきた。

2021/11/05

仮想マシンマネージャーでIDEディスクを選びたい

目的


Ubuntu 20.04 で利用できる仮想マシンマネージャー(virt-manager)でIDEのディスクを選べるようにします。

方法


新しい仮想マシンを作成するときに、チップセットをQ35ではなく、i440FXを選択します。

詳細


新しい仮想マシンを作成する際の4つあるステップの最後に「インストールの前に設定をカスタマイズする」というチェックボックスが現れるので、 チェックを入れて完了ボタンを押すと仮想マシンの設定をする画面が表示されます。

左のリストから「概要」を選択し、右の「詳細」タブの下の方を見るとチップセットを選ぶドロップダウンリストが見つかります。 リストではQ35とi440FXが選択できます。

Q35を選ぶとSATAやSCSI、USBコントローラは選択できるものの、IDEコントローラが選択できません。

チップセットをi440FXにしておくと、仮想ディスクの詳細なオプションに表示されるディスクバスの選択肢に

  • IDE
  • SATA
  • SCSI
  • USB
  • VirtIO
が現れます。

チップセットは仮想マシン作成後には変更できないため、作成中にi440FXを指定する必要があります。

まっさらな状態から仮想ディスクを作成する場合にはあえてIDEを選択する必要はありませんし、 SATAのHDDからイメージを作成したときもSATAを選べば良いので使う機会は多くの人にはないでしょう。

しかし、どうしてもIDE接続の古いHDDを仮想ディスクに変換し、仮想マシン上で動作させたいときには、IDEを選択できるチップセットi440FXが役に立つことでしょう。

補足


チップセットにQ35を指定していて、ディスクの詳細タブの右側のXMLタブを直接書き換えて、無理やりIDEを指定すると
libvirt.libvirtError: unsupported configuration: IDE controllers are unsupported for this QEMU binary or machine type
が表示され、結局IDEは選択できません。

2021/08/28

インフルエンザとか空気感染するんじゃ?

インフルエンザやライノウイルスなどの呼吸器感染症の原因となるウイルスの空気感染に関して調査したレビュー論文です。

Airborne transmission of respiratory viruses (https://doi.org/10.1126/science.abd9149)

呼吸したり話をしたり咳をすることで吐き出される粒子の多くは直径1μm未満で、1μmの粒子が1.5mの高さから地面に到達するには12.2hかかるとのこと(Fig. 3)。 また、しゃべると、100μmより大きい粒子に対して100μm未満の粒子が100倍から1000倍排出されるもよう。

粒子を吸い込むと、直径0.01μmくらいの粒子は効率よく肺胞や気管支に付着し、1μm以上の粒子は咽頭、喉頭、鼻咽腔に付着するようです(Fig. 5)。 また、なぜか0.1μm〜1μmの粒子が付着する効率は低いようです(効率が低いだけで付着しないわけではない)。

参考までに、線香の煙の粒子径は0.2μm以下。
http://gakui.dl.itc.u-tokyo.ac.jp/cgi-bin/gazo.cgi?no=215414

タバコの粒子サイズは0.1〜1.0μm。時間が経つと凝集しサイズが大きくなる。
https://www.sciencedirect.com/science/article/abs/pii/0095852260900374 https://www.jstage.jst.go.jp/article/jar/1/3/1_3_156/_pdf

ということは、煙の類を効率よく排出したり空気清浄機などで集塵できるような環境を整えないと、 室内では話し手から2mくらい離れていようが、アクリル版などで衝立を立てようが、見えない煙だと思うとほぼ意味はなさそう。

https://www.ims.u-tokyo.ac.jp/imsut/jp/about/press/page_00042.html
にあるようにマスクは効果はありそうだけれども、見えない煙相当のウイルスが充満している室内にいると、その効果も限定的になると思って行動したほうがよさそう。

2021/08/01

天の川銀河の構造

2012年の古い記事ですが、天の川銀河(Milky Way)がどのようになっているのか解説されている記事です。

https://www.nature.com/articles/490024a

この記事から9年の間にさらなる発見がありそうですが、どんな姿かざっと知るにはちょうどよいですね。

2021/07/30

PyTorchでMNIST

PyTorchでMNISTを動かしてみました。CPUのみで動作します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#
# Ref: https://github.com/pytorch/examples/blob/master/mnist/main.py
# Ref: https://qiita.com/ryu1104/items/76126a1d2ce22c59fe97
#
# Requirements:
#   pyenvでpythonをインストールするときはliblzma-devが必要。
#   pip install pylzma
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 64, (5,5), stride=(2,2))
        self.conv2 = nn.Conv2d(64, 128, (5,5), stride=(2,2))
        self.linear1 = nn.Linear(2048, 256)
        self.linear2 = nn.Linear(256, 10)
        self.dropout1 = nn.Dropout(0.5)

    def forward(self, x):
        x = F.leaky_relu(self.conv1(x), negative_slope=0.02)
        x = F.leaky_relu(self.conv2(x), negative_slope=0.02)
        x = torch.flatten(x, 1)
        x = self.dropout1(F.leaky_relu(self.linear1(x), negative_slope=0.02))
        x = self.linear2(x)
        return x

def main():
    torch.manual_seed(123)
    dataset_train = datasets.MNIST(root="./data", train=True, download=True, transform=transforms.ToTensor())
    dataset_test = datasets.MNIST(root="./data", train=False, download=True, transform=transforms.ToTensor())
    loader_train = DataLoader(dataset_train, batch_size=32, shuffle=True)
    loader_test = DataLoader(dataset_test, batch_size=128)
    model = Model()
    opt = torch.optim.Adam(model.parameters(), lr=0.001)
    for epoch in range(10):
        model.train()
        loss_train = 0
        for batch_index, (x, t) in enumerate(loader_train):
            opt.zero_grad()
            y = model(x)
            loss = F.cross_entropy(y, t, reduction="sum")
            loss_train += loss.item()
            loss.backward()
            opt.step()
        loss_train /= len(loader_train.dataset)

        # Test
        model.eval()
        loss_test = 0
        correct = 0
        with torch.no_grad():
            for x, t in loader_test:
                y = model(x)
                loss_test += F.cross_entropy(y, t, reduction="sum").item()
                pred = y.argmax(dim=1, keepdim=True)
                a = t.view_as(pred)
                correct += pred.eq(a).sum().item()
        loss_test /= len(loader_test.dataset)
        acc_test = 100.0 * correct / len(loader_test.dataset)
        print("epoch={} loss_train={} loss_test={} acc_test={}".format(epoch, loss_train, loss_test, acc_test))

if __name__ == "__main__":
    main()

実行すると、

epoch=0 loss_train=0.15844096369811644 loss_test=0.04875367822442204 acc_test=98.39
epoch=1 loss_train=0.05745177720999345 loss_test=0.03826701421057806 acc_test=98.81
epoch=2 loss_train=0.04121023142867489 loss_test=0.03071835657870397 acc_test=98.93
epoch=3 loss_train=0.03073415454996381 loss_test=0.031469110992277276 acc_test=99.05
epoch=4 loss_train=0.024984311143002317 loss_test=0.033686953871918376 acc_test=99.04
epoch=5 loss_train=0.02134333044563282 loss_test=0.04148742442613293 acc_test=98.79
epoch=6 loss_train=0.017344313688603386 loss_test=0.043801980772903655 acc_test=98.99
epoch=7 loss_train=0.015290370488148755 loss_test=0.04075671738231176 acc_test=99.09
epoch=8 loss_train=0.0152512503207066 loss_test=0.04280102529609985 acc_test=99.0
epoch=9 loss_train=0.015672046943081695 loss_test=0.043737064159646434 acc_test=98.98
となります。

2021/01/08

OpenBLASのビルド

はじめに


OpenBLASのビルド方法いろいろです。リビジョンは 78702753f を使用しています。

make時に利用できるオプションは Makefile.rule に記載されています。

Linuxでビルド


単にOpenBLASをLinux環境でビルドするだけなら簡単です。Debian 10だと以下のようになります。
$ git clone https://github.com/xianyi/OpenBLAS.git
$ cd OpenBLAS
$ make -j2
<中略>
 OpenBLAS build complete. (BLAS CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_haswellp-r0.3.13.dev.a (Multi-threading; Max num-threads is 8)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
-j2で2並列ビルドにしています。gfortranがインストールされていない環境なのでLAPACK関連はビルドされていません。

ビルドしたライブラリを呼び出せるか確認するため、インストールします。

$ make PREFIX=$(pwd)/build install
https://github.com/xianyi/OpenBLAS/wiki/User-Manual#call-cblas-interface に記載されている例をビルドして実行してみます。例に記載されてるコードをコピーしたファイルがa.cです。
$ LD_LIBRARY_PATH=../build/lib gcc -I ../build/include -lopenblas a.c
$ LD_LIBRARY_PATH=../build/lib ldd a.out
        linux-vdso.so.1 (0x00007ffd9019f000)
        libopenblas.so.0 => ../build/lib/libopenblas.so.0 (0x00007f17e22f7000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f17e2110000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f17e1f8d000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f17e1f6c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f17e26aa000)
$ LD_LIBRARY_PATH=../build/lib ./a.out
11.000000 -9.000000 5.000000 -9.000000 21.000000 -1.000000 5.000000 -1.000000 3.000000 
計算結果が出力されていることを確認できました。

VirtualBox内のLinuxでビルド


CPUの自動判定ができない環境では、動かしたいCPUの系統をTARGETで指定する必要があります。 少なくともVirtualBox内では自動判定できませんでした。 TARGETの一覧はTargetList.txt に記載されています。

ここでは、VirtualBox内のDebian 10でNEHALEMを指定してみます。CPUは2個です。gfortranはインストール済みの環境です。

$ make TARGET=NEHALEM -j2
<中略>
 OpenBLAS build complete. (BLAS CBLAS LAPACK LAPACKE)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Fortran compiler ... GFORTRAN  (cmd & version : GNU Fortran (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_nehalemp-r0.3.13.dev.a (Multi-threading; Max num-threads is 2)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
依存しているライブラリは以下のようになります。
$ ldd libopenblas_nehalemp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007f5cdda3e000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5cdcba7000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5cdcb86000)
        libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007f5cdc918000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5cdc757000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5cdda40000)
        libquadmath.so.0 => /lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f5cdc715000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f5cdc4f7000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5cdc4db000)

CBLASのみビルド


FortranインターフェイスもLAPACKも不要であれば、
$ make TARGET=NEHALEM ONLY_CBLAS=1 -j2
<中略>
 OpenBLAS build complete. (CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_nehalemp-r0.3.13.dev.a (Multi-threading; Max num-threads is 2)

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblas_nehalemp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007fff91ebd000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff87e467000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff87e446000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff87e285000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff87e992000)
のようにすることで依存するライブラリの数を減らせます。なお、異なるオプションでmakeを実行済みの場合は、最初にmake cleanを実行しておく必要があります。

BLASとCBLASのみビルド


gfortranがインストールされている環境であれば、NO_LAPACK=1を指定することでBLASとCBLASのみをビルドできます。
$ make TARGET=NEHALEM NO_LAPACK=1 -j2
<中略>
 OpenBLAS build complete. (BLAS CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Fortran compiler ... GFORTRAN  (cmd & version : GNU Fortran (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_nehalemp-r0.3.13.dev.a (Multi-threading; Max num-threads is 2)

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblas_nehalemp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007fff1b6ed000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8826dc6000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8826da5000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8826be4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8827317000)

マルチスレッドなしでビルド


LAPACKが不要かつマルチスレッドも不要であれば
$ make TARGET=NEHALEM ONLY_CBLAS=1 USE_THREAD=0 -j2
<中略>
 OpenBLAS build complete. (CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_nehalem-r0.3.13.dev.a (Single-threading)  

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblas_nehalem-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007ffcdf5d1000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb537e1d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb537c5c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fb538218000)
のようにすることで、依存するライブラリの数をさらに減らせます。

マルチCPU対応でビルド


Linux環境でマルチCPU対応のビルドしてみます。
$ make DYNAMIC_ARCH=1 -j2
<中略>
 OpenBLAS build complete. (BLAS CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblasp-r0.3.13.dev.a (Multi-threading; Max num-threads is 8)
  Supporting multiple x86_64 cpu models with minimum requirement for the common code being HASWELL

To install the library, you can run "make PREFIX=/path/to/your/installation install".
$ ldd libopenblasp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007ffec9b63000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6da587d000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6da585c000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6da569b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6da6d60000)
$ du -b libopenblasp-r0.3.13.dev.so
20676824        libopenblasp-r0.3.13.dev.so
makeのログを見る限り、
PRESCOTT
CORE2
NEHALEM
SANDYBRIDGE
HASWELL
SKYLAKEX
COOPERLAKE

BARCELONA
BULLDOZER
PILEDRIVER
STEAMROLLER
EXCAVATOR
ZEN
がビルドされてるようです。

比較のため、haswellの場合のサイズもみてみます。

$ ldd libopenblas_haswellp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007ffd066e2000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f37a4b71000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f37a4b50000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f37a498f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f37a50dc000)
$ du -b libopenblas_haswellp-r0.3.13.dev.so
4077872 libopenblas_haswellp-r0.3.13.dev.so
複数のCPUに対応したことで .so のサイズが増えていることが分かります。

続いて、VirtualBox内のLinux環境でマルチCPU対応のビルドしてみます。

$ make TARGET=NEHALEM DYNAMIC_ARCH=1 NO_LAPACK=1 -j2
<中略>
 OpenBLAS build complete. (BLAS CBLAS)

  OS               ... Linux             
  Architecture     ... x86_64               
  BINARY           ... 64bit                 
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Fortran compiler ... GFORTRAN  (cmd & version : GNU Fortran (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblasp-r0.3.13.dev.a (Multi-threading; Max num-threads is 2)
  Supporting multiple x86_64 cpu models with minimum requirement for the common code being NEHALEM

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblasp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007ffdc5bfd000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa9101af000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa91018e000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa90ffcd000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa91168c000)
$ du -b libopenblasp-r0.3.13.dev.so
20676824        libopenblasp-r0.3.13.dev.so
同じようにビルドされました。

Windows10 WSL1


Windows10のWSL1環境でビルドしてみます。gfortranがインストールされている環境です。こちらもDebian 10です。

この環境でもCPU自動検出は動作しないのでTARGETを指定する必要があります。

$ make TARGET=NEHALEM ONLY_CBLAS=1 -j2
<中略>
 OpenBLAS build complete. (CBLAS)

  OS               ... Linux
  Architecture     ... x86_64
  BINARY           ... 64bit
  C compiler       ... GCC  (cmd & version : cc (Debian 8.3.0-6) 8.3.0)
  Library Name     ... libopenblas_nehalemp-r0.3.13.dev.a (Multi-threading; Max num-threads is 8)

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblas_nehalemp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007ffff07e4000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f74fdea0000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f74fde7f000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f74fdcb0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f74fe3ba000)
$ du -b libopenblas_nehalemp-r0.3.13.dev.so
3817776 libopenblas_nehalemp-r0.3.13.dev.so

Windows10 WSL1 + clang


WSL1環境でgccではなくclangでビルドしてみます。
$ make TARGET=NEHALEM ONLY_CBLAS=1 CC=clang -j2
<中略>
 OpenBLAS build complete. (CBLAS)

  OS               ... Linux
  Architecture     ... x86_64
  BINARY           ... 64bit
  C compiler       ... CLANG  (cmd & version : clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final))
  Library Name     ... libopenblas_nehalemp-r0.3.13.dev.a (Multi-threading; Max num-threads is 8)

To install the library, you can run "make PREFIX=/path/to/your/installation install".

$ ldd libopenblas_nehalemp-r0.3.13.dev.so
        linux-vdso.so.1 (0x00007fffd93c6000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc764ab0000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc764a8f000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc7648c0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc764fb5000)
$ du -b libopenblas_nehalemp-r0.3.13.dev.so
3692824 libopenblas_nehalemp-r0.3.13.dev.so
gccでビルドした場合に比べて、若干ですが .so のサイズが小さくなっています。

Windows10 WSL1 + Android NDK


Android NDKをWSL1に準備して、Android用にクロスコンパイルしてみます。 ここで利用するAndroid NDKのバージョンはr21d (21.3.6528147)です。

リリースノートによると、

  • platforms
  • sources/cxx-stl
  • sysroot
  • toolchains(toolchains/llvm を除く)
がNDKのパスから削除されるとのことですので、toolchains/llvmのみを用いてOpenBLASをビルドしてみます。

x86 32-bit


x86の32-bit向けのビルドするためのシェルスクリプトの例は以下のとおりです。
#!/bin/bash
API_VERSION=24
NDK=/path/to/ndk/android-ndk-r21d-linux-x86_64/android-ndk-r21d
NDK_BINPATH=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
NDK_SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
NDK_LIBPATH=$NDK_SYSROOT/usr/lib/i686-linux-android/$API_VERSION
NDK_CC="i686-linux-android$API_VERSION-clang --sysroot $NDK_SYSROOT -B$NDK_LIBPATH"
PATH=$NDK_BINPATH:$PATH make TARGET=NEHALEM ONLY_CBLAS=1 AR=ar CC="$NDK_CC" LDFLAGS="-L$NDK_LIBPATH" HOSTCC=gcc USE_THREAD=0 -j2
これを実行してビルドが成功すると、
 OpenBLAS build complete. (CBLAS)

  OS               ... Android
  Architecture     ... x86
  BINARY           ... 32bit
  C compiler       ... CLANG  (cmd & version : Android (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project
 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn))
  Library Name     ... libopenblas_nehalem-r0.3.13.dev.a (Single-threading)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
が表示されます。なお、AR=ar を AR=i686-linux-android-ar としてもビルドできます。

x86 64-bit


x86の64-bit向けのビルドするためのシェルスクリプトの例は以下のとおりです。
#!/bin/bash
API_VERSION=24
NDK=/path/to/ndk/android-ndk-r21d-linux-x86_64/android-ndk-r21d
NDK_BINPATH=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
NDK_SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
NDK_LIBPATH=$NDK_SYSROOT/usr/lib/x86_64-linux-android/$API_VERSION
NDK_CC="x86_64-linux-android$API_VERSION-clang --sysroot $NDK_SYSROOT -B$NDK_LIBPATH"
PATH=$NDK_BINPATH:$PATH make TARGET=NEHALEM ONLY_CBLAS=1 AR=ar CC="$NDK_CC" LDFLAGS="-L$NDK_LIBPATH" HOSTCC=gcc USE_THREAD=0 -j2
これを実行してビルドが成功すると、
 OpenBLAS build complete. (CBLAS)

  OS               ... Android
  Architecture     ... x86_64
  BINARY           ... 64bit
  C compiler       ... CLANG  (cmd & version : Android (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project
 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn))
  Library Name     ... libopenblas_nehalem-r0.3.13.dev.a (Single-threading)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
が表示されます。なお、AR=ar を AR=x86_64-linux-android-ar としてもビルドできます。

arm 32-bit


armの32-bit向けのビルドするためのシェルスクリプトの例は以下のとおりです。
#!/bin/bash
API_VERSION=24
NDK=/path/to/ndk/android-ndk-r21d-linux-x86_64/android-ndk-r21d
NDK_BINPATH=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
NDK_SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
NDK_LIBPATH=$NDK_SYSROOT/usr/lib/arm-linux-androideabi/$API_VERSION
NDK_CC="armv7a-linux-androideabi24-clang --sysroot $NDK_SYSROOT -B$NDK_LIBPATH"
PATH=$NDK_BINPATH:$PATH make TARGET=ARMV7 ONLY_CBLAS=1 ARM_SOFTFP_ABI=1 AR=ar CC="$NDK_CC" LDFLAGS="-L$NDK_LIBPATH" HOSTCC=gcc USE_THREAD=0 -j2
これを実行してビルドが成功すると、
 OpenBLAS build complete. (CBLAS)

  OS               ... Android
  Architecture     ... arm
  BINARY           ... 32bit
  C compiler       ... CLANG  (cmd & version : Android (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project
 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn))
  Library Name     ... libopenblas_armv7-r0.3.13.dev.a (Single-threading)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
が表示されます。なお、AR=ar を AR=arm-linux-androideabi-ar としてもビルドできます。

arm 64-bit


armの64-bit向けのビルドするためのシェルスクリプトの例は以下のとおりです。
#!/bin/bash
API_VERSION=24
NDK=/path/to/ndk/android-ndk-r21d-linux-x86_64/android-ndk-r21d
NDK_BINPATH=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
NDK_SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
NDK_LIBPATH=$NDK_SYSROOT/usr/lib/aarch64-linux-android/$API_VERSION
NDK_CC="aarch64-linux-android24-clang --sysroot $NDK_SYSROOT -B$NDK_LIBPATH"
PATH=$NDK_BINPATH:$PATH make TARGET=ARMV8 ONLY_CBLAS=1 AR=ar CC="$NDK_CC" LDFLAGS="-L$NDK_LIBPATH" HOSTCC=gcc USE_THREAD=0 -j4
mkdir -p build-aarch64
INSTALL_DIR=$(readlink -f build-aarch64)
PATH=$NDK_BINPATH:$PATH make TARGET=ARMV8 ONLY_CBLAS=1 PREFIX=$INSTALL_DIR install
これを実行してビルドが成功すると、
 OpenBLAS build complete. (CBLAS)

  OS               ... Android
  Architecture     ... arm64
  BINARY           ... 64bit
  C compiler       ... CLANG  (cmd & version : Android (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project
 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn))
  Library Name     ... libopenblas_armv8-r0.3.13.dev.a (Single-threading)

To install the library, you can run "make PREFIX=/path/to/your/installation install".
が表示されます。なお、AR=ar を AR=aarch64-linux-android-ar としてもビルドできます。

2020/12/24

git-crecord

はじめに


gitのコミット時に行単位でコミットする部分を選択できるツール git-crecord に4年ぶりにリリースタグが付けられていましたので、 設定方法をメモしておきます。

git-crecordには、

  • 部分選択コミット作業に特化
  • テキストユーザーインターフェイス(ncursesベースのCUI)
  • 操作方法が直感的なので覚えることはほぼなし(習得が簡単!)
という特徴があります。コミット以外の作業もテキストユーザーインターフェイスで行いたい場合は 多機能なtigのほうが便利でしょう。 なお、git-crecordはMercurialの拡張機能であるcrecord(※1)のgit移植版です。

設定


https://github.com/andrewshadura/git-crecord からgitでcloneします。このメモの作成時点では Python 3.6 以降が必要とのことです。

あとは、cloneしたディレクトリにあるgit-crecordがgitから見つけられるようPATHを通すだけです。 すでに、~/.local/bin/にパスが通っているのであれば、 そこにgit-crecordへのリンクを作成するのが最も簡単でしょう。 名前はgit-crecordのままである必要があります。

実行例


gitリポジトリでgit crecordを実行すると、
Select hunks to commit - [x]=selected **=collapsed  c: confirm     
q: abort  arrow keys: move/expand/collapse  space: deselect        
?: help                                                            
[x]    diff --git a/aaa.txt b/a.txt                                
       similarity index 100%                                       
       rename from aaa.txt                                         
       rename to a.txt                                             
                                                                   
___________________________________________________________________
[x]    diff --git a/b.txt b/b.txt                                  
       new file mode 100644                                        
                                                                   
   [x]     @@ -0,0 +1,1 @@                                         
      [x]  +bbb                                                    
___________________________________________________________________
[~]    diff --git a/c.txt b/c.txt                                  
       index 1e2c877..7bd5b45 100644                               
       2 hunks, 3 lines changed                                    
                                                                   
   [~]     @@ -1,3 +1,4 @@                                         
            ccc                                                    
      [x]  -ddd                                                    
      [ ]  +111                                                    
      [x]  +dDd                                                    
            eee                                                    
                                                                   
   [x]     @@ -3,0 +5,1 @@                                         
      [x]  +333                                                    
のような画面が表示されます。使い方はみたままです。 スペースキーでコミットする部分を行単位またはハンク単位、ファイル単位で選択できますので、選んだ後にcキーを押せばコミット処理が開始されます。

補足


(※1) Mercurialの設定ファイルに
[ui]
interface = curses
と書いておけば hg commit -i で使えます。

2020/12/23

仮想ファイルシステムをユーザー権限でマウント

準備


libguestfs-toolsが必要ですので、apt等でインストールしておきます。

ファイルシステムの作成


マウントしてアクセスしたいファイルシステムを作成します。ここでは例として、ディレクトリ1個とファイルが2個あるファイルシステムを作ります。
$ mkdir fs
$ echo "abc" > fs/abc.txt
$ mkdir fs/sub
$ echo "cde" > fs/sub/cde.txt
$ tree
.
├── abc.txt
└── sub
    └── cde.txt

1 directory, 2 files
$ virt-make-fs -t ext4 -s +10M fs fs.img
これで、fs.imgにファイルシステムが作成されます。 -t ext4により、ext4でファイルシステムを作成することを指定しています。軽量なものが良ければ、ext2がよいそうです。 -s +10M により、空き容量を10MB付け加えたファイルシステムを作るよう指定しています。

ファイルシステムのマウント


ファイルシステムが作成できましたので、これをマウントしてみます。マウントポイントはmpとします。ルート権限は不要です。
$ mkdir mp
$ guestmount -a fs.img -m /dev/sda mp
$ tree mp
mp
├── abc.txt
├── lost+found
└── sub
    └── cde.txt

2 directories, 2 files
マウントできました。今回作成したイメージの場合、-mオプションは省略できません。

dfで見てもマウントできていることが確認できます。

$ df -h -t fuse
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/fuse         11M  199K  9.1M    3% /home/xxx/yyy/mp
ファイルの書き込みもできますし、もともと用意していたファイルの表示もできます。
$ cd mp
$ echo "xyz" > xyz.txt
$ cat xyz.txt
xyz
$ cat abc.txt
abc
$ cat sub/cde.txt 
cde

ファイルシステムのアンマウント


アンマウントも簡単にできます。
$ guestunmount mp
$ tree mp
mp

0 directories, 0 files

まとめ


仮想ディスクの作成からマウントし、読み書きして、アンマウントするところまで簡単にできました。 この仕組みを使えば、何かデータを処理したい計算機にファイルシステムごとデータを移動したり、 結果を回収したり、バックアップしたりする作業がお手軽にできそうです。

2020/12/21

Kubernetesでコンテナ間ssh接続を試してみる

はじめに


Kubernetes (k8s) のPOD間でssh接続できるように設定してみます。

minikubeのインストール


k8sの環境を作るのにminikubeを利用します。
https://minikube.sigs.k8s.io/docs/start/
を参考にインストールします。LinuxとWindows、macOSに対応しているようです。

ここでは、Windowsで試してみます。仮想マシンが必要ですのでVirtualBoxなどをインストールしておきましょう。

インストールが完了したら、クラスタを開始します。

Windowsなのでコマンドプロンプトを開いて、

minikube start
を実行します。

自動的に準備が始まります。最初にいろいろダウンロードしますが、大きいものは、

  • VMブートイメージ(minikube-v1.16.0) 212.6MiB
  • Kubernetes(v1.20.0) 491MiB
でした。 ダウンロードが完了すると、virtualbox上にVMを作成し始めます。今回実行した環境ではCPUs=2, Memory=6000MB, 20000MBで作成されました。

kubectlが見つからないと言われるので、メッセージに書いてあるとおり、

minikube kubectl --get pods -A
を実行すると、39.52MiBのダウンロードが始まり、完了するとkubectlコマンドを使えるようになります。 上記コマンド自体は
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   coredns-74ff55c5b-srhzs            1/1     Running   0          2m35s
kube-system   etcd-minikube                      1/1     Running   0          2m50s
kube-system   kube-apiserver-minikube            1/1     Running   0          2m50s
kube-system   kube-controller-manager-minikube   1/1     Running   0          2m50s
kube-system   kube-proxy-s8wbb                   1/1     Running   0          2m35s
kube-system   kube-scheduler-minikube            1/1     Running   0          2m50s
kube-system   storage-provisioner                1/1     Running   1          2m50s
という出力をします(出力前にコマンドがなかったら自動でダウンロードされるということのようです)。

sshキーの作成


コンテナ内にアクセスできるユーザを制限するため、sshの公開鍵と秘密鍵を作成しておきます。 Linuxではssh-keygenコマンドで作成できます。Windows環境ならWSL1で動作しているLinuxで作成すれば良いでしょう。詳細は省略しますが、ここでは id_rsa_xyz というキーを作成したとして進めます。

Pod上で動作させるDockerイメージの作成


https://minikube.sigs.k8s.io/docs/handbook/pushing/によると、 minikubeにssh接続してDockerのイメージを作るのがもっとも簡単のようです。
minikube ssh
でminikubeのノード内(VirtualBox内の環境)に入ることができます。ただし、コマンドプロンプトから入るとエスケープシーケンスが処理できず、バックスペースで文字の削除すらできません。

WindowsではWSL1が利用できるので、そこから入ることで回避します(WSL1の準備方法は省略)。WSLのターミナルを立ち上げて(ここではwslttyを利用)、同じコマンドを実行すると、今度はエスケープシーケンスの処理が正しくできます。

どのユーザでログインしたのかは、

$ pwd
/home/docker
$ who
docker  pts/0    xxxxxx
で確認できます。接続先のユーザはdockerになっているようです。

c:\Usersが最初からマウントされていて、minikubeのノード内からは/c/Users/...でアクセスできますので、これを使えばホストであるWindowsとファイルのやりとりができます。

このディレクトリに先程作成したsshキーの公開鍵(ここではid_rsa_xyz.pub)をコピーしておきます。

次に、sshサーバを動作させるDockerイメージを作成します。今回はWindows上でsshsrv.dockerファイルを以下の内容で作成します。

FROM ubuntu:20.04
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN useradd -m xyz && echo "xyz:xyz" | chpasswd
RUN mkdir -p /home/xyz/.ssh && chown xyz /home/xyz/.ssh && chmod 700 /home/xyz/.ssh
ADD ./id_rsa_xyz.pub /home/xyz/.ssh/authorized_keys
RUN chown xyz /home/xyz/.ssh/authorized_keys && chmod 600 /home/xyz/.ssh/authorized_keys
RUN bash -c "echo ForwardAgent yes" > ~/.ssh/config
CMD ["/usr/sbin/sshd", "-D"]
sshサーバの設定は
https://qiita.com/YumaInaura/items/1d5c18a9e55484ccad89
http://kotaroito.hatenablog.com/entry/2016/03/07/094423
を参考にしました。

なお、3行目の /var/run/sshd がないと

Missing privilege separation directory: /run/sshd
とメッセージが出てsshdを起動できません。

Dockerイメージを作成します。

docker build -f sshsrv.docker -t sshsrv:v1 .
sshdをコンテナ内で実行してみます。
docker run -d -p 222:22 --name sshsrv sshsrv:v1
-dはコンテナをバックグラウンドで動かすための引数です。付けわすれるとそのターミナルでは操作できなくなります(Ctrl+DもCtrl+Cも効かない )。--nameで名前を付けておくと、docker psしたときに名前が表示されます。

コンテナ外からsshできるか試してみます。Windowsからアクセスするわけではなく、minikubeのノード内からsshsrvコンテナにアクセスします。 アクセスには秘密鍵かつパーミッションが適切である必要があるので、minikubeのノード内に秘密鍵であるid_rsa_xyzをコピーしてパーミッションも設定しておきます。

cp /c/Users/path/to/id_rsa_xyz ~/.ssh/
chmod 600 ~/.ssh/id_rsa_xyz
ssh-agent bash
ssh-add ~/.ssh/id_rsa_xyz
ssh -p 222 xyz@localhost
とすると、動いているコンテナの中に入ることができます。

動作確認ができましたので、コンテナ内から抜けて、今のコンテナは停止しておきます。

docker kill sshsrv
docker rm sshsrv

あとでコンテナ間接続で使うので、.ssh/configも設定しておきます。

echo "ForwardAgent yes" > ~/.ssh/config
chmod 600 ~/.ssh/config
なお、できあがったイメージの中にsshを使わずに入るには、
docker run --rm -it sshsrv:v1 /bin/bash
を実行すれば中にはいれますが、こちらは今回の目的とは異なりますので使う必要はありません。

k8sで実行


sshサーバを動かすコンテナが準備できましたので、ここではk8s経由で複数のsshサーバを立ててみます。 今回は試しに動作させて見るだけですので、Deploymentを使わずReplicaSetを使ってみます。

まず、k8sに指示するためのsshsrv.yamlファイルを作成します。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sshsrvset
spec:
  selector:
    matchLabels:
      app: sshsrv-template-label
  replicas: 3
  template:
    metadata:
      labels:
        app: sshsrv-template-label
    spec:
      containers:
      - name: sshsrv-template
        image: sshsrv:v1
        ports:
        - containerPort: 22
spec.template.metadata.labels に記述しているapp: sshsrv-template-labelがコンテナのテンプレート名です。

spec.template.spec 以下に、コンテナの設定が記述されています。

spec.template.spec.containers.name がテンプレートそのものの名前で、k8sが立ち上げるコンテナの名前の一部になります。

spec.template.spec.containers.image は前節で作成したDockerイメージの名前で、ここで指定したDockerイメージからコンテナが作成されます。

spec.template.spec.containers.ports のcontainerPort:22はssh接続用のポート番号となります。コメントアウトしてもsshでアクセスできるのでなくても良いのかもしれません。

spec.selector.matchLabels の app: sshsrv-template-labelは spec.template.metadata.labels に記載した内容と同じにします。このラベルを使って、PODに適用するテンプレートを探しているようです。同じyamlファイル中のtemplateが1個だけなら原理的にはtemplateは一意に特定できるので、わざわざlabelを設定する必要はなさそうにも思うのですが、selectorとtemplateの両方を書かないと動作しないので仕方がありません。

spec/replicas の3は、3個同じコンテナを立ち上げることを指示しています。

さて、yamlファイルが準備できましたので、コマンドプロンプトから実行します(WSL1からだとパスが処理できずminikubeを実行できません)。

minikube kubectl -- apply -f sshsrv.yml
minikube sshでminikubeのノード内に入って、docker ps -aを実行すると、
$ docker ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS                     PORTS     NAMES
f14472bc0ace   66c4d55614da           "/usr/sbin/sshd -D"      3 minutes ago   Up 3 minutes                         k8s_sshsrv-template_sshsrvset-m8784_
default_48b8f9f7-0c48-4681-957e-96aad5d7ac57_0
8b9c796bc762   66c4d55614da           "/usr/sbin/sshd -D"      3 minutes ago   Up 3 minutes                         k8s_sshsrv-template_sshsrvset-t79pr_
default_72cb56bd-d4d8-42f5-8378-34ef7b6d9a1a_0
97849d1f2fbc   66c4d55614da           "/usr/sbin/sshd -D"      3 minutes ago   Up 3 minutes                         k8s_sshsrv-template_sshsrvset-wgqpr_
default_62c6fcee-26ac-4799-8e3d-59749ef8a3db_0
のような表示が得られます。3つ立ち上がっていることが確認できます。コマンドプロンプトに戻って
minikube kubectl -- get pods -o wide -l app=sshsrv-template-label
を実行すると、k8s上では
NAME              READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
sshsrvset-m8784   1/1     Running   0          3m    172.17.0.5   minikube              
sshsrvset-t79pr   1/1     Running   0          3m    172.17.0.4   minikube              
sshsrvset-wgqpr   1/1     Running   0          3m    172.17.0.3   minikube              
のような名前でコンテナが立ち上がっていることがわかります。IPアドレスも別々に割り振られているので、 minikubeのノード内から
$ ssh xyz@172.17.0.5
のようにすると、コンテナ内に接続できます。

コンテナを止めるには、コマンドプロンプトから

minikube kubectl -- delete replicaset sshsrvset
を実行します。

minikubeのノード内から各コンテナにssh


前節のようにコンテナを立ち上げても、IPアドレスがわからない場合には接続できません。 そこで、ランダム接続にはなってしまいますが、Serviceを作ります。 Serviceをつくると各コンテナに直接接続せず、Serviceで作成したIPアドレスとポートにつなぎにいけば、コンテナのいずれかに接続することができます。

まず、sshd-service.yamlを作成します。

apiVersion: v1
kind: Service
metadata:
  name: sshd-service
spec:
  type: ClusterIP
  selector:
    app: sshsrv-template-label
  ports:
  - protocol: TCP
    port: 22
    targetPort: 22
重要な点は、spec.selectorに書くラベルはReplicaSetのspec.template.metadata.labelsに記載しているラベルということです。 ReplicaSetのmetadata.nameではありません。また、ReplicaSetのyamlにmetadata.labelsの項目を作ってそこにラベルを書いてもそこは検索対象になりません。 なぜ、template側を参照する設計になっているのかは謎です。高度すぎてまるで分かりません。

さて、コマンドプロンプトからServiceを立ち上げます。

minikube kubectl -- apply -f sshd-service.yaml
立ち上げ後、
minikube kubectl -- get service -o wide
を実行すると表示されるsshd-serviceの行のCLUSTER-IPをたたけば、ReplicaSetで立ち上げたコンテナのいずれかにランダム(?)で接続できます。
ssh xyz@xxx.xxx.xxx.xxx
xxx.xxx.xxx.xxxにはCLUSTER-IPに表示されたIPアドレスを入れます。

コンテナの中からさらに

ssh xyz@xxx.xxx.xxx.xxx
を実行すると、同様に接続できます。確証はありませんが、20回試した範囲では、接続先からは自分自身は除かれているようです。 ただし、2段の場合は自分自身に戻ってくることがあります。 コンテナA→コンテナB→コンテナAというパターンはあるが、コンテナA→コンテナAはなさそうということです。

ランダムではなく各ノードの負荷状況を考慮して接続するサーバを選びたいのですが、残念ながら方法がわかりませんでした。

コンテナ内からであれば、IPアドレスではなくドメイン名でアクセスすることもできます。

ssh xyz@sshd-service.default.svc.cluster.local
または、サービス名のみで
ssh xyz@sshd-service
でアクセスすることもできます。コンテナ内で/etc/resolv.confの中身を表示すれば、ドメイン名の解決のための 設定がどのようになっているのかが分かるかと思います。

Serviceの停止は、

minikube kubectl -- delete service sshd-service
で停止できます。

参考


https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/ がk8sのAPIリファレンスです。kindがたくさんありますが、各kindがどういう役割のものなのかは、ここには記載されていません。yamlに記載する各フィールドの説明はしっかり記載されていますので、各kindを理解してから読むようにしましょう。

各kindがどういうものなのかはは、https://kubernetes.io/ja/docs/home/の検索窓にkind名を入力して検索すれば説明ページがでてきますので、それを参考にしましょう。

DeploymentとStatefulSetとJobだけはAPIリファレンスに短い解説がありましたので引用します。

  • Deployments for stateless persistent apps (e.g. HTTP servers).
  • StatefulSets for stateful persistent apps (e.g. databases).
  • Jobs for run-to-completion apps (e.g. batch Jobs).
また、Pod, ReplicaSet, Deploymentについては https://blog.a-know.me/entry/2018/08/14/185324#Deploymentに解説記事があります。

kind名はたくさんありますし、一覧と概要説明がないと不便ですので、一部ではありますが一覧を作りました。 各説明文はkubernetes.io/ja/docsからの引用となります(kubernetes.ioのドキュメントのライセンス表記に従い、この一覧のみCC BY 4.0が適用されます)。

Kind説明
PodPod は、Kubernetesアプリケーションの基本的な実行単位です。これは、作成またはデプロイするKubernetesオブジェクトモデルの中で最小かつ最も単純な単位です。Podは、クラスターで実行されているプロセスを表します。
https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-overview/
JobJobは1つ以上のPodを作成し、指定された数のPodが正常に終了することを保証します。 JobはPodの正常終了を追跡します。正常終了が指定された回数に達すると、そのタスク(つまりJob)は完了します。Jobを削除すると、そのJobが作成したPodがクリーンアップされます。簡単な例としては、1つのPodを確実に実行して完了させるために、1つのJobオブジェクトを作成することです。ノードのハードウェア障害やノードの再起動などにより最初のPodが失敗したり削除されたりした場合、Jobオブジェクトは新たなPodを立ち上げます。また、Jobを使用して複数のPodを並行して実行することもできます。
https://v1-18.docs.kubernetes.io/ja/docs/concepts/workloads/controllers/job/
ReplicaSetReplicaSetの目的は、どのような時でも安定したレプリカPodのセットを維持することです。これは、理想的なレプリカ数のPodが利用可能であることを保証するものとして使用されます。
https://kubernetes.io/ja/docs/concepts/workloads/controllers/replicaset/
DeploymentDeployment はPodとReplicaSetの宣言的なアップデート機能を提供します。Deploymentにおいて 理想的な状態 を記述すると、Deploymentコントローラーは指定された頻度で現在の状態を理想的な状態に変更します。Deploymentを定義することによって、新しいReplicaSetを作成したり、既存のDeploymentを削除して新しいDeploymentで全てのリソースを適用できます。
https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/
https://qiita.com/tkusumi/items/01cd18c59b742eebdc6a
StatefulSetStatefulSetはステートフルなアプリケーションを管理するためのワークロードAPIです。StatefulSetはDeploymentとPodのセットのスケーリングを管理し、それらのPodの順序と一意性を保証します。 Deploymentのように、StatefulSetは指定したコンテナのspecに基づいてPodを管理します。Deploymentとは異なり、StatefulSetは各Podにおいて管理が大変な同一性を維持します。これらのPodは同一のspecから作成されますが、それらは交換可能ではなく、リスケジュール処理をまたいで維持される永続的な識別子を持ちます。ワークロードに永続性を持たせるためにストレージボリュームを使いたい場合は、解決策の1つとしてStatefulSetが利用できます。StatefulSet内の個々のPodは障害の影響を受けやすいですが、永続化したPodの識別子は既存のボリュームと障害によって置換された新しいPodの紐付けを簡単にします。
https://kubernetes.io/ja/docs/concepts/workloads/controllers/statefulset/
ServicePodの集合で実行されているアプリケーションをネットワークサービスとして公開する抽象的な方法です。Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。 KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。
https://kubernetes.io/ja/docs/concepts/services-networking/service/
SecretKubernetesのSecretはパスワード、OAuthトークン、SSHキーのような機密情報を保存し、管理できるようにします。 Secretに機密情報を保存することは、それらをPodの定義やコンテナイメージに直接記載するより、安全で柔軟です。
https://kubernetes.io/ja/docs/concepts/secret/configuration/
ConfigMapConfigMapは、機密性のないデータをキーと値のペアで保存するために使用されるAPIオブジェクトです。Podは、環境変数、コマンドライン引数、またはボリューム内の設定ファイルとしてConfigMapを使用できます。
https://kubernetes.io/ja/docs/concepts/configuration/configmap/
Ingressクラスター内のServiceに対する外部からのアクセス(主にHTTP)を管理するAPIオブジェクトです。Ingressは負荷分散、SSL終端、名前ベースの仮想ホスティングの機能を提供します。
https://kubernetes.io/ja/docs/concepts/services-networking/ingress/