Eng (なりたい)

はやく エンジニア になりたい

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
  • 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) 補足

ref. http://docs.docker.jp/engine/reference/commandline/create.html create — Docker-docs-ja 17.06.Beta ドキュメント

  • 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

(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
  • 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

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) 補足

実行後にマウントしていた$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