Docker@コンテナ型仮想化¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. Dockerの仕組み¶
アーキテクチャ¶
Dockerは、ホストOS、Dockerコンテナ (ベースイメージ、コンテナイメージレイヤー、コンテナレイヤー) といったコンポーネントから構成される。
Dockerコンテナ¶
▼ Dockerコンテナとは¶
namespaceとcgroupsを使用して、ホストOSを分割した領域である。
namespaceでは、カーネルを分離できるため、カーネルの要素 (プロセス、マウントポイント、ネットワーク、ファイル構造、ユーザー、グループなど) を独立させられる。
▼ ベースイメージ¶
ベースイメージは、実行OSによらずに一貫してビルドできるため、配布できる。
各イメージレジストリ (例:DockerHub、AWS ECR、Google Container Registry、Artifactory、Harborなど) には、カスタマイズする上でのベースとなるベースイメージが提供されている。
▼ イメージレイヤー¶
イメージレイヤーの実体は、/var/lib/docker/overlay2
ディレクトリ配下にハッシュ値の名前からなるファイルとして保管されている。
Dockerは、オーバーレイファイルシステムを使用して、各ファイルを層状に管理する。
1つの命令につき、1つのコンテナイメージレイヤーを積み重ねるようになっている。
$ docker container inspect foo-container -f "{{json .GraphDriver.Data}}" | jq .
{
"LowerDir": "/var/lib/docker/overlay2/*****-init/diff:/var/lib/docker/overlay2/*****/diff:/var/lib/docker/overlay2/*****/diff:/var/lib/docker/overlay2/*****/diff:/var/lib/docker/overlay2/*****/diff",
"MergedDir": "/var/lib/docker/overlay2/*****/merged",
"UpperDir": "/var/lib/docker/overlay2/*****/diff",
"WorkDir": "/var/lib/docker/overlay2/*****/work"
}
▼ コンテナレイヤー¶
コンテナイメージからコンテナを作成する時に、コンテナイメージレイヤーの上にコンテナレイヤーが積み重ねられる。
権限別コンテナの種類¶
▼ 特権コンテナ¶
rootユーザー権限のCapability (CHOWN、NET_RAW、CAP_SYS_BOOT、CAP_AUDIT_WRITEなど) の全て持つユーザーで実行したコンテナのこと。
例えば、特権コンテナの実行ユーザーはルートファイルシステムにある/proc
に書き込みする権限を持つ。
/proc配下にはNodeへのアクセスを仲介するファイルがあるため、特権コンテナの実行ユーザーはNode上で任意のコマンドを実行できる。
▼ 通常コンテナ¶
rootユーザーで実行したコンテナのこと。
▼ 非rootコンテナ¶
コンテナランタイムとコンテナ自体の両方を非rootユーザーで実行したコンテナのこと。
これらのユーザーは、Capabilityを全く持たない。
02. Dockerクライアント¶
dockerクライアント¶
▼ dockerクライアントとは¶
dockerクライアントは、docker
コマンドを使用してdockerデーモンAPIをコールできる。
dockerデーモン¶
▼ dockerデーモンとは¶
ホスト側に常駐し、コンテナの操作を担うデーモン。
dockerクライアントにdockerデーモンAPIを公開する。
クライアントがdocker
コマンドを実行することにより、dockerデーモンAPIがコールされ、コマンドに沿ってコンテナが操作される。
03. cgroups¶
コンテナが使用できるハードウェアリソースを分離する。
04. namespace¶
namespaceとは¶
各namespaceを使用して、ホストのカーネルを論理的に分離する。
論理的に分離された各領域をコンテナとして使用する。
コンテナ間では、ハードウェアリソース要求やプロセス間通信が独立している。
注意点として、Kubernetesとはnamespaceの種類が異なる。
IPC namespace¶
SysV IPCオブジェクト、POSIXメッセージキュー、を分離する。
コンテナは、同じIPC namespaceに属する他のプロセスと通信できる。
Network namespace¶
ネットワークデバイス、アドレス、ポート、ルーティングテーブル、フィルタ、を分離する。
各コンテナが独立した、ネットワークデバイス、アドレス、ポート、ルーティングテーブル、フィルタ、を持てるようになる。
Mount namespace¶
マウントに関する処理を分離する。
各コンテナが独立してマウントを処理できるようになる。
PID namespace¶
プロセスIDを分離する。
各コンテナが独立したPIDを持てるようになる。
逆に言うと、同じPID namespaceに属するプロセスはPIDは同じになる。
User namespace¶
ユーザーID (UID)、グループID (GID)、を分離する。
各コンテナが独立したUIDやGIDを持てるようになる。
ただし、Dockerでは機能が制限されることを嫌って、User Namespaceをデフォルトで無効化している。
そのため、コンテナとホストのUID/GIDが同じになっている。
これに伴い、コンテナをrootユーザーで実行することに脆弱性がある。
UTS namespace¶
ドメインを分離する。
各コンテナが独立したドメインを持てるようになる。
03. ロギング¶
ロギングドライバー¶
▼ ロギングドライバーとは¶
コンテナ内の標準出力 (/dev/stdout
) と標準エラー出力 (/dev/stderr
) に出力されたログを、ファイルやAPIに対して転送する。
$ docker run -d -it --log-driver <ロギングドライバー名> --name <コンテナ名> <コンテナイメージ名>:<バージョンタグ> /bin/bash
▼ json-file¶
標準出力/標準エラー出力に出力されたログを、/var/lib/docker/containers/<コンテナID>/<コンテナID>-json.log
ファイルに転送する。
デフォルトの設定値である。
labels
キーで文字列リストを設定すると、属性キーを付与できる。
{
"log-driver": "json-file",
# ドライバーのオプション
"log-opts": {
"max-size": "10m",
"max-file": "3",
# JSONに付与する属性キー
"labels": "app,env",
},
}
▼ fluentd¶
構造化ログに変換し、サイドカーとして稼働するFluentdコンテナに送信する。
AWS ECSコンテナのawsfirelensドライバーは、fluentdドライバーをラッピングしたものである。
{
"log-driver": "fluentd",
# ドライバーのオプション
"log-opts": {
"fluentd-address": "<Fluentdコンテナのホスト名>:24224"
}
}
▼ none¶
標準出力/標準エラー出力に出力されたログを、ファイルやAPIに転送しない。
ファイルに出力しないことにより、開発環境のアプリケーションサイズの肥大化を防ぐ。
▼ awslogs¶
標準出力/標準エラー出力に出力されたログをAWS CloudWatch-APIに送信する。
{
"log-driver": "awslogs",
# ドライバーのオプション
"log-opts": {"awslogs-region": "us-east-1"},
}
▼ gcplogs¶
標準出力/標準エラー出力に出力されたログを、Google Cloud LoggingのAPIに転送する。
{
"log-driver": "gcplogs",
# ドライバーのオプション
"log-opts": {"gcp-meta-name": "example-instance-12345"},
}
各ベンダーのコンテナイメージのログ出力先¶
▼ コンテナの標準出力/標準エラー出力¶
Linuxでは、標準出力は『/proc/<プロセスID>/fd/1
』、標準エラー出力は『/proc/<プロセスID>/fd/2
』である。
コンテナでは、『/dev/stdout
』が『/proc/self/fd/1
』のシンボリックリンク、また『/dev/stderr
』が『/proc/<プロセスID>/fd/2
』のシンボリックリンクとして設定されている。
[root@<コンテナID>:/dev] $ ls -la
total 4
drwxr-xr-x 5 root root 340 Oct 14 11:36 .
drwxr-xr-x 1 root root 4096 Oct 14 11:28 ..
lrwxrwxrwx 1 root root 11 Oct 14 11:36 core -> /proc/kcore
lrwxrwxrwx 1 root root 13 Oct 14 11:36 fd -> /proc/self/fd
crw-rw-rw- 1 root root 1, 7 Oct 14 11:36 full
drwxrwxrwt 2 root root 40 Oct 14 11:36 mqueue
crw-rw-rw- 1 root root 1, 3 Oct 14 11:36 null
lrwxrwxrwx 1 root root 8 Oct 14 11:36 ptmx -> pts/ptmx
drwxr-xr-x 2 root root 0 Oct 14 11:36 pts
crw-rw-rw- 1 root root 1, 8 Oct 14 11:36 random
drwxrwxrwt 2 root root 40 Oct 14 11:36 shm
lrwxrwxrwx 1 root root 15 Oct 14 11:36 stderr -> /proc/self/fd/2 # 標準エラー出力
lrwxrwxrwx 1 root root 15 Oct 14 11:36 stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Oct 14 11:36 stdout -> /proc/self/fd/1 # 標準出力
crw-rw-rw- 1 root root 5, 0 Oct 14 11:36 tty
crw-rw-rw- 1 root root 1, 9 Oct 14 11:36 urandom
crw-rw-rw- 1 root root 1, 5 Oct 14 11:36 zero
▼ nginxイメージ¶
公式のnginxイメージは、/dev/stdout
というシンボリックリンクを、/var/log/nginx/access.log
ファイルに作成している。
また、/dev/stderr
というシンボリックリンクを、/var/log/nginx/error.log
ファイルに作成している。
これにより、これらのファイルに対するログの出力は、/dev/stdout
と/dev/stderr
に転送される。
▼ php-fpmイメージ¶
記入中...