メーリングリスト管理ツール linkmonk を試してみる。

こんにちは k-jun です。今回はメーリングリストを管理するツール listmonk を試してみます。

https://github.com/knadh/listmonk

軽く見た感じは SendGrid みたいなことが出来るといいなぁと思っています。

Deploy

'Deploy to Heroku' ボタンがあったのでここから Heroku にデプロイしてみます。このボタン実は使ったことなかったんですよね。 Basic 認証の ユーザーとパスワードを設定して、デプロイ後に覗いてみます。

f:id:K-jun1221:20211009132718p:plain

シンプルなデザインには見えますが、良さそうですね。あとは何が出来るのか。ひとまず、メールアドレスの追加は流石にできそうです。

f:id:K-jun1221:20211009133217p:plain

あとは、キャンペーンと呼ばれるものを作成すると、管理されているメールのリストに対してメールが飛ぶようですね。 メール送信のスケジューリングもできるようです。

メールの編集画面はそれなりにちゃんとしていました。

f:id:K-jun1221:20211009133411p:plain

キャンペーンをスタートしてメールを送信してみるも届かない...。なんでだろうと思っていると smtp サーバーを設定する必要があることに気づきました笑。

f:id:K-jun1221:20211009133829p:plain

googlesmtp サーバーを利用して設定を行ったところ、正常にメールが送信されましたね。実際に利用する際には google のものは API 上限などもありそうなので避けたほうが良さそうですが。 Docker なども用意されているので、Deploy までたどり着くのは簡単そう。となると、API がほしいですね。

https://listmonk.app/docs/apis/lists/

Document もありました。Basic 認証なのが気になるところですが、まあ listmonk を使用する程度の規模であれば許容するで良い気もします。 サクッと試せて面白かったです。それでは今回はこのへんで。

Docker オーケストレーションツール Nomad を使ってみる。

こんにちは k-jun です。今回は docker や podman などの container や Virtual Machine などのリソースを動的にスケールさせるオーケストレーションツール Nomad を使ってみようと思います。

https://github.com/hashicorp/nomad

立ち位置としては Kubernetes のようになるんでしょうか。Terraform と連携できたり、GUI もあるようなのでワクワクです。以下のリンクに従って構築してみます。

https://learn.hashicorp.com/collections/nomad/get-started

Install

https://learn.hashicorp.com/tutorials/nomad/get-started-install?in=nomad/get-started

$ brew tap hashicorp/tap
$ brew install hashicorp/tap/nomad
$ which nomad
/usr/local/bin/nomad

大丈夫そう。Cluster を起動してみます。

$ sudo nomad agent -dev -bind 0.0.0.0 -log-level INFO
==> No configuration files loaded
==> Starting Nomad agent...
==> Nomad agent configuration:

       Advertise Addrs: HTTP: 172.31.96.6:4646; RPC: 172.31.96.6:4647; Serf: 172.31.96.6:4648
            Bind Addrs: HTTP: 0.0.0.0:4646; RPC: 0.0.0.0:4647; Serf: 0.0.0.0:4648
                Client: true
             Log Level: INFO
                Region: global (DC: dc1)
                Server: true
               Version: 1.1.5

==> Nomad agent started! Log data will stream in below:

    2021-10-06T04:32:32.842+0900 [INFO]  agent: detected plugin: name=exec type=driver plugin_version=0.1.0
    2021-10-06T04:32:32.842+0900 [INFO]  agent: detected plugin: name=qemu type=driver plugin_version=0.1.0
    2021-10-06T04:32:32.842+0900 [INFO]  agent: detected plugin: name=java type=driver plugin_version=0.1.0
...

これも行けてそう。何かが起動したようです。別 Terminal から Node の状態を見てみます。

$ nomad node status
ID        DC   Name         Class   Drain  Eligibility  Status
bc09b3da  dc1  O-14731-MAC  <none>  false  eligible     ready

$ nomad server members
Name                Address      Port  Status  Leader  Protocol  Build  Datacenter  Region
O-14731-MAC.global  172.31.96.6  4648  alive   true    2         1.1.5  dc1         global

