Más contenido relacionado
La actualidad más candente (20)
Similar a すごく分かるwarden (20)
すごく分かるwarden
- 2. Warden(ウォードン)とは
https://github.com/cloudfoundry/warden
DEA上でアプリケーションを隔離する仕組み
2012-07-26 NTT Software Innovation Center 2
- 3. Outline
なぜWardenが必要なのか
Wardenの動作原理
2012-07-26 NTT Software Innovation Center 3
- 5. なぜWardenが必要なのか
ユーザ権限で
動作
App App App
DEAホスト(OS)
Appはユーザが自由に開発する
– 悪意のあるAppの可能性もある
現在はUNIX UserによりAppを隔離
2012-07-26 NTT Software Innovation Center 5
- 6. Unix Userの問題点
App App App
脆弱性に弱い
– 特権昇格
DEAホスト(OS)
App
A
p
A
p
他のAppの影響を受ける
– CPU、メモリ、IO、etc.
p p
DEAホスト(OS)
App App App
情報が他Appに伝わる
– PID、CPU、メモリ、etc.
– 気持ち悪い
DEAホスト(OS)
2012-07-26 NTT Software Innovation Center 6
- 7. 求められるもの
App App App 制限
DEAホスト
一方通行
App環境の隔離
リソース制限の導入
操作用API
2012-07-26 NTT Software Innovation Center 7
- 8. FAQ
AppごとにVM建てればいいのでは?
– パフォーマンス的に難しい
chroot jailではダメ?
– マウントポイントしか隠ぺいできない
LXCではダメ?
– 初期のWardenはLXCを利用していたが…
– Linuxでしか動かない
– 機能過多
2012-07-26 NTT Software Innovation Center 8
- 10. 基本方針
コンテナ
– 環境の隔離:Namespaces
– リソース制限:Cgroups
– /sbin/init起動によるシステムコンテナ
操作用API
– Wardenサーバがコンテナを管理
– Warden Protocl経由でサーバにアクセス
2012-07-26 NTT Software Innovation Center 10
- 11. Cgroups
Linux Kernel 2.6.24から
プロセスをグループに分離
– メモリ使用量、CPU・IOの優先度
書いてあるよ!
2012-07-26 NTT Software Innovation Center 11
- 12. Namepaces
プロセスの名前空間を分離
– PID、Network, Mount、UTS、IPC、User
– unshare(1), clone(2)
マウント状況も分離される
– 高級版chroot jail
ネットワークも分離される
– 仮想NIC(veth)を使用
2012-07-26 NTT Software Innovation Center 12
- 13. Wardenの概要
Warden
クライアント
②コンテナの起動
EMサーバ シェル
(Ruby) スクリプト群
Linux
クラス clone.c DEA
コンテナ
①コンテナの生成
ジョブ
sshd
③ジョブの起動
OS
2012-07-26 NTT Software Innovation Center 13
- 14. サーバ本体
Warden
クライアント
②コンテナの起動
EMサーバ シェル
(Ruby) スクリプト群
Linux
クラス clone.c DEA
コンテナ
①コンテナの生成
ジョブ
sshd
③ジョブの起動
OS
2012-07-26 NTT Software Innovation Center 14
- 15. サーバ本体
/lib/warden
命令を受け取ってコンテナの操作を行う
– EMがListen
– OS・環境ごとのクラスに委譲
Linuxクラス
– シェルスクリプトに処理を委託
2012-07-26 NTT Software Innovation Center 15
- 16. サーバ本体
/lib/warden/container/linux.rb
def do_create
sh "#{env_command} #{root_path}/create.sh #{handle}", :timeout => nil
debug "container created"
write_bind_mount_commands コンテナの生成
debug "wrote bind mount commands"
sh "#{container_path}/start.sh", :timeout => nil
debug "container started"
end
コンテナの起動
(コンテナは常時起動)
2012-07-26 NTT Software Innovation Center 16
- 17. シェルスクリプト部分
Warden
クライアント
②コンテナの起動
EMサーバ シェル
(Ruby) スクリプト群
Linux
クラス clone.c DEA
コンテナ
①コンテナの生成
ジョブ
sshd
③ジョブの起動
OS
2012-07-26 NTT Software Innovation Center 17
- 18. シェルスクリプト部分
/root/linux
コンテナの生成・削除
Skeleton
– ファイルがコンテナごとにコピーされる
2012-07-26 NTT Software Innovation Center 18
- 19. シェルスクリプト部分(コンテナ生成)
/root/linux/create.sh
# インスタンスごとのディレクトリ
target="instances/${1}"
mkdir -p instances
…
cp -r skeleton "${target}“
unshare -m "${target}"/setup.sh
– スケルトンをコピー
– マウント名前空間をunshareしてsetup.shを実行
/root/linux/skeleton/setup.sh
– 設定を/etc内に書きだす
– /etc/ssh, /etc/init.d, /etc/hosts, etc.
2012-07-26 NTT Software Innovation Center 19
- 21. シェルスクリプト部分
Warden
クライアント
②コンテナの起動
EMサーバ シェル
(Ruby) スクリプト群
Linux
クラス clone.c DEA
コンテナ
①コンテナの生成
ジョブ
sshd
③ジョブの起動
OS
2012-07-26 NTT Software Innovation Center 21
- 22. clone.c
/src/clone/clone.c
システムコールによるコンテナ生成
– clone(2)
2012-07-26 NTT Software Innovation Center 22
- 23. clone.c
/src/clone/clone.c
rv = unshare(CLONE_NEWNS);
…
# clone前のフック
# コンテナ用のファイルシステムをマウントする
rv = run("./hook-parent-before-clone.sh");
…
# コンテナ内のinitプロセスを起動する
rv = parent_clone_child(h);
…
# clone後のフック
rv = run("./hook-parent-after-clone.sh");
2012-07-26 NTT Software Innovation Center 23
- 24. clone.c
/src/clone/clone.c
rv = unshare(CLONE_NEWNS);
…
# clone前のフック
# コンテナ用のファイルシステムをマウントする
rv = run("./hook-parent-before-clone.sh");
…
# コンテナ内のinitプロセスを起動する
rv = parent_clone_child(h);
…
# clone後のフック
rv = run("./hook-parent-after-clone.sh");
2012-07-26 NTT Software Innovation Center 24
- 25. skeletonに寄り道
/root/linux/skeleton/hook-parent-before-clone.sh
setup_fs
/root/linux/skeleton/common.sh:setup_fs()
if [ ! -f fs ]; then
dd if=/dev/null of=fs bs=1M seek=${disk_size_mb}
…
fi
mkdir -p rootfs ${target}
mount -n -o loop fs rootfs
…
mount -n -t overlayfs -o
rw,upperdir=rootfs,lowerdir=../../base/rootfs none ${target}
– コンテナごとのファイルをループバックマウント
– OSが入っているベースにオーバーレイ
• ベースは書き込み禁止状態で共有
2012-07-26 NTT Software Innovation Center 25
- 26. clone.c
/src/clone/clone.c
rv = unshare(CLONE_NEWNS);
…
# clone前のフック
# コンテナ用のファイルシステムをマウントする
rv = run("./hook-parent-before-clone.sh");
…
# コンテナ内のinitプロセスを起動する
rv = parent_clone_child(h);
…
# clone後のフック
rv = run("./hook-parent-after-clone.sh");
2012-07-26 NTT Software Innovation Center 26
- 27. clone.c
int parent_clone_child(clone_helper_t *h) {
…
# 名前空間分離の設定
/* Setup namespaces */
flags |= CLONE_NEWIPC;
flags |= CLONE_NEWNET;
flags |= CLONE_NEWNS;
flags |= CLONE_NEWPID;
flags |= CLONE_NEWUTS;
# start()から子プロセス起動
pid = clone(start, stack, flags, h);
…
}
2012-07-26 NTT Software Innovation Center 27
- 28. clone.c
int start(void *data) {
…
rv = run(hook_before_pivot
…
rv = run(hook_after_pivot);
…
# /sbin/initをexecvpして起動完了
char * const argv[] = { "/sbin/init", "--debug", NULL };
execvp(argv[0], argv);
…
}
2012-07-26 NTT Software Innovation Center 28
- 29. clone.c
/src/clone/clone.c
rv = unshare(CLONE_NEWNS);
…
# clone前のフック
# コンテナ用のファイルシステムをマウントする
rv = run("./hook-parent-before-clone.sh");
…
# コンテナ内のinitプロセスを起動する
rv = parent_clone_child(h);
…
# clone後のフック
rv = run("./hook-parent-after-clone.sh");
2012-07-26 NTT Software Innovation Center 29
- 30. skeletonに寄り道
/root/linux/skeleton/hook-parent-after-clone.sh
# 新しいcgroupを作って
mkdir -p /dev/cgroup/instance-${id}
pushd /dev/cgroup/instance-${id} > /dev/null
# 上限などを決め
cat ../cpuset.cpus > cpuset.cpus
cat ../cpuset.mems > cpuset.mems
# 子プロセスに値をコピーするコールバックを呼ぶ設定
echo 1 > cgroup.clone_children
# cgroupsに現在のプロセスを登録
echo ${PID} > tasks
2012-07-26 NTT Software Innovation Center 30
- 31. ジョブの起動
Warden
クライアント
②コンテナの起動
EMサーバ シェル
(Ruby) スクリプト群
Linux
クラス clone.c DEA
コンテナ
①コンテナの生成
ジョブ
sshd
③ジョブの起動
OS
2012-07-26 NTT Software Innovation Center 31
- 32. ファイルの送受信とコマンドの実行
DEA用の特別な仕掛けは見当たらない
– ファイルの送受信(rsync)
– コマンドの実行(ssh)
• ジョブとして入出力を管理
2012-07-26 NTT Software Innovation Center 32
- 33. ジョブの起動
/lib/warden/container/linux.rb
def create_job(request)
user = request.privileged ? "root" : "vcap"
# -T: Never request a TTY
# -F: Use configuration from <container_path>/ssh/ssh_config
args = ["-T",
"-F", File.join(container_path, "ssh", "ssh_config"),
"#{user}@container"]
args << { :input => request.script }
child = DeferredChild.new("ssh", *args)
…
2012-07-26 NTT Software Innovation Center 33
- 34. ファイルの送受信
/lib/warden/container/linux.rb
def do_copy_in(request, response)
src_path = request.src_path
dst_path = request.dst_path
perform_rsync(src_path, "vcap@container:#{dst_path}")
nil
end
def do_copy_out(request, response)
src_path = request.src_path
dst_path = request.dst_path
perform_rsync("vcap@container:#{src_path}", dst_path)
if request.owner
sh "chown", "-R", request.owner, dst_path
end
nil
end
private
def perform_rsync(src_path, dst_path)
ssh_config_path = File.join(container_path, "ssh", "ssh_config")
# Build arguments
args = ["rsync"]
args += ["-e", "ssh -T -F #{ssh_config_path}"]
args += ["-r"] # Recursive copy
args += ["-p"] # Preserve permissions
args += ["--links"] # Preserve symlinks
args += [src_path, dst_path]
# Add option hash
args << { :timeout => nil }
sh *args
end
2012-07-26 NTT Software Innovation Center 34
- 35. まとめ
WardenはApp隔離用のコンテナ
LinuxではCgroupsとNamespacesを使用
サーバがコンテナの操作を行う
ファイルを転送してコマンドを実行する
2012-07-26 NTT Software Innovation Center 35