跳到正文Seminar Week 3 Summary · Jimmy Huang's Blog欢迎来到容器的世界
容器的优势
虚拟机与容器
虚拟化中的虚拟化
容器 vs. 虚拟机
相同点
不同点
Docker 作为容器使能技术
Docker的多种含义
Docker, Inc
Docker project
Docker Engine
Docker Engine 组件
Docker Daemon(守护进程):管理容器、镜像、构建等。
Docker Client(客户端):与 Docker Daemon 通信以执行命令。
REST API:可用于远程与 Docker Daemon 交互。
Docker Images(镜像):只读模板,通过写在 Dockerfile 中的一组指令构建。
Docker container(容器):将应用软件及其运行所需的一切封装在一个“盒子”里。
Docker registry(镜像注册表):用于存储和分发具名 Docker 镜像的系统。
注册表允许 Docker 用户将镜像拉取到本地,也允许在有足够权限的情况下将新镜像推送到注册表中。
镜像(Images)
官方 Alpine Linux Docker 镜像 大约为 4MB。
Ubuntu Docker 镜像 目前大约为 110MB。
基于 Windows 的镜像通常比基于 Linux 的镜像更大。
例如,最新的 Microsoft .NET 镜像(microsoft/dotnet:latest)在拉取并解压后超过 1.7GB。
将镜像放到 Docker 主机上的过程称为 pulling(拉取)
docker image pull ubuntu:latest
镜像注册表(Image Registries)
任何在本地注册表中未找到的组件,都会从指定位置下载。
mongo:仓库(Repository)
3.3.11:标签(Tag)
层(Layers)
Docker 镜像本质上只是由一组松散连接的、只读层 组成。
镜像是一层一层构建的
可以通过 Docker 命令检查镜像中的各层
每一层都有自己的 256 位哈希
例如:先安装 Ubuntu 操作系统
再安装 Python 包
再安装一个针对 Python 的安全补丁
这些层可以被多个容器共享
上层中的文件会遮蔽它正下方层中的同名文件。
这使得更新后的文件版本可以作为新的层添加到镜像中。
多个镜像可以并且确实会共享层,这会在空间和性能上带来效率提升。
每一层都由一个 加密 ID(crypto ID) 标识,这个 ID 是其所含内容的哈希值。
改变镜像或其任意层的内容,都会导致相应的加密哈希发生变化。
内容哈希(Content hashes)
分发哈希(Distribution hash)
一个简单的例子
启动一个新容器
当你在 Docker CLI 中输入命令时,Docker 客户端会将这些命令转换成相应的 API 负载,并通过 POST 发送到正确的 API 端点。
一旦守护进程接收到创建新容器的命令,它就会调用 containerd。
containerd 使用 runc 来创建容器。
runc 与操作系统内核交互,组合出创建容器所需的所有机制(如 namespaces、cgroups 等)。
shim 到底是干什么的?
shim 是实现 无守护进程容器(daemonless containers) 的关键部分。
containerd 使用 runc 来创建新容器。
它会为它创建的每个容器派生一个新的 runc 实例。
然而,一旦每个容器被创建出来,它的父进程 runc 就会退出。
这意味着我们可以运行数百个容器,而不必同时运行数百个 runc 实例。
shim 会让容器持续运行,并保持 stdin/stdout 打开。
对应的 containerd-shim 进程会成为该容器的父进程。
启动一个简单容器
启动容器最简单的方式是使用 docker container run 命令。
你可以根据需要多次对一个容器执行 stop、start、pause 和 restart。
如果你把容器数据存储在 volume(卷) 中,那么即使容器已经被删除,这些数据仍然会保留下来。
Web服务器案例
$ docker container run -d --name webserver -p 80:8080/ nigelpoulton/pluralsight-docker-ci
将应用容器化
Dockerfile
Dockerfile 是一个纯文本文件,用于描述如何将一个应用构建成 Docker 镜像。
它包含了用户在命令行中本可逐条执行、用于组装镜像的所有命令。
是编写 Dockerfile,还是直接“编译”一个镜像?
压缩镜像
左侧情况:
只推送唯一的层(灰色部分)
共享层:FROM alpine(基础层)
唯一层:RUN apk add npm...
COPY . /src
RUN npm install...
右侧情况:
整个镜像都是唯一的
整个镜像都需要被推送
压缩后的镜像(不共享层)
$ docker image build -t web:latest .
这条命令会构建一个名为 web:latest 的新镜像。命令末尾的句点(.)告诉 Docker 使用当前 shell 的工作目录作为 构建上下文(build context)。
使用 Docker Compose 部署应用
大多数现代应用由多个较小的服务组成,这些服务相互交互以形成一个有用的应用。我们称之为 微服务(microservices)。
与其使用脚本和冗长的 Docker 命令把所有东西“粘”在一起,Docker Compose 允许你用一个声明式配置文件来描述整个应用,然后用一条命令完成部署。
你可以在一个 YAML 文件中定义多容器(多服务)应用,把这个 YAML 文件传给 docker-compose 可执行程序,然后 Compose 会通过 Docker Engine API 完成部署。
如果我是初学者,你再用更简单的话解释一遍
以前我们为了让一台电脑同时跑很多东西,会用 虚拟机 VM。
这样做当然有好处,比如隔离更强、更完整,但代价也很明显。
后来大家发现,很多时候其实没必要给每个应用都配一整套 OS。
大家共用一套操作系统
每个应用只带自己需要的程序和依赖
所以更轻、更快
这就是为什么容器常常几秒甚至更快就能起来,而 VM 往往要更久。
而老师前面讲 migration、downtime、dirty pages,是想让你知道:
技术选型不是只看“能不能跑”,而是要看“性能、速度、停顿、资源、隔离性”这些现实问题。
VM 重但隔离强;container 轻且启动快;Docker 是把 container 真正跑起来的常用工具。
docker image pull mongo:3.3.11
$ docker container run--name ctr1-it alpine:latestsh
$ cat Dockerfile
FROM alpine
LABEL maintainer="[email protected]"
RUN apk add --update nodejs nodejs-npm
COPY . /src
WORKDIR /src
RUN npm install
EXPOSE 8080
ENTRYPOINT ["node", "./app.js"]