Docker学习

本文围绕Docker展开,介绍其基于Linux内核技术,具有高效利用资源、快速启动等优势。阐述了镜像、容器、仓库三大组件,讲解了在各类系统下的安装及加速器配置,还介绍了镜像、容器的操作和仓库访问方法,最后说明了数据卷和挂载主机目录等高级管理与配置内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Docker学习

参考网址:
Docker — 从入门到实践 · Yuque

一,Docker简介

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroupnamespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

1.1 Docker的优势

  • 更高效的利用系统资源

    由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。

  • 更快速的启动时间

    传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。

  • 一致的运行环境

    Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。

  • 持续交付和部署

    使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

  • 更轻松的迁移

    由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。

  • 更轻松的维护和扩展

    Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。

特性容器虚拟机
启动秒级分钟级
硬盘使用一般为 MB一般为 GB
性能接近原生弱于
系统支持量单机支持上千个容器一般几十个

1.2 Docker三大组件

1.2.1 镜像

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

docker镜像采用分层存储的架构,是由一组文件系统组成,或者说,由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。

1.2.2 容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

1.2.3 仓库

Docker Registry 是一个集中的存储、分发镜像的服务。一个 Docker Registry 中可以包含多个仓库Repository);每个仓库可以包含多个标签Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

  • Docker Registry 公开服务

    最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。除此以外,还有 CoreOSQuay.io,CoreOS 相关的镜像存储在这里;Google 的 Google Container RegistryKubernetes 的镜像使用的就是这个服务。

  • 私有 Docker Registry

    除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 一节中,会有进一步的搭建私有 Registry 服务的讲解。

二,Docker上手

同时 Docker 划分为 CE 和 EE。CE 即社区版(免费,支持周期三个月),EE 即企业版,强调安全,付费使用。

Docker CE 每月发布一个 Edge 版本 (17.03, 17.04, 17.05…),每三个月发布一个 Stable 版本 (17.03, 17.06, 17.09…),Docker EE 和 Stable 版本号保持一致,但每个版本提供一年维护。

项目说明
版本格式YY.MM
Stable 版本每个季度发行
Edge 版本每个月发行

2.1 Docker安装

2.1.1 各类系统下的安装

参考官方文档

2.1.2 加速器

国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。Docker 官方和国内很多云服务商都提供了国内加速器服务,例如:

我们以 Docker 官方加速器为例进行介绍。

  • Ubuntu 16.04+、Debian 8+、CentOS 7

对于使用systemd的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)

{
"registry-mirrors": [
"https://registry.docker-cn.com"
]
}

注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。

之后重新启动服务:

sudo systemctl daemon-reload
sudo systemctl restart docker
  • Windows 10

对于使用 Windows 10 的系统,在系统右下角托盘 Docker 图标内右键菜单选择 Settings,打开配置窗口后左侧导航菜单选择 Daemon。在 Registry mirrors 一栏中填写加速器地址 https://registry.docker-cn.com,之后点击 Apply 保存后 Docker 就会重启并应用配置的镜像地址了。

  • macOS

对于使用 macOS 的用户,在任务栏点击 Docker for mac 应用图标 -> Perferences… -> Daemon -> Registry mirrors。在列表中填写加速器地址 https://registry.docker-cn.com。修改完成之后,点击 Apply & Restart 按钮,Docker 就会重启并应用配置的镜像地址了。

  • 检查加速器是否生效

配置加速器之后,如果拉取镜像仍然十分缓慢,请手动检查加速器配置是否生效,在命令行执行 docker info,如果从结果中看到了如下内容,说明配置成功。

Registry Mirrors:
https://registry.docker-cn.com/

2.2 使用镜像

2.2.1 拉取镜像:docker pull

从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

# 格式
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

# 举例
docker pull ubuntu:16.04

具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。

  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
  • 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

使用Docker run命令运行镜像:

docker run -it --rm \
    ubuntu:16.04 \
    bash

docker run 参数解读:

  • it:这是两个参数,一个是 i:交互式操作,一个是 t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • -rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 -rm 可以避免浪费空间。
  • ubuntu:16.04:这是指用 ubuntu:16.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash

最后通过 exit 退出容器。

2.2.2 查看镜像:docker image ls

  • 虚悬镜像

    由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,下面会给出命令专门显示这类镜像。一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的镜像删除命令来删除。

  • 中间层镜像

    为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。查看包括中间层镜像在内的所有镜像的见以下命令。

# 注:这些命令都需要root权限或者sudo命令来执行

# 以下两个命令等效
docker image ls
docker images

# 查看镜像体积
docker system df

# 查看虚悬镜像
docker image ls -f dangling=true

# 查看包括中间层镜像在内的所有镜像
docker image ls -a

# 删除镜像
docker image prune

# 过滤
docker image ls -f <过滤条件>

# 以特定格式输出
docker image ls -q

2.2.3 启动镜像:docker start

# 启动所有镜像
docker start $(docker ps -a -q)

2.2.4 删除镜像:docker image rm

  • Untagged 和 Deleted

    如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged,另一类是 Deleted。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。

    因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete 行为就不会发生。所以并非所有的 docker rmi 都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。

    当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 docker pull 看到的层数不一样的原因。

    除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。

  • 批量删除

    像其它可以承接多个实体的命令一样,可以使用 docker image ls -q 来配合使用 docker image rm,这样可以成批的删除希望删除的镜像。

# 注:这些命令都需要root权限或者sudo命令来执行

# 基本命令
docker image rm <镜像名或镜像ID>

# 批量删除举例
docker image rm $(docker image ls -q redis)

# 删除所有镜像
docker rmi $(docker images -q)