イマイチわからんが、Status が ready や alive だし大丈夫そう。この Cluster に対して job と呼ばれる単位のコンポーネントを定義し、与えていきます。 テンプレートを生成。

$ nomad job init
Example job file written to example.nomad

生成されたファイルのコメントを全て削除すると以下のような内容になっています。コメントを一通り読めばそれぞれのパラメーターの設定値は理解できますが、僕はせっかちなのでひとまず先に進みます。

パット見は redis が docker で起動して、port: 6379 で待ち構えるようになりそうですね。

job "example" {
  datacenters = ["dc1"]
  type = "service"
  update {
    max_parallel = 1
    min_healthy_time = "10s"
    healthy_deadline = "3m"
    progress_deadline = "10m"
    auto_revert = false
    canary = 0
  }
  migrate {
    max_parallel = 1
    health_check = "checks"
    min_healthy_time = "10s"
    healthy_deadline = "5m"
  }
  group "cache" {
    count = 1
    network {
      port "db" {
        to = 6379
      }
    }
    service {
      name = "redis-cache"
      tags = ["global", "cache"]
      port = "db"
    }

    restart {
      attempts = 2
      interval = "30m"
      delay = "15s"
      mode = "fail"
    }
    ephemeral_disk {
      size = 300
    }
    task "redis" {
      driver = "docker"
      config {
        image = "redis:3.2"
        ports = ["db"]
      }
      resources {
      }
    }
  }
}

job を実行して走らせてみます。

$ nomad job run example.nomad
==> 2021-10-06T04:44:14+09:00: Monitoring evaluation "9a75cb51"
    2021-10-06T04:44:14+09:00: Evaluation triggered by job "example"
==> 2021-10-06T04:44:15+09:00: Monitoring evaluation "9a75cb51"
    2021-10-06T04:44:15+09:00: Evaluation within deployment: "00e4f022"
    2021-10-06T04:44:15+09:00: Allocation "4f77c19b" created: node "bc09b3da", group "cache"
    2021-10-06T04:44:15+09:00: Evaluation status changed: "pending" -> "complete"
==> 2021-10-06T04:44:15+09:00: Evaluation "9a75cb51" finished with status "complete"
==> 2021-10-06T04:44:15+09:00: Monitoring deployment "00e4f022"
  ✓ Deployment "00e4f022" successful

    2021-10-06T04:44:36+09:00
    ID          = 00e4f022
    Job ID      = example
    Job Version = 0
    Status      = successful
    Description = Deployment completed successfully

    Deployed
    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
    cache       1        1       1        0          2021-10-06T04:54:35+09:00

何やら動き出しましたね。ちなみに何度やっても同じ実行結果なので、冪等性がありそうです。Job の状態を見てみます。

$ nomad job status example
ID            = example
Name          = example
Submit Date   = 2021-10-06T04:44:14+09:00
Type          = service
Priority      = 50
Datacenters   = dc1
Namespace     = default
Status        = running
Periodic      = false
Parameterized = false

Summary
Task Group  Queued  Starting  Running  Failed  Complete  Lost
cache       0       0         1        0       0         0

Latest Deployment
ID          = 00e4f022
Status      = successful
Description = Deployment completed successfully

Deployed
Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
cache       1        1       1        0          2021-10-06T04:54:35+09:00

Allocations
ID        Node ID   Task Group  Version  Desired  Status   Created    Modified
4f77c19b  bc09b3da  cache       0        run      running  2m48s ago  2m27s ago

Allocation という項目がこの Job がどの Node で実行されているのかを示しているようです。これも状態を見るコマンドが存在するようなので見ていきます。

$ nomad alloc status 4f77c19b
ID                  = 4f77c19b-e49a-56d3-c5cd-764bd84c63a0
Eval ID             = 9a75cb51
Name                = example.cache[0]
Node ID             = bc09b3da
Node Name           = O-14731-MAC
Job ID              = example
Job Version         = 0
Client Status       = running
Client Description  = Tasks are running
Desired Status      = run
Desired Description = <none>
Created             = 4m48s ago
Modified            = 4m27s ago
Deployment ID       = 00e4f022
Deployment Health   = healthy

