Category Archives

146 Articles

Ubuntu 22.04 / OpenSSH 8.9 使用 gpg-agent 登錄報錯 agent refused operation 的解決方法

0   4615 轉為簡體

Ubuntu 22.04 升級了 OpenSSH 到8.9,這個版本默認開啟 [email protected] 作為密鑰交換(KEX)方法。這個算法使用 512 bit 的 hash。

如果客戶端和服務端都升級到了8.9或以上,則成功協商使用這一KEX算法,這時如果使用 gpg-agent 的 SSH 功能簽名則會報 agent refused operation。

打印 gpg-agent 的日誌可看到報錯為 Provided object is too large。

解決方法是在客戶端(~/.ssh/config)或服務端(/etc/ssh/sshd_config)中禁用這個算法

同理 diffie-hellman-group16-sha512 和 diffie-hellman-group18-sha512 也應該被禁用,但它們優先級本來就很低。

如果仍然有問題,把Kex Host Key Algorithm也改一下,如改成

Go中JSON解碼非UTF-8二進制值的問題

0   6869 轉為簡體

我們在一個項目中創(luan)新(xie)地用JSON來編碼msgpack編碼後的結果(即encoded = json_encode(msgpack_encode(txt))),結果發現Golang側無法解碼。

首先我們可以確定msgpack沒有問題,因為輸入給msgpack解碼數據就與輸入值不一致。

我們使用lua-cjson來編碼一個JSON,因為結果不是printable的,所以在外面加一層base64.encode

結果是eyJhIjoihjEyMyJ9。

在Python里解碼它:

結果是{‘a’: ‘\x86123’}。沒有問題,和輸入一致。

在Go里解碼它:

結果是[239 191 189 49 50 51],可以看到\x86被解碼成了\239 \191 \189即\xefbfbd,表示無效的UTF8字符。

這是因為Go默認採用UTF-8解碼,如果field被標記為string,則json.Unmarshal會使用utf8.DecodeRune來嘗試解碼輸入https://github.com/golang/go/blob/master/src/encoding/json/decode.go#L1304。但在我們的場景中,\x86是一個單字節的非UTF-8字符,所以utf8.DecodeRune返回了utf8.RuneError並把它放到了結果里。

那麼到底是哪裡出了問題呢?

首先,JSON的RFC指出,其中的字符串必須以UTF-8編碼(https://datatracker.ietf.org/doc/html/rfc8259#section-8.1),但是同時也提到,除了幾個特殊的字符外,其中的字符可以被escape也可以不escape(https://datatracker.ietf.org/doc/html/rfc8259#section-7)。所以lua-cjson的這種編碼方式似乎也是合法的?

解決辦法是寫一個自己的Unmarshal方法。首先把結構體中的field標記為自定義類型:

然後我們魔改unquote方法,在原來的基礎上加上對解碼結果是否為utf8.RuneError的判斷

還需要注意的是,Go的json包默認對[]byte類型的field進行base64編解碼:

結果是> [123 34 120 34 58 34 107 119 61 61 34 125] {“x”:”kw==”};同理Unmarshal時也會需要輸入為base64編碼結果。

因此在上面這個解決方法中,我們用rawBytes這個新類型來alias到[]byte,而並不直接使用[]byte類型再在之後自己解碼。

發了一個issue:https://github.com/golang/go/issues/51094。

另外的JSON庫沒有這個問題,測試了https://github.com/json-iterator/go 和 https://github.com/bytedance/sonic

開源了鹹魚撿的京付的三色墨水屏驅動

0   6165 轉為簡體

35塊一個,長這樣

經過一番Google找到了對應的原廠屏,是Gooddisplay的GDEH042Z96,屏幕芯片是SSD1619A,這個芯片初始化序列比幻塔的新手教程還長。

整理了一下官方例程之後,發了一個PR:https://github.com/ZinggJM/GxEPD2/pull/47;有一些點需要注意:

  1. 三色屏(實際上是雙色)是兩種液晶分開刷新的,先刷黑色,再刷紅色。其中SSD1619A的紅色輸入值需要取反,否則屏幕整塊都是紅的。
  2. 這塊屏只支持全刷,全刷一次要20秒,要把GxEPD2的默認等待BUSY pin的時間調長。

效果如下圖所示,用的是我魔改的中文版天氣:https://github.com/fffonion/ESP32-e-Paper-Weather-Display

 

Hashicorp Nomad的坑

0   6156 轉為簡體

因為組裡k8s大佬濃度不夠,最後用了Nomad來做容器編排。開個文章記錄一下踩過的坑:

network allocation配額沒有明確的提示

Nomad的文檔以及各種Grafana dashboard都沒有提到node上的network allocation其實是有上限的,雖然metrics里是有這一項的(nomad_client_allocated_network/nomad_client_unallocated_network)。具體如何計算尚不明確,可能需要看代碼。我們的EC2上有看到500Mb和1000Mb的上限。

如果不指定,默認每個task佔用100Mb的速度(見文檔),這是一個硬上限,如果node完全被allocate的時候,超過這個限制的容器會被限速。個人覺得Nomad的這個設計是坑爹的,網速這類資源相比於CPU和內存是更加體現突發的特性的,如果只能設置硬性上限,利用率顯然會非常低。這個是上個世紀的QoS了吧。

allocation啟動時的template re-render

這是一個bug:https://github.com/hashicorp/nomad/issues/5459。如果用了集成的consul-template來做服務發現,某些情況下可能在allocation啟動過程中觸發re-render,從而nomad client向容器發送信號;但當容器還沒起來的時候,nomad client會拒絕發送信號並且把這個容器幹掉,並且不會嘗試重新啟動

也不知道是哪個神仙想出來的這種奇葩設計。

system類型的task

如果一個task是system類型, 那它會在所有滿足條件的node上運行。但是它默認的restart參數很容易會因為一些臨時性的錯誤讓整個task掛掉,我們重新設置了restart參數

容器里的單個端口無法映射成多個端口

docker里我們可以把容器里的一個端口映射成任意多個端口;但是nomad無法做到,看起來像是處理job definition時的一個bug(issue鏈接)。

下面的配置,只有8001端口會被映射;http1這個端口在port_map里被http2覆蓋了。

下面的配置不會報錯,但是仍然只有8001會被映射。

解決的辦法是在容器內開多個端口,分別映射到不同的外部端口。

terraform provider無法檢查nomad job的更改

遠古bug: https://github.com/hashicorp/terraform-provider-nomad/issues/1

如果在terraform外部修改了nomad的job定義,在terraform provider里是無法檢測到的。

不是很懂那我有它何用?