Docker - 一步到位的应用部署与上线
Docker简介
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。
Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)
总而言之,Docker所使用的容器技术使得应用程序和对应的配置环境能够统一整合起来并交付给其他环境,避免了需要反复从头配置环境甚至debug的苦恼。
容器与虚拟机
虚拟机同样也是一种可携带环境安装状态实现跨平台的解决方案。虚拟机在云计算中发挥着至关重要的作用,它通过在隔离的实例中运行操作系统来模拟物理计算机。
当然,虚拟机和容器是两种不同的虚拟化技术,它们在应用部署和资源管理方面有明显的区别。
虚拟机
- 虚拟机是基于硬件的虚拟化技术。它通过完全模拟硬件环境来实现虚拟化。
- 每个虚拟机运行一个完整的操作系统,包括内核和用户空间。这意味着每个虚拟机都需要占用大量的磁盘空间和内存。
- 虚拟机之间相互隔离,每个虚拟机都有自己的操作系统和依赖。
- 启动虚拟机需要数分钟,因为它们需要加载整个操作系统。
- 虚拟机的资源利用率较低,因为它们运行独立的操作系统。
容器
- 容器是应用程序级别的虚拟化技术,不需要模拟整个操作系统环境。
- 容器共享主机操作系统内核,因此它们更轻量级。每个容器只包含应用程序和其依赖,而不需要额外的操作系统。
- 容器之间相互隔离,但共享同一个操作系统。它们运行在相同的内核上,因此启动速度非常快。
- 容器的资源利用率高,因为它们共享主机操作系统。
- 容器更易于移植,可以在不同的环境中运行。

总之,虚拟机更适合彻底隔离整个运行环境,例如云服务提供商使用虚拟机隔离不同的用户。而容器更适用于隔离不同的应用,例如前端、后端和数据库。选择虚拟机还是容器取决于具体的使用场景和需求。
Docker架构
Docker 包括三个基本概念:
- 镜像(Image):Docker 镜像(Image),就相当于是一个
root文件系统。比如官方镜像ubuntu:16.04就包含了完整的一套 Ubuntu16.04 最小系统的root文件系统。 - 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。类似于 Github 仓库,官方也有自己仓库网站: https://hub.docker.com/

