ナンモワカランアザラシ

技術的なアレコレを自分の言葉で書いて保管・公開しておくための静かなインターネット

Dockerを動かすためのコンポーネントって何があるの

runcのアレがあったのでバージョンを上げようとしていたら、この辺が全く分からないことに気づいた。

~ $ docker version
Client: Docker Engine - Community
 Version:           25.0.2
 API version:       1.44
 Go version:        go1.21.6
 Git commit:        29cf629
 Built:             Thu Feb  1 00:22:57 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          25.0.2
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.21.6
  Git commit:       fce6e0c
  Built:            Thu Feb  1 00:22:57 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.28
  GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

ClientとServerがあるらしい。それはなんとなくわかる。クライアント-サーバーアプリケーションとして動いているのだろう。 Clientの方は、それぞれ書かれていることが概ね推測できる。 Serverの方、それぞれどれが何を担当しているのかを知りたい。

Engine

https://docs.docker.com/engine/ Docker Engineは、サーバーとしてふるまうdockerd, API, CLIコマンドで構成されている。 docker versionコマンドで出たServer.Engineはおそらくdockerdを表すのだろう。

https://docs.docker.com/engine/reference/commandline/dockerd/ dockerdはコンテナを管理する永続的なプロセスである。 クライアントからのAPIリクエストをリッスンする。APIリクエストはunix, tcp, fdという3系統のソケットから来る。fdってなんだ?ファイルディスクリプタか。 デフォルトはunix、リモートで操作するときはtcp、systemdであれこれしたいときはfd、という理解でよいだろうか。

containerd

https://docs.docker.com/engine/reference/commandline/dockerd/#runtime-options dockerdがコンテナのあれこれを操作する際にnamespace, cgroups, SELinuxをいじるのにcontainerdをインターフェースとして使う。 namespaceはそのまま名前空間、cgroupsはメモリとかの管理、SELinuxってなんだ?

https://www.redhat.com/ja/topics/linux/what-is-selinux#:~:text=SELinux%20(Security%2DEnhanced%20Linux),%E7%94%A8%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%BB%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%A7%E3%81%99%E3%80%82 SELinuxはSecurity-Enhanced Linux、ユーザー権限の制御をするためのアーキテクチャ

runc

https://docs.docker.com/engine/reference/commandline/dockerd/#configure-container-runtimes dockerdがコンテナランタイムとしてruncを使う。

コンテナランタイムってなんだ?

https://github.com/opencontainers/runc runcはコンテナの発生と実行をするためのツールらしい。それぞれ「発生」「実行」ってなんだ?になると沼りそうなのでこの辺で引き返しておく。

docker-init

https://docs.docker.com/engine/reference/commandline/init/ プロジェクト上で必要なファイルを生成するコマンド?多分違うなこれ。

https://docs.docker.com/engine/reference/commandline/container_run/#init これか。AIに聞いてもdocker initコマンドのことしか話さないからドキュメントを探すのに手こずった。

Docker daemonプロセスのシステムpathで最初に見つかった実行可能なファイルが、コンテナ内のPID 1のプロセスとして動くらしい。docker versionコマンドで出たdocker-initは、おそらくデフォルトのdocker-initバイナリを指す。

tiniってやつにbackedされているらしい。backedってなんだ?英語がわからない。雑に機械翻訳したら「サポートされている」とか「バックアップされている」とかになった。なるほど?

https://github.com/krallin/tini tiniはコンテナの中でゾンビプロセスを刈り取る1プロセスとして動くらしい。ほむ。

雑理解のまとめ

  • dockerdがデーモンプロセスとしてAPIとしてふるまう。あといろいろやる。
  • containerdはnamespace, cgroups, SELinuxを操作するためのインターフェースとして使われる
  • runcはコンテナランタイムとして使われる(コンテナランタイムって結局具体的になんだろう)
  • docker-initはそれぞれのコンテナのPID 1のプロセスとして動くバイナリファイル

サブネットマスクって何

毎回わからなくなってるので理解を書き起こす。

せっかくなので、サブネットについて書かれているRFC950を眺めた。読んだとは言ってない。 https://www.rfcreader.com/#rfc7322

IPv4のアドレスは32ビットで表現される。232 ≒ 43億通りのアドレスが表現できる。足りるのか足りないのかは分からない。なんか足りないらしいということはよく聞く。

