操作系统为 CentOS 7.9 。
第一章:Docker 简介
1.1 Docker 是什么?
1.1.1 为什么会出现 Docker ?
- 如果我们正在开发一个商城系统,使用是一台笔记本电脑,并且本地的开发环境具有特定的配置,然而其他开发人员身处的环境以及配置也各不相同。我们正在开发的应用依赖于我们当前的配置,并且还要依赖于某些配置文件。此外,企业还拥有标准化的测试和生产环境,具有自身的配置和一系列的支持文件,如果我们希望尽可能多的在本地模拟这些环境而不产生重新创建服务器环境的开销,怎么办?
- 我们如何确保应用能够在这些环境中运行并通过质量检测?在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复?
- 答案就是使用容器。Docker 之所以发展如此迅速,也是因为它给出了一个标准化的解决方案 ——
系统平滑迁移,容器虚拟化技术
。 - 环境配置相当麻烦,换一台机器,就要重新再来一次,费时费力。很多人相当,能不能从根本上解决问题,
软件可以带环境安装?
换言之,安装的时候,将原始的环境一模一样的复制过来
。开发人员利用 Docker 可以消除协作编码时 “在我的机器上可以正常工作” 的问题。
- 之前在服务器配置一个应用的运行环境,需要安装各种软件,就拿电商系统的环境来说,JDK、RabbitMQ、Redis、MySQL 等,安装和配置这些软件有多麻烦不说,它还不能跨平台。假如我们在 Windows 上安装的这些环境,到了 Linux 又需要重新安装。况且就算不跨操作系统,换另一台同样的操作系统的服务器,要
移植
应用也是非常麻烦。 - 传统上认为,软件编码开发、测试结束后,所产出的成果就是程序或者能编译执行的二进制字节码等。而为了让这些程序可以顺利的执行,开发团队也需要准备完整的部署文档,以便运维团队得以部署应用系统,
开发需要清楚的告诉运维团队,所用的全部配置文件和所有的软件环境
。不过,即便如此,依然会发生部署失败的状况。Docker 的出现使得 Docker 得以打破以前的『 程序即应用 』的概念
。通过镜像(images)将系统内核除外,运行应用程序所需要的系统环境,由下向上打包,达到应用程序间跨平台间的无缝接轨运作。
1.1.2 Docker 的理念
Docker 是基于 GO 语言实现的云开源项目
。- Docker 的主要目标是
“Build,Ship and Run Any App,Anywhere”
,也就是通过对应用组件的封装、分发、部署、运行等生命周期的姑奶,使得用户的 APP (可以是一个 WEB 应用或者数据库应用等)及其运行环境能够做到一次镜像,处处运行
。
Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的
。将应用打成镜像,通过镜像成为运行在 Docker 容器上面的实例,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机器就可以一键部署,大大简化了操作流程
。
1.1.3 总结
- Docker 解决了
运行环境和配置问题
的软件容器
,可以方便做持续集成并有助于整体发布的容器虚拟化技术。
1.2 容器 VS 虚拟机
1.2.1 容器发展简史
1.2.2 传统虚拟化技术
- 虚拟机(Virtual Machine)就是带环境安装的一种解决方案。
- 它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 10 系统里面运行 Linux 系统 CentOS 7 。应用程序对此毫无感知,因为虚拟机看上去和真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了删除即可,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序、操作系统和硬件三者的逻辑不变。
- 传统虚拟机技术基于安装在主操作系统上的虚拟机管理系统(如:VirtualBox 和 VMWare 等),可以创建虚拟机(虚拟各种硬件),在虚拟机上安装从操作系统,然后在从操作系统上安装部署各种应用。
- 虚拟机的缺点:
- ① 资源占用多。
- ② 冗余步骤多。
- ③ 启动慢。
1.2.3 容器虚拟化技术
- 由于传统虚拟机的某些缺点,Linux 发展出了另外一种虚拟化技术:
Linux 容器(Linux Containers,简称为 LXC)
。 - Linux 容器是和系统其他部分隔离的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因此在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。
Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离
。有了容器,就可以将软件运行的所有资源打包到一个隔离的容器中。容器和虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置
。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一的运行。
- Docker 容器是在操作系统层面上实现虚拟化,直接复用本地主机上的操作系统,而传统虚拟机则是在硬件层面实现虚拟化。和传统虚拟机相比,Docker 优势体现为启动速度快、占用体积小。
1.2.4 对比
- ① 传统的虚拟机是虚拟出一整套硬件后,在其上运行一个完整的操作系统,在该系统上再运行所需要的应用进程。
- ② 容器内的应用进程直接运行于宿主机的内核,
容器内没有自己的内核也没有直接进行硬件虚拟
。因此容器要比传统虚拟机更为轻便。 - ③ 每个容器之间互相隔离,每个容器都有自己的文件系统,容器之间的进程不会相互影响,能区分计算资源。
1.3 Docker 能干嘛?
1.3.1 技术职称变化
- coder。
- programmer。
- software engineer。
- DevOps engineer。
1.3.2 开发运维(DevOps)新一代开发工程师
- 一次构建,到处运行:
- 更快速的应用交付和部署:传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker 化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。
- 更便捷的升级和扩缩容:随着微服务架构和 Docker 的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个 Docker 容器将变成一块
“积木”
,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。 - 更简单的系统运维:应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的 BUG 。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。
- 更高效的计算资源利用:Docker 是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的 Hypervisor 支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的 CPU 和内存的利用率。
- Docker 应用场景:Docker 借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地,Docker 将这个模型运用到自己的设计中,唯一不同的是:集装箱运输货物,而 Docker 运输软件。
1.4 Docker 去哪下?
第二章:Docker 安装和卸载
2.1 前提说明
- CentOS 7 安装 Docker:
- Docker 并非是一个通用的容器工具,它依赖于已经存在并运行的 Linux 内核环境。
- Docker 实际上是在已经运行的 Linux 下制造一个隔离的文件环境,因此它执行的效率几乎等同于所部署的 Linux 主机。
- 因此,Docker 必须部署在 Linux 内核的系统上。如果其他系统想要部署 Docker 就必须要安装一个虚拟的 Linux 环境。
- 在 Windows 系统上部署 Docker 的方法就是先安装一个虚拟机,并在安装 Linux 系统的虚拟机中运行 Docker(当然,现在 Win 10+ 系统也支持 Docker ,本次不考虑)。
- 前提条件:
- 目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在 CentOS 7 (64-bit)上,要求系统为 64 位、Linux 系统内核版本为 3.8 以上,这里选用 Centos 7.9 。
- 查看 CentOS 的版本:
cat /etc/redhat-release
- 查看 Linux 内核:
uname -r
2.2 Docker 的基本组成
2.2.1 镜像(image)
- Docker 镜像(image)就是一个
只读
的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器
。 - Docker 镜像相当于一个 root 文件系统。比如:官方镜像中的
centos:7
就包含了一套完成的 CentOS7 最小系统的 root 文件系统。 - Docker 镜像相当于容器的
源代码
,Docker 镜像文件类似于 Java 的类模板,Docker 容器实例就类似于 Java 中 new 出来的实例对象。 - 容器和镜像的关系类似于面向对象编程中的对象和类: | Docker | 面向对象 | | —- | —- | | 镜像 | 类 | | 容器 | 对象 |
2.2.2 容器(container)
- 从面向对象角度:Docker 利用容器(container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,
容器是用镜像创建的运行实例
。就像是 Java 中的类和实例对象一样,镜像是静态的定义,容器是镜像运行的实例。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。 - 从镜像容器角度:
可以将容器看做是一个简易版的 Linux 环境
(包括 root 用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
2.2.3 仓库(registry)
- 仓库(registry)是
集中存放镜像文件
的场所。 - 仓库类似于 Maven 仓库,存放各种 jar 包的地方;也类似于 github 仓库,存放各种 git 项目的地方。
- Docker 容器提供的官方 registry 被称为 Docker Hub,存放各种镜像模板的地方。
- 仓库分为公开仓库(public)和私有仓库(private)两种,最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。
- 国内的公开仓库包括阿里云、网易云等。
2.2.4 总结
- Docker 本身是一个容器运行载体或称之为管理引擎。我们将应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是 image 镜像文件,只有通过这个镜像文件才能生成 Docker 容器实例(类似于 Java 中 new 出来的一个对象)。
- image 文件可以看做是容器的模板,Docker 根据 image 文件生成容器的实例,同一个 image 文件,可以生成多个同时运行的容器实例。
2.3 Docker 平台架构
- Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
- Docker 运行的基本流程为:
- ① 用户是使用 Docker Client 和 Docker Daemon 建立通信,并发送请求给后者。
- ② Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
- ③ Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以 Job 的形式存在的。
- ④ Job 的运行过程中,当需要容器镜像时,从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver 将下载的镜像以 Graph 的形式存储。
- ⑤ 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
- ⑥ 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Exec driver 来完成。
- ⑦ Libcontainer 是一项独立的容器管理包,Network driver 以及 Exec driver 都是通过 Libcontainer 来实现具体对容器进行的操作。
2.4 Docker 的隔离原理
2.4.1 概述
- Docker 用 Go 编程语言编写,并利用 Linux 内核的多种功能来交付其功能。 Docker 使用一种称为名称空间的技术来提供容器的隔离工作区。 运行容器时,Docker 会为该容器创建一组名称空间。 这些名称空间提供了一层隔离。 容器的每个方面都在单独的名称空间中运行,并且对其的访问仅限于该名称空间。
2.4.2 namespace 6 项隔离 (资源隔离)
namespace | 系统调用参数 | 隔离内容 |
---|---|---|
UTS | CLONE_NEWUTS | 主机和域名。 |
IPC | CLONE_NEWIPC | 信号量、消息队列和共享内存。 |
PID | CLONE_NEWPID | 进程编号。 |
Network | CLONE_NEWNET | 网络设备、网络栈、端口等。 |
Mount | CLONE_NEWNS | 挂载点(文件系统)。 |
User | CLONE_NEWUSER | 用户和用户组。 |
2.4.3 cgroups 资源限制
- cgroup 提供的主要功能如下:
- 资源限制:限制任务使用的资源总额,并在超过这个配额时发出提示。
- 优先级分配:分配CPU时间片数量及磁盘 IO 带宽大小、控制任务运行的优先级。
- 资源统计:统计系统资源使用量,如 CPU 使用时长、内存用量等。
- 任务控制:对任务执行挂起、恢复等操作。
- cgroup 资源控制系统,每种子系统独立地控制一种资源。功能如下: | 子系统 | 功能 | | —- | —- | | cpu | 使用调度程序控制任务对 CPU 的使用。 | | cpuacct(CPU Accounting) | 自动生成 cgroup 中任务对 CPU 资源使用情况的报告。 | | cpuset | 为 cgroup 中的任务分配独立的 CPU (多处理器系统时)和内存。 | | devices | 开启或关闭 cgroup 中任务对设备的访问。 | | freezer | 挂起或恢复 cgroup 中的任务。 | | memory | 设定 cgroup 中任务对内存使用量的限定,并生成这些任务对内存资源使用情况的报告。 | | perf_event(Linux CPU 性能探测器) | 使 cgroup 中的任务可以进行统一的性能测试。 | | net_cls(Docker 未使用) | 通过等级识别符标记网络数据包,从而允许 Linux 流量监控程序(Traffic Controller)识别从具体 cgroup 中生成的数据包。 |
2.5 Docker 的安装
2.5.1 准备工作
操作系统 | IP 地址 |
---|---|
CentOS 7.9 | 192.168.65.100 |
注意:请确保你的 CentOS 7.9 能连上互联网。
2.5.2 关闭防火墙
- 命令:
# 关闭防火墙
systemctl stop firewalld
# 禁用防火墙开机自动启动
systemctl disable firewalld
2.5.3 卸载旧版本
- 命令:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2.5.4 yum 安装 gcc 相关
- 命令:
yum -y install gcc
yum -y install gcc-c++
2.5.5 安装所需要的软件包
- 命令:
yum -y install yum-utils
2.5.6 设置 stable 镜像仓库
- 命令:
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
2.5.7 更新 yum 软件包索引
- 命令:
yum makecache fast
2.5.8 查看存储库中 Docker 的版本
- 命令:
yum list docker-ce --showduplicates | sort -r
2.5.9 安装 Docker
- 命令:安装指向版本的 Docker,用上面查询的版本号替换
,如果不指定就安装最新版本的
yum -y install docker-ce-<VERSION_STRING>.x86_64 docker-ce-cli-<VERSION_STRING>.x86_64 containerd.io
- 命令:安装最新版本的 Docker
yum -y install docker-ce docker-ce-cli containerd.io
注意
:本次安装的版本是 3:20.10.9-3.el7
yum -y install docker-ce-3:20.10.9-3.el7.x86_64 docker-ce-cli-3:20.10.9-3.el7.x86_64 containerd.io
2.5.10 启动 Docker
- 命令:
# 启动 Docker
systemctl start docker
# 开启自动启动
systemctl enable docker
2.5.11 验证 Docker 是否安装成功
- 命令:
docker version
2.5.12 阿里云镜像加速
- 命令:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://du3ia00u.mirror.aliyuncs.com"],
"live-restore": true,
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"},
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"storage-driver": "overlay2"
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
2.6 解决警告
- 如果发现 WARNING: IPv4 forwarding is disabled. Networking will not work. 这样的警告。
- 解决方案:
vim /etc/sysctl.conf
net.ipv4.ip_forward=1 # 添加这段代码
systemctl restart network && systemctl restart docker
2.7 Docker 的卸载
- 命令:
systemctl stop docker
systemctl disable docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
2.8 为什么 Docker 比 VM 虚拟机快?
- ① Docker 有着比虚拟机更少的抽象层:由于 Docker 不需要 Hypervisor (虚拟机) 实现硬件资源虚拟化,运行在 Docker 容器上的程序直接使用的都是实际物理机的硬件资源,因此在 CPU 、内存利用率上 Docker 将会在效率上有明显的优势。
- ② Docker 利用的是宿主机的内核,而不需要加载操作系统 OS 内核:当新建一个容器的时候,Docker 不需要和虚拟机一样重新加载一个操作系统内核。进而避免了寻找、加载操作系统内核返回等比较耗时耗资源的过程;当新建一个虚拟机的时候,虚拟机需要加载 OS ,返回新建过程是分钟级的。而 Docker 由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个 Docker 容器只需要几秒钟。
第三章:Docker 常用命令
3.1 帮助启动类命令
3.1.1 启动 Docker
- 命令:
systemctl start docker
3.1.2 停止 Docker
- 命令:
systemctl stop docker
3.1.3 重启 Docker
- 命令:
systemctl restart docker
3.1.4 查看 Docker 状态
- 命令:
systemctl status docker
3.1.5 开启自动启动 Docker
- 命令:
systemctl enable docker
3.1.6 查看 Docker 概要信息
- 命令:
docker info
3.1.7 查看 Docker 总体帮助文档
- 命令:
docker --help
3.1.8 查看 Docker 命令帮助文档
- 命令:
docker 具体命令 --help
3.2 镜像命令
3.2.1 列出本地主机上的镜像
- 命令:
docker images [-qa]
- 参数:
- -q:只列出镜像 ID 。
- -a:列出所有镜像,包括历史镜像。
注意
:在 Docker 中镜像名称 + TAG = 镜像 ID ,容器名称 = 容器 ID 。
- 示例:
docker images
注意:
- 同一个仓库中可以有多个 tag 版本,代表这个仓库的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
- 如果不知道一个镜像的版本标签,比如:只是用了 ubuntu,Docker 将默认使用 ubuntu:latest 镜像。
3.2.2 搜索镜像
- 命令:
docker search 镜像名称
- 示例:
docker search redis
3.2.3 拉取镜像
- 命令:
docker pull 镜像名称[:TAG]
注意
:没有 TAG 就表示 latest 。
- 示例:
docker pull mysql:5.7
3.2.4 查看镜像、容器、数据卷所占的空间
- 命令:
docker system df
- 示例:
docker system df
3.2.5 删除镜像
- 命令:删除某个镜像
docker rmi 镜像名称|镜像ID
- 命令:强制删除某个镜像
docker rmi -f 镜像名称|镜像ID
- 命令:强制删除所有的镜像
docker rmi -f $(docker images -qa)
- 示例:
docker rmi ubuntu
docker rmi mysql:5.7
- 示例:
docker rmi -f mysql
- 示例:
docker rmi -f $(docker images -qa)
3.3 容器命令
3.3.1 前提说明
- 有镜像才能创建容器,这是根本前提,本次以 ubuntu 为例演示。
- 拉取 ubuntu :
docker pull ubuntu
3.3.2 新建 + 启动容器
- 命令:
docker run [OPTIONS] 镜像名称|镜像ID [COMMAND] [ARG...]
- OPTIONS(可选项):
--name="容器名称"
,为容器指定一个名称。-d
:后台运行容器并返回容器 ID ,即启动守护式容器(后台运行)。-i
:以交互模式运行容器,通常和 -t 同时使用。-t
:为容器重新分配一个伪输入终端,通常和 -i 同时使用,即启动交互式容器(前台有伪终端,等待交互)。- -P:随机端口映射。
-p
:指定端口映射。- —dns 8.8.8.8:指定容器使用的 DNS 服务器,默认和宿主一致。
- —dns-search example.com:指定容器 DNS 搜索域名,默认和宿主一致。
- -h “mars”:指定容器的 hostname 。
-e username="dog"
:设置环境变量。--env-file=[]
:从指定文件读入环境变量。--cpuset="0-2" or --cpuset="0,1,2"
:绑定容器到指定 CPU 运行。-m
:设置容器使用内存最大值。--network="bridge"
:指定容器的网络连接类型,支持 bridge 、host 、none、container 四种类型,默认 bridge 。- —link=[]:添加链接到另一个容器。
- —expose=[]:开放一个端口或一组端口。
--restart
:指定重启策略,可以写 —restart=awlays 总是故障重启。--volume , -v
::绑定一个卷。一般格式为主机文件或文件夹:虚拟机文件或文件夹
。
- COMMAND(启动命令)。
ARG(启动参数)。
示例:启动交互式容器:
docker run -it --name=ubuntu ubuntu /bin/bash
3.3.3 列出当前所有正在运行的容器
- 命令:
docker ps [-qa]
参数:
- -a:累出当前所有正在运行的容器 + 历史上运行过的容器。
- -q:只显示容器编号。
示例:
docker ps
3.3.4 退出容器
- ① exit :run 进容器,exit 退出,容器停止。
② ctrl + p + q:run 进容器,ctrl + p + q 退出,容器不停止。
示例:
exit
- 示例:
ctrl + p + q
3.3.5 启动已停止的容器
- 命令:
docker start 容器名称或容器ID
- 示例:
docker start ubuntu
3.3.6 重启容器
- 命令:
docker restart 容器名称或容器ID
- 示例:
docker restart ubuntu
3.3.7 停止容器
- 命令:
docker stop 容器名称或容器ID
- 示例:
docker stop ubuntu
3.3.8 强制停止容器
- 命令:
docker kill 容器名称或容器ID
- 示例:
docker kill ubuntu
3.3.9 删除已停止的容器
- 命令:
docker rm 容器名称或容器ID
- 命令:一次强制删除多个容器
docker rm -f $(docker ps -qa)
docker ps -qa | xargs docker rm -f
- 示例:
docker rm -f ubuntu
- 示例:
docker rm -f $(docker ps -qa)
3.3.10 实验
3.3.10.1 前提说明
- 本次以 Redis 6.0.8 镜像作为演示。
3.3.10.2 拉取镜像
- 命令:
docker pull redis:6.0.8
3.3.10.3 启动守护式容器
- 在大部分场景下,我们希望 Docker 的服务是在后台运行的,我们可以通过 -d 指定容器的后台运行模式。
- 命令:
docker run -d 容器名
- 示例:启动 ubuntu 容器,以守护式方式
docker run -d unbutu
如果用 docker ps 查看,会发现容器已经退出了,这是因为
Docker 容器后台运行的时候,必须有一个前台的进程
,这个是 Docker 的机制问题:如果容器中运行的命令不是一直挂起的命令(比如:top、tail 等),当容器以守护式方式启动就会退出容器;当然如果是命令行模式,表示有交互默认,Docker 也会认为是前台进行的方式启动,不会将容器杀死。
- 示例:以交互式方式启动 redis 容器:
docker run -it redis:6.0.8 /bin/bash
- 示例:以守护式启动 redis 容器
docker run -d redis:6.0.8
3.3.10.4 查看容器日志
- 命令:
docker logs [-f] 容器名称|容器ID
- 示例:
docker logs -f redis
3.3.10.5 查看容器内运行的进程
- 命令:
docker top 容器名称|容器ID
- 示例:
docker top redis
3.3.10.6 查看容器内部细节
- 命令:
docker inspect 容器名称|容器ID
- 示例:
docker inspect redis
3.3.10.7 进入正在运行的容器并以命令行交互
- 命令:
docker exec -it 容器名称|容器ID [COMMAND]
注意:使用 exec 时,当 exit 退出容器时,不会导致容器终止。
- 示例:
docker exec -it redis /bin/bash
3.3.10.8 容器和主机文件的互相拷贝
- 命令:拷贝容器中的文件到主机
docker cp CONTAINER:SRC_PATH DEST_PATH|-
- 命令:拷贝主机文件到容器内
docker cp SRC_PATH|- CONTAINER:DEST_PATH
说明:
- SRC_PATH:指定为一个文件。
- DEST_PATH 不存在:文件名为 DEST_PATH,内容为SRC的内容。
- DEST_PATH 不存在并且以 / 结尾:报错。
- DEST_PATH 存在并且是文件:目标文件内容被替换为 SRC_PATH 的文件内容。
- DEST_PATH 存在并且是目录:文件复制到目录内,文件名为 SRC_PATH 指定的名字。
- SRC_PATH:指定为一个目录。
- DEST_PATH 不存在:DEST_PATH 创建文件夹,复制源文件夹内的所有内容。
- DEST_PATH 存在是文件:报错。
- DEST_PATH 存在是目录:
- SRC_PATH 不以 /. 结束:源文件夹复制到目标里面。
- SRC_PATH 以 /. 结束:源文件夹里面的内容复制到目标里面。
- 自动创建文件夹不会做递归。需要把父文件夹手动创建。
- SRC_PATH:指定为一个文件。
示例:
docker cp redis:/data/a.txt .
3.3.10.9 导入和导出容器(不常用)
- 命令:导出容器,将容器的内容导出为一个 tar 包(或 tar.gz 包,以及 zip 包)
docker export 容器ID|容器名称 > 文件名.tar
- 命令:导入容器,从 tar 包(或 tar.gz 包,以及 zip 包)中的内容创建一个新的文件系统再导入为镜像
docker import 文件名.tar 镜像名称:TAG|[用户名/镜像名称:TAG]
- 示例:
docker export redis > redis.tar.gz
docker import redis.tar.gz xudaxian/redis
3.4 总结
命令 | 描述 |
---|---|
attach | 当前 shell 下 attach 连接指定运行镜像。 |
build | 通过 Dockerfile 定制镜像。 |
commit | 提交当前容器为新的镜像。 |
cp | 从容器中拷贝指定文件或者目录到宿主机中。 |
create | 创建一个新的容器,同 run,但不启动容器。 |
diff | 查看 docker 容器变化。 |
events | 从 docker 服务获取容器实时事件。 |
exec | 在已存在的容器上运行命令。 |
export | 导出容器的内容流作为一个 tar 归档文件[对应 import ]。 |
history | 展示一个镜像形成历史。 |
images | 列出系统当前镜像。 |
import | 从tar包中的内容创建一个新的文件系统映像[对应 export ]。 |
info | 显示系统相关信息。 |
inspect | 查看容器详细信息。。 |
kill | kill 指定 docker 容器 |
load | 从一个 tar 包中加载一个镜像[对应 save ]。 |
login | 注册或者登陆一个 docker 源服务器。 |
logout | 从当前 Docker registry 退出。 |
logs | 输出当前容器日志信息。 |
port | 查看映射端口对应的容器内部源端口。 |
pause | 暂停容器。 |
ps | 列出容器列表。 |
pull | 从docker镜像源服务器拉取指定镜像或者库镜像。 |
push | 推送指定镜像或者库镜像至docker源服务器。 |
restart | 重启运行的容器。 |
rm | 移除一个或者多个容器。 |
rmi | 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]。 |
run | 创建一个新的容器并运行一个命令。 |
save | 保存一个镜像为一个 tar 包[对应 load ]。 |
search | 在 docker hub 中搜索镜像。 |
start | 启动容器。 |
stop | 停止容器。 |
tag | 给源中镜像打标签。 |
top | 查看容器中运行的进程信息。 |
unpause | 取消暂停容器。 |
version | 查看 docker 版本号。 |
wait | 截取容器停止时的退出状态值。 |
第四章:Docker 镜像
4.1 概述
4.1.1 Docker 镜像是什么?
- 镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需要的所有内容,我们将应用程序和配置打包好形成一个可交付的运行环境(包括代码、运行时所需要的库、环境变量和配置文件等),这个打包好的运行环境就是 image 镜像文件。
- 只有通过镜像文件才能生成 Docker 容器实例。
4.1.2 分层的镜像
- 以拉取 tomcat 镜像为例,我们可以看到 Docker 的镜像好像是一层层的下载。
- 命令:
docker pull tomcat
4.1.3 UnionFS(联合文件系统)
注意:UnionFS 的实现是 aufs 存储驱动,而 aufs 是 Docker 存储驱动的简单实现,如果 Linux 内核是 4.0+ 版本,推荐使用 overlay2 存储驱动,当然我们在安装的时候已经指定了 overlay2 存储驱动。
- UnionFS(联合文件系统):Union 文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(
scratch
,没有父镜像),可以制作各种具体的应用镜像。
- 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
4.1.4 Docker 镜像的加载原理
- Docker 的镜像实际上由一层层的文件系统组成,这种层级的文件系统就是 UnionFS 。
- bootfs (boot file system)主要包含 bootloader 和 kernel ,bootloader 主要是引导加载 kernel ,Linux 刚启动的时候会加载 bootfs 文件系统,在 Docker 镜像的最底层是引导文件 bootfs。这一层和典型的 Linux/Unix 系统是一样的,包含 bootloader 和 kernel,当 bootloader 加载完成之后整个内核就在内存之中了,此时内存的使用权已经由 bootfs 转交给内核,此时系统也会卸载 bootfs 。
- rootfs(root file system),在 bootfs 之上,包含的就是典型 Linux 系统中的 /dev、/proc、/etc 等标准目录和文件。rootfs 就是各种不同操作系统发行版,如:ubuntu、centos 等。
- 『问』平时我们安装进虚拟机的 CentOS 都是 4G 以上,为什么Docker 才 200+ MB?
- 『答』对于一个精简的 OS ,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用的宿主机的 kernel ,自己只需要提供 rootfs 就可以了。由此可见对于不同的 Linux 发行版,bootfs 基本是一致的,rootfs 会有所差别,因为不同的发行版可以共用 bootfs 。
4.1.5 为什么 Docker 镜像要采用这种分层结构?
- 镜像分层最大的一个好处就是共享资源,方便复制迁移。
- 比如:多个镜像都是从相同的 base 镜像构建而来,那么 Docker 只需要在磁盘中保存一份 base 镜像,同时内存中也只是加载一份 base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。
4.2 Docker 镜像的理解
- 写时复制,用时分配:
Docker 镜像层都是只读的,容器层是可写的
。 - 当容器启动的时候,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层之下的都叫做镜像层。
- 所有对容器的改动,无论添加、删除还是修改文件都只会发生在容器层中,只有容器层是可写的,容器层下面的所有镜像层都是只读的。
4.3 使用 commit 制作镜像
- 需求:在 ubuntu 镜像(官方镜像)中添加 vim 命令,安装制作为新的镜像。
- 命令:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:TAG
- 示例:
- ① 拉取 ubuntu 镜像到本地:
docker pull ubuntu
- ② 运行 ubuntu 镜像,查看是否携带 vim 命令:
docker run -it --name="ubuntu" ubuntu /bin/bash
vim a.txt
- ③ 在连接互联网的情况下,在容器内部安装 vim :
# 更新包管理器
apt-get update
# 安装 vim 命令
apt-get -y install vim
- ④ 安装完成后,commit 新的镜像:
docker commit -m="安装有vim的ubuntu镜像" -a="许大仙" ubuntu xudaxian/ubuntu
- ⑤ 启动新的镜像,并进行测试:
docker run -it --name="xudaxian-ubuntu" xudaxian/ubuntu /bin/bash
vim a.txt
4.4 总结
- Docker 中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似于 Java 中继承一个 Base 基础类,然后自己按需扩展。
- 新的镜像是从 base 镜像一层一层的叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
第五章:本地镜像发布到阿里云
5.1 本地镜像发布到阿里云流程
5.2 镜像的生成方法
- ① 基于当前容器创建镜像,使用 docker commit 命令。
- ② 基于 Dockerfile 文件。
5.3 本地镜像推送到阿里云
5.3.1 创建仓库镜像
- 选择控制台,进入容器镜像服务。
- 选择个人实例:
- 命名空间:
- 镜像仓库:
5.3.2 将镜像推送到阿里云:
- 登录阿里云:
docker login --username=**** registry.cn-shanghai.aliyuncs.com
- 查看镜像,并给镜像打标签:
docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/xudaxian/xudaxian-ubuntu:[镜像版本号]
- 推送镜像:
docker push registry.cn-shanghai.aliyuncs.com/xudaxian/xudaxian-ubuntu:1.0
5.4 将阿里云上的镜像下载到本地
- 删除本地镜像:
docker rmi -f registry.cn-shanghai.aliyuncs.com/xudaxian/xudaxian-ubuntu:1.0
- 下载镜像到本地:
docker pull registry.cn-shanghai.aliyuncs.com/xudaxian/xudaxian-ubuntu:1.0
第六章:本地镜像发布到私有库
6.1 本地镜像发布到私有库流程
6.2 Docker Registry
- Docker Registry 是官方提供的工具,可以用于构建私有镜像仓库。
6.3 将本地镜像推送到私有库
- 下载 Docker Registry 镜像:
docker pull registry
- 运行Docker Registry 私有库 ,相当于本地有个私有的 Docker Hub:
docker run -d -p 5000:5000 --name="registry" -v /var/registry/:/tmp/registry --privileged=true registry
注意:默认情况,仓库被创建在容器的 /var/lib/registry 目录下,建议自行用容器卷映射,方便于宿主机联调。
- curl 验证私服库上有什么镜像:
curl -XGET http://192.168.65.100:5000/v2/_catalog
- 命令:将镜像打标签
docker tag 镜像:Tag Host:Port/Repository:Tag
- 示例:
docker tag xudaxian/ubuntu 192.168.65.100:5000/xudaxian-ubuntu:1.0
- 修改配置文件以支持 http :
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://du3ia00u.mirror.aliyuncs.com"],
"live-restore": true,
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"},
"storage-driver": "overlay2",
"insecure-registries":["192.168.65.100:5000"]
}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker
- 将本地镜像推送到私有库:
docker push 192.168.65.100:5000/xudaxian-ubuntu:1.0
- curl 验证私服库上有什么镜像:
curl -XGET http://192.168.65.100:5000/v2/_catalog
- 拉取本地镜像:
docker pull 192.168.65.100:5000/xudaxian-ubuntu:1.0
第七章:Docker 容器数据卷
7.1 坑
- 容器卷记得加入
--privileged=true
。 - Docker 挂载主机目录访问,如果出现 cannot open directory .: Permission denied ,解决方法就是在挂载目录的时候添加
--privileged=true
参数即可。 - 因为 CentOS 7 安全模块会之前的系统版本要强,不安全的会先禁止掉,目录挂载默认被认为是不安全的行为。如果我们要开启,一般使用
--privileged=true
,扩大容器的全局解决挂载目录没有权限的问题,即用了该参数,容器内的 root 就拥有了外部主机的真正的 root 权限;否则,容器内的 root 只是外部主机的一个普通用户。
注意
:学习的时候,可以使用该参数,但是如果使用 Dockerfile 来制作镜像的时候,禁止使用 root 用户来制作镜像,推荐使用普通用户制作镜像,防止被黑客攻击。
7.2 Docker 容器数据卷是什么?
- 卷就是目录或文件,存在于一个或多个容器中,由 Docker 挂载到容器,但是不属于联合文件系统(UnionFS),因此能够绕过 UnionFS 提供一些用于持续存储或共享数据的特性。
- 卷的设计目的就是
数据的持久化
,完全独立于容器的生命周期,因此 Docker 不会在容器删除的时候删除其挂载的容器数据卷。 - 命令:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
- 总结:将 Docker 容器内的数据保存进宿主机的磁盘中。
7.3 Docker 容器数据卷能干嘛?
- 将应用和运行的环境打包成镜像,run 后形成容器实例运行,但是我们希望
数据能够持久化
。Docker 容器产生的数据,如果不使用容器数据源,当容器实例删除之后,容器内的数据自然就丢失了,为了解决这个问题,我们使用了容器的数据卷功能。
7.4 Docker 容器数据卷的特点
- ① 数据卷可以在容器之间共享或重用数据。
- ② 数据卷中的更改可以实时生效。
- ③ 数据卷中的更改不会包含在镜像的更新中。
- ④ 数据卷的生命周期一直持续到没有容器使用它为止。
7.5 Docker 容器数据卷案例
7.5.1 宿主机和容器之间映射添加容器数据卷
- 命令:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
- 示例:
docker run -it --privileged=true -v /tmp/ubuntu:/tmp/docker --name=ubuntu ubuntu
- 查看数据卷是否挂载成功:
docker inspect 容器ID|容器名称
- 示例:
docker inspect ubuntu
7.5.2 读写规则映射添加说明
- 默认情况下,容器内目录是读写(rw),对应的命令为:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
- 如果想设置容器内目录只能读取,不能写入,可以设为只读(ro),对应的命令为(此时如果宿主机写入内容,可以同步给容器内,容器可以读取数据):
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
7.5.3 容器数据卷的继承和共享
- ① 容器 1 完成和宿主机的映射:
docker run -it --privileged=true -v /var/tmp:/tmp --name u1 ubuntu
- ② 容器 2 继承容器 1 的卷规则:
docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu
注意:继承的仅仅是容器数据卷的映射规则,容器 1 和 容器 2 之间并没其他什么关系,容器 1 挂了不会影响到 容器 2 。
第八章:Docker 应用常规安装
8.1 总体步骤
- ① 搜索镜像。
- ② 拉取镜像。
- ③ 查看镜像。
- ④ 启动容器:服务端口映射。
- ⑤ 停止容器。
- ⑥ 移除容器。
注意
:拉取镜像或者使用 Dockerfile 制作镜像的时候,尽量选择镜像带有alpine
或slim
后缀的,因为这种类型的镜像的体积相对而言比较小,更易于构建和传输。
8.2 安装 MySQL
- 搜索镜像:
docker search mysql
- 拉取镜像:
docker pull mysql:5.7
- 查看镜像:
docker images
- 启动容器:
docker run -d -p 3306:3306 --name mysql5.7 -v /var/mysql5.7/conf:/etc/mysql/conf.d -v /var/mysql5.7/logs:/var/log/mysql -v /var/mysql5.7/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -e MYSQL_DATABASE=ssm --restart=always mysql:5.7 --lower_case_table_names=1 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --default-authentication-plugin=mysql_native_password
8.3 安装 Tomcat
- 搜索镜像:
docker search tomcat
- 拉取镜像:
docker pull billygoo/tomcat8-jdk8
- 查看镜像:
docker images
- 启动容器:
docker run -d -p 8080:8080 --name tomcat8 billygoo/tomcat8-jdk8
8.4 安装 Redis
- 搜索镜像:
docker search redis
- 拉取镜像:
docker pull redis:6.0.8
- 查看镜像:
docker images
- 启动容器:
docker run -p 6379:6379 --name redis -v /var/redis/data:/data -d redis:6.0.8 redis-server --appendonly yes --requirepass "123456"
- 使用配置文件启动 Redis 容器:
vim /var/redis/redis.conf
# 更多配置参照 https://raw.githubusercontent.com/redis/redis/6.0/redis.conf
port 6379
appendonly yes
docker run -p 6379:6379 --name redis -v /var/redis/data:/data -v /var/redis/redis.conf:/etc/redis/redis.conf -d redis:6.0.8 redis-server /etc/redis/redis.conf --appendonly yes
第九章:其他
9.1 Docker 中容器的状态
- ① Created(新建)。
- ② Up(运行中)。
- ③ Pause(暂停)。
- ④ Exited(退出)。
9.2 docker run 和 docker create 的异同点
- 同:两个命令都可以创建容器。
- 异:docker run 创建完容器后会立即启动(常用);docker create 创建完容器后,需要手动使用 docker start 启动容器。
9.3 Docker 中容器的重启策略
- ① no:默认策略,在容器退出时不重启容器。
- ② on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
- ③ on-failure:3:在容器非正常退出时重启容器,最多重启 3 次。
- ④ always:在容器退出时总是重启容器。
- ⑤ unless-stopped:在容器退出时总是重启容器,但是不考虑在 Docker 守护进程启动时就已经停止了的容器。