macOSでDocker Desktopをアンインストールしてdocker-cli + docker-machineで動かすようにする
Docker Desktopがここ最近活発に開発されているというか、かなり見た目がオシャレになってきてて「ヤル気あるな〜」と思って眺めていたのですが、なるほど有料化するということなのですね。
Docker Desktop remains free for personal use, education, non-commercial open source projects, and small businesses (fewer than 250 employees AND less than $10M USD in annual revenue).
Commercial use of Docker Desktop in larger enterprises (more than 250 employees OR more than $10 million USD in annual revenue) requires a Docker Pro, Team or Business subscription for as little as $5 per user per month.
実際、こういうところに注力して利益を得ていくというのは良いことだと思います! 頑張れdocker!
それはそうとしてDocker Desktopの機能をあまり使ってこず、実際のところcliでdockerが操作できればよい、つまりdocker engineが動けば良いという感じだったので、docker-machineを使ってローカルでdockerデーモンのためのVMを動かし、ホストからそのVMにcliを繋いでdockerを使うという方法をやっていくこととします。どことなく懐しいですね。podman使うとかでも良かったんですけど、ひとまずdocker cliでやります。
まずDocker Desktopをアンインストールする。
"Troubleshoot" メニューを開きます。この虫マークは "Troubleshoot" というメニューだったのですね。バグレポートボタンだと思ってた……
アンインストールしましょう。これで完了です。
そしてdocker cliとdocker-machineを入れる。
$ brew install docker docker-machine
で、docker-machineを使ってローカルにVMを立ててそこでdockerデーモンを動かすこととする。このとき、ローカルマシンにあらかじめVirtualBoxがインストールされている必要があります。
やりかたとしては右のページに従うと良い: Get started with Docker Machine and a local VM | Docker Documentation
おおざっぱに書くと以下のようなかんじ。
$ docker-machine create --driver virtualbox default $ echo 'eval "$(docker-machine env default)"' >> .bash_profile
そして docker ps
などと打ってみてちゃんとレスポンスが返ってくると成功です。
Docker Desktopで動かしていた時と比較するとなにか制限等があるかもしれませんがそれは遭遇した時に考える、あるいは遭遇したらLinux Desktopに乗り換えるなどを検討していきたいと思います。実際Linux Desktopへ移行していきたい……
[追記]
良くみてみるとdocker-machineの開発が停滞しているように見えるので、そこは懸念ポイントと言えそうですね……
github.com
まあなんかあったら手でVM運用していきましょう。俺たちにはそれができるはずだ。
[追記]
どれくらい実用的かはわかりませんが docker-machine は gitlab が fork してました https://t.co/RQkIQp7JOp
— Hiroshi SHIBATA (@hsbt) 2021年9月1日
Gitlabがforkしたdocker-machineがあるとのこと。
IntelliJ IDEAのsbt pluginがPrivateなGitHubのmaven repositoryに上げたライブラリを解決してくれないとき
表題の件で、sbtの依存解決コンポーネントが突然HTTP Status 400を返却してきてなにをやっても無駄、一生解決してくれない、みたいなことが原因不明ながら周期的に起きていて、そういうときにどうすれば良いかというと、
$ GITHUB_REGISTRY_TOKEN="YOUR-TOKEN" open /Applications/IntelliJ\ IDEA.app/
みたいな感じでトークンを環境変数で与えながらIDEAを起動してやるととりあえず動く……が、まったく本望ではない。
実際IDEAの環境変数を適切に設定すれば動くでしょ、とは思いつつも環境変数どこで設定すりゃ良いんだよ、つーかそもそもsbt pluginでは環境変数を設定することができず本当につらい、mavenやgradleのpluginではできるのだが……という気持ちでいっぱいです。
忙しいときにこういうの踏むと本当に大変ですね。以上です。
Elasticsearchの"index.mapping.total_fields.limit"を監視する話
Elasticsearchには index.mapping.total_fields.limit
という設定があり、これは何かというと「1つのindexあたりが保存できるフィールドの上限数」を表現しており、この上限に触れると Limit of total fields [1000] in "your_index" index has been exceeded
のようなエラーが発生してindexができなくなります。
この上限への対症療法としては先人たちが示している通り様々あるのでそちらに譲り *1、本記事ではこの index.mapping.total_fields.limit
を監視する方法について考えていきましょう。上にも書きましたが、この上限にヒットするとそのindexに対するindexingが完全にストップするのでマズいんですよ……
(もちろん、Elasticsearchのパフォーマンスを考えると1つのindexに大量のフィールドを生やすのは良くないし、そもそも理性的な使いかたをしていれば起きないことだとは思うのですが……まあ実際にElasticsearchを運用していると色々なことがありますね)
というわけで、johtaniさんに色々教えてもらったことについて以下に記します。いつもありがとうざいます。
情報は取れなそうだから、mappingから数えるとかかなぁ
— Jun Ohtani (@johtani) February 18, 2021
Mappingが変更されるタイミングでチェックしてるだけだからねぇ。https://t.co/l51A1Wgawp
— Jun Ohtani (@johtani) February 18, 2021
なるほど、コードを読んでみると確かにシンプルなリミットチェックを行っているだけっぽい。
これが一番楽そう?(正しい値化は確認してない)https://t.co/wOIWd5DTlt
— Jun Ohtani (@johtani) February 18, 2021
ハハア、なるほど。APIを叩いてそのindexのフィールド数を回収することで現在のステータスを回収しよう、ということですね。
というわけで以下のようなスクリプトを一定周期で流してメトリクスとして回収し、可視化およびアラートを設定することで現状なんとかしております、というお話でした。
for idx in $(curl -Ss "${ES_ENDPOINT}/_cat/indices?format=json" | jq -r .[].index); do num_of_fields=$(curl -Ss "${ES_ENDPOINT}/${idx}/_field_caps?fields=*" | jq '.fields | length') echo "$idx: $num_of_fields" store_metric "$idx" "$num_of_fields" done
jitterをかけたtickerを提供するgoのライブラリjickerを書いた
定期的に実行したい何かがあって、そしてそのインターバルにjitterが入っていてほしいということがしばしばあり、必要な時に都度そういうコードを書いていたのですが、毎度書くのもしんどいな〜と思ったのでこの度ライブラリにしたという次第です。
READMEのUsageに書いてあるとおり、
package main import ( "context" "log" "time" "github.com/moznion/jicker" ) func main() { ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() c := jicker.NewJicker().Tick(ctx, 1*time.Second, 0.05) for t := range c { log.Printf("tick: %v", t) } }
というふうに Tick()
を使用すると、1秒に対して±5% jitterがかかったインターバル (すなわち0.95秒から1.05秒の間でランダムなインターバル) おきにtickしてくれるtickerを得ることができます。
package main import ( "context" "log" "time" "github.com/moznion/jicker" ) func main() { ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() c, err := jicker.NewJicker().TickBetween(ctx, 1*time.Second, 2*time.Second) if err != nil { log.Fatal(err) } for t := range c { log.Printf("tick: %v", t) } }
一方別の関数 TickBetween()
を使用すると、任意の区間でjitterがかかったインターバル (この場合1秒から2秒の間でランダムなインターバル) おきにtickしてくれるtickerがやってきます。
「実家」のような名前のライブラリですが今年のゴールデンウィークは実家に帰れません。世界が大変ですね。
小粒なライブラリですが、ぜひご利用くださいませ。
Goのhttptestパッケージを使ってUNIX domain socketを使ったHTTPサーバのテストをする
Goが提供するHTTPのテストのためのユーティリティであるところのhttptestを使って、UNIX domain socketを使用するHTTPサーバのテストをするという内容についてのメモです。
import ( "log" "net" "net/http" "net/http/httptest" "os" "testing" ) func TestFoo(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) { _, err := w.Write([]byte("hello")) if err != nil { log.Printf("error: %s", err) w.WriteHeader(500) return } w.WriteHeader(200) }) tempSock, err := os.CreateTemp("", "sock") if err != nil { t.Fatal(err) } err = os.Remove(tempSock.Name()) if err != nil { t.Fatal(err) } listener, err := net.Listen("unix", tempSock.Name()) if err != nil { t.Fatal(err) } server := httptest.NewUnstartedServer(mux) server.Listener = listener server.Start() defer server.Close() // do something }
os.CreateTemp()
でtemporaryなファイルを作り、それを削除してファイル名だけを引っ張りつつ (削除せず実ファイルが残っているとbind(2)がEADDRINUSEを吐く)- それを
net.Listen()
に渡してlistenerを作り httptest.NewUnstartedServer()
でテスト用のサーバのインスタンスを作り- listenerをそのサーバのインスタンスに食わせ
- サーバスタート
- あとはUNIX domain socketを使ったクライアントを使ってテストを書く
という感じで使うことが可能です。簡単ですね。
もちろんtemp fileを使わずに任意のパスをソケットファイルとして与えても良い (server.Close()
が実行されるとそのソケットファイルも削除されるので) のですが、うっかりserver.Close()
が実行されないとゴミファイルが残ってしまったりしてダルいので、まあ保険のようなものです。
macOSでgit-send-emailがsmtpauthオプションを上手く扱えないという問題
brewでインストールしたgitのgit-send-mailで smtpauth
を指定してもそれが上手く適用されず、問答無用で DIGEST-MD5
が利用されるという問題に当たったので、その解決方法をメモとして記します。
さくらのメールボックスは MD5-DIGEST
をサポートしておらず、PLAIN
もしくは CRAM-MD5
を使う必要があるのでこの挙動は困るんですよね……
TL;DR
- brewで入れたgitのgit-send-mailが依存しているCPANモジュールのバージョンが古い
- 新しいバージョンのCPANモジュールがインストールされているPerlランタイムの
PERL5LIB
をGITPERLLIB
環境変数に渡すと動く- 例:
$ GITPERLLIB="/path/to/.plenv/versions/5.32.1/lib/perl5/5.32.1/:/usr/local/Cellar/git/2.30.0/share/perl5" git send-email --smtp-debug 1 --smtp-auth CRAM-MD5 0001-something.patch
- もしくは依存している
Net::SMTP
のバージョンを上げる (例えば3.11) と動く
環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 $ git version git version 2.30.0 $ perl --version This is perl 5, version 32, subversion 1 (v5.32.1) built for darwin-2level
なぜperlが必要かというとgit-send-mailはperlで実装されているためです。
なお、gitはbrewでインストールされており、おそらくこれも原因の一つです。
症状
$ git send-email 0001-something.patch ...snip... Died at /usr/local/Cellar/git/2.30.0/libexec/git-core/git-send-email line 1578.
死んでまんな。そしてこのエラーメッセージは見覚えが……perlですね。
debug modeをenableにして再度見てみましょう。
$ git send-email --smtp-debug 1 0001-something.patch ...snip... Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): y Net::SMTP>>> Net::SMTP(2.31) Net::SMTP>>> Net::Cmd(2.29) Net::SMTP>>> Exporter(5.68) Net::SMTP>>> IO::Socket::INET(1.33) Net::SMTP>>> IO::Socket(1.36) Net::SMTP>>> IO::Handle(1.34) ...snip... Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250-AUTH CRAM-MD5 DIGEST-MD5 LOGIN PLAIN Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250-DELIVERBY Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250 HELP Net::SMTP::SSL=GLOB(0x7ff38a07c878)>>> AUTH DIGEST-MD5 ...snip... Net::SMTP::SSL=GLOB(0x7ff38a07c878)>>> Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 235 2.0.0 OK Authenticated ...snip... Died at /usr/local/Cellar/git/2.30.0/libexec/git-core/git-send-email line 1578.
依存しているCPANモジュールが軒並み古く、なおかつ >>> AUTH DIGEST-MD5
によって DIGEST-MD5
が指定されており、そして死んでいることがわかりますね (表面上は OK Authenticated
が返ってきている一方、これは上手く動かない様子。参照: https://adiary.adiary.jp/0407)。
ウェブで検索をかけてみると、過去に同じような原因で詰まっており解決されている方が。
なるほど〜、smtpauth
を PLAIN
とかにしてみると良いんですね。現在はさくらのメールボックスは CRAM-MD5
もサポートしているので、これを指定してみましょう。
$ git send-email --smtp-debug 1 --smtp-auth CRAM-MD5 0001-something.patch ...snip... Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250-AUTH CRAM-MD5 DIGEST-MD5 LOGIN PLAIN Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250-DELIVERBY Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 250 HELP Net::SMTP::SSL=GLOB(0x7ff38a07c878)>>> AUTH DIGEST-MD5 ...snip... Net::SMTP::SSL=GLOB(0x7ff38a07c878)>>> Net::SMTP::SSL=GLOB(0x7ff38a07c878)<<< 235 2.0.0 OK Authenticated ...snip... Died at /usr/local/Cellar/git/2.30.0/libexec/git-core/git-send-email line 1578.
うーん、オプションで明示しても DIGEST-MD5
がまだ使われていますね。困った。
解決
とりあえずコード読んで、ちまちまデバッグしてみたところコード的には問題なさそう。つまり依存しているモジュールあるいはそのロードっぽいな〜、ということで git-send-email
のコードを読んでみる。
#!/usr/bin/perl use lib (split(/:/, $ENV{GITPERLLIB} || '/usr/local/Cellar/git/2.30.0/share/perl5:/Applications/Xcode.app/Contents/Developer/Library/Perl/5.18/darwin-thread-multi-2level:/Library/Developer/CommandLineTools/Library/Perl/5.18/darwin-thread-multi-2level')); # # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
なるほど〜、 GITPERLLIB
環境変数が渡されていない時はなんか全体的に古いモジュールを見てそうですね。
というわけで GITPERLLIB
に使っているperlの PERL5LIB
相当を渡して実行してみましょう。
$ GITPERLLIB="/path/to/.plenv/versions/5.32.1/lib/perl5/5.32.1/:/usr/local/Cellar/git/2.30.0/share/perl5" git send-email --smtp-debug 1 --smtp-auth CRAM-MD5 0001-something.patch ...snip... Net::SMTP>>> Net::SMTP(3.11) Net::SMTP>>> Net::Cmd(3.11) Net::SMTP>>> Exporter(5.74) Net::SMTP>>> IO::Socket::IP(0.39) Net::SMTP>>> IO::Socket(1.36) Net::SMTP>>> IO::Handle(1.34) ...snip... Net::SMTP=GLOB(0x7fb7d9825d38)<<< 250-AUTH CRAM-MD5 DIGEST-MD5 LOGIN PLAIN Net::SMTP=GLOB(0x7fb7d9825d38)<<< 250-STARTTLS Net::SMTP=GLOB(0x7fb7d9825d38)<<< 250-DELIVERBY Net::SMTP=GLOB(0x7fb7d9825d38)<<< 250 HELP Net::SMTP=GLOB(0x7fb7d9825d38)>>> AUTH CRAM-MD5 ...snip... Result: 250 Net::SMTP=GLOB(0x7fb7d9825d38)>>> QUIT
モジュールのバージョンが新しめで、ちゃんと >>> AUTH CRAM-MD5
が指定され、そして成功していますね。やりました。
なお /usr/local/Cellar/git/2.30.0/share/perl5
も併せて指定している理由は、これが存在しないとgitが用意しているモジュールをロードできない為です。ここは適宜環境に合わせて変更する必要があるでしょう。
ちなみに、今回は新しめのバージョンのperlランタイムのライブラリパスを渡すことで解決しましたが、単純に Net::SMTP
のバージョンを上げる (3.11とか)、でも解決できると思います。
というわけでようやく動きました……ところで git-send-email、実ははじめて使いました。以上です。
独自ドメインのメールアドレスを使うようにした
2021年の記事とは思えないタイトルですが、そのようにしたのです。
特定のメールサービスが提供するメールアドレスに依存していると、そのメールサービスからBANされた際に人権を維持できない可能性があります。というのも仮にメールアドレスが凍結すると、そのアドレスをアカウントのidentifierとして登録しているサービスを巻き込んでしまい大惨事が起きてしまいます。
プレッパーじみた危機意識ではありますが、そのような気持ちになったのでこのたび独自ドメインでメールアドレスを払い出し、それを使うようにしてみました。
しかし自前でpostfixを運用する……みたいなことは断固やりたくなかったので、今回はさくらのメールボックスを利用して、元々保有していたドメインのサブドメインを使ったメールアドレスを払い出し、そこに送られてくる全てのメールをGmailへと転送するという構成を取りました。
メールボックスに保存せず、即座に転送するような設定とすることで、さくらのメールボックスの容量制限を考えずに済むので便利です。GmailのUI/Appをそのまま使えるというのもグッドポイント。これでGoogleから仮にBANされてもメール機能については「UIが使えなくなるだけ」というところで被害を食いとめることができますね。
自分のドメインにメール用のサブドメインを切り、そのサブドメインに対して以下のようにNSエントリを設定すると、ドメインの移管等をすることなくメール用にドメインが使えるのは簡単で良いですね。
subdomain NS ns1.dns.ne.jp. subdomain NS ns2.dns.ne.jp.
なぜサブドメインをわざわざ使っているかというと、主ドメインを使おうとするとさくらが管理するネームサーバーを利用する必要があるのですが、しかし今使っているネームサーバーはCloudflareのものなので引越し等がだるい。しかし、サブドメインだとサブドメインだけNSレコードの設定 (僕の場合はCloudflareで設定する) によりネームサーバーを差し向けることができるので楽ちん、という感じの動機でした。
さくらのメールボックスの特筆事項としては以下のような感じ。
※1 同じメールアカウント名で異なるドメイン毎のメールアドレスの運用は利用できません。
(例:「info@◯◯◯.com」と「info@△△△.net」の場合、同じ「info」のメールボックスに配信されます)
さくらのレンタルサーバとメールボックスには同一のドメインを登録することはできません。
https://www.sakura.ne.jp/mail/
- DKIMは使えない
というわけで最小労力で自ドメインのメールアドレスをゲットしましたから、今後はこれを使っていきたいと思います。
メールサービスの選定のようなものは以下にメモを残しておきました:
scrapbox.io
moznion@mail.moznion.net
メル友募集中です。ちなみに僕はメールを見るという習慣がありません。
[追記]
「メールをメールボックスに保存せずにGmailへ転送だけ行うと、GmailからBANされたときに送られてきたメールがロストするのでは?」という指摘があり、それはその通りだと思いますが、僕はまあそれで良いかなと思っています。GoogleからBANされたらメールだけでなくありとあらゆるものが大倒壊し、暮らしがめちゃくちゃなことになると思うので、メールのロスト程度はかすり傷でしょう……という心意気です。メール自体の機能よりも「安定したアカウントのIdentifier」として使いたいというところが大きいというのもありますね。
とはいえ心配であれば、メールボックスに保存した上で転送、という方法を採用するのも手だと思います。さくらのメールボックスは10GBもあるし、メール用途であれば実質無限と言っても差し支えなさそうですし。