IPアドレスはネットワーク上の住所を表す。パブリックとプライベートの区別がある。 なんやかんやでネットワークを区分する需要があったため"subnet"の概念が誕生したらしい。

サブネットによって、ネットワークアドレスとホストアドレスに分けることができる。

ネットワークアドレス

IPアドレスの前半部分。どのネットワークセグメントかを識別できる。

ホストアドレス

IPアドレスの後半部分。ネットワークセグメントの中のどのデバイスかを識別できる。

どこからが前半でどこからが後半?

というのを「サブネットマスク」の値が決める。

たとえばサブネットマスク/8だったら前半8ビットがネットワークアドレスになる。残り24ビットをホストの識別に使える。

具体例

firewall rule

インバウンド通信について、192.168.1.0/24からのみを許可する場合。 前半24ビット、つまり192.168.1がネットワークアドレスである。このネットワークセグメントからのインバウンド通信が許可される。

プライベートIP

192.168.0.0/16はプライベートIPアドレスとして予約されてるらしい。 ほかには10.0.0.0/8172.16.0.0/12も同様にプライべートIPとして予約されている。 それぞれネットワークアドレス、ホストアドレスの広さが異なるのがサブネットマスクの値によって表現されている。

terraformなんもわからん

plan, applyはなんとなく想像がつく。providerに応じてAPIを叩いているのだろう。 stateファイルもなんとなく想像がつく。applyしたときのリソースの状態を記述するのだろう。

initって何やってるの?たまに-migrate-stateとか-reconfigureとか何やってるか理解せずにコマンドを叩いてるから本当に不安。そのうち事故るだろうから今のうちに理解しておきたい。

https://developer.hashicorp.com/terraform/docs ソースコードを読むのはちょっと重たいので公式ドキュメントを読む。

Command: init

https://developer.hashicorp.com/terraform/cli/commands/init

  • いろいろやられるコマンドだが、とりあえず最初に実行されるべきコマンドである
  • 冪等性がある
  • このコマンドによって現存するstateやconfigurationが削除されることはない

行われること

普段の使用で意識するべきは次の2点だろうか。

  • backendが初期化される
  • 子モジュール、プラグインがインストールされる

backendが初期化される

ドキュメントを読んでも、結局何がされてるのかよくわからなかった。 冒頭に挙げたフラグについては次のような説明がされていた。

  • -migrate-stateは既存のstateファイルを新しいbackendにコピーする
  • -reconfigureは既存の設定を無視する

ここでいう「設定」configuration が何なのかが分からない。これ以上はソースを読むしかないか...?

以下、自分の勝手な想像による認識。

  • backendはなんらかのストレージにあるファイル
  • initすることでbackendとして指定されたファイルを認識する?

なんかいろいろインストールされる

これはなんとなくわかる。ローカルの.terraformディレクトリにいろいろ入ってくるからそこにモジュールやプラグインがダウンロードされているのだろう。パブリッククラウドAPIを叩くときのソースコードだったりするのだろう。

pythonで構成図を書く`diagram`

github.com

pythonで宣言的に構成図が書ける。

アイコンも有名どころは揃っている。AWSとかGoogle Cloudとか。 https://diagrams.mingrammer.com/docs/nodes/gcp

from diagrams.onprem.client import Client

こんな感じでimportできる。

with Diagramでダイアグラム、with Clusterクラスターを表現できる。

https://dev.classmethod.jp/articles/diagrams-introduction/ この記事がわかりやすい。

python全部わすれたけど勘で書けたので助かる

aptってなに

neovim周りを触っていて、どうやらapt-get installでいれたものが最新バージョンでなかったらしい。 ソースからビルドしようとしたらcmakeがなかったので入れた。そしたらどうやらapt-get installで入れたものが最新バージョンでなかったらしい。 なので https://zenn.dev/suudai/articles/8b484ac39fde38 を参考に現時点で最新のcmake v3.28.1を入れた。めっちゃ時間かかってる。sudo makeコマンドの実行にめっちゃ時間かかっている。

暇なので、そういえばきちんと理解していなかったaptについて調べて書いていく。

apt

https://manpages.ubuntu.com/manpages/bionic/ja/man8/apt.8.html

Ubuntu用のパッケージマネージングコマンド という理解であっているだろうか?

apt-get

