Docker
一. 数据管理
- 数据卷
数据卷是一个可供容器使用的特殊目录,他将主机操作系统目录直接映射进容器,类似Linux的mount操作。数据卷的特性如下:
- 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效方便;
- 对数据卷内数据的修改会马上生效,无论是容器内操纵还是本地操作;
- 对数据卷的更新不会影响镜像,解耦了应用和数据;
- 卷会一直存在,直到没有容器使用,可以安全地卸载它;
Docker run命令的时候,使用-v标记可以在容器内创建一个数据卷,多次使用-v创建多个数据卷;使用-v标记指定挂载一个本地的已有目录到容器中去作为数据卷.
加载主机的/src/webapp目录到容器的opt/webapp目录,本地目录的路径必须是绝对路径,如果目录不存在Docker,会自动创建。
docker run -d -p --name web -v /src/webapp:/opt/webapp ubuntu
Docker挂载数数据卷的默认权限是读写(rw),用户也可以哦通过ro指定为只读.
docker run -d -p --name web -v /src/webapp:/opt/webapp:ro ubuntu
不推荐将单个本地文件作为数据卷。
- 数据卷容器
需要在多个容器之间共享一些持续更新的数据可以使用数据卷容器。数据卷容器也是个容器,目的是专门用来提供数据卷供其他容器使用:
docker run -it -v /dbdata --name dbdata ubuntudocker run -it --volumn-from dbdata --name db1 ubuntudocker run -it --volumn-from dbdata --name db2 ubuntu
或者可以从其他已经挂载了容器卷的容器来挂载数据卷:
docker run -it --volumn-from db1 --name db3 ubuntu
如果删除挂载的容器,数据卷不会被删除,如果要删除一个数据卷,必须在删除最后一个挂载着它的容器时显示使用docker rm -v命令来指定同时删除关联的容器。
- 利用数据卷容器迁移数据
//创建worker的容器,使用--volumn-from挂载dbdata容器的数据卷/dbdata,使用-v $(pwd):/backup 挂载本地的当前目录到worker容器的backup目录,worker容器启动后,使用tar zcf /backup/backup.tar /dbdata将dbdata目录额内容备份为容器内的/backup/backup.tar,即当前目录的backup.tar文件,实现数据的备份。docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata//创建一个新的容器docker run -v /dbdata --name dbdata2 ubuntu /bin/bashdocker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
二. 端口映射与容器互联
端口映射通过-P或者-p。
容器互联使用-link。
--link 参数的格式为 --link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名。
使用 --link 参数可以让容器之间安全的进行交互。
先创建一个新的数据库容器,然后创建一个新的 web 容器,并将它连接到 db 容器。
docker run -d --name db training/postgresdocker run -d -P --name web --link db:db training/webapp python app.pydocker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db, web/dbaed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp we
可以看到自定义命名的容器,db 和 web,db 容器的 names 列有 db 也有 web/db。这表示 web 容器链接到 db 容器,web 容器将被允许访问 db 容器的信息。
Docker 在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动 db 容器的时候并没有使用 -p 和 -P 标记,从而避免了暴露数据库端口到外部网络上。
Docker 通过 2 种方式为容器公开连接信息:
(1)环境变量
(2)更新 /etc/hosts 文件
使用 env 命令来查看 web 容器的环境变量
$ sudo docker run --rm --name web2 --link db:db training/webapp env. . .DB_NAME=/web2/dbDB_PORT=tcp://172.17.0.5:5432DB_PORT_5000_TCP=tcp://172.17.0.5:5432DB_PORT_5000_TCP_PROTO=tcpDB_PORT_5000_TCP_PORT=5432DB_PORT_5000_TCP_ADDR=172.17.0.5
其中 DB_ 开头的环境变量是供 web 容器连接 db 容器使用,前缀采用大写的连接别名。
除了环境变量,Docker 还添加 host 信息到父容器的 /etc/hosts 的文件。下面是父容器 web 的 hosts 文件
$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bashroot@aed84ee21bde:/opt/webapp# cat /etc/hosts172.17.0.7 aed84ee21bde. . .172.17.0.5 db
这里有 2 个 hosts,第一个是 web 容器,web 容器用 id 作为他的主机名,第二个是 db 容器的 ip 和主机名。 可以在 web 容器中安装 ping 命令来测试跟db容器的连通。
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-pingroot@aed84ee21bde:/opt/webapp# ping dbPING db (172.17.0.5): 48 data bytes56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
用 ping 来测试db容器,它会解析成 172.17.0.5。
注意:官方的 ubuntu 镜像默认没有安装 ping,需要自行安装。用户可以链接多个父容器到子容器,比如可以链接多个 web 到 db 容器上
三. 安全防护和配置
Docker容器的安全性,很大程度依赖于Linux系统自身,评估Docker的安全性时,主要考虑:
- Linux内核命名空间机制提供的容器隔离安全;
- Linux控制组机制对容器资源的控制能力安全;
- Linux内核的能力机制所带来的操作权限安全;
- Docker程序(特别是服务器)本身的抗攻击能力;
- 其他安全增强机制(包括AppArmor,SELinux)对容器安全性的影响;
- 通过第三方工具(Docker bench)对Docker环境的安全性进行评估;
- 命名空间隔离
当Docker run命令启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了最直接最基础的隔离,在容器运中行的进程不会被运行在本地主机上的进程和其他容器通过正常渠道发现和影响。
- 控制组资源控制的安全
控制组时Linux容器机制中的另外一个关键组件,负责实现资源的审计和限制。Docker run启动一个容器时,Docker将通过linux相关调用,在后台为容器创建一个独立的控制组策略集合,该集合将限制容器内应用对资源的消耗。确保每个容器公平地分享主机的内存,CPU,磁盘IO等资源,更重要的是可以通过控制组,限制容器对资源的占用,确保当某容器对资源消耗过大时,不会影响到本地主机系统和其他容器。
- 内核能力机制
能力机制(Capability)是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。例如,一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限,并不需要 root 权限。那么它只需要被授权 net_bind_service 能力即可。此外,还有很多其他的类似能力来避免进程获取 root 权限。
默认情况下,Docker 启动的容器被严格限制只允许使用内核的一部分能力。
使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块(例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理。
- ssh 访问被主机上ssh服务来管理;
- cron 通常应该作为用户进程执行,权限交给使用它服务的应用来处理;
- 日志系统可由 Docker 或第三方服务管理;
- 硬件管理无关紧要,容器中也就无需执行 udevd 以及类似服务;
- 网络管理也都在主机上设置,除非特殊需求,容器不需要对网络进行配置。
从上面的例子可以看出,大部分情况下,容器并不需要“真正的” root 权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限。
- 完全禁止任何 mount 操作;
- 禁止直接访问本地主机的套接字;
- 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等;
- 禁止模块加载。
这样,就算攻击者在容器中取得了 root 权限,也不能获得本地主机的较高权限,能进行的破坏也有限。
- 服务器的防护
为了加强对服务端的保护,Docker 的 REST API(客户端用来跟服务端通信)在 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字,因为后者容易遭受跨站脚本攻击。现在用户使用 Unix 权限检查来加强套接字的访问安全。
用户仍可以利用 HTTP 提供 REST API 访问。建议使用安全机制,确保只有可信的网络或 VPN,或证书保护机制(例如受保护的 stunnel 和 ssl 认证)下的访问可以进行。此外,还可以使用 HTTPS 和证书来加强保护。
最近改进的 Linux 名字空间机制将可以实现使用非 root 用户来运行全功能的容器。这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题。
终极目标是改进 2 个重要的安全特性:
- 将容器的 root 用户映射到本地主机上的非 root 用户,减轻容器和主机之间因权限提升而引起的安全问题;
- 允许 Docker 服务端在非 root 权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。
最后,建议采用专用的服务器来运行 Docker 和相关的管理服务(例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。
- 其他安全特性
除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, SELinux, GRSEC 等。
Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如:
- 在内核中启用 GRSEC 和 PAX,这将增加很多编译和运行时的安全检查;通过地址随机化避免恶意探测等。并且,启用该特性不需要 Docker 进行任何配置。
- 使用一些有增强安全特性的容器模板,比如带 AppArmor 的模板和 Redhat 带 SELinux 策略的模板。这些模板提供了额外的安全特性。
- 用户可以自定义访问控制机制来定制安全策略。
跟其它添加到 Docker 容器的第三方工具一样(比如网络拓扑和文件系统共享),有很多类似的机制,在不改变 Docker 内核情况下就可以加固现有的容器。