dockerコマンド無しでコンテナを動かしてみる
以下のブログを参考にコンテナ周りの技術についての学習も兼ねてDockerコマンドなしでコンテナを動かす。
ref. Container Runtimes Part 2: Anatomy of a Low-Level Container Runtime - Ian Lewis
Dockerコマンドを使わずにコンテナを走らせる。(ファイルシステムの用意では使う)
(後始末が面倒なのでVirtualboxやクラウドサービスのVMなどを推奨)
0. 環境
- Google Compute Engine
- Machine Type:
f1-micro
- OS:
Ubuntu 18.04 LTS
- Machine Type:
- Cloud Shellからアクセス
1. ファイルシステムのセットアップ
まずはファイルシステムをセットアップする。
(早速Dockerコマンドという感じですが、ファイルの雛形を用意するためでコンテナの実行には使わないのでご容赦ください。)
今回はbusybox
のDockerイメージからファイルとディレクトリを抽出する。
$ sudo su # (1) $ CID=$(docker create busybox) # (2) $ ROOTFS=$(mktemp -d) # (3) $ docker export $CID | tar -xf - -C $ROOTFS
(1) 補足
docker create
は書込み可能なコンテナレイヤを作成する。- つまり「コンテナはは作成するが runはしない」状態
- 通常の
docker container ls
では作成したコンテナは作成されないが、-a
オプションで出力できる。 - コンテナIDを標準出力に表示する。
Example
$ docker create busybox 64aad11d274cec50b6e03f4422d50e01bfec2d894692934cd6965afd693a7c49 $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 64aad11d274c busybox "sh" 8 seconds ago Created silly_swartz
(2) 補足
ref. mktemp(1): create temporary file/directory - Linux man page
- 一時ファイルまたはディレクトリを作成するコマンド
-d
オプションなのでディレクトリが作成される。- 引数で
X
を3個以上渡すとその文字数分ランダム文字列のファイルまたはディレクトリが作成される。 - 指定しない場合は
/tmp/tmp.XXXXXXXXXX
になる。
Example
$ mktemp /tmp/tmp.ZTZHxN7V7B $ mktemp -d /tmp/tmp.Svu9ewej2o $ mktemp XXXX t5rk
(3) 補足
ref. Dockerイメージのexportとimport( save, load ) - Qiita
docker export <CONTAINER_ID>
はコンテナをtarファイルにする。tar -xf - -C $ROOTFS
にリダイレクトしてtarファイルを展開-x
: eXtract(展開)-f
: fileから展開(デフォルトはテープデバイスらしい)-C <DIR>
:<DIR>
に移動してから実行
2. コントロールグループを作成
$ apt install cgroup-tools # (4) $ UUID=$(uuidgen) # (5) $ cgcreate -g cpu,memory:$UUID # (6) $ cgset -r memory.limit_in_bytes=100000000 $UUID $ cgset -r cpu.shares=512 $UUID # (7) $ cgset -r cpu.cfs_period_us=1000000 $UUID $ cgset -r cpu.cfs_quota_us=2000000 $UUID
(4) 補足
ref. uuidgen(1) - Linux manual page
- UUIDを生成する
- UUIDは結構奥が深いらしいが、今回はメインじゃないので割愛。(Universally unique identifier - Wikipedia)
(5) 補足
refs.
そもそも cgroup
とは
ref. 第1章 コントロールグループについて (cgroup) - Red Hat Customer Portal
cgroup(control group)を用いることでCPU時間、システムメモリ、ネットワーク帯域などのリソースをシステムで実行中のユーザ定義タスクグループ(プロセス)に割り当てることができる。
コマンドについて
cgcreate
でコントロールグループ作成後、以下のコマンドで確認できる。
$ lscgroup | grep $UUID cpu,cpuacct:/*86aec293-c8c7-47f4-8158-817d978570ea* memory:/*86aec293-c8c7-47f4-8158-817d978570ea*
(6) 補足
ref. cgroupを使ってCPUとメモリの割り当てを制限する - 偏った言語信者の垂れ流し
(5)
で作成したコントロールグループの制限を設定する。
以下のコマンドで確認できる。
# cgset で設定した値になっている $ cat /sys/fs/cgroup/cpu/$UUID/cpu.shares 512 $ cat /sys/fs/cgroup/memory/$UUID/memory.limit_in_bytes 99999744
- Ubuntuでは
/sys/fs/cgroup
以下にcgroupの情報が格納される cpu.shares
はスケジューリングの優先度の値limit_in_bytes
はそのままメモリのバイト単位の制限
(7) 補足
ref. リソース管理ガイド - Red Hat Customer Portal
cpu.cfs_quota_us
- cgroupによるCPUリソースの再割り当てが行われる間隔(μs だが、ここでは
us
と表記されている) 1,000 < cpu.cfs_quota_us < 1,000,000
- cgroupによるCPUリソースの再割り当てが行われる間隔(μs だが、ここでは
cpu.cfs_period_us
- cgroup内のすべてのタスクが
cpu.cfs_quota_us
間に利用できるCPU時間(μs) - 特定のタスクが使い切った場合はcgroup内の他のタスクはスロットリングされ、次の期間まで実行ができない
- Ex) cgroupが1秒あたり0.2秒間単一ののCPUにアクセスするためには以下のように設定する
-
cpu.cfs_period_us = 1,000,000
-
cpu.cfs_period_us = 200,000
-
- cgroup内のすべてのタスクが
CFS (Completely Fair Scheduler)とは
ref. Linux カーネル 2.6 Completely Fair Scheduler の内側
CFS の背後にある主な概念は、タスクに与えるプロセッサー時間のバランス (公平性) を維持するためのものです。つまり、それぞれのプロセスには公平にプロセッサー時間が与えられるようにしなければなりません。
3. コンテナ内でコマンドを実行
1.
2.
で作成したファイルシステムとコントロールグループでコンテナを作成し、その中でコマンドを実行する。
# (8) $ cgexec -g cpu,memory:$UUID \ unshare -uinpUrf --mount-proc \ sh -c "/bin/hostname $UUID && chroot $ROOTFS /bin/sh" # (9) / # echo "Hello from in a container" Hello from in a container / # touch hoge.txt / # exit
(8) 補足
cgexec
- ref. cgexec(1): run task in given control groups - Linux man page
cgexec [-g <controllers>:<path>] [—sticky] command [arguments]
-g
オプションでコントロールグループを指定command
はunshare
以降を呼び出し
unshare
- refs.
unshare [options] [program [arguments]]
- オプション
-uinpUrf
-u
: UTS namespace を共有しない- システム識別子である(
nodename
,domainname
を独立させる)
- システム識別子である(
-n
: network namespace を共有しない- 独立した仮想ネットワークを構築する
-i
: IPC(Inter-Process Communication:プロセス間通信) namespace を共有しない- 異なるIPC namespace の共有メモリやセマフォにアクセスできないようにする
-p
: PID(Process ID) namespace を共有しない- 別空間のPIDと重複を許す
-U
: user namespace を共有しない- 別空間の
UID/GID
の重複を許す
- 別空間の
-r (--map-root-user)
: 新しいNameSpaceのrootユーザを起動したときのユーザIDに対応させる-f (—fork)
:unshare
で実行するプログラムを現在のプロセスの子ではなく、unshare
の子プロセスとしてForkする--mount-proc
: 実行直前にprocファイルシステムをmountpoint(デフォルトは/proc
)にマウントする- PID namespaceを新たに作成するのに役立つ
- オプション
/bin/hostname
- hostnameを変更する
- linux でのデフォルトは
localhost.localdomain
らしい
chroot
- ref. chroot(1) - Linux manual page
- ルートディレクトリを変更して
COMMAND
を実行 chroot [OPTION] NEWROOT [COMMAND [ARG]…]
実行後にマウントしていた$ROOTFS
以下を確認するとhoge.txt
がある。
$ ls $ROOTFS bin dev etc hoge.txt home proc root sys tmp usr var
(一応)クリーンアップ
$ cgdelete -r -g cpu,memory:$UUID $ rm -r $ROOTFS