https://manpages.ubuntu.com/manpages/bionic/ja/man8/apt-get.8.html

apt-get は、パッケージを操作するコマンドラインツールで、APT ライブラリを用いる他のツールの ユーザ側「バックエンド」といえるものです。

よくわからん...。何が違うんだ

https://phoenixnap.com/kb/apt-vs-apt-get

aptが後発のもので、apt-getを含むコマンドなのか。完全に順序を逆に認識していた。

Most Linux users suggest using the apt command instead of apt-get whenever you can. Not only is it easier to type and remember, it performs tasks much faster.

基本的にaptを使う方が正道。

リポジトリ

リポジトリという概念があるらしいということしか知らない。

https://ubuntu.com/server/docs/package-management

この辺が公式ドキュメントか。流し読みしたところ、リポジトリはパッケージのソースらしい。Debianパッケージは.deb拡張子で扱われる。/etc/apt/sources.listリポジトリ情報が管理される。

調べているうちにcmakeのインストールが終わった。しかしまだneovimのmakeでエラーが出る。。。

追記

最新版neovimのインストール自体は https://qiita.com/hwatahik/items/123a0e6bc5cc283ac597 でできた。 wslはwindowsのファイルを/mntでマウントしているのね。

vim-plugでNeovimのパッケージ管理

私物のPCでのエディタをNeovimにしはじめた。

tsを書くにあたってLS(Language Server)による型チェックをしてほしかったのでパッケージを入れることにした。すでにcopilotは入れていたのだが、直に.config/nvim/packにcloneしていた。

LSPであれこれするのに、直にpackに突っ込んでいたらなんかうまくいかなかったのでパッケージマネージャに頼ることにした。

なんかいろいろあるらしいが勘でvim-plugにした。たぶんどれも変わらんでしょう。

nvimの設定は基本的にinit.vimに書くのだろうか。プラグインの設定もinit.vimに書いた。

" TypeScript用のシンタックスハイライトとLSPサポート
Plug 'leafgarland/typescript-vim'
Plug 'peitalin/vim-jsx-typescript'
Plug 'neoclide/coc.nvim', {'branch': 'release'}

call plug#end()

" coc.nvimの設定
let g:coc_global_extensions = ['coc-tsserver', 'coc-json', 'coc-html', 'coc-css']

いろいろ調べつつコピペで書いた。coc.nvimについてはよくわかっていない。ChatGPTの言うがままにした。

github.com

cocとはこれか。Nodeで動くVSCodeライクは拡張機能マネージャーといったところだろうか。察するにグローバルにいろいろ有効化するための記述だろう。 勘で入れたけどおそらくvim-jsx-typescriptは不要だったな。jsxファイル書かないし。

さて、dotfilesで管理するにあたっては、vim-plugで入るプラグインやcocで導入される拡張機能init.vimで管理されるからOKだ。

せっかくなのでvim-plugのインストールやパッケージ群のインストールもスクリプトに記述する。

$ cat install-package-manager.sh
#!/bin/sh

if [! -f ~/.local/share/nvim/site/autoload/plug.vim]; then
  echo "Installing vim-plug..."
  curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \
  https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  echo "vim-plug install complete!"
else
  echo "vim-plug already installed!"
fi

echo "Installing neovim plugins..."

nvim +PlugInstall +qall

echo "Neovim setup complete!"

多分これで動くはずだ。

リモートと同期したローカルのgithubリポジトリを一発で作るコマンドを作った

fishスクリプトで書いた。

github.com

function ghq-create --argument repo_name 
  gh repo create $repo_name --public
  ghq get "git@github.com:"(git config user.name)"/"$repo_name".git"
  cd (ghq root)"/github.com/"(git config user.name)"/"$repo_name
end

基本的にgitリポジトリghqで管理している。 ローカルにしかリポジトリがない状況が嫌なので常にリモートリポジトリが存在していてほしい。 これまでは次の手順でリポジトリを用意していた。

  1. GitHubリポジトリを作成
  2. ghq get $repo_url
  3. リポジトリディレクトリに移動

めんどいのでghコマンドを使って、この流れを一発で実行するようにした。 gh repo createはリモートにリポジトリを作るコマンド。 ghq getはリモートリポジトリを適切な場所にcloneするコマンド。 cdディレクトリを移動するコマンド。

fishスクリプトにも慣れてきた。