Allocation Addresses
Label  Dynamic  Address
*db    yes      127.0.0.1:31671 -> 6379

Task "redis" is "running"
Task Resources
CPU         Memory           Disk     Addresses
20/100 MHz  960 KiB/300 MiB  300 MiB

Task Events:
Started At     = 2021-10-05T19:44:25Z
Finished At    = N/A
Total Restarts = 0
Last Restart   = N/A

Recent Events:
Time                       Type        Description
2021-10-06T04:44:25+09:00  Started     Task started by client
2021-10-06T04:44:14+09:00  Driver      Downloading image
2021-10-06T04:44:14+09:00  Task Setup  Building Task Directory
2021-10-06T04:44:14+09:00  Received    Task received by client

おお、Port Forward っぽいものが見えましたね。一応 telnet で観測してみます。

$ telnet 127.0.0.1 31671
Trying 127.0.0.1...
Connected to localhost.

Job ごとの Log を観測するには以下のようなコマンドを使用します。

$ nomad alloc logs 4f77c19b
1:C 05 Oct 19:44:25.047 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 3.2.12 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

1:M 05 Oct 19:44:25.048 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 05 Oct 19:44:25.048 # Server started, Redis version 3.2.12
1:M 05 Oct 19:44:25.048 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 05 Oct 19:44:25.048 * The server is now ready to accept connections on port 6379

いい感じですね。Kubernetes と同様に Container の起動、log の収集、Port Fowarding と同等のことが観測できています。Job の更新も試してみます。

$ cat example.nomad | grep count
    count = 3
$ nomad job plan example.nomad
+/- Job: "example"
+/- Task Group: "cache" (2 create, 1 in-place update)
  +/- Count: "1" => "3" (forces create)
      Task: "redis"

Scheduler dry-run:
- All tasks successfully allocated.

$ nomad job run example.nomad
$ nomad job status example
...
Allocations
ID        Node ID   Task Group  Version  Desired  Status   Created     Modified
9d06b72d  bc09b3da  cache       1        run      running  41s ago     30s ago
d05b931b  bc09b3da  cache       1        run      running  41s ago     29s ago
4f77c19b  bc09b3da  cache       1        run      running  14m56s ago  30s ago

Terraform チックな Dry-run も試せるようです。なかなか良さげですね。適用した結果も Allocations の箇所に ID が追加されているのできちんと起動してそうです。 Local PC 上で試しているので、Node ID が単一のものですが、Cluster を VM 上で構成すると、ここもいい感じに分散してくれそうです。

なお run command 実行時に、-check-index のパラメーターを付与することで 変更前の状態が plan command 実行時と変わらないことを確認してくれるようです。 これにより、複数人で作業しており plan command から run command を実行する間に他の作業者の run command が挟まっていないことを保証してくれるようです。

次に web interface を確認してみます。 localhost:4646/ui/jobs から確認。

f:id:K-jun1221:20211006050653p:plain

この UI はすごいですね... 一発で状態把握ができそうです。

f:id:K-jun1221:20211006050826p:plain

詳細設定なども見てみると、使用できる Memory 量などは Docker の設定を参照しているようですね。それにしてもこの UI は凄い。 Kubernetes はあまり詳しくないのですが、同等の UI を提供できるプラグインなどは存在するのでしょうか。

他の画面は以下のページを参照すると大体の雰囲気がつかめると思います。結構未来を感じますね...。

https://learn.hashicorp.com/tutorials/nomad/get-started-ui?in=nomad/get-started

それでは今回はこのへんで!

Google Analytics の代替ツール umami を試してみる。

こんにちは k-jun です。今回は Google Analytics の代替品 umami を試してみます。

https://github.com/mikecao/umami

普通に自分が日本人なのでバイアスが掛かっているだけだと思いますが、日本語の単語をもとにしたプロダクト名が結構あるように感じています。 umami だの youki だの tokei だの。なんかアルファベットになっているのでかっこよく見えますけどね !!

Install

