Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
コンテナ起動への道
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
xorphitus
August 16, 2016
Programming
170
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
コンテナ起動への道
コンテナの要素技術を使ってみました。
xorphitus
August 16, 2016
More Decks by xorphitus
See All by xorphitus
オリジナリティのあるGitLabを標準に近づける
xorphitus
1
790
マイクロサービスを作ろう
xorphitus
0
150
型システムを学ぼうとした結果
xorphitus
0
79
M-x doctor
xorphitus
0
170
型で数を表そう
xorphitus
0
110
AOT と direct linking
xorphitus
0
87
CFS入門
xorphitus
0
89
HyperLogLog
xorphitus
0
130
immutable database
xorphitus
0
320
Other Decks in Programming
See All in Programming
FDEとは、何者なのか?
masapyon1212
0
140
Press start. Python's next generation.
willingc
PRO
3
300
XHTMLが残したもの
yosuke_furukawa
PRO
1
390
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
4
1.7k
信頼性の目標を誰も求めてない
shubox
0
490
Oxlintはいいぞ(続)
yug1224
1
540
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
53
35k
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
630
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
0
420
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
4
2.8k
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
460
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
250
Featured
See All Featured
Bash Introduction
62gerente
615
220k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.6k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
Accessibility Awareness
sabderemane
1
200
The Cost Of JavaScript in 2023
addyosmani
55
10k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Building Applications with DynamoDB
mza
96
7.2k
How STYLIGHT went responsive
nonsquared
100
6.3k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
430
Measuring & Analyzing Core Web Vitals
bluesmoon
9
990
For a Future-Friendly Web
brad_frost
183
10k
Transcript
コンテナ起動への道 @xorhitus (2016-08)
Linuxコンテナの仕組み コンテナはVMとは違い、隔離された空間で動く通常のプロセスで云々 と、いう説明は今回はしません 以下のあたりが分かりやすくておすすめ • https://speakerdeck.com/tenforward/jin-sarawen-kenai-linux-kontenafalseji-ch u-2015-06-20 ◦ 氏が技評でやってる連載も良いと思う •
http://www.slideshare.net/enakai/docker-34668707
別に新しくないコンテナ技術 以下の組み合わせで隔離された空間を作っているらしい 1. Namespace 2. Cgroup 3. ネットワーク機能 4. ルートディレクトリの変更
5. bind mount 6. CRIU 7. overlayfs
よし、流行ってるし コンテナを立ち上げてみよう
$ docker run
Dockerは甘え $ docker run
まずはNamespaceから
Namespace自体は全く新しくない 初出はLinux Kernel 2.4.19 その後、2.6系の時に大部分の機能がそろう ちなみに2016年7月19日時点のArch Linux $ uname -sr
Linux 4.6.4-1-ARCH
どんなシステムコールで操作するの? • clone(2) ◦ Namespaceの設定をした新しいプロセスを生成する • unshare(2) ◦ 実行中プロセスのNamespaceを制御する ◦
unshare(1) もあるからシェルスクリプトからも色々できるよ • setns(2) ◦ プロセスを既存のNamespaceに紐付ける
clone(2)によるPIDの隔離 Cでの実装 #define _GNU_SOURCE #include <sched.h> #include <stdio.h> #include <stdlib.h>
#include <sys/wait.h> #include <unistd.h> #define STACK_SIZE 1024*1024 static char child_stack[STACK_SIZE]; static int child_fn() { printf("child - self pid: %ld\n", (long) getpid()); printf("child - parent pid: %ld\n", (long) getppid()); exit(0); } int main(int argc, char *argv[]) { int flags = SIGCHLD; int opt; while ((opt = getopt(argc, argv, "p")) != -1) { if (opt) { flags |= CLONE_NEWPID; } else { exit(1); } } pid_t child_pid = clone(child_fn, child_stack + STACK_SIZE, flags, NULL); printf("current - clone pid: %ld\n", (long) child_pid); printf("current - self pid: %ld\n", (long) getpid()); waitpid(child_pid, NULL, 0); exit(0); } -p option付与で PID隔離フラグ 噂のclone(2)
clone(2)によるPIDの隔離 実行してみる $ gcc さっきの.c $ sudo ./a.out current -
clone pid: 15573 current - self pid: 15572 child - self pid: 15573 child - parent pid: 15572 $ sudo ./a.out -p current - clone pid: 15635 current - self pid: 15634 child - self pid: 1 child - parent pid: 0 CLONE_NEWPIDフラ グを 渡さなければ PIDは隔離されない フラグを渡して PIDの隔離に成功 PID 1 は本来(?)initだよ! $ pgrep -fa init 1 /sbin/init 重複が許されている
Namespaceの情報ってどこにあるの? /proc/[pid]/ns にある 先ほどのプログラムを少し変更して、上記のパスを見てみる static int child_fn() { printf("child -
self pid: %ld\n", (long) getpid()); printf("child - parent pid: %ld\n", (long) getppid()); // この sleep を追記 (せっかくなのでC99スタイル) // ここで止まっている間に /proc/[pid]/ns を ls する作戦 (プログラム中で ls 呼べばいいとか言わないこと) sleep(100); exit(0); }
Namespace見てみますよ / PID隔離なしver $ sudo ./a.out current - clone pid:
20026 current - self pid: 20025 child - self pid: 20026 child - parent pid: 20026 $ sudo ls -l /proc/20025/ns 合計 0 lrwxrwxrwx 1 root root 0 7月 19 02:58 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 7月 19 02:58 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 7月 19 02:58 mnt -> 'mnt:[4026531840]' lrwxrwxrwx 1 root root 0 7月 19 02:58 net -> 'net:[4026531957]' lrwxrwxrwx 1 root root 0 7月 19 02:58 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 7月 19 02:58 uts -> 'uts:[4026531838]' $ sudo ls -l /proc/20026/ns 合計 0 lrwxrwxrwx 1 root root 0 7月 19 02:59 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 7月 19 02:59 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 7月 19 02:59 mnt -> 'mnt:[4026531840]' lrwxrwxrwx 1 root root 0 7月 19 02:59 net -> 'net:[4026531957]' lrwxrwxrwx 1 root root 0 7月 19 02:59 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 7月 19 02:59 uts -> 'uts:[4026531838]' 両者は一致
Namespace見てみますよ / PID隔離ver $ sudo ./a.out -p current - clone
pid: 20332 current - self pid: 20331 child - self pid: 1 child - parent pid: 0 $ sudo ls -l /proc/20331/ns 合計 0 lrwxrwxrwx 1 root root 0 7月 19 02:59 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 7月 19 02:59 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 7月 19 02:59 mnt -> 'mnt:[4026531840]' lrwxrwxrwx 1 root root 0 7月 19 02:59 net -> 'net:[4026531957]' lrwxrwxrwx 1 root root 0 7月 19 02:59 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 7月 19 02:59 uts -> 'uts:[4026531838]' $ sudo ls -l /proc/20332/ns 合計 0 lrwxrwxrwx 1 root root 0 7月 19 02:59 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 7月 19 02:59 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 7月 19 02:59 mnt -> 'mnt:[4026531840]' lrwxrwxrwx 1 root root 0 7月 19 02:59 net -> 'net:[4026531957]' lrwxrwxrwx 1 root root 0 7月 19 02:59 pid -> 'pid:[4026532213]' lrwxrwxrwx 1 root root 0 7月 19 02:59 uts -> 'uts:[4026531838]' PIDの所に注目 違う値に なっている
他のNamespace • IPC: System V IPC, POSIX メッセージキュー • Network:
ネットワークデバイス、スタック、ポートなど • Mount: マウントポイント ◦ clone, unshareした内部でmountしたものの中身が外から見えなくなる • User: ユーザー ID とグループ ID • UTS: ホスト名と NIS ドメイン名 https://linuxjm.osdn.jp/html/LDP_man-pages/man7/namespaces.7.html http://gihyo.jp/admin/serial/01/linux_containers/0002?page=2
とりあえず次、chroot
ルートディレクトリを変更する chroot(1) はみんながArch Linuxをインストールするときに いつも使っているやつ 今日はシステムコールなので chroot(2) > chrootシステムコールは、1982年3月18日(4.2BSDリリースの17ヶ月前)、 >
ビル・ジョイがインストールおよびビルドシステムのテスト用に > 作成したのが期限である。 Wikipediaより
chroot(2) によるルートディレクトリ隔離 #include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <unistd.h>
#define PATHNAME_SIZE 512 void show_dir(char *dirname) { struct dirent **namelist; int r = scandir(dirname, &namelist, NULL, NULL); if (r == -1) { exit(1); } printf("--- list files in directory '%s' ---\n", dirname); for (int i = 0; i < r; i++) { printf("%s\n", namelist[i]->d_name); } } int main(int argc, char *argv[]) { show_dir("/"); char current_path[PATHNAME_SIZE]; getcwd(current_path, sizeof current_path); printf("\nchange root to '%s'\n\n", current_path); int r = chroot(current_path); if (r == -1) { printf("chroot failed"); exit(1); } else { show_dir("/"); exit(0); } } 噂のchroot(2)
chroot(2) によるルートディレクトリ隔離 $ sudo ./a.out --- list files in directory
'/' --- lib boot srv bin run tmp root sys lib64 etc (以下略) (実行結果の続き) change root to '/var/tmp/my_chroot' --- list files in directory '/' --- my_chroot.c a.out . .. / の変更に成功
と、ここで気付く Cでシステムコールするより、やっぱユーザコマンドを叩いた方が楽だよね $ unshare -imnpuU $ chroot … $ cgcreate
… $ ip link … いや、分かっていたけど気づかないフリをしていたんだ
すごいぞユーザコマンド! コンテナを作るのが楽になる!!
まとめというか感想 • こんな感じで地道にやっていけばいつか自前コンテナは立ち上がる ◦ ユーザコマンドまじ有能 ◦ Dockerは甘え • 温故知新 •
WebプログラマはWeb f/w使いになりがちなので、たまにはこういうのを書くのは充 足感がある • ちなみに今回のコードはここに置いた ◦ https://github.com/xorphitus/making-linux-container