Imperfection

てっくぶろぐ

Rustを学ぶならこの海外ブログは見逃すな!4選

日本語の公式ドキュメントもあって充実してはいるものの、Rustのイディオムっぽい書き方やキレイなコードの書き方、アンチパターン等のTipsは自分で書いて学んでいくよりも、積極的に先人の知恵を借りたいところ。

2022年4月時点の私個人の感覚では、ブログやサイトは海外の方が圧倒的に多く、日本人が日本語のみで得られる知見はかなり限定されてしまう。 そこで、私が最近情報収集として見るようにしているブログを紹介する。

fasterthanli.me

海外では壮絶な読者を抱えるブログ。ポストされた記事のうち、多くがRustに関する記事となっている。 サンプルコードも充実していて、要所でキャラクターがポイントとなるコメントを入れてくれる。 1記事あたりの文章量もかなり多い(1時間かけても読み終わらないものもある)のだが、ポップな語りや説明が多いのでとても読みやすい。 Rustのコアな部分を対象とした記事から、かなり初心者向けの内容もあるので、初級者から上級者までお勧めできるブログ。

https://fasterthanli.me

Baby steps

著者がRustの開発チームに所属しているだけあって、Rustブログの中ではかなりの古参。2011年ごろからブログを掲載している。1記事当たりの文章量はfasterthanli.meに比べるとかなりコンパクトで、「非同期処理例外ではPanicにすべき?非同期キャンセル(async cancellation)すべき?」などのように実践的な内容を取り扱うことが多い。基礎を抑えたうえで、Rustをもっと深く知りたい!ベストプラクティスやTipsを学びたい!という人におススメ。

smallcultfollowing.com

Chris Biscardi's Digital Garden

Rust以外にもAws, js等の記事も取り扱っている。そして今回紹介するブログの中で一番UIがキレイ。記事自体もBaby stepsやfasterthanli.meに比べてとっつきやすいものが多い。「for loopとiteratorどっちがよいか?」等。英語の文章量も少ないので先述のブログで心が折れかけたときはこのブログで元気を取り戻しています。

トイレにでも入った10分足らずの間に読める記事もあるので、英語に抵抗ある人もまずはここから初めて見るといいかもしれません。

www.christopherbiscardi.com

lpalmieri.com

ルーカス・パルミエーリという界隈では結構有名な人らしく、RustのPodcastといえば!の「Rustacean Studio」や「Building with Rust」にもゲスト出演をしていた。(家事をしながら聞いていた時に偶然発見)

podcasts.google.com

それ故、実力者であるからかブログはかなり濃ゆい。かなり厳密に書いてあるので、日々の情報収集として読むにはハードルが高いがHow To Write A REST Client In Rustのような自分が実際に経験したことのある内容や、苦労した領域に関する部分については一読すべし!

www.lpalmieri.com

最後に

私の場合は、Feedly使ってTech系のブログをまとめて見るようにしています。(他によく見るのはDEVCommunityなど) 海外のサイトを追っかけていると日本ではまだ出ていないような情報が当たり前にフィードに出てくるので、そのあたりに日本と海外の情報が回る早さの差を感じました。

日本語で勉強していても難しいRustを英語で勉強するのはそりゃ難しいよね。と理解しつつもそこはあきらめずに。 技術に関する文章は繊細な部分も多く、翻訳機にかけるとニュアンスが若干異なる場合も少なくないのでなるべく原文のまま理解できるようになりたい。なんてことを考えていました。

Dockerじゃないコンテナの話

なんでDockerじゃないコンテナの話をするの?

2020年12月、Kubernetesのマイナーリリース(v1.20)にてこんなアップデートがありました。

Docker support in the kubelet is now deprecated and will be removed in a future release. The kubelet uses a module called "dockershim" which implements CRI support for Docker and it has seen maintenance issues in the Kubernetes community. We encourage you to evaluate moving to a container runtime that is a full-fledged implementation of CRI (v1alpha1 or v1 compliant) as they become available.