ここ に従うだけで大丈夫そう。 npm install とは何とも原始的な。。。OSS みを感じますね。自分で全部やって的な。

git clone https://github.com/mikecao/umami.git
cd umami
npm install

あとは MySQL と .env を編集していきます。PostgreSQL でも行けるみたいです。

$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_USER=test -e MYSQL_PASSWORD=test -e MYSQL_DATABASE=test -d mysql:5.7
$ mysql -uroot -proot -h127.0.0.1 -Dtest < sql/schema.mysql.sql
$ echo "DATABASE_URL=mysql://root:root@127.0.0.1:3306/test\nHASH_SALT=B3F1BFB6-32D3-47C9-8709-D2D57C727293" > .env

Run

起動してみます。

$ npm run build
$ npm run start

f:id:K-jun1221:20211004015133p:plain

初期ログイン情報を打ち込んでログインするといい感じのダッシュボードが。良さそうですね。

f:id:K-jun1221:20211004015230p:plain

ではでは実際に Javascript を使用してトラッキングさせてみます。以前 markdown から静的サイトを生成する zola を試した際に 作ったブログを使ってみます。

の中に以下のようなスクリプトを埋め込めば良いようですね。

<script async defer data-website-id="cdf529d2-5e58-4868-bfca-0beb02879481" src="http://localhost:3000/umami.js"></script>

f:id:K-jun1221:20211004021802p:plain

リアルタイムに反映されるの結構すごいですね。Hackathon などで簡易的なトラッキングサービスで問題ないのであれば、たしかに問題なさそうです。 何よりサクッと出来るのが良いですね。Google Analytics を実は使ったことがないので後で使って比べてみます。それでは今回はこのへんで。

開発環境を https 化する mkcert を試してみる。

こんにちは k-jun です。今回は手軽に SSL 証明書を発行できる cli ツール mkcert を試してみます。

https://github.com/FiloSottile/mkcert

開発環境の https 化を目指したものなので、オレオレ証明書の自動作成ツールとはなりませんが。

Install

$ brew install mkcert

Run

$ mkcert filippo@example.com
Note: the local CA is not installed in the system trust store.
Run "mkcert -install" for certificates to be trusted automatically ⚠️

Created a new certificate valid for the following names 📜
 - "filippo@example.com"

The certificate is at "./filippo@example.com.pem" and the key at "./filippo@example.com-key.pem" ✅

It will expire on 2 January 2024 🗓
$ ls filippo@example.com*
filippo@example.com-key.pem     filippo@example.com.pem

S/MIME certificate なんてものもあるんですね。初めて知りました...。 適当に証明書を作ってみます。ドメインlocalhostで。

$ mkcert localhost
Note: the local CA is not installed in the system trust store.
Run "mkcert -install" for certificates to be trusted automatically ⚠️

Created a new certificate valid for the following names 📜
 - "localhost"

The certificate is at "./localhost.pem" and the key at "./localhost-key.pem" ✅

It will expire on 4 January 2024 🗓

localhost.pemlocalhost-key.pem が生成されました。これを用いて SSL の設定をしていきます。Docker で Nginx を起動し、これに設定ができれば大丈夫と思いますのでこれでやっていきます。

# nginx.conf
http {
  server_names_hash_bucket_size 128; # this seems to be required for some vhosts

  server { # simple reverse-proxy

    listen 443;
    ssl on;
    ssl_certificate /tmp/localhost.pem;
    ssl_certificate_key /tmp/localhost-key.pem;

    location / {
      # proxy_pass http://host.docker.internal:5000;
      return 200 "Hello World";
    }
  }
}[f:id:K-jun1221:20211004012754p:plain]
# docker-compose.yml
version: "3.3"
services:
  nginx: 
    ports:
      # - "8080:80"
      - "8443:443"
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /tmp:/tmp

大丈夫そう。それでは起動します。

