ようへいの日々精進XP

よかろうもん

Docker コンテナランタイムについて少しだけ勉強した (7)

tl;dr

会社から借りっぱなしの Software Design 2020 年 2 月号で特集されている Docker コンテナランタイムについての記事を読んでみたメモです.

gihyo.jp

読みながら気になる単語や内容をマインドマップにまとめていきたいと思います.

今回は cgroup について手を動かしてみたいと思います.

マインドマップ

f:id:inokara:20200425171901p:plain

ハンズオンメモ

検証環境

ホスト側の OS は以下の通り.

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

各種ツールのバージョンは以下の通り.

$ runc --version
runc version spec: 1.0.1-dev

$ unshare --version
unshare from util-linux 2.31.1

$ taskset --version
taskset from util-linux 2.34

事前準備

隔離環境の Alpine Linux に taskset をインストールする

巣の Alpine Linux には taskset ユーティリティはインストールされていなかったので, util-linux パッケージをインストールします.

尚, インストールに際しては, 改めて docker コンテナを起動してパッケージをインストールしてから rootfs を再作成することになります.

$ docker run --rm -d --name rootfs alpine tail -f /dev/null
$ docker exec -t -i rootfs /bin/sh
/ # apk update && apk add bash util-linux
/ # exit
$ docker export rootfs > rootfs.tar
$ tar xvf rootfs.tar -C bundle/rootfs

taskset の動作確認

taskset を動かしてみる. 以下のように隔離環境において 0 及び 1 のプロセッサが利用出来ることが判ります.

$ unshare -pfmur chroot bundle/rootfs /bin/sh
/ # taskset -c 0 echo 'test 0'
test 0
/ # taskset -c 1 echo 'test 1'
test 1
/ #

隔離環境にて CPU (プロセッサ) 利用を制限する

利用可能なプロセッサの確認

ホスト上で以下のように実行して利用可能なプロセッサを確認します.

$ cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1

01 の二つのプロセッサが利用可能であることが判ります. また, この値は, 以下のように /proc/cpuinfoprocessor 項目に該当します.

$ cat /proc/cpuinfo | grep 'processor'
processor       : 0
processor       : 1

隔離環境にて 0 番のプロセッサのみ利用可能にする

まずはホスト側で以下を実行する. (すでに隔離環境は unshare -pfmur chroot bundle/rootfs /bin/sh で起動している前提.)

$ sudo mkdir /sys/fs/cgroup/cpuset/demo
$ cd /sys/fs/cgroup/cpuset/demo

# -> 利用可能なプロセッサの設定 0 番のプロセッサのみを利用する
$ sudo su -
# echo 0 > cpuset.cpus

# -> 既存の設定を継承
# echo 0 > cpuset.mems

# -> 隔離環境で実行されるプロセスのホスト側から見える PID を tasks に書き込む
# ps ao pid,cmd | grep '[/]bin/sh' | grep -v unshare | awk '{print $1}' > tasks

隔離環境で実行されるプロセスのホスト側から見える PID を書き込むことで, そのプロセスから作られるすべての子プロセスに対して, 0 番の CPU のみを利用するように制限が掛かることになります.

実際に確認してみます.

/ #
/ # taskset -c 0 echo 'test 0'
test 0
/ # taskset -c 1 echo 'test 1'
taskset: failed to set pid 3's affinity: Invalid argument
/ #

確かに 1 番のプロセッサを利用しようとすると, taskset: failed to set pid 3's affinity: Invalid argument というエラーが出力され, 期待通りに 0 番のプロセッサのみが利用可能な状態を確認出来ました.

参考

tenforward.hatenablog.com

sasaki.hateblo.jp

以上

namespace, cgroup と触ってきて, あれ, コンテナのランタイムどこ行った!って思ってしまうほど, runc については Linux の環境隔離の仕組みをゴリゴリと使って実現していることを実感出来ました. Kubernetes や Docker のような上モノを触るのも楽しいけど, コンテナランタイムを通してコンテナの深淵に触れてみることで, このレイヤーのことについて何も知らないことに愕然となりましたが, 今後も引き続き, このあたりのインプットはやっていきたいなと思います.

とても面白い記事でした. 借りっぱなしなってしまい本当に申し訳ございません.