これはKubernetesでは内部のコンテナランタイムにDockerを利用していたが、v1.20のアップデートでDocker(あくまでコンテナランタイムとしての利用)が非推奨になったことを意味していて、2021年後半リリース予定のKubernetes 1.22で削除される予定みたいです。これを受けて、Docker以外のコンテナランタイムについて触れてみることで、Kubernetesを舞台裏で支えているコンテナランタイムとは何ぞや?というところにスポットライトを当ててみたいと思います。

こうなった(せざるを得なかった)理由

Kubernetesはコンテナオーケストレーションのプラットフォームなのでもちろん内部にコンテナランタイムを必要とします。しかしKubernetesとしては、ランタイムはDockerのみに依存するのではなく、選択肢の一つとしてあるべき。と考えられていたのです。 もう一つの理由ですが、こっちはKubernetes内部の話です。 Kubernetesのノード内でPodを操作する際にはkubeletと呼ばれるエージェントを使ってコンテナと通信を行います。ここではCRI(Container Runtime Interface)と呼ばれる規定に則ってコンテナとの通信が行われます。

Introducing Container Runtime Interface (CRI) in Kubernetes

kubernetes.io

実はDockerはこのCRIに則っておらずKubernetesの開発者がdockershimというブリッジを用意し、このdockershimによってkubeletとコンテナの通信を可能にしていました。

それはそれで問題ないのですが、dockershimのメンテに高いコストがかかっていたようです。多様なコンテナランタイムの選択肢を提供したいKubernetesにとっては、dockerにしか利用されないdockershimをメンテし続けるのも骨が折れる作業だろうなぁ。。

Dockerに代わるコンテナランタイム

コンテナランタイムについて話してきましたが、実はコンテナランタイムには高レベルランタイムと低レベルランタイムという言葉があります。ついでにこれらについても軽く触れます。

高レベルランタイム

DockerやKubernetesからの命令を受けて、低レベルコンテナランタイムに渡す役割を担っており、本記事で扱う、Dockerの代替となるコンテナランタイムもこの高レベルランタイムに属します。 高レベルランタイムはホストOS上にdaemonプロセスとして常駐し、CRIによりKubernetesやDockerと対話をします。ローカルでのイメージの管理などもこの高レベルランタイムが行ってます。 先ほど述べた通り、高レベルランタイムにおいてはコンテナを作成する機能や実行する機能は持たず、クライアントからの「docker run」などの命令を低レベルランタイムに引き渡す役割を担います。

低レベルランタイム

低レベルランタイムの実体はdaemonではなくバイナリで、高レベルランタイムによって呼び出され実行されます。 コンテナ作成時には「OCI(Open Container Initiative)」と呼ばれる、いわゆるコンテナの標準仕様に基づいてコンテナが作成されます。もう少し厳密にいうと、低レベルランタイムがこの仕様を把握できるようにconfig.jsonというjsonファイルに標準仕様が記載されているため、低レベルランタイムはこれを読み取ってその通りにコンテナの作成を行います。

代表的な高レベルランタイム

Containerd

元々はDocker社が開発していましたが、2017年にCloud Native Foundation(CNCF)に寄贈され、その後2019年2月末にCNCFを卒業しています。

{{< blogcard url="https://www.cncf.io/announcements/2019/02/28/cncf-announces-containerd-graduation/" >}}

実は、containerdはずっと前からDocker内部で使われていました。 「containerd v1.0」ではCRIに対応ができておらず、Docker内部に隠れたままでしたが、「containerd v1.1」ではついにCRIに対応され、晴れてKubernetesから直接containerdを操作できるようになりました。 なのでKubernetesがコンテナの操作をする際はdockerもdockershimを経由する必要もなく、直接containerdを使ってコンテナを操作することができるようになりました。 「Docker非推奨?!え、、マイナーバージョンアップにしてはえぐいことするな。。」という風にとらえられがちですが、内部的にはDockerからcontainerdを取り出しただけ。そんなに大したことをしていないのです。

