dockerコンテナを作成するプロセスのしくみ(docker runからruncまで)

記事の翻訳は、コース「Kubernetesに基づくインフラストラクチャプラットフォーム」の開始を見越して作成されました








過去数か月間、私はLinuxコンテナがどのように機能するかを学ぶことに多くの個人的な時間を費やしてきました。特に、それは正確に何をしますかdocker runこの記事では、私が見つけたものを要約し、個々の要素がどのように全体像を形成するかを示すことを試みます。dockerrunを使用して高山コンテナを作成することから旅を始めます。



$ docker run -i -t --name alpine alpine ash


このコンテナは、以下の出力で使用されます。docker runコマンドが呼び出されると、コマンドラインで渡されたパラメーターが解析され、dockerが作成する必要のあるオブジェクトを表すJSONオブジェクトが作成されます。次に、このオブジェクトは、UNIXドメインソケット/var/run/docker.sockを介してdockerデーモンに送信されます。API呼び出しを監視するには、straceユーティリティを使用できます



$ strace -s 8192 -e trace=read,write -f docker run -d alpine


[pid 13446] write(3, "GET /_ping HTTP/1.1\r\nHost: docker\r\nUser-Agent: Docker-Client/1.13.1 (linux)\r\n\r\n", 79) = 79
[pid 13442] read(3, "HTTP/1.1 200 OK\r\nApi-Version: 1.26\r\nDocker-Experimental: false\r\nServer: Docker/1.13.1 (linux)\r\nDate: Mon, 19 Feb 2018 16:12:32 GMT\r\nContent-Length: 2\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nOK", 4096) = 196
[pid 13442] write(3, "POST /v1.26/containers/create HTTP/1.1\r\nHost: docker\r\nUser-Agent: Docker-Client/1.13.1 (linux)\r\nContent-Length: 1404\r\nContent-Type: application/json\r\n\r\n{\"Hostname\":\"\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[],\"Cmd\":null,\"Image\":\"alpine\",\"Volumes\":{},\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{},\"HostConfig\":{\"Binds\":null,\"ContainerIDFile\":\"\",\"LogConfig\":{\"Type\":\"\",\"Config\":{}},\"NetworkMode\":\"default\",\"PortBindings\":{},\"RestartPolicy\":{\"Name\":\"no\",\"MaximumRetryCount\":0},\"AutoRemove\":false,\"VolumeDriver\":\"\",\"VolumesFrom\":null,\"CapAdd\":null,\"CapDrop\":null,\"Dns\":[],\"DnsOptions\":[],\"DnsSearch\":[],\"ExtraHosts\":null,\"GroupAdd\":null,\"IpcMode\":\"\",\"Cgroup\":\"\",\"Links\":null,\"OomScoreAdj\":0,\"PidMode\":\"\",\"Privileged\":false,\"PublishAllPorts\":false,\"ReadonlyRootfs\":false,\"SecurityOpt\":null,\"UTSMode\":\"\",\"UsernsMode\":\"\",\"ShmSize\":0,\"ConsoleSize\":[0,0],\"Isolation\":\"\",\"CpuShares\":0,\"Memory\":0,\"NanoCpus\":0,\"CgroupParent\":\"\",\"BlkioWeight\":0,\"BlkioWeightDevice\":null,\"BlkioDeviceReadBps\":null,\"BlkioDeviceWriteBps\":null,\"BlkioDeviceReadIOps\":null,\"BlkioDeviceWriteIOps\":null,\"CpuPeriod\":0,\"CpuQuota\":0,\"CpuRealtimePeriod\":0,\"CpuRealtimeRuntime\":0,\"CpusetCpus\":\"\",\"CpusetMems\":\"\",\"Devices\":[],\"DiskQuota\":0,\"KernelMemory\":0,\"MemoryReservation\":0,\"MemorySwap\":0,\"MemorySwappiness\":-1,\"OomKillDisable\":false,\"PidsLimit\":0,\"Ulimits\":null,\"CpuCount\":0,\"CpuPercent\":0,\"IOMaximumIOps\":0,\"IOMaximumBandwidth\":0},\"NetworkingConfig\":{\"EndpointsConfig\":{}}}\n", 1556) = 1556
[pid 13442] read(3, "HTTP/1.1 201 Created\r\nApi-Version: 1.26\r\nContent-Type: application/json\r\nDocker-Experimental: false\r\nServer: Docker/1.13.1 (linux)\r\nDate: Mon, 19 Feb 2018 16:12:32 GMT\r\nContent-Length: 90\r\n\r\n{\"Id\":\"b70b57c5ae3e25585edba898ac860e388582391907be4070f91eb49f4db5c433\",\"Warnings\":null}\n", 4096) = 281