安装引擎
Docker Engine 的安装具体可以查看 官方文档:Docker Engine overview | Docker Docs
通过如下命令核实安装情况:
1 | sudo systemctl start docker #启动Docker服务 |
OpenSUSE Leap 的安装方法详见:Docker - openSUSE Wiki
镜像加速
通过 阿里云的镜像服务(个人版)获取镜像加速器的 URL,并将其添加至配置文件中:
1 | sudo mkdir -p /etc/docker |
可通过命令 docker info 查看是否存在 Registry Mirrors: xxx 项判断是否配置成功。
常用命令
启动与停止
1 | sudo systemctl start docker #启动Docker服务 |
镜像相关命令
查看镜像情况
查看本地镜像:docker images [-a列出含历史镜像层的所有镜像] [-q只显示镜像ID]
1 | localhost:~ # docker images |
查看占用空间情况:docker system df
虚悬镜像,待更
1 | docker image ls -f dangling=true |
搜索与拉取
搜索相关镜像:docker search <image_name> [--limit n 仅显示前n条]
1 | localhost:~ # docker search ubuntu --limit 4 |
拉取对应版本的镜像:docker pull <image_name>[:tag指定版本号]
1 | localhost:~ # docker pull ubuntu |
镜像的删除
删除指定镜像:docker rmi <image_name/image_id> [-f强制删除]
1 | docker rmi a b c #同时删除镜像a、镜像b和镜像c |
容器相关命令
查看当前正在运行的容器:
1 | docker ps [-a列出历史运行过的所有容器] [-n x, 只显示最近x个] [-p只显示容器ID]` |
容器的运行与重进
1 | docker run <image_name>[:tag] [--name对容器进行自定义命名] |
该命令将根据镜像生成(新的)容器并运行之,此外特别注意的是其他的可用参数有:
-it:前台交互终端运行(是-i前台和-t终端的结合)-d:后台静默运行-P:随机端口映射-p:指定端口映射 【常用:-p HostPort:ContainerPort】
例如进入 Ubuntu 容器:
1 | localhost:~ # docker run -it ubuntu |
在容器中通过命令 exit 可退出该容器(容器会停止运行);
而通过快捷键Ctrl+P+Q 退出交互式终端状态(容器依然后台运行)。
要想重新进入正在运行的容器时,可通过如下命令实现:
1 | docker exec [-it / -d] <container_id> bash |
值得注意的是,如果使用 exec 重进容器,在容器内使用 exit 退出时,容器不会停止会继续在后台运行。
停止、再启动和删除
在容器中(交互方式)通过命令 exit 可退出该容器,并且容器会停止运行。
在容器外(静默方式)通过命令 docker stop <container_id> 停止正在运行的容器;将 stop 替换为 kill 则是强制停止。
通过 docker ps -a 会列出所有曾经运行过的容器(即使已经停止了):
1 | localhost:~ # docker ps -a |
可以在 STATUS 中看出某容器是否仍在运行:Up 是在运行,Exited.. 则是已停止但存在过。
接下来,我们可通过命令将该容器再次激活:
1 | docker start <container_id> [<container_name>] |
示例:
1 | localhost:~ # docker start confident_chaum |
然后是删除容器:
1 | docker rm <container_id> |
注意,此处是 rm 代表删除的是容器,如果是 rmi 则是删除镜像。
当容器正在运行时不予删除,需要先停止之再删除,或者使用 -f 强制删除;
此外,删除后通过 docker ps -a 在历史中也再也找不到该容器了,同理也无法再 start 重新启动了。
示例如下:
1 | localhost:~ # docker rm confident_chaum |
容器的日志与进程
docker logs <container_id>:查看正在运行的容器后台打印的日志docker top <container_id>:查看正在运行的容器内的进程运行情况
容器与主机文件传输
docker cp <container_id>:<container_file_path> <host_path> 将容器内的文件复制到主机指定目录下。
示例:
1 | localhost:~ # docker cp ccd87ecf82c1:/home/myfile.txt /home/data |
容器的导入与导出
docker export <container_id> > filename.tar
cat filename.tar | docker import - user/myimagename:mytag
镜像创建与仓库管理
Docker 镜像是分层的,最底层通常是复制主机的 kernel bootfs 进行引导,然后往上堆叠不同操作系统的最精简 rootfs。再往上可以继续堆叠不同的环境和资源包。
镜像内容是只读的,按镜像生成的容器则是可读写的。为了在原有镜像上进行修改并生成新的镜像以便复用,我们需要对进行修改的容器进行反射以构建出新的镜像。
Commit
1 | docker commit -m="description" -a="author" <container_id> <myImageName>:<myTag> |
以 Docker 的 Ubuntu 镜像为例,其中不含有 vim 命令,我们为其安装上之后再将其打包成含有 vim 命令的新的 Ubuntu 镜像。
1 | localhost:/home # docker run -it ubuntu |
阿里云推送与拉取
在阿里云中创建【命名空间】和【仓库】后,
待更
搭建私有仓库
除了阿里云、DockerHub等第三方公网的Docker仓库以外,Docker自然也运行搭建自己的私有仓库,供可信任的人员访问。这个搭建私有Registry的环境甚至也被Docker官方做成了镜像供开发者、运维快速复现。
容器数据卷
容器数据卷实现了容器内指定的文件夹和主机指定文件夹的“映射共享”。使得在容器外/主机上可以对该文件夹加入删除或是修改文件,这些操作会同步到容器对应的文件夹内。
其实就是一个持久性挂载的作用——即使容器被停止或删除,主机上该文件夹的内容不会被删除。
如果不使用容器数据卷方法,临时进行简单的文件传输,则可使用 cp 命令。
使用容器数据卷的命令如下,它执行在通过镜像运行一个容器之前,利用 -v 实现:
1 | docker run [-it/-d] -v /HostPath:/ContainerPath IMAGE |
通常,为了防止权限bug,还需要添加参数 --privileged=true!
读写权限
在编写映射时,还可以对容器进行读写权限的限制:
1 | docker run -it --privileged=true -v /home/slie:/tmp/shared_floder:ro --name="u1" ubuntu |
上述命令使得主机下的 /home/slie 文件夹与名为 u1 的一个Ubuntu容器内的 /tmp/shared_floder 文件夹实现共享,并且主机自由可读写,但是容器只能读不能写,即 Read Only ro。
容器卷的继承
当我们想让 容器b 继承 容器a 的映射方式时,可以在其运行启动前利用 --volumes-from 参数:
1 | docker run [-it/-d] --volumes-from <container_a> IMAGE |
Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
简单来说,一个 Dockerfile 文件就是一个脚本文件(类似于 .sh 文件),通过它我们可以使用 build 命令 一键实现对镜像的构建,区别于以往不断在容器内定制内容最后反复 commit 的繁琐过程。
Dockerfile 文件的文本内容模板如下,每行开头全大写的关键词我们称之为“保留字”,是 Dockerfile 的重要组成部分,表明应该做的事情。
1 | # 符号`#`用于注释, 注释必须单独一行 |
CMD
shell格式exec格式
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
build
在 Dockerfile 文件目录下,运行下列命令以构建新的镜像:
1 | docker build IMAGE:TAG . |
注意末尾有一个点 . 不能丢!
Docker网络
当我们在通过 sudo systemctl start docker启动Docker服务后,主机会产生一个名为 docker0 的虚拟网桥。(可通过 ifconfig 查看验证)
通过下列命令我们可以查看 Docker 的网络模式:
1 | docker network ls |
一般有三大模式:bridge,host,none。
相关网络命令
通过 docker network --help 可查看所有可用的命令:
1 | localhost:~ # docker network --help |