CRI-O

CRI-Oとは、Kubernetes Incubator Projectとして開発され、OCI準拠の軽量コンテナランタイムです。2017年10月にv1.0が正式にリリースされています。 本記事では特にこれ以上触れませんが、containerd同様CRIに準拠していることからkubeletと直接連携することができます。

containerdを触ってみる

containerdを導入する手順とctrコマンドを使った簡単なイメージ・コンテナ操作について触れる。

ctrコマンド

コンテナランタイムであるcontainerdと対話するためのCLIコマンド。 主に実行中のコンテナの作成および管理、コンテナイメージの管理(レジストリへのPush、Pull)などが主な役割。 containerdとの通信はgRPCによって行われる。

containerdインストール

$ ctr

NAME:
   ctr - 
        __
  _____/ /______
 / ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/

containerd CLI

USAGE:
   ctr [global options] command [command options] [arguments...]

VERSION:
   1.4.3

DESCRIPTION:
ctr is an unsupported debug and administrative client for interacting
with the containerd daemon. Because it is unsupported, the commands,
options, and operations are not guaranteed to be backward compatible or
stable from release to release of the containerd project.

COMMANDS:
   plugins, plugin            provides information about containerd plugins
   version                    print the client and server versions
   containers, c, container   manage containers
   content                    manage content
   events, event              display containerd events
   images, image, i           manage images
   leases                     manage leases
   namespaces, namespace, ns  manage namespaces
   pprof                      provide golang pprof outputs for containerd
   run                        run a container
   snapshots, snapshot        manage snapshots
   tasks, t, task             manage tasks
   install                    install a new package
   oci                        OCI tools
   shim                       interact with a shim directly
   help, h                    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug                      enable debug output in logs
   --address value, -a value    address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
   --timeout value              total timeout for ctr commands (default: 0s)
   --connect-timeout value      timeout for connecting to containerd (default: 0s)
   --namespace value, -n value  namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]
   --help, -h                   show help
   --version, -v                print the version

containerdのdaemonのオプションを/etc/containerd/config.tomlで設定する。 今回は、デフォルト設定を反映させるため、下記のコマンドを実行する。

$ containerd config default > /etc/containerd/config.toml

daemonの設定ファイルの編集

containerdのdaemonのオプションを/etc/containerd/config.tomlで設定する。 今回は、デフォルト設定を反映させるため、下記のコマンドを実行する。

$ containerd config default > /etc/containerd/config.toml

下記のようにconfig.tomlが変更されていることを確認する。

$ cat /etc/containerd/config.toml 

version = 2
root = "/var/lib/containerd"
state = "/run/containerd"
plugin_dir = ""
disabled_plugins = []
required_plugins = []
oom_score = 0

[grpc]
  address = "/run/containerd/containerd.sock"
  tcp_address = ""
...

ctrコマンドを使ったイメージ/コンテナ操作

dockerhubからイメージのpull

$ sudo ctr image pull docker.io/library/hello-world:latest

docker.io/library/hello-world:latest:                                             resolved       |++++++++++++++++++++++++++++++++++++++|                                                               index-sha256:7e02330c713f93b1d3e4c5003350d0dbe215ca269dd1d84a4abc577908344b30:    done           |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042: done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:0e03bdcc26d7a9a57ef3b6f1bf1a210cff6239bff7c8cac72435984032851689:    done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b:   done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 5.2 s                                                                    total:  6.5 Ki (1.3 KiB/s)                                       
unpacking linux/amd64 sha256:7e02330c713f93b1d3e4c5003350d0dbe215ca269dd1d84a4abc577908344b30...
done

image一覧の取得

$ sudo ctr image ls

REF                                  TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                                             LABELS                                                                               -      
docker.io/library/hello-world:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:7e02330c713f93b1d3e4c5003350d0dbe215ca269dd1d84a4abc577908344b30 6.5 KiB  linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x,windows/amd64 -    

コンテナの作成

