dockerの基礎（仕組みなど）


## 1 docker基本操作

### 1.1 dockerコンテナを立ち上げる
~~~
# docker run -d --name httpd-test httpd:latest
~~~

### 1.2 起動状態確認
~~~
# docker ps -a 
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS               NAMES
5a3835e4ff7b        httpd:latest        "httpd-foreground"   5 minutes ago       Up 5 minutes        80/tcp              httpd-test
~~~

### 1.3 dockerコンテナの詳細情報
~~~
# docker inspect <コンテナID>
~~~

### 1.4 起動中のコンテナに入る
~~~
# docker exec -it <コンテナID> /bin/bash
~~~

### (補足)dockerのプロセス
dockerでコンテナを起動すると、コンテナ内で起動するプロセスはdockerdの子プロセスとして起動する  

コンテナ内で起動しているプロセスの確認

ここではhttpdとnginxのコンテナを起動している

~~~
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2007cce4b2b9        httpd:latest        "httpd-foreground"       14 minutes ago      Up 14 minutes       80/tcp              httpd-test
9263f766a4ae        nginx:latest        "nginx -g 'daemon of…"   20 minutes ago      Up 20 minutes       80/tcp              nginx-test
~~~

~~~
# docker top <コンテナID>
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                3980                3970                0                   17:14               ?                   00:00:00            httpd -DFOREGROUND
bin                 4013                3980                0                   17:14               ?                   00:00:00            httpd -DFOREGROUND
bin                 4014                3980                0                   17:14               ?                   00:00:00            httpd -DFOREGROUND
bin                 4015                3980                0                   17:14               ?                   00:00:00            httpd -DFOREGROUND
~~~

ホスト上で起動しているプロセスの確認

~~~
# ps -alfx
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
(略)
4    99   864     1  20   0  15608  1292 poll_s Ss   ?          0:00 /usr/sbin/dnsmasq -k
4     0   865     1  20   0 607156 41412 wait   Ssl  ?          1:33 /usr/bin/dockerd
4     0  2013   865  20   0 300652 25656 futex_ Ssl  ?          1:01  \_ docker-containerd --config /var/run/docker/containerd/containerd.toml
4     0  3862  2013  20   0   8920  3804 futex_ Sl   ?          0:00      \_ docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/9263f766a4aede8cefa3fff1fffb29d
4     0  3874  3862  20   0  32608  3244 sigsus Ss   ?          0:00      |   \_ nginx: master process nginx -g daemon off;
5   101  3901  3874  20   0  33060  1588 ep_pol S    ?          0:00      |       \_ nginx: worker process
4     0  3970  2013  20   0   7512  4332 futex_ Sl   ?          0:00      \_ docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/2007cce4b2b93c63bfc072a04184752
4     0  3980  3970  20   0  79288  2952 poll_s Ss   ?          0:00          \_ httpd -DFOREGROUND
5     1  4013  3980  20   0 368468  4140 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     1  4014  3980  20   0 368468  4140 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     1  4015  3980  20   0 368468  4140 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     0  1325     1  20   0  82960  1388 poll_s Ss   ?          0:00 /usr/sbin/sshd
4     0  2348  1325  20   0 146188  5904 poll_s Ss   ?          0:01  \_ sshd: root@pts/0
4     0  2350  2348  20   0 115528  2176 n_tty_ Ss+  pts/0      0:00  |   \_ -bash
4     0  3181  1325  20   0 146156  5812 flush_ Ss   ?          0:00  \_ sshd: root@pts/2
4     0  3183  3181  20   0 115528  2168 wait   Ss   pts/2      0:00  |   \_ -bash
0     0  4105  3183  20   0 149080  1728 -      R+   pts/2      0:00  |       \_ ps -alfx
4     0  3740  1325  20   0 146020  5816 poll_s Ss   ?          0:00  \_ sshd: root@pts/1
4     0  3742  3740  20   0 115528  2128 n_tty_ Ss+  pts/1      0:00      \_ -bash
(略)
~~~