$ docker-compose up
Starting nginx_nginx_1 ... done
Attaching to nginx_nginx_1
nginx_1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_1  | 10-listen-on-ipv6-by-default.sh: error: IPv6 listen already enabled
nginx_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx_1  | 2021/10/03 16:28:30 [warn] 1#1: the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:30
nginx_1  | nginx: [warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:30

Chrome からアクセスしてみる。

[f:id:K-jun1221:20211004012754p:plain

大丈夫そうですね! 開発環境の https は mkcert で簡単に実現できそうです。正直最初はオレオレ証明書簡単生成ツールとして見ていましたが、開発環境限定でした...。 まあ、オレオレ証明書ぐらい自分で生成しろって話ですね。それでは今回はこのへんで。

DB Streaming ツール materialize を試してみた。

こんにちは k-jun です。今回は Rust 製の DB Streaming ツール materialize を試してみようとおもいます。

https://github.com/MaterializeInc/materialize

某デザインツールと名前が似ているは気にしなかったのでしょうか...? どうやら PostgreSQL を利用するようです。 どうやら firestore のように Client と非同期に通信するのではなく、Database 自体が非同期にデータを取り込んでいるっぽい...?

Run

Docker が用意されているのでこれで起動してみます。

$ docker run -p 6875:6875 materialize/materialized:v0.9.6 --workers 1

PostgereSQL 互換のようなので、psql で接続していきます。

$ psql -U materialize -h localhost -p 6875 materialize
psql (13.4, server 9.5.0)
Type "help" for help.

materialize=>

何やら怪しげな SQL を叩いていきます。

materialize=> CREATE SOURCE market_orders_raw
FROM PUBNUB
SUBSCRIBE KEY 'sub-c-4377ab04-f100-11e3-bffd-02ee2ddab7fe'
CHANNEL 'pubnub-market-orders';
CREATE SOURCE
materialize=> SHOW COLUMNS FROM market_orders_raw;
 name | nullable | type
------+----------+------
 text | f        | text
(1 row)

どうも、ここ からデータを取り込んで Stream で流すみたいですね。それがなぜ Database の層で完結するのかは謎ですが。

materialize=> CREATE VIEW market_orders AS
SELECT
    ((text::jsonb)->>'bid_price')::float AS bid_price,
    (text::jsonb)->>'order_quantity' AS order_quantity,
    (text::jsonb)->>'symbol' AS symbol,
    (text::jsonb)->>'trade_type' AS trade_type,
    to_timestamp(((text::jsonb)->'timestamp')::bigint) AS ts
FROM market_orders_raw;
CREATE VIEW

うーん。知らん syntax だし色々と謎。

CREATE MATERIALIZED VIEW avg_bid AS
SELECT symbol,
       AVG(bid_price) AS avg
FROM market_orders
GROUP BY symbol;

materialize=> SELECT * FROM avg_bid;
   symbol    |        avg
-------------+--------------------
 Apple       | 200.12943851142316
 Google      | 303.64465372226175
 Elerium     |  153.0859976127034
 Bespin Gas  | 221.24196606620828
 Linen Cloth | 245.64254669609824
(5 rows)

なんか取れたけど。なるほど、実際に流れているデータをカテゴライズした結果が返ってきているのか。

https://materialize.com/use-cases/

usecases を見てみると、リアルタイムな分析やエラー検知とどうもサービスで使用するというよりはその周りで使用することが想定されているみたい...? 今の所使いみちは自分も思いついていませんが、時間ができたらもう少し触ってみようと思います。

それでは今回はこのへんで。

次世代の データベース CockroachDB を試してみた。

こんにちは、 k-jun です。今回は Spanner の OSS 実装であり次の世代のデータベースとなりうる CockroachDB を試していこうと思います。 同系統の TiDB が MySQL 互換なのに対してこちらは Postgres 互換のようですね。Aurora 互換のこういう DB 出ないかしら...?

https://github.com/cockroachdb/cockroach

https://www.cockroachlabs.com/

公式のドキュメントを参照してみると以下の項目が羅列されており、Cockroach の由来はここら辺なんじゃないのかなぁとなんとなく思っています。

  • SCALE FAST
    • Build fast & build to last Familiar SQL
    • Elastic Scale Grow locally and/or globally
  • SURVIVE ANYTHING
    • Bulletproof Resilience Survive any failure
    • Consistent Transactions Guarantee data correctness
  • THRIVE EVERYWHERE
    • Geo-partitioned data Performance & Regulatory Compliance
    • Hybrid and multi-cloud Deploy on and across any cloud

ゴキブリのような生命力を DB に求めるかと言われればそれは YES なんですけれども...。システムの最も重要な箇所がゴキブリに荒らされているような感覚に陥りますね...。 Docker でサクッと試せそうなのでそちらで起動してみます。あとは適当に sysbench で SQL が使えるかどうかと性能を見てみます。ゴキブリのような生命力を有しているのかの確認もしてみたいですが 笑、今回はパスです。

Run

ここら辺 を参考にやってみる。

# docker network
$ docker network create -d bridge roachnet

# cockroach cluster
$ docker run -d \
--name=roach1 \
--hostname=roach1 \
--net=roachnet \
-p 26257:26257 -p 8080:8080  \
-v "${PWD}/cockroach-data/roach1:/cockroach/cockroach-data"  \
cockroachdb/cockroach:v21.1.9 start \
--insecure \
--join=roach1,roach2,roach3

# cockroach node
$ docker run -d \
--name=roach2 \
--hostname=roach2 \
--net=roachnet \
-v "${PWD}/cockroach-data/roach2:/cockroach/cockroach-data" \
cockroachdb/cockroach:v21.1.9 start \
--insecure \
--join=roach1,roach2,roach3
c0b9420b32548db935009c779b1e23d7277d3e6599ac4c07642c3e2b30ac22f
$ docker run -d \
--name=roach3 \
--hostname=roach3 \
--net=roachnet \
-v "${PWD}/cockroach-data/roach3:/cockroach/cockroach-data" \
cockroachdb/cockroach:v21.1.9 start \
--insecure \
--join=roach1,roach2,roach3

謎のコマンド。initialization みたい。

$ docker exec -it roach1 ./cockroach init --insecure
Cluster successfully initialized
$ docker exec -it roach1 grep 'node starting' cockroach-data/logs/cockroach.log -A 11
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +CockroachDB node starting at 2021-09-23 20:21:01.726278 +0000 UTC (took 109.8s)
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +build:               CCL v21.1.9 @ 2021/09/20 21:47:27 (go1.15.14)
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +webui:               ‹http://roach1:8080›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +sql:                 ‹postgresql://root@roach1:26257?sslmode=disable›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +RPC client flags:    ‹/cockroach/cockroach <client cmd> --host=roach1:26257 --insecure›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +logs:                ‹/cockroach/cockroach-data/logs›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +temp dir:            ‹/cockroach/cockroach-data/cockroach-temp470954380›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +external I/O path:   ‹/cockroach/cockroach-data/extern›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +store[0]:            ‹path=/cockroach/cockroach-data›
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +storage engine:      pebble
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +status:              initialized new cluster
I210923 20:21:01.726415 85 1@cli/start.go:704 ⋮ [-] 182 +clusterID:           ‹6ee045f0-07a0-455a-bf12-bfe6c95e138d›

以下のコマンドを実行することで SQL の Interface を利用することが出来る。

$ docker exec -it roach1 ./cockroach sql --insecure
#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
CREATE DATABASE bank;
CREATE TABLE bank.accounts (id INT PRIMARY KEY, balance DECIMAL);
INSERT INTO bank.accounts VALUES (1, 1000.50);
SELECT * FROM bank.accounts;

うーん... 実行しても出力が何も返らない... ダメそう ...。なにか間違えたのだろうか...? console が localhost:8080 に立っているようなのでこれを見てみる。

f:id:K-jun1221:20210924053018p:plain

database が defaultdb / postgres / system 以外に作成されていないのでダメそう。 しかし local の docker で構築しても console が付与されているのは非常に体験として良いな。

postgres の client app で直接中身を覗いてみる。

$ psql -h 127.0.0.1 -p 26257 -U root -d defaultdb
psql (13.4, server 13.0.0)
Type "help" for help.

defaultdb=# CREATE DATABASE bank;

もろもろ確認してみるとどうやら node が2つとも落ちていたようです。詳細にログを追ってはいないので詳細は不明ですが。 再起動してみると動くようになったので先程の SQL をポチポチしてみます。

defaultdb=# CREATE TABLE bank.accounts (id INT PRIMARY KEY, balance DECIMAL);
defaultdb=# INSERT INTO bank.accounts VALUES (1, 1000.50);
defaultdb=# SELECT * FROM bank.accounts;
 id | balance
----+---------
  1 | 1000.50
(1 row)

おおお...! 実行できていそうです。いい感じに postgres 互換ですね。sysbench を実行してみますか。

$ brew install sysbench --with-postgresql
...
Error: invalid option: --with-postgresql

https://github.com/akopytov/sysbench/issues/302

brew install ができないじゃねえか...。辛い...。うーん。。。まあ、CockroachDB が起動することは確認できましたし今回はこれでよしとしましょう。 後で ubuntu 環境に TiDB と CockroachDB を起動して sysbench で性能を比べてみるとかやって見ます 笑。

それでは今回はこのへんで。

AWS の 新サービス AppRunner を今頃試してみる。

こんにちは k-jun です。AWS から提供されている新サービスの AppRunner を試してみようと思います。

2021/05AWS から提供が開始されたサービスです。GCP の Cloud Run を意識したような 名前をしています。

実態としては Container Image を指定するだけでアプリケーションのスケール・分散まで行ってくれる、まさに Container を指定すればあとはこっちで勝手にやっとくわ。なサービスです。 c5.large 料金的に比較してみます。

ap-northeast-1 vCPU RAM(GB) vCPU per hour RAM(GB) per hour doller per hour doller per month
c5.large 2 4 - - 0.107 77.04
apprunner 2 4 0.081 0.009 0.198 142.56

ざっと ec2 と比較して 2倍位ですね。スケーリングすることを加味すると良さげにも見えますが、ec2 も結局オートスケール出来るので Deploy の手間賃が加算されているんでしょうね。

今回は簡単なアプリケーションを Rust で作成し、Github Actions で Build したものを ECR に Push。App Runner で設定しその後の Deploy を自動化するところまでやってみます。

まずはアプリケーションの作成から。面白そうな API があったのでこれを in-memory に保存するアプリにします。プロトコルHTTPS/HTTP が対応しているようですね。

https://github.com/k-jun/advices-api

Actions も設定して、master に push したら ECR に image を push するようにしておきました。

ではでは AppRunner の設定に入ります。vCPU と Memory は 1 core と 2 GB に。in-memroy なのでスケーリングすると整合性が取れなくなりますが、そこらへんはご愛嬌です。 Auto Scaling もデフォルトのものを使用。Port は 3000 に。

f:id:K-jun1221:20210921031417p:plain

あとは設定していて気づきましたが、これは Health Check は TCP ベースなんですね...。リソースがフルに使われでもしない限り TCP ヘルスチェックは引っかからないと思うので、それなりにスケーリングは遅そうです。後で HTTP ペースのものが追加されるんですかね。

$ curl https://d68fmvi2ky.ap-northeast-1.awsapprunner.com/
0.1.0
$ curl -XPOST https://d68fmvi2ky.ap-northeast-1.awsapprunner.com/advices
{"id":168,"advice":"Do a bit more for your friends."}
$ curl -XPOST https://d68fmvi2ky.ap-northeast-1.awsapprunner.com/advices
{"id":198,"advice":"Sing in the shower."}
$ curl -XPOST https://d68fmvi2ky.ap-northeast-1.awsapprunner.com/advices
{"id":57,"advice":"If you get stuck, try doing the opposite of what the solution requires."}

いい感じですね。Dockerfile の内容ですが、Rust の Multi Container Build を試してみたところ、AppRunner の log が "Service status is set to OPERATION_IN_PROGRESS." からさきに進まず 約一時間程度立った後に終了するという自体が発生したので Single Container Build にしました。本格的に使用する際にはもう少し確認してみます。

CI からの Deploy が出来ることもわかりましたし、いい感じですね。それでは今回はこのへんで。