ここではコンテナIDが'demo'であるコンテナを作成する。

$ sudo ctr container create docker.io/library/hello-world:latest demo

コンテナ一覧の取得

$ sudo ctr container list

CONTAINER    IMAGE                                   RUNTIME                  
demo         docker.io/library/hello-world:latest    io.containerd.runc.v2    

イメージの削除

$ sudo ctr image remove docker.io/library/hello-world:latest

コンテナの削除

$ sudo ctr container remove demo

コンテナの実行

$ sudo ctr run docker.io/library/hello-world:latest demo

dockerでビルドしたDockerImageの実行

DockerImageのエクスポート(.tar)

-oの後は任意のディレクトリ、<IMAGE_NAME>は対象のDockerImageを指定。

$ docker save -o ~/images/<IMAGE_NAME>.tar <IMAGE_NAME>

containerdでのインポート

$ sudo ctr image import <IMAGE_NAME>.tar

unpacking <IMAGE_NAME>:latest (sha256:ef4acfd85c856ea020328959ff3cac23f37fa639b7edfb1691619d9bfe1e06c7)...done

run

$ sudo ctr run docker.io/library/hello-java-app:latest v1

dockerと同じ感覚で使えますね。

【初学者必読!】O’REILLYの『入門 監視』を読んでみた

これまで当たり前のようにメトリクス!ログ!ヘルスチェック!と監視に関連する単語を使ってきたが、もしどこかで「監視ってなんですか?何のためにやるんですか?」と聞かれた際に、回答はできるだろうけど、どこかモヤっとした不安感があるなぁ、、と思ったのがきっかけでこそこそと勉強することに。 ただそれだけだったら勉強するには至らなかったが、Kubernetesとかマイクロサービスとかを扱っていると、監視というのは非常に重要なキーワードとなる。 ここでは自分と同じような人も含め、下記のような人は特に一読をお勧めしたい。

  • 「監視」をこれからやるので地盤となる基礎を固めておきたい初学者
  • 「監視」やってきたけど基礎が不安、、一応さらっと復習したい中級者
  • クラウドネイティブな監視ってこれまでとどう違うの?中級者亜種

今日ご紹介する本

この本を購入したのだが、翌週にはO’REILLYサブスクリプションサービスに登録したので後々後悔することに....

読んだ中でためになった部分の抜粋と感想

構成管理ツール、データベースの管理方法に詳しいのがプロジェクトで1人だけ、ということがないのと同様に監視を役割として特定の人に与えるのはアンチパターン。 監視は役割ではなくスキルであり、チーム内のメンバーが一定の知識を持っている必要がある。

自分も含め、身の回りでも監視について考えるのは決まって一部のインフラ・アプリ開発者でその他の人は設計がどうなっているか、仕組みがどうなっているかすら興味を持たないことが多かった。 「監視は役割ではなくスキル」という言葉があるように、Kubernetesの台頭によって監視にまつわるエコシステムも活発にコードラインが伸びていて、(サービスメッシュの代表的なOSSであるIstioは3か月に1度のアップデートが行われている。)テクノロジによって多くの課題が解決できるようになった事に対して、導入や管理に一定以上の技術的な難度も加わったのも確実にあると感じる。 そんな中でIstioやPrometheus等の技術スタックを使って監視を実現できるというのはどうみてもスキルとして認識されていいはず。

監視とは複雑な問題であり、たった一つのツールで解決できるような問題ではない。プロのメカニックが工具箱を持ち歩くのと同じように汎用的・もしくは専門的なツールが必要になる

たった一つで解決できるような万能的なツールは存在しないからこそ、我々は専門的なツールを組み合わせて「組み合わせ可能な監視基盤」を作る。 メトリクス収集はPrometheus、サービスメッシュはIstioでやってみるか、ダッシュボードはGrafanaで一本化したいな。とか、複数のツールを疎に結合させることでPrometheusよりもイケてるメトリクス収集ツールがあれば即チェンジ!を可能にする。 なので特定の技術スタックに依存しない、常にツール間は疎結合であるというのが、近年のクラウドネイティブな監視システムと言える。

