一台のサーバをk8sのjoinしたところ、containerd runtime is not runningというエラーでjoinできなかった。systemctl status containerdしてもアクティブなので、起動はしているが、トラブルシューティングもめんどいので(journalctl -e -u containerdさえもしてない)ので、ググった。以下の手順で解決した。
業務では原因と対策をロジカルに文章にして作業を実施しないといけないが、まぁ、自宅の環境なのでよしとする。
一台のサーバをk8sのjoinしたところ、containerd runtime is not runningというエラーでjoinできなかった。systemctl status containerdしてもアクティブなので、起動はしているが、トラブルシューティングもめんどいので(journalctl -e -u containerdさえもしてない)ので、ググった。以下の手順で解決した。
業務では原因と対策をロジカルに文章にして作業を実施しないといけないが、まぁ、自宅の環境なのでよしとする。
Contextを使って、キャンセルやタイムアウト処理をするときに、以下のようなコードを書く。
select {
case <- ctx.Done():
}
見て分かる通り、コンテキストを使わないとdone := make(chan struct{})でdoneチェネルを実装している感じだが、Done()とメソッドになっている
コンテキストインターフェースのメソッドを覗いてみると、こんな風になっている。
赤字のところ。
type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never be canceled. Successive calls to Done return the same value. // The close of the Done channel may happen asynchronously, // after the cancel function returns. // // WithCancel arranges for Done to be closed when cancel is called; // WithDeadline arranges for Done to be closed when the deadline // expires; WithTimeout arranges for Done to be closed when the timeout // elapses. // // Done is provided for use in select statements: // // // Stream generates values with DoSomething and sends them to out // // until DoSomething returns an error or ctx.Done is closed. // func Stream(ctx context.Context, out chan<- Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // See https://blog.golang.org/pipelines for more examples of how to use // a Done channel for cancellation. Done() <-chan struct{} // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: // Canceled if the context was canceled // or DeadlineExceeded if the context's deadline passed. // After Err returns a non-nil error, successive calls to Err return the same error. Err() error // Value returns the value associated with this context for key, or nil // if no value is associated with key. Successive calls to Value with // the same key returns the same result. // // Use context values only for request-scoped data that transits // processes and API boundaries, not for passing optional parameters to // functions. // // A key identifies a specific value in a Context. Functions that wish // to store values in Context typically allocate a key in a global // variable then use that key as the argument to context.WithValue and // Context.Value. A key can be any type that supports equality; // packages should define keys as an unexported type to avoid // collisions. // // Packages that define a Context key should provide type-safe accessors // for the values stored using that key: // // // Package user defines a User type that's stored in Contexts. // package user // // import "context" // // // User is the type of value stored in the Contexts. // type User struct {...} // // // key is an unexported type for keys defined in this package. // // This prevents collisions with keys defined in other packages. // type key int // // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. // var userKey key // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext returns the User value stored in ctx, if any. // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key any) any }
つまり、受信用のstruct{}型のチャネルを返すメソッドだった。
そうか、そうなっているのか、シンプル過ぎて調べて恥ずかしくなる。
インストール方法は、以下でhelmで入れるだけ。
https://zero-to-jupyterhub.readthedocs.io/en/latest/
TraefikやNginx Controllerで80ポートを使っていると、デーモンセットでポートが激突して起動しない可能性がある。
その時は、values.yamでIngress:trueと、サービスをLoadBalancerからClusterIPに変更するとうまくいくかもしれない。
■課題
・アーキテクチャをみると、どのようにk8s上でJupyterHubが動作しているかなんとなくわかるが、エンジニアリング的に掘り下げたいと思う。
自宅の開発マシンで久々にapt-get updateしようと思ったら、以下のエラーが出た。
/etc/apt/source.listのURLがおかしくなった?
今日は眠いので、週末にやるかと思ったら、tsc --initする用事があったのだった。かったるい。
8/4 追記
以下のサイトのsources.listを使って、普及した。しかし、無駄なURLから取得しているぽい?
Ubuntu Hirsute Hippo (21.04) Mirrors sources.list · GitHub
8/3 追記
以下、副次的な事象として
- apt install upgradeしたら、kubeletのバージョンがあがって(バージョンにmarkしてない)、kubeletが起動しなくなった
チーム全員は揃っていないが、私入れて3名のチームメンバーで夕食に焼肉を食べに行った。
結構お手頃な価格でメチャクチャ美味しかったし、楽しい話も弾んだ。
一昨日は有給休暇をとって、芦ノ湖の西側をハイキングしてきた。夏日の晴天に恵まれた。
さて、いつも通りの電車で揺られて箱根湯本駅に到着。平日なので電車に乗っている乗客の雰囲気が違う。
箱根湯本駅に着くと、何故だか落ち着く。
箱根湯本商店街(正式名称は知らない)も、観光客で賑わう感じでなく、平日の平常営業といったところか...それはそれでいい。
奥湯本方面を眺める。
箱根湯本駅から、桃源台行きのバスで出発。
途中の仙石原高原(秋にススキで有名)の写真をバスの中から撮る。数年前の秋にススキに囲まれたここを歩いた頃が懐かしい。
最終のバス停である桃源台に到着。
ハイキングを始める前に行程の確認をする。
うん!ワクワクした。
芦ノ湖キャンプ村を通る。去年の11月末にここのテントサイトでテントを張った⛺️
そして、テントカバーを忘れて寒さを耐えて寝た記憶を思い出す。
芦ノ湖の湖畔を歩くこと30分。美しい風景に
遭遇。夏の空、湖の色と緑と素敵すぎる。
浜らしき場所に到着。ここで靴を脱いで湖に少し入った。これまで芦ノ湖には何度も来たが、芦ノ湖の水に触れるのは初めて。すごく気持ちが良い。
歩きながら上を向くと、緑が広がる。
木の間から覗く芦ノ湖の色に落ち着く。
もう少しで箱根町港のゴールが近い。
桃源台から歩くこと通算4時間で箱根町港のバス停到着した。結構疲れた。
箱根関所。そういえばこの辺りに三島方面に抜ける道があった。いつかドライブしたい。
ランチはブライトという老舗の洋食屋さんに入る。ずっーと行きたかったところ。
51年も営業しているらしくて、店内の雰囲気と店員の人達の人柄に魅了された。
食べたのは、ビーフシチュー。
ランチに満足して、歩いて元箱根へ向かう。
芦ノ湖に浮かぶ、海賊船と遊覧船。カッコいい。
時々お世話になっている、パン屋のBakery &Tableで足を休める。
平日なので空いている。芦ノ湖の眺めを堪能しながら、アイスコーヒーとパンを食べる。
お店前。
芦ノ湖のランドマークの写真を撮る。暑いが、
芦ノ湖から涼しい風が少し吹く。
元箱根から急行バス(箱根新道経由 本数少なめ)に乗って、箱根湯本に到着。
箱根湯本から無料の送迎バスで箱根湯寮へ向かい、楽しみな温泉に入る♨️
箱根湯寮を19:00くらい出た時の風景。
そろそろ帰宅の時間。箱根湯本駅を出る。
以上、芦ノ湖ハイキングの日帰りの旅。