ここから本当の楽しみが始まります。すぐドッカーデーモンとしては、要求を受信すると、それがあろう解析出力と通信containerd介しgRPCのAPIコマンドラインに渡されたパラメータを使用して、容器のランタイム(または実行)を設定します。この相互作用を観察するために、ctrユーティリティを使用できます。



$ ctr --address "unix:///run/containerd.sock" events


TIME                           TYPE                           ID                             PID                            STATUS
time="2018-02-19T12:10:07.658081859-05:00" level=debug msg="Calling POST /v1.26/containers/create" 
time="2018-02-19T12:10:07.676706130-05:00" level=debug msg="container mounted via layerStore: /var/lib/docker/overlay2/2beda8ac904f4a2531d72e1e3910babf145c6e68dfd02008c58786adb254f9dc/merged" 
time="2018-02-19T12:10:07.682430843-05:00" level=debug msg="Calling POST /v1.26/containers/d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f/attach?stderr=1&stdin=1&stdout=1&stream=1" 
time="2018-02-19T12:10:07.683638676-05:00" level=debug msg="Calling GET /v1.26/events?filters=%7B%22container%22%3A%7B%22d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f%22%3Atrue%7D%2C%22type%22%3A%7B%22container%22%3Atrue%7D%7D" 
time="2018-02-19T12:10:07.684447919-05:00" level=debug msg="Calling POST /v1.26/containers/d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f/start" 
time="2018-02-19T12:10:07.687230717-05:00" level=debug msg="container mounted via layerStore: /var/lib/docker/overlay2/2beda8ac904f4a2531d72e1e3910babf145c6e68dfd02008c58786adb254f9dc/merged" 
time="2018-02-19T12:10:07.885362059-05:00" level=debug msg="sandbox set key processing took 11.824662ms for container d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f" 
time="2018-02-19T12:10:07.927897701-05:00" level=debug msg="libcontainerd: received containerd event: &types.Event{Type:\"start-container\", Id:\"d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f\", Status:0x0, Pid:\"\", Timestamp:(*timestamp.Timestamp)(0xc420bacdd0)}" 
2018-02-19T17:10:07.927795344Z start-container                d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f                                0
time="2018-02-19T12:10:07.930283397-05:00" level=debug msg="libcontainerd: event unhandled: type:\"start-container\" id:\"d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f\" timestamp:<seconds:1519060207 nanos:927795344 > " 
time="2018-02-19T12:10:07.930874606-05:00" level=debug msg="Calling POST /v1.26/containers/d1a6d87886e2d515bfff37d826eeb671502fa7c6f47e422ec3b3549ecacbc15f/resize?h=35&w=115" 


コンテナのランタイムの構成は、かなり重要なタスクです。名前空間を構成し、イメージをマウントし、セキュリティ制御を有効にする必要があります(アプリケーション保護プロファイル、seccompプロファイル、機能)など。かなり良いアイデアを得ることができます。出力docker inspect containeridとランタイムスペックファイルを見て、ランタイムをセットアップするために必要なすべてのことconfig.json(これについては後で詳しく説明します)。



厳密に言えば、containerdはコンテナランタイムを作成しません。環境を設定してからcontainerd-shimを呼び出します構成済みのOCIランタイム(containerdの「–runtime」パラメーターで制御)を介してコンテナーランタイムを実行します。最近のほとんどのシステムは、runcに基づいてコンテナランタイムを実行しますこれは、pstreeユーティリティを使用して確認できます