「ユーザ視点での監視」
まず監視を追加すべきなのはユーザが一番気にするところである「アプリケーションが動いているか。」そこからWebノードやワーカノードといったコンポーネントに素早く対象を広げていきつつも、「このメトリクスはユーザへの影響をどう教えてくれるのか」と常に自問自答してみてください。

監視をいざやるとすると、特に複雑な基盤構成だとなおさら混乱して手を付ける順序を誤ったり、本来監視可能な場所を意図せず見逃す可能性が高い。 そこで本書で記載されているのが、「迷ったらまずはユーザが気にするところから作っていけ」ということ。 ユーザを発起点としてロードバランサ、Webおよびアプリケーションサーバ、DB...というように段階を踏んでいくと網羅的に組み込んでいける。

最後に

  • 監視の定義やフロントエンドからサーバサイドそれぞれでどんなことを考えるべき?を知るには持ってこいの本
  • ビジネス的な「監視とは」な内容にとどまらず、技術的にかなり細かいところまで記載されていて、技術的なところを期待して買ったもののむしろニッチすぎて読み飛ばした章もあったくらい
  • 初学者向けとは思いつつも、監視を一度現場で構築したことがある・考えてみたことがある人にはさらに深い気づきを与える本だと思うのでぜひおすすめしたい

本書の内容を簡潔にまとめているスライドがあったので共有

この本読んでおくと、これから先、どこかで監視について向き合うための正しい考え方を身に付けられそう。そんな風に感じた本でした!!!

【試験内容改定後】CKADに合格しました(2021/11)

CKADの概要

CKAD: Certified Kubernetes Application Developerで、CNCF公認の資格です。試験は120分で20問弱。実技試験で各自ターミナルが与えらえれるので、ターミナルを使ってKubenetesリソースを作ったり動かないPodを修正する、というのが試験の内容です。 試験中は公式ドキュメントのみ参照することができるので、kubectlコマンドで作成できないリソースは公式Docからコピペして持ってくるというのがこの試験での通例みたいです。

そして、この試験ですが2021年9月に試験範囲が大幅に改定されました。

CKADプログラムの変更:2021-LinuxFoundation-トレーニング

  • アプリケーションの設計と構築–20%
  • アプリケーションの展開–20%
  • アプリケーションの可観測性とメンテナンス–15%
  • アプリケーション環境、構成、およびセキュリティ–25%
  • サービスとネットワーキング–20%

以前と見比べると、章立てからだいぶ変わったように見えます。具体的には、

  • Helmを使ったリソースのデプロイ
  • KubennetesAPIの非推奨
  • カスタムリソース(CRD)
  • 認証、アドミッションコントロール

このあたりが盛り込まれていて、だいぶ焦りました。(実は試験内容が変わってることに気づいたのは試験受験の1週間前...) 他の合格体験記ブログのほとんどは、試験内容の改定前のものが多くどこまで参考になるのかかなり不安でした。。 そして私はCKAD-JPを受験するつもりが、誤ってCKAD(英語版)を購入してしまいました。ボロボロ...

Kubernetesの経験と受験背景

ほとんどなく、Kubernetesを軽く触ったことがある程度。Dockerにはある程度の知見がありました。 普段はアプリばっかりやってるのでインフラ系の知識には疎く、Kubennetesの各リソースの概念を感覚的に理解するのに若干苦戦していました。 k8sを体系的に学べるいい機会かな、という軽い気持ちで受験を決めました。

準備期間とやったこと

試験改定後でもやったことは他の方とおんなじです。

■Udemy - Kubernetes Certified Application Developer (CKAD) with Tests -

www.udemy.com

