docker解決了雲計算環境難於分發而且管理複雜,而用KVM、Xen等虛擬化又浪費系統資源的問題。Docker最初是基於lxc構建了容器引擎,爲了提供跨平臺支持,後又專門開發了libcontainer來抽象容器引擎。但不管是libcontainer仍是lxc,其底層所依賴的內核特性都是相同的。咱們來看看docker都使用了技術來實現容器引擎的。html
Docker使用了pid、network、ipc、美mnt、uts等命名空間來隔離網絡、文件系統、進程等資源。注意,因爲Linux並非namespace了全部東西(如cgroups、/sys、SELinux、/dev/sd*、內核模塊等),僅靠這幾個namespace是沒法實現像KVM那樣的徹底資源隔離的。linux
對於容器所依賴的內核文件系統(這些都是non-namespaced),爲了保證安全性,docker將其限制爲只讀的:git
. /sys . /proc/sys . /proc/sysrq-trigger . /proc/irq . /proc/bus
cgroups 實現了對資源的配額和度量。 cgroups 的使用很是簡單,提供相似文件的接口,在 /cgroup目錄下新建一個文件夾便可新建一個group,在此文件夾中新建task文件,並將pid寫入該文件,便可實現對該進程的資源控制。groups能夠限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系統的資源,如下是每一個子系統的詳細說明:github
對於centos7來講,經過systemd-cgls來查看系統cgroups tree:docker
... ├─docker-b1f965f8e682e9d2ff9ed3039fca63c008810efd9c5e6d796344b0270d329a98.scope │ ├─18853 /usr/lib/systemd/systemd │ └─system.slice │ ├─keepalived.service │ │ ├─19307 /usr/sbin/keepalived -D -d -S 7 │ │ └─19309 /usr/sbin/keepalived -D -d -S 7 │ ├─haproxy.service │ │ ├─25195 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid │ │ ├─25210 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds │ │ └─25211 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds │ ├─rsyslog.service │ │ └─23648 /usr/sbin/rsyslogd -n │ └─systemd-journald.service │ └─18990 /usr/lib/systemd/systemd-journald ...
特權模式下的容器:centos
└─system.slice ├─NetworkManager-dispatcher.service │ └─2580 /usr/libexec/nm-dispatcher.action ├─var-lib-docker-devicemapper-mnt-a80a5f851d00842414d5fb03866c19424df1f2afb47a04f41dd056b54c4df7ac.mount ├─docker-a80a5f851d00842414d5fb03866c19424df1f2afb47a04f41dd056b54c4df7ac.scope │ ├─2558 /usr/sbin/init │ └─system.slice │ ├─systemd-journald.service │ │ └─2605 /usr/lib/systemd/systemd-journald │ ├─dbus.socket │ ├─dbus.service │ ├─system-getty.slice │ ├─rc-local.service │ ├─systemd-user-sessions.service │ ├─dev-dm\x2d0.swap │ ├─etc-yum.repos.d.mount │ ├─etc-hosts.mount │ ├─etc-hostname.mount │ ├─etc-resolv.conf.mount │ └─-.mount
cgroups配置方法:安全
(1) cpu相對權重:docker run -it --rm -c 512
,若是未設置,默認爲1024網絡
# cat /sys/fs/cgroup/cpu/system.slice/docker-a80a5f851d00842414d5fb03866c19424df1f2afb47a04f41dd056b54c4df7ac.scope/cpu.shares 1024
若是在容器開啓的時候沒有設置cpu權重,能夠在容器啓動後修改,如session
[root@fei ~]# systemctl set-property --runtime docker-a80a5f851d00842414d5fb03866c19424df1f2afb47a04f41dd056b54c4df7ac.scope CPUShares=128 [root@fei ~]# cat /sys/fs/cgroup/cpu/system.slice/docker-a80a5f851d00842414d5fb03866c19424df1f2afb47a04f41dd056b54c4df7ac.scope/cpu.shares 128
(2) 設置cpu pin:docker run -it --rm --cpuset=0,1
app
# cat /sys/fs/cgroup/cpuset/system.slice/docker-b0848aa49a03b8541bb698c1544b6c411c584dce5e86831f84803228e93e61d4.scope/cpuset.cpus 0-1
(3) 內存限制: docker run -it --rm -m 128m
,默認swap爲mem的兩倍
[root@fei ~]# cat /sys/fs/cgroup/memory/system.slice/docker-c9fed54afc8986be888b231b984be9c1a2a533c739f7a5458a56882fb13b4b93.scope/memory.limit_in_bytes 134217728 [root@fei ~]# cat /sys/fs/cgroup/memory/system.slice/docker-c9fed54afc8986be888b231b984be9c1a2a533c739f7a5458a56882fb13b4b93.scope/memory.memsw.limit_in_bytes 268435456
若是不設置-m 128m
,則默認容器內存是不設限的
[root@fei ~]# cat /sys/fs/cgroup/memory/system.slice/docker-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2.scope/memory.limit_in_bytes 9223372036854775807
(4) 磁盤IO限制,docker自己默認沒有作磁盤io的限制,不過咱們能夠經過直接操做cgroups來實現
# 磁盤寫 [root@fei ~]# cid=641cdebd22b5 [root@fei ~]# nsenter --target $(docker inspect -f '{{ .State.Pid }}' $cid) --mount --uts --ipc --net --pid mount | head -1 /dev/mapper/docker-253:1-138011042-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2 on / type ext4 (rw,relatime,discard,stripe=16,data=ordered) [root@fei ~]# systemctl set-property --runtime docker-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2.scope "BlockIOWriteBandwidth=/dev/mapper/docker-253:1-138011042-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2 1M" # 磁盤讀 [root@fei ~]# systemctl set-property --runtime docker-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2.scope "BlockIOReadBandwidth =/dev/mapper/docker-253:1-138011042-641cdebd22b55f2656a560cd250e661ab181dcf2f5c5b78dc306df7ce62231f2 1M"
(5) 磁盤大小,docker容器默認都會分配10GB的空間,若是想改變這個值,須要修改docker服務啓動參數,並重啓docker服務:docker -d --storage-opt dm.basesize=5G
。其餘磁盤相關的配置能夠參考https://github.com/docker/docker/tree/master/daemon/graphdriver/devmapper。
Linux把原來和超級用戶相關的高級權限劃分紅爲不一樣的單元,稱爲Capability,這樣就能夠獨立對特定的Capability進行使能或禁止。一般來說,不合理的禁止Capability,會致使應用崩潰。
Docker默認爲容器刪除了如下capability:
CAP_SETPCAP Modify process capabilities CAP_SYS_MODULE Insert/Remove kernel modules CAP_SYS_RAWIO Modify Kernel Memory CAP_SYS_PACCT Configure process accounting CAP_SYS_NICE Modify Priority of processes CAP_SYS_RESOURCE Override Resource Limits CAP_SYS_TIME Modify the system clock CAP_SYS_TTY_CONFIG Configure tty devices CAP_AUDIT_WRITE Write the audit log CAP_AUDIT_CONTROL Configure Audit Subsystem CAP_MAC_OVERRIDE Ignore Kernel MAC Policy CAP_MAC_ADMIN Configure MAC Configuration CAP_SYSLOG Modify Kernel printk behavior CAP_NET_ADMIN Configure the network CAP_SYS_ADMIN Catch all
若是確實須要這些capability,能夠經過--cap-add or --cap-drop
添加或刪除,如docker run --cap-add all --cap-drop sys-admin -ti rhel7 /bin/sh
。
SELinux是一個標籤系統,進程有標籤,每一個文件、目錄、系統對象都有標籤。SELinux經過撰寫標籤進程和標籤對象之間訪問規則來進行安全保護。
對於這種疊加的文件系統,有一個很好的實現是AUFS,在Ubuntu比較新的發行版裏都是自帶的,這個能夠作到以文件爲粒度的copy-on-write,爲海量的container的瞬間啓動,提供了技術支持,也會持續部署提供了幫助(注意,centos7系統是基於devicemapper來實現相似的功能的)。
AUFS支持爲每個成員目錄(相似Git Branch)設定readonly、readwrite 和 whiteout-able 權限, 同時 AUFS 裏有一個相似分層的概念, 對 readonly 權限的 branch 能夠邏輯上進行修改(增量地, 不影響 readonly 部分的)。一般 Union FS 有兩個用途, 一方面能夠實現不借助 LVM、RAID 將多個disk掛到同一個目錄下, 另外一個更經常使用的就是將一個 readonly 的 branch 和一個 writeable 的 branch 聯合在一塊兒,Live CD正是基於此方法能夠容許在 OS image 不變的基礎上容許用戶在其上進行一些寫操做。Docker 在 AUFS 上構建的 container image 也正是如此。
主要用來作端口映射以及NAT轉換,端口映射已經集成到Docker命令中,但NAT轉換須要手動執行iptables命令。