$ pstree -l -p -s -T
systemd,1 --switched-root --system --deserialize 24
  ├─docker-containe,19606 --listen unix:///run/containerd.sock --shim /usr/libexec/docker/docker-containerd-shim-current --start-timeout 2m --debug
  │   ├─docker-containe,19834 93a619715426f613646359863e77cc06fa85502273df931517ec3f4aaae50d5a /var/run/docker/libcontainerd/93a619715426f613646359863e77cc06fa85502273df931517ec3f4aaae50d5a /usr/libexec/docker/docker-runc-current


以来pstreeコマンドは、ストリッププロセス名オフ、我々は確認することができPIDをしてPS



$ ps auxwww | grep [1]9606


root     19606  0.0  0.2 685636 10632 ?        Ssl  13:01   0:00 /usr/libexec/docker/docker-containerd-current --listen unix:///run/containerd.sock --shim /usr/libexec/docker/docker-containerd-shim-current --start-timeout 2m --debug


$ ps auxwww | grep [1]9834


root     19834  0.0  0.0 527748  3020 ?        Sl   13:01   0:00 /usr/libexec/docker/docker-containerd-shim-current 93a619715426f613646359863e77cc06fa85502273df931517ec3f4aaae50d5a /var/run/docker/libcontainerd/93a619715426f613646359863e77cc06fa85502273df931517ec3f4aaae50d5a /usr/libexec/docker/docker-runc-current


dockerd、containerd、shim の相互作用を最初に調べ始めたときshimが何のためにあるのか完全には理解していませんでした幸いにもGoogleは優れたにつながったことにより、書き込み マイケル・クロスビーシムにはいくつかの目的があります。



  1. デーモンなしでコンテナを起動できます。
  2. STDIO FD containerd docker.
  3. containerd .


1番目と2番目の重要なポイントは非常に重要です。これらの機能は、あなたからコンテナを分離できるようにするドッキングウィンドウのデーモンできるよう、dockerdがする更新または再起動され実行されているコンテナに影響を与えず。非常に効果的!シムrunc実行して実際にコンテナを起動する責任があると述べましたRuncその仕事をするためには、スペックファイルとルートファイルシステムイメージへのパス(バンドルと呼ばれる組み合わせ)の2つが必要です。この作品は、私たちが作成する方法を参照するにはrootfsのをによってエクスポート高山ドッキングウィンドウの画像を



$ mkdir -p alpine/rootfs


$ cd alpine


$ docker export d1a6d87886e2 | tar -C rootfs -xvf -


time="2018-02-19T12:54:13.082321231-05:00" level=debug msg="Calling GET /v1.26/containers/d1a6d87886e2/export" 
.dockerenv
bin/
bin/ash
bin/base64
bin/bbconfig
.....


エクスポートオプションは、出力にあるコンテナを受け入れますdocker ps -arunc specコマンドを使用して、スペックファイル作成できます



$ runc spec


これconfig.jsonにより、現在のディレクトリに名前が付けられたスペックファイルが作成されます。このファイルは、ニーズと要件に応じてカスタマイズできます。ファイルに満足したら、rootfsディレクトリを唯一の引数としてruncを実行できます(コンテナ構成はファイルから読み取られますconfig.json)。



$ runc run rootfs


この簡単な例では、高山の灰のラッパーを作成します。



$ runc run rootfs


/ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.7.0
PRETTY_NAME="Alpine Linux v3.7"
HOME_URL="http://alpinelinux.org"
BUG_REPORT_URL="http://bugs.alpinelinux.org"


コンテナを作成し、runcランタイム 仕様を操作する機能は非常に強力です。dockerをインストールしなくても、さまざまなアプリケーションプロファイルを評価し、Linux機能をテストし、コンテナランタイムのあらゆる側面を試すことができます。私は表面を少し引っかいただけなので、runcコンテナ化されたドキュメントを読むことを強くお勧めしますとてもクールなツール!






コースの詳細をご覧ください。







All Articles