2.3 操作容器

2.3.1 启动容器:docker run

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。

  • 新建容器并启动:docker run

    当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

    • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
    • 利用镜像创建并启动一个容器
    • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
    • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
    • 从地址池配置一个 ip 地址给容器
    • 执行用户指定的应用程序
    • 执行完毕后容器被终止
  • 启动已终止容器:docker container start

2.3.2 后台运行:docker run -d

默认直接将容器运行的输出打印到终端,因此要实现后台运行需要添加一个-d的参数,例如

docker run -d ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"

使用-d参数后,容器启动会返回一个唯一的id输出到终端,此时可以利用这个id来查看容器的输出信息,命令为:

docker container logs <contain-id or container-name>

此外,也可以通过docker container ls命令来查看正在运行的容器信息从而获得容器ID。

2.3.3 终止容器:docker container stop

  • 可以使用 docker container stop 来终止一个运行中的容器。此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
  • 终止状态的容器可以用 docker container ls -a 命令看到。处于终止状态的容器,可以通过 docker container start 命令来重新启动。
  • 此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。

2.3.4 进入容器:docker exec -it

在使用 -d 参数时,容器启动后会进入后台。这时候,如果因为某些需要而不得不进入容器进行操作,可以使用 docker attach 命令或 docker exec 命令,推荐使用 docker exec 命令。

# 例子
docker exec -it ubuntu bash

2.3.5 退出容器:exit

  • exit :run进去容器,exit退出,容器停止;
  • ctrl+p+q :run进去容器,ctrl+p+q退出,容器不停止;

2.3.6 查看容器状态:docker ps -xx

列出当前正在运行的容器:docker ps [OPTIONS]

OPTIONS:

(1) -a : 列出当前所有正在运行的容器 + 历史上运行过的

(2) -l : 显示最近创建的容器

(3) -n : 显示最近n个创建的容器

(4) -q : 静默模式,只显示容器编号

2.3.7 容器快照:docker export/import

  • 导出容器快照:docker export

  • 导出容器快照:docker import

    注意:docker load导入的是镜像存储文件

2.3.8 删除容器:docker container rm

可以使用 docker container rm 来删除一个处于终止状态的容器。用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,用下面的命令可以清理掉所有处于终止状态的容器。

# 注:这些命令都需要root权限或者sudo命令来执行

# 删除特定容器
docker container rm  <container-id>

# 删除运行中的容器
docker container rm -f <container-id>

# 删除全部处于终止状态的容器
docker container prune

# stop停止所有容器
docker stop $(docker ps -a -q)
 
# remove删除所有容器
docker rm $(docker ps -a -q)

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

2.4 访问仓库

2.4.1 DockerHub

这是docker官方维护的一个公共仓库:https://cloud.docker.com

# 注:这些命令都需要root权限或者sudo命令来执行

# 命令行中登录/退出dockerhub
docker login
docker logout

# 在dockerhub中搜索镜像
docker search <image-name>

# 下载仓库镜像
docker pull <image-name>

# 推送镜像到dockerhub:例子
docker tag ubuntu:17.10 username/ubuntu:17.10
docker push username/ubuntu:17.10

根据是否是官方提供,可将镜像资源分为两类。

一种是类似 centos 这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。

还有一种类型,比如 tianon/centos 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。可以通过前缀 username/ 来指定使用某个用户提供的镜像,比如 tianon 用户。

2.4.2 私有仓库

在私有仓库中的docker操作类似DockerHub。

三,高级管理与配置

这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

  • 数据卷(Volumes)
  • 挂载主机目录 (Bind mounts)

3.1 数据管理

3.1.1 数据卷

数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷 可以在容器之间共享和重用
  • 对 数据卷 的修改会立马生效
  • 对 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷。

选择 -v 还是 -–mount 参数

Docker 新用户应该选择 --mount 参数,经验丰富的 Docker 使用者对 -v 或者 --volume 已经很熟悉了,但是推荐使用 --mount 参数。

创建数据卷:

# 创建一个数据卷
docker volume create my-vol

# 查看所有的数据卷
docker volume ls

# 查看指定数据卷
docker volume inspect my-vol

# 查看指定数据卷的详细信息
docker inspect web

# 删除数据卷
docker volume rm my-vol

# 清楚所有数据卷
docker volume prune

启动一个挂载数据卷的容器:

在用 docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个 数据卷。

下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /webapp 目录。

docker run -d -P \
    --name web \
    # -v my-vol:/wepapp \
    --mount source=my-vol,target=/webapp \
    training/webapp \
    python app.py

3.1.2 挂载主机目录

挂载一个主机目录作为数据卷

# 使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去
docker run -d -P \
    --name web \
    # -v /src/webapp:/opt/webapp \
    --mount type=bind,source=/src/webapp,target=/opt/webapp \
    training/webapp \
    python app.py

上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 -v 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount 参数时如果本地目录不存在,Docker 会报错。

Docker 挂载主机目录的默认权限是 读写,用户也可以通过增加 readonly 指定为 只读。

# 查看数据卷的具体信息
docker inspect web

# 挂载主机目录 的配置信息在 "Mounts" Key 下面
"Mounts": [
    {
        "Type": "bind",
        "Source": "/src/webapp",
        "Destination": "/opt/webapp",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
],

挂载一个本地主机文件作为数据卷

# --mount 标记也可以从主机挂载单个文件到容器中
docker run --rm -it \
   # -v $HOME/.bash_history:/root/.bash_history \
   --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
   ubuntu:17.10 \
   bash

root@2affd44b4667:/# history
1  ls
2  diskutil list
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值