他のブログでも数多く見かけて推奨されてるやつです。 2000円弱だったので失敗しても痛くない!と割り切り、細かいことは何も見ずに購入しました。 Kubernetesの各リソースについて、概念からしっかり説明してくれるのでかなり整理できました。ServiceってClusterIPとNondeportとかあるけど何が違うの?DeploymentとかPodとかよくわからん。って状態の自分にはかなり良かったです。 音声が英語のみですが、字幕がすべて表示できるのと説明するときはほとんどアニメーション付いてるのでだいぶ理解しやすかったです。 あとは他の有料サービスとかと比べても、試験改定後の内容についても対応してるのはこのUdemyの講座だけらしいです。

■CKAD-exercises

Udemyでみっちり演習できるので基本的にはなくてもいいですが、本番をよりイメージした問題で演習したかったのでやりました。 Udemyでカバーできてはいますが、小手先のテクニック的なものはこの演習で習得できた気がします。 このリポジトリの演習される方で、GCPの無料期間を使ってKubennetes環境を構築したりする方もいるようですが、私の場合はUdemyの講座で利用する演習用のWebターミナルを使ってこのGithubの演習をしてましたw

最終的には2周して全部解ける状態にしました。

github.com

ちなみに、本番の試験ではこれらの演習を複数組み合わせたものが1問として出てきます。なので感触としてはもうちょいムズイのが出てきます。

受験の流れ

受験予約

Myportalから予約をしますが、空いている時間を確認するだけでものすっごい時間がかかる。。(処理が遅い) 割と混んでたので予約するだけで30分くらいかかりました。

ポータルから試験の受験

15分前から受験が可能になります。CKAD-JPではないので心配してましたが、外国人とのチャットのみで会話をする必要はありませんでした。 日本人でもわかるレベルの短文で「パスポートある?」「部屋の中をカメラで移して歩き回ってほしい」「ヘッドホンは使わないからしまってね」みたいなことを言われました。

自信満々にパスポート見せたところ、 「有効期限が切れてるね」と言われ、運転免許証とクレジットカード(裏の署名なくてその場で署名😂)を見せてなんとか本人確認も突破しました。

試験本番

他の合格体験記を呼んでいて、問題の比重(4%、8%など)が各問題に振り分けられているので、重いものからやれ!、簡単なものからやれ!というものを見かけていたのですが、 緊張していたのと英文で表示していたので飛ばし読みができずパニックに。1問6分のペースを守るのを心に決め、1問目から闘うことにしました。

私が受けた試験では、1問目~3問目くらいがだいぶ意地悪な問題で、正直これまでやってきた演習からははるかに難易度が上がった内容に感じ、「改定されて難化してんじゃないのか?!」と半分絶望してました。(自分に) 絶望しながらも問題を進めていくとこれまでやってきたような問題が数多くでてきたので、なんとか平静を取り戻しました。 試験中のトラブルは特になく、ターミナルがフリーズするような現象が起こりましたが、試験画面上でターミナルを再起動できるボタンがあったので大事には至りませんでした。

20問弱でしたが、最後の問題が終わったときに予想外に時間が15分程度余っていたので、途中飛ばしたところも含め前半の難しい問題に時間を割くことができました。 ほとんどはkubectl create コマンドでリソースを作りつつ、コマンドオプションで対応していない細かい設定値が出てきたら公式Docからコピペで拾ってくる、という感じで解き進めていきました。 kubectl explainで時間かかるようであれば、ささっと公式Docからコピペで持ってきた方が早いように感じます。

合否の連絡

試験改定されてから24h以内に合否が来るようになっているらしく、結果待ちでずっとソワソワしてました。22、23時間後くらいにMyportalで結果を確認しました。 結果は見事合格。

一発合格できてホッとしました。。

試験を終えて

一言でいうと想像していたよりも難しかったです。試験を通じてKubernetesの概念を体系的に学べたので、今後プロジェクトに活かせるよう引き続き学習を頑張りたいと思います。 終わった今は達成感や解放感に満ち溢れていますが、資格試験は精神衛生上良くないので頻繁にはやりたくはないです。 ここからはKubernetesエコシステム(特に監視系)の導入を頑張りたいと思います!