文章转载自:
https://learnku.com/articles/22822
前面两篇文章,基于Docker搭建的MySQL主从复制。后来有网友QQ问我有没有Docker的相关文章,说没有接触过这个Docker,不知道如何上手,今天就借花献佛,转载一篇比较全面的Docker大全文章。本篇篇幅比较长,请耐心看完。如果转载请注明原文出处。文章来自:learnku编程者知识社区,一个很不错的社区。 下面开始正文。 作者Docker仓库(改进后的 Fork 仓库): https://github.com/wi1dcard/docker-cheat-sheet(中文版本位于 zh-CN 目录)
「通过 Docker,开发者可以使用任何语言任何工具创建任何应用。“Dockerized” 的应用是完全可移植的,能在任何地方运行 - 不管是同事的 OS X 和 Windows 笔记本,或是在云端运行的 Ubuntu QA 服务,还是在虚拟机运行的 Red Hat 产品数据中心。
Docker Hub 上有 13000+ 的应用,开发者可以从中选取一个进行快速扩展开发。Docker 跟踪管理变更和依赖关系,让系统管理员能更容易理解开发人员是如何让应用运转起来的。而开发者可以通过 Docker Hub 的共有 / 私有仓库,构建他们的自动化编译,与其他合作者共享成果。
Docker 帮助开发者更快地构建和发布高质量的应用。」—— 什么是 Docker
我用的是 Oh My Zsh 和 Docker 插件,它可以自动补全 Docker 命令。你的环境可能有所不同。这里加一句,看个人选择吧。
Docker 对于 Linux 内核版本的 最低要求 为 3.10.x。
10.8「Mountain Lion」或更新版本。
时刻关注你当前正在使用的 Docker 版本是十分重要的,这能够帮助你了解可用的特性。同时,可以让你在查找镜像时选择使用的版本。接下来让我们看看如何操作。
docker version查看你正在运行的 Docker 版本。 获取 Docker 服务版本: docker version --format '{{.Server.Version}}'你也可以输出原始的 JSON 数据:
docker version --format '{{json .}}'Docker 官方提供了快速、易用的安装脚本:
curl -sSL https://get.docker.com/ | sh如果你不想执行一个不明不白的 Shell 脚本,那么请看 安装说明,选择你在用的发行版本。
如果你是一个 Docker 超新手,那么你应当先去看看 系列教程。
下载并安装 Docker Community Edition。如果你在使用 Homebrew-Cask,只需在命令行输入 brew cask install docker即可。下载安装 Docker Toolbox 亦可。Docker For Mac 很赞,但是它的安装过程与 VirtualBox 不太一样。详情请查阅 比较。
注意:Docker Toolbox 已经过时。你应当使用 Docker Community Edition,详见 Docker Toolbox
安装好 Docker Community Edition 后,点击 Launchpad 内的 Docker 图标。接着即可启动容器了:
docker run hello-world好了,现在你有了一个运行中的 Docker 容器了。
关于 Docker 进程隔离的基础。容器 (Container) 之于虚拟机 (Virtual Machine) 就好比线程之于进程。或者你可以把他们想成是「吃了类固醇的 chroots」。
通常情况下,不使用任何命令行选项启动一个容器,该容器将会立即启动并停止。若需保持其运行,你可以使用 docker run -td container_id命令。选项 -t表示分配一个 pseudo-TTY 会话,-d表示自动将容器与终端分离(也就是说在后台运行容器,并输出容器 ID)。
如果你需要一个临时容器,可使用 docker run --rm会在容器停止之后删除它。
如果你需要映射宿主机 (host) 的目录到 Docker 容器内,可使用 docker run -v $HOSTDIR:$DOCKERDIR。详见 卷标 (Volumes) 一节。
如果你想同时删除与容器相关联的卷标,那么在删除容器的时候必须包含 -v选项,像这样 docker rm -v。
从 Docker 1.10 起,其内置一套各容器独立的 日志引擎,每个容器可以独立使用。你可以使用 docker run --log-driver=syslog来自定义日志引擎(例如以上的 syslog)。
如果你想将容器的端口 (ports) 暴露至宿主机,请见 暴露端口 一节。
关于 Docker 实例崩溃后的重启策略,详见 该文。
你可以限制 CPU 资源占用,无论是指定百分比,或是特定核心数。
例如,你可以设置 cpu-shares。该配置看起来有点奇怪 – 1024 表示 100% CPU,因此如果你希望容器使用所有 CPU 内核的 50%,应将其设置为 512:
docker run -ti --c 512 agileek/cpuset-test更多信息请参阅 https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/#_cpu。 通过 cpuset-cpus 可使用特定 CPU 内核。
docker run -ti --cpuset-cpus=0,4,6 agileek/cpuset-test请参阅 https://agileek.github.io/docker/2014/08/06/docker-cpuset/获取更多细节以及一些不错的视频。
注意,Docker 在容器内仍然能够 看到 全部 CPU – 它仅仅是不使用全部而已。请参阅 https://github.com/moby/moby/issues/20770获取更多细节。
同样,亦可给 Docker 设置 内存限制:
docker run -it -m 300M ubuntu:14.04 /bin/bashLinux 的 Capability 可以通过使用 cap-add和 cap-drop设置。请参阅 https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities获取更多细节。这有助于提高安全性。
如需要挂载基于 FUSE 的文件系统,你需要结合 --cap-add和 --device使用:
docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs授予对某个设备的访问权限:
docker run -it --device=/dev/ttyUSB0 debian bash授予对所有设备的访问权限:
docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash有关容器特权的更多信息请参阅 该文。
镜像是 Docker 容器的模板。
虽然你可以用 docker rmi命令来删除指定的镜像,不过有个名为 docker-gc 的工具,它可以以一种安全的方式,清理掉那些不再被任何容器使用的镜像。Docker 1.13 起,使用 docker image prune亦可删除未使用的镜像。参见 清理。
从文件中加载镜像:
docker load < my_image.tar.gz保存既有镜像:
docker save my_image:my_tag | gzip > my_image.tar.gz从文件中导入容器镜像:
cat my_container.tar.gz | docker import - my_image:my_tag导出既有容器:
docker export my_container | gzip > my_container.tar.gz通过 load命令来加载镜像,会创建一个新的镜像,并继承原镜像的所有历史。 通过 import将容器作为镜像导入,也会创建一个新的镜像,但并不包含原镜像的历史,因此会比使用 load 方式生成的镜像更小。
Docker 具备 网络 功能。我并不是很了解它,所以这是一个扩展本文的好地方。文档 使用网络 指出,这是一种无需暴露端口即可实现 Docker 容器间通信的好方法。
仓库 (repository) 是 被托管 (hosted) 的已命名镜像 (tagged images) 的集合,这组镜像用于构建容器文件系统。
仓管中心 (registry) 则是 托管服务 (host) – 用于存储仓库并提供 HTTP API,以便 管理仓库的上传和下载。
Docker 官方托管着自己的 仓管中心,包含着数量众多的仓库。不过话虽如此,这个仓管中心 并没有很好地验证镜像,所以如果你担心安全问题的话,请尽量避免使用它。
docker login 登入仓管中心。docker logout 登出仓管中心。docker search 从仓管中心检索镜像。docker pull 从仓管中心拉取镜像到本地。docker push 从本地推送镜像到仓管中心。你可以使用 docker distribution 项目搭建本地的仓管中心,详情参阅 本地发布 (local deploy) 的介绍。
科学上网后,也可以看看 Google+ Group。
当你执行 docker build时,Docker 将会根据 配置文件 启动 Docker 容器。远优于使用 docker commit。
以下是一些编写 Dockerfile 的常用编辑器,并链接到适配的语法高亮模块︰
如果你在使用 jEdit,你可以使用我开发的 Dockerfile 语法高亮模块。
Sublime Text 2AtomVimEmacsTextMate 更多信息请参阅 Docker 遇上 IDE。Docker 的版本化文件系统是基于层的。就像 Git 的提交或文件变更系统 一样。
链接 (links) 通过 TCP/IP 端口 实现 Docker 容器之间的通讯。Atlassian 展示了可用的例子。你还可以 通过主机名 (hostname) 链接。
在某种意义上来说,该特性已经被 自定义网络 所替代。
注意:如果你希望容器之间只通过链接进行通讯,在启动 Docker 守护进程时,请使用 -icc=false 来禁用内部进程通讯。
假设你有一个名为 CONTAINER 的容器(通过 docker run --name CONTAINER 指定)并且在 Dockerfile 中,暴露了一个端口:
EXPOSE 1337然后,我们创建另外一个名为 LINKED 的容器:
docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress然后 CONTAINER 暴露的端口和别名将会以如下的环境变量出现在 LINKED 中:
$ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR那么你便可以通过这种方式来连接它了。
使用 docker rm --link即可删除链接。
通常,Docker 容器(亦可理解为「服务」)之间的链接,是「服务发现」的一个子集。如果你打算在生产中大规模使用 Docker,这将是一个很大的问题。请参阅 The Docker Ecosystem: Service Discovery and Distributed Configuration Stores 获取更多信息。
Docker 的卷标 (volumes) 是 独立的文件系统。它们并非必须连接到特定的容器上。
你可以一次性将其挂载到多个 docker 容器上,通过 docker run --volumes-from。
因为卷标是独立的文件系统,它们通常被用于存储各容器之间的瞬时状态。也就是说,你可以配置一个无状态临时容器,关掉之后,当你有第二个这种临时容器实例的时候,你可以从上一次保存的状态继续执行。
查看 卷标进阶 来获取更多细节。Container42 非常有用。
你可以 将宿主 MacOS 的文件夹映射为 Docker 卷标:
docker run -v /Users/wsargent/myapp/src:/src你也可以用远程 NFS 卷标,如果你觉得你 有足够勇气。
还可以考虑运行一个纯数据容器,像 这里 所说的那样,提供可移植数据。
记得,文件也可以被挂载为卷标。
通过宿主容器暴露输入端口相当 繁琐但有效的。
例如使用 -p 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage你可以使用 EXPOSE 告知 Docker,该容器在运行时监听指定的端口:
EXPOSE <CONTAINERPORT>但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 -p。比如说你要在 localhost 上暴露容器的端口:
iptables -t nat -A DOCKER -p tcp --dport <LOCALHOSTPORT> -j DNAT --to-destination <CONTAINERIP>:<PORT>如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 forwarded_port 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end如果你忘记了将什么端口映射到宿主机上的话,可使用 docker port查看:
docker port CONTAINER $CONTAINERPORT这里有一些最佳实践,以及争论焦点:
The Rabbit Hole of Using Docker in Automated TestsBridget Kromhout has a useful blog post on running Docker in production at Dramafever.There’s also a best practices blog post from Lyst.A Docker Dev Environment in 24 Hours!Building a Development Environment With DockerDiscourse in a Docker Container这节准备讨论一些关于 Docker 安全性的问题。Docker 官方文档 安全 页面讲述了更多细节。
首先第一件事:Docker 是有 root 权限的。如果你在 docker 组,那么你就有 root 权限。如果你将 Docker 的 Unix Socket 暴露给容器,意味着你赋予了容器 宿主机 root 权限。
Docker 不应当作为唯一的防御措施。你应当使其更加安全可靠。
为了更好地理解容器暴露了什么,可参阅由 Aaron Grattafiori 编写的 Understanding and Hardening Linux Containers。这是一个完整全面且包含大量链接和脚注的容器问题指南,介绍了许多有用的内容。即使你已经加固过容器,以下的安全提示依然十分有帮助,但并不能代替理解的过程。
为了最大的安全性,你应当考虑在虚拟机上运行 Docker。这是直接从 Docker 安全团队拿来的资料 – slides / notes。之后,可使用 AppArmor、seccomp、SELinux、grsec 等来 限制容器的权限。更多细节,请查阅 Docker 1.10 security features。
Docker 镜像 ID 属于 敏感信息 所以它不应该向外界公开。请将它们当作密码来对待。
阅读由 Thomas Sjögren 编写的 Docker Security Cheat Sheet:关于加固容器的不错的建议。
查看 Docker 安全测试脚本,下载 最佳实践白皮书。
你应当远离使用非稳定版本 grsecurity /pax 的内核,比如 Alpine Linux。如果在产品中用了 grsecurity,那么你应该考虑使用有 商业支持 的 稳定版本,就像你对待 RedHat 那样。虽然要 $200 每月,但对于你的运维预算来说不值一提。
从 Docker 1.11 开始,你可以轻松的限制在容器中可用的进程数,以防止 fork 炸弹。 这要求 Linux 内核 >= 4.3,并且要在内核配置中打开 CGROUP_PIDS=y。
docker run --pids-limit=64同时,你也可以限制进程再获取新权限。该功能是 Linux 内核从 3.5 版本开始就拥有的。你可以从 这篇博客 中阅读到更多关于这方面的内容。
docker run --security-opt=no-new-privileges以下内容摘选自 Container Solutions 的 Docker Security Cheat Sheet(PDF 版本,难以使用,故复制至此):
关闭内部进程通讯:
docker -d --icc=false --iptables设置容器为只读:
docker run --read-only通过 hashsum 来验证卷标:
docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be设置卷标为只读:
docker run -v $(pwd)/secrets:/secrets:ro debian在 Dockerfile 中定义用户并以该用户运行,避免在容器中以 ROOT 身份操作:
RUN groupadd -r user && useradd -r -g user user USER user还可以通过使用 用户命名空间 – 自 1.10 版本起已内置,但默认并未启用。
要在 Ubuntu 15.10 中启用用户命名空间 (remap the userns),请 跟着这篇博客的例子 来做。
Docker 的路线图提到关于 seccomp 的支持。 一个名为 bane 的 AppArmor 策略生成器正在实现 安全配置文件。
最新的 数据管理命令 已在 Docker 1.13 实现:
docker system prunedocker volume prunedocker network prunedocker container prunedocker image prunedocker system df将显示当前 Docker 各部分占用的磁盘空间。
Heredoc 声明 Docker 容器:
docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF最近一次的容器 ID:
alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld带命令的提交(需要 Dockerfile):
docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres获取 IP 地址:
docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4或使用 jq:
docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress'或使用 go 模板:
docker inspect -f '{{ .NetworkSettings.IPAddress }}' <container_name>或在通过 Dockerfile 构建镜像时,通过构建参数 (build argument) 传入:
DOCKER_HOST_IP=`ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/获取端口映射:
docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' <containername>通过正则匹配容器:
for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done`获取环境变量配置:
docker run --rm ubuntu env强行终止运行中的容器:
docker kill $(docker ps -q)删除所有容器(强行删除!无论容器运行或停止):
docker rm -f $(docker ps -qa)删除旧容器:
docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm删除已停止的容器:
docker rm -v `docker ps -a -q -f status=exited`停止并删除容器:
docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq)删除无用 (dangling) 的镜像:
docker rmi $(docker images -q -f dangling=true)删除所有镜像:
docker rmi $(docker images -q)删除无用 (dangling) 的卷标(Docker 1.9 版本起):
docker volume rm $(docker volume ls -q -f dangling=true)1.9.0 中,参数 dangling=false 居然 没 用 - 它会被忽略然后列出所有的卷标。
查看镜像依赖:
docker images -viz | dot -Tpng -o docker.pngDocker 容器瘦身:
在某层 (RUN layer) 清理 APT这应当和其他 apt 命令在同一层中完成。 否则,前面的层将会保持原有信息,而你的镜像则依旧臃肿。
RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 压缩镜像 ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name 备份 ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name监视运行中容器的系统资源利用率: 检查某个容器的 CPU、内存以及网络 I/O 使用情况,你可以:
docker stats <container>按 ID 列出所有容器:
docker stats $(docker ps -q)按名称列出所有容器:
docker stats $(docker ps --format '{{.Names}}')按指定镜像名称列出所有容器:
docker ps -a -f ancestor=ubuntu删除所有未标签命名 (untagged) 的容器:
docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}')通过正则匹配删除指定容器:
docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f删除所有已退出 (exited) 的容器:
docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }')将文件挂载为卷标: 文件也可以被挂载为卷标。例如你可以仅仅注入单个配置文件:
# 从容器复制文件 docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # 编辑文件 vim httpd.conf # 挂载修改后的配置启动容器 docker run --rm -ti -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd好了,到这里就结束了。这篇文章确实篇幅比较长,想要一次学会其中的内容显然不太可能,要结合自己的不断练习运用,慢慢熟悉这些命令和Docker的使用。 文中部分链访问不成功的时候需要梯子。 希望各位有所收获。