## 2 dockerのネットワーク

dockerはコンテナを動作させるための内部NWを構成し、docker NW内でコンテナを起動する  


![NW1.png](https://qiita-image-store.s3.amazonaws.com/0/246372/f40f7fb7-18a5-51ec-c9ec-8f92e63b246b.png)


### 2.1 dockerホストからdockerコンテナへの通信

以下により起動したコンテナにアクセスできる

~~~
# curl http://172.17.0.2:80
~~~

dockerホストはdocker0をNICとして認識している  

~~~
# ip a

~略~
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:27:72:c4 brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.210/24 brd 192.168.2.255 scope global enp0s3
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe27:72c4/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:07:b0:63:fe brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:7ff:feb0:63fe/64 scope link
       valid_lft forever preferred_lft forever

~略~
~~~

また、dockerインストール時にdockerホストにdocker NW向けスタティックルートが追加される

~~~
# ip route
default via 192.168.2.1 dev enp0s3  proto static  metric 100
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
172.18.0.0/16 dev br-9fad9e88c990  proto kernel  scope link  src 172.18.0.1
172.19.0.0/16 dev br-b0717a45afd9  proto kernel  scope link  src 172.19.0.1
192.168.2.0/24 dev enp0s3  proto kernel  scope link  src 192.168.2.210  metric 100
~~~

これによりdocker NW内のコンテナに対し、dockerホストからのアクセスが可能になる

![NW2.png](https://qiita-image-store.s3.amazonaws.com/0/246372/94de7576-d395-a315-859e-9f0055532e6c.png)


### 2.2 dockerコンテナからdockerホスト外部(およびdockerホストNIC)への通信


dockerコンテナ内のスタティックルートは以下のようにデフォルトGWがdocker0になっている

~~~
root@c47e20352770:/usr/local/apache2# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2
~~~

さらにdockerホストのスタティックルートは以下のようになっている  
外部向け通信（デフォルトGW）および192.168.2.0/24通信のNEXT HOPはenp0s3（192.168.2.210）

~~~
# ip route
default via 192.168.2.1 dev enp0s3  proto static  metric 100
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1
172.18.0.0/16 dev br-9fad9e88c990  proto kernel  scope link  src 172.18.0.1
172.19.0.0/16 dev br-b0717a45afd9  proto kernel  scope link  src 172.19.0.1
192.168.2.0/24 dev enp0s3  proto kernel  scope link  src 192.168.2.210  metric 100
~~~

また、dockerホストのiptablesには以下のNATルールが設定されており、
docker NW（172.17.0.0/16）からの通信はMASQUERADE（SNAT）するように設定されている  
※172.17.0.0/16からどこか（0.0.0.0/0）へ行くときは
  sourceをサーバから出るときのIPである192.168.2.210に変換する（MASQUERADE）

~~~
# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0  ★172.17.0.0/16から外部に行くものはMASQUERADE（SNAT）する
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0
MASQUERADE  all  --  172.19.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
~~~

以上のことからコンテナと外部の通信が可能になる

![NW3.png](https://qiita-image-store.s3.amazonaws.com/0/246372/edb3be93-0346-1bb4-3c83-e983c3ae123d.png)


例えばコンテナ内からLAN内のGWであるインターネットルータ（192.168.2.1）への通信経路を確認すると

~~~
root@c47e20352770:/usr/local/apache2# traceroute 192.168.2.1
traceroute to 192.168.2.1 (192.168.2.1), 30 hops max, 60 byte packets
 1  172.17.0.1 (172.17.0.1)  0.035 ms  0.009 ms  0.083 ms
 2  192.168.2.1 (192.168.2.1)  13.655 ms  14.107 ms  14.034 ms
~~~

となりdocker0へ行った後、ホストのスタティックルートでルーティングしているのがわかる


### 2.3 dockerホスト外部からdockerコンテナへの通信

外部からdockerコンテナにアクセスする場合はdockerホストのポートとdockerコンテナのポートを紐づけて、
dockerホスト宛に来た通信をdockerコンテナにフォワードする

以下によりホストのポートとコンテナのポートを紐づけてコンテナを起動する

~~~
# docker run -d -p 80:80 --name httpd-test httpd:latest

# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
5d7a40aa6425        httpd:latest        "httpd-foreground"   3 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp   httpd-test
~~~

ホストのポートとコンテナのポートを紐づけてコンテナを起動すると、
iptablesに以下のようにNATルールが追加される

~~~
# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0
MASQUERADE  all  --  172.19.0.0/16        0.0.0.0/0
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80   ★DNATにより80番ポート宛通信を172.17.0.2:80にフォワード
~~~

以上により外部からコンテナにアクセスできる

![NW4.png](https://qiita-image-store.s3.amazonaws.com/0/246372/24826928-e70c-3c42-864e-6108084605d1.png)

### iptableコマンドの補足
---

-vオプションをつけるとルールを詳細表示する

~~~
# iptables -t nat -L -nv
Chain PREROUTING (policy ACCEPT 39 packets, 6005 bytes)
 pkts bytes target     prot opt in     out     source               destination
   46  3018 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 39 packets, 6005 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 4 packets, 304 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2   140 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 4 packets, 304 bytes)
 pkts bytes target     prot opt in     out     source               destination
   64  3879 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
    0     0 MASQUERADE  all  --  *      !br-9fad9e88c990  172.18.0.0/16        0.0.0.0/0
    0     0 MASQUERADE  all  --  *      !br-b0717a45afd9  172.19.0.0/16        0.0.0.0/0
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
   44  2914 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
    0     0 RETURN     all  --  br-9fad9e88c990 *       0.0.0.0/0            0.0.0.0/0
    0     0 RETURN     all  --  br-b0717a45afd9 *       0.0.0.0/0            0.0.0.0/0
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80
~~~

in,outはどこのNWからどこのNW宛の通信の場合に該当ルールを適用するかを示す(!は否定を示す)  
例えば最終行は、docker0 NW以外からすべてのNW宛通信かつ、sourceIP,destIPがどのような値の場合に対してもDNATを適用する


### 2.4 dockerネットワークの確認

dockerでは自動的に3つのネットワークが作成される  
何も指定しなければ起動したコンテナはbridgeに属する

~~~
# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
aa19eb8af62f        bridge              bridge              local
da8be1f1d8eb        host                host                local
c24fdaafe0d8        none                null                local
~~~

### 参考

https://christina04.hatenablog.com/entry/2016/07/22/193000  
https://qiita.com/Arturias/items/b538e6bbf05dd3364397  
https://blog.tiqwab.com/2018/02/12/learniing-iptables.html
http://docs.docker.jp/engine/userguide/networking/dockernetworks.html  
https://christina04.hatenablog.com/entry/2016/07/22/193000


## 3 コンテナの仕組み

### 3.1 コンテナが実現すること
実行単位(httpd,nginx,redmine etc...)ごとの

- 環境の隔離(namespace)
- リソースの制限(cgroup)  

※()内は実現するLinuxの機能  

※参考  
https://www.slideshare.net/Hiroaki_UKAJI/warden-45589749

## 4 namespace

実行環境を隔離してnamespaceとして管理  
具体的には以下の6つをnamespaceとして隔離する

- IPC名前空間
- マウント名前空間
- ネットワーク名前空間
- PID名前空間
- ユーザー名前空間
- UTS名前空間

### 4.1 名前空間の一覧確認

~~~
# ls -l /proc/$$/ns/

lrwxrwxrwx 1 root root 0  5月 29 00:12 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0  5月 29 00:12 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0  5月 29 00:12 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0  5月 29 00:12 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  5月 29 00:12 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0  5月 29 00:12 uts -> uts:[4026531838]
~~~

dockerコンテナの中で表示すると

~~~
# docker exec -it 84f456cf9da1 /bin/bash
# ls -l /proc/$$/ns/
lrwxrwxrwx 1 root root 0 May 28 15:45 ipc -> ipc:[4026532179]
lrwxrwxrwx 1 root root 0 May 28 15:45 mnt -> mnt:[4026532177]
lrwxrwxrwx 1 root root 0 May 28 15:45 net -> net:[4026532182]
lrwxrwxrwx 1 root root 0 May 28 15:45 pid -> pid:[4026532180]
lrwxrwxrwx 1 root root 0 May 28 15:45 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 May 28 15:45 uts -> uts:[4026532178]
~~~

といった具合にnamespaceが異なっているのがわかる

![namespace.png](https://qiita-image-store.s3.amazonaws.com/0/246372/6d08d8c9-3d59-fba2-f2e8-ec426a182a15.png)

※参考  
http://www.usupi.org/sysad/260.html  
https://qiita.com/wellflat/items/7d62f2a63e9fcddb31cc  
https://linuxjm.osdn.jp/html/LDP_man-pages/man7/namespaces.7.html  

## 5 cgroup
プロセスのグループを作り、状態やリソースの利用上限などを一括して管理

### cgroupで管理する項目一覧の表示
cgroupではcpu、メモリ、プロセスの状態などを管理する。  
/sys/fs/cgroup配下に管理項目(cpu、メモリ、プロセスの状態など)ごとのディレクトリがある。

~~~
# ll /sys/fs/cgroup
合計 0
drwxr-xr-x 5 root root  0  6月 28 01:23 blkio
lrwxrwxrwx 1 root root 11  6月 28 01:23 cpu -> cpu,cpuacct   *CPU管理*
drwxr-xr-x 5 root root  0  6月 28 01:23 cpu,cpuacct
lrwxrwxrwx 1 root root 11  6月 28 01:23 cpuacct -> cpu,cpuacct
drwxr-xr-x 3 root root  0  6月 28 01:23 cpuset
drwxr-xr-x 5 root root  0  6月 28 01:23 devices
drwxr-xr-x 3 root root  0  6月 28 01:23 freezer   *プロセスの状態管理*
drwxr-xr-x 3 root root  0  6月 28 01:23 hugetlb
drwxr-xr-x 5 root root  0  6月 28 01:23 memory   *メモリ管理*
lrwxrwxrwx 1 root root 16  6月 28 01:23 net_cls -> net_cls,net_prio
drwxr-xr-x 3 root root  0  6月 28 01:23 net_cls,net_prio
lrwxrwxrwx 1 root root 16  6月 28 01:23 net_prio -> net_cls,net_prio
drwxr-xr-x 3 root root  0  6月 28 01:23 perf_event
drwxr-xr-x 3 root root  0  6月 28 01:23 pids
drwxr-xr-x 5 root root  0  6月 28 01:23 systemd
~~~

### 管理項目ディレクトリ配下の構成
各管理項目のディレクトリ配下ではデフォルトのcgroupが定義されている。  
個別でcgroupを定義してリソース制限等を行う場合は配下にサブディレクトリを作成する。  
管理項目のディレクトリ配下はこんな感じ

~~~
管理する項目のディレクトリ
(デフォルトcgroup)
 |-tasks   *ここに記載されたPIDがデフォルトのcgroupに属する*
 |-デフォルトcgroupに関する設定ファイル
 |-管理項目のデフォルトcgroupに関する設定ファイル   *デフォルトのcgroupに属するプロセスはここに記載された定義に従う*
(個別で管理するcgroup)
 |-個別cgroupのディレクトリ
    |-tasks   *ここに記載されたPIDがこのcgroupに属する*
    |-個別cgroupに関する設定ファイル
    |-管理項目の個別cgroupに関する設定ファイル   *このcgroupのプロセスはここに記載された定義に従う*

~~~

例えばメモリの場合

~~~
# pwd
/sys/fs/cgroup/memory

# tree -L 1
.
(デフォルトcgroupに関する設定ファイル)
|- tasks
|- cgroup.clone_children
|- cgroup.event_control
|- cgroup.procs
|- cgroup.sane_behavior
(デフォルトcgroupに関するメモリ管理)
|- memory.failcnt
|- memory.force_empty
|- memory.kmem.failcnt
|- memory.kmem.limit_in_bytes
|- memory.kmem.max_usage_in_bytes
|- memory.kmem.slabinfo
|- memory.kmem.tcp.failcnt
|- memory.kmem.tcp.limit_in_bytes
|- memory.kmem.tcp.max_usage_in_bytes
|- memory.kmem.tcp.usage_in_bytes
|- memory.kmem.usage_in_bytes
|- memory.limit_in_bytes
|- memory.max_usage_in_bytes
|- memory.memsw.failcnt
|- memory.memsw.limit_in_bytes
|- memory.memsw.max_usage_in_bytes
|- memory.memsw.usage_in_bytes
|- memory.move_charge_at_immigrate
|- memory.numa_stat
|- memory.oom_control
|- memory.pressure_level
|- memory.soft_limit_in_bytes
|- memory.stat
|- memory.swappiness
|- memory.usage_in_bytes
|- memory.use_hierarchy
|- notify_on_release
|- release_agent
(個別cgroupごとのサブディレクトリ)
|- system.slice
   |- (略)
|- user.slice
   |- (略)
|- docker  *dockerのcgroupが定義され、さらに配下にコンテナごとのcgroupが定義される*
   (dockerのcgroupに関する設定ファイル)
   |-tasks
   |-cgroup.clone_children
   |-cgroup.event_control
   |-cgroup.procs
   (dockerのcgroupに関するメモリ管理)
   |-memory.failcnt
   |-memory.force_empty
   |-memory.kmem.failcnt
   |-memory.kmem.limit_in_bytes
   |-memory.kmem.max_usage_in_bytes
   |-memory.kmem.slabinfo
   |-memory.kmem.tcp.failcnt
   |-memory.kmem.tcp.limit_in_bytes
   |-memory.kmem.tcp.max_usage_in_bytes
   |-memory.kmem.tcp.usage_in_bytes
   |-memory.kmem.usage_in_bytes
   |-memory.limit_in_bytes
   |-memory.max_usage_in_bytes
   |-memory.memsw.failcnt
   |-memory.memsw.limit_in_bytes
   |-memory.memsw.max_usage_in_bytes
   |-memory.memsw.usage_in_bytes
   |-memory.move_charge_at_immigrate
   |-memory.numa_stat
   |-memory.oom_control
   |-memory.pressure_level
   |-memory.soft_limit_in_bytes
   |-memory.stat
   |-memory.swappiness
   |-memory.usage_in_bytes
   |-memory.use_hierarchy
   |-notify_on_release
   |-315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2   *コンテナのcgroup*
     |-(コンテナのcgroupに関する設定ファイル)
     |-(コンテナのcgroupに関するメモリ管理)

※分かりやすいように順番入れ替え

~~~

### (具体例)dockerでコンテナをデプロイし、メモリ上限を設定した場合  
コンテナをデプロイするとき、以下のようにオプションを指定するとそのコンテナが利用できるメモリの上限値を設定できる。  

ここではhttpdのコンテナをメモリ上限1GBとしてデプロイ

~~~
# docker run -d --memory 1g  --name httpd-test httpd:latest
~~~

確認

~~~
# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS               NAMES
315bed8bc0cc        httpd:latest        "httpd-foreground"   6 hours ago         Up 6 hours          80/tcp              httpd-test

# docker inspect 315bed8bc0cc
[
    {
        "Id": "315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2",
        "Created": "2018-06-28T01:45:20.616375695Z",
        "Path": "httpd-foreground",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3407,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2018-06-28T01:45:20.840125572Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:fb2f3851a97186bb0eaf551a40b94782712580c2feac0d15ba925bef2da5fc18",
        "ResolvConfPath": "/var/lib/docker/containers/315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2/hostname",
        "HostsPath": "/var/lib/docker/containers/315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2/hosts",
        "LogPath": "/var/lib/docker/containers/315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2/315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2-json.log",
        "Name": "/httpd-test",
        "RestartCount": 0,
        "Driver": "overlay",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "shareable",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 1073741824,  ★メモリの上限値が1,073,741,824byteに設定されている★
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 2147483648,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay/39c9171569ef42fe40bdaa93c713511889874a574fe1a5cdb5bbf04c6d20be7a/root",
                "MergedDir": "/var/lib/docker/overlay/519e2361e4189ef721879d87a942999f34e8dd99080d51ba742ca1897852d71b/merged",
                "UpperDir": "/var/lib/docker/overlay/519e2361e4189ef721879d87a942999f34e8dd99080d51ba742ca1897852d71b/upper",
                "WorkDir": "/var/lib/docker/overlay/519e2361e4189ef721879d87a942999f34e8dd99080d51ba742ca1897852d71b/work"
            },
            "Name": "overlay"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "315bed8bc0cc",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "HTTPD_PREFIX=/usr/local/apache2",
                "NGHTTP2_VERSION=1.18.1-1",
                "OPENSSL_VERSION=1.0.2l-1~bpo8+1",
                "HTTPD_VERSION=2.4.33",
                "HTTPD_SHA256=de02511859b00d17845b9abdd1f975d5ccb5d0b280c567da5bf2ad4b70846f05",
                "HTTPD_PATCHES=",
                "APACHE_DIST_URLS=https://www.apache.org/dyn/closer.cgi?action=download&filename= \thttps://www-us.apache.org/dist/ \thttps://www.apache.org/dist/ \thttps://archive.apache.org/dist/"
            ],
            "Cmd": [
                "httpd-foreground"
            ],
            "ArgsEscaped": true,
            "Image": "httpd:latest",
            "Volumes": null,
            "WorkingDir": "/usr/local/apache2",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "eed75a39c6bfd055dd010d8b8e45ad247489d1d24bc9bf75477be6dcd5e0bf8d",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "80/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/eed75a39c6bf",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "1fdb54756a0e9870a3d2ab0e8c871ffe6a2c1881266bc69b5e1d87f28d0ad68d",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "cf93040834003474a1aba5fc9973e7794880faf2e42e962eb4a0d90f8b95a8b1",
                    "EndpointID": "1fdb54756a0e9870a3d2ab0e8c871ffe6a2c1881266bc69b5e1d87f28d0ad68d",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]
~~~

また、実際にコンテナとして起動してるプロセスを確認すると、  

コンテナ内で起動しているプロセスの確認

~~~
# docker top httpd-test
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                3407                3395                0                   10:45               ?                   00:00:01            httpd -DFOREGROUND
bin                 3438                3407                0                   10:45               ?                   00:00:00            httpd -DFOREGROUND
bin                 3439                3407                0                   10:45               ?                   00:00:00            httpd -DFOREGROUND
bin                 3440                3407                0                   10:45               ?                   00:00:00            httpd -DFOREGROUND
~~~

ホスト上で起動しているプロセスの確認

~~~
# ps aflx
(略)
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4    99   864     1  20   0  15608  1292 poll_s Ss   ?          0:00 /usr/sbin/dnsmasq -k
4     0   865     1  20   0 598380 36992 wait   Ssl  ?          1:25 /usr/bin/dockerd
4     0  2013   865  20   0 292456 24712 futex_ Ssl  ?          0:58  \_ docker-containerd --config /var/run/docker/containerd/containerd.toml
4     0  3395  2013  20   0   8920  4068 futex_ Sl   ?          0:00      \_ docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/315bed8bc0cc6fdf1ecb1a52b84705d
4     0  3407  3395  20   0  79288  2944 poll_s Ss   ?          0:01          \_ httpd -DFOREGROUND
5     1  3438  3407  20   0 368468  4132 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     1  3439  3407  20   0 368468  4132 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     1  3440  3407  20   0 368468  4132 pipe_w Sl   ?          0:00              \_ httpd -DFOREGROUND
5     0  1325     1  20   0  82960  1388 poll_s Ss   ?          0:00 /usr/sbin/sshd
4     0  2348  1325  20   0 146188  5904 poll_s Ss   ?          0:01  \_ sshd: root@pts/0

(略)
~~~

→httpdコンテナのプロセスとして、PID=3407,3438,3439,3440が起動している  

cgroupでは実際どのように管理されているか  


~~~
# cd /sys/fs/cgroup/memory
# ls
cgroup.clone_children  memory.failcnt                  memory.kmem.slabinfo                memory.kmem.usage_in_bytes   memory.memsw.max_usage_in_bytes  memory.pressure_level       memory.use_hierarchy  user.slice
cgroup.event_control   memory.force_empty              memory.kmem.tcp.failcnt             memory.limit_in_bytes        memory.memsw.usage_in_bytes      memory.soft_limit_in_bytes  notify_on_release
cgroup.procs           memory.kmem.failcnt             memory.kmem.tcp.limit_in_bytes      memory.max_usage_in_bytes    memory.move_charge_at_immigrate  memory.stat                 release_agent
cgroup.sane_behavior   memory.kmem.limit_in_bytes      memory.kmem.tcp.max_usage_in_bytes  memory.memsw.failcnt         memory.numa_stat                 memory.swappiness           system.slice
docker                 memory.kmem.max_usage_in_bytes  memory.kmem.tcp.usage_in_bytes      memory.memsw.limit_in_bytes  memory.oom_control               memory.usage_in_bytes       tasks

→dockerのcgroupが定義されている

# cd docker
# ls 
315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2  memory.kmem.failcnt             memory.kmem.tcp.max_usage_in_bytes  memory.memsw.limit_in_bytes      memory.pressure_level       notify_on_release
cgroup.clone_children                                             memory.kmem.limit_in_bytes      memory.kmem.tcp.usage_in_bytes      memory.memsw.max_usage_in_bytes  memory.soft_limit_in_bytes  tasks
cgroup.event_control                                              memory.kmem.max_usage_in_bytes  memory.kmem.usage_in_bytes          memory.memsw.usage_in_bytes      memory.stat
cgroup.procs                                                      memory.kmem.slabinfo            memory.limit_in_bytes               memory.move_charge_at_immigrate  memory.swappiness
memory.failcnt                                                    memory.kmem.tcp.failcnt         memory.max_usage_in_bytes           memory.numa_stat                 memory.usage_in_bytes
memory.force_empty                                                memory.kmem.tcp.limit_in_bytes  memory.memsw.failcnt                memory.oom_control               memory.use_hierarchy

→dockerのcgroup内で、さらにコンテナごとのcgroupが定義されている

# cd 315bed8bc0cc6fdf1ecb1a52b84705dfd409cc053457f30567a7c2b955de14e2/
# ls
cgroup.clone_children  memory.kmem.failcnt             memory.kmem.tcp.limit_in_bytes      memory.max_usage_in_bytes        memory.move_charge_at_immigrate  memory.stat            tasks
cgroup.event_control   memory.kmem.limit_in_bytes      memory.kmem.tcp.max_usage_in_bytes  memory.memsw.failcnt             memory.numa_stat                 memory.swappiness
cgroup.procs           memory.kmem.max_usage_in_bytes  memory.kmem.tcp.usage_in_bytes      memory.memsw.limit_in_bytes      memory.oom_control               memory.usage_in_bytes
memory.failcnt         memory.kmem.slabinfo            memory.kmem.usage_in_bytes          memory.memsw.max_usage_in_bytes  memory.pressure_level            memory.use_hierarchy
memory.force_empty     memory.kmem.tcp.failcnt         memory.limit_in_bytes               memory.memsw.usage_in_bytes      memory.soft_limit_in_bytes       notify_on_release

# cat tasks
3407
3438
3439
3440

# cat memory.limit_in_bytes
1073741824

→httpdコンテナとして起動しているプロセスに対して1GBのメモリ制限が行われている

~~~


---
### 宣伝
弱小Twitterやってます。良かったら少し付き合ってください。
https://twitter.com/mochizuki875