Skip to content

Docker(v20.10.x) 基础篇

操作系统为 CentOS 7.9 。

第一章:Docker 简介

1.1 Docker 是什么?

1.1.1 为什么会出现 Docker ?

  • 如果我们正在开发一个商城系统,使用是一台笔记本电脑,并且本地的开发环境具有特定的配置,然而其他开发人员身处的环境以及配置也各不相同。我们正在开发的应用依赖于我们当前的配置,并且还要依赖于某些配置文件。此外,企业还拥有标准化的测试和生产环境,具有自身的配置和一系列的支持文件,如果我们希望尽可能多的在本地模拟这些环境而不产生重新创建服务器环境的开销,怎么办?
  • 我们如何确保应用能够在这些环境中运行并通过质量检测?在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复?
  • 答案就是使用容器。Docker 之所以发展如此迅速,也是因为它给出了一个标准化的解决方案 ---- 系统平滑迁移,容器虚拟化技术
  • 环境配置相当麻烦,换一台机器,就要重新再来一次,费时费力。很多人相当,能不能从根本上解决问题,软件可以带环境安装? 换言之,安装的时候,将原始的环境一模一样的复制过来开发人员利用 Docker 可以消除协作编码时 “在我的机器上可以正常工作” 的问题。

1645865583052-29ceabac-d10a-4928-b885-9a091e14f06d.bmp

  • 之前在服务器配置一个应用的运行环境,需要安装各种软件,就拿电商系统的环境来说,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 应用或者数据库应用等)及其运行环境能够做到 一次镜像,处处运行

1645865618924-76aacb6b-56b6-49dd-b33e-55ffa0db35bf.png

  • Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的 。将应用打成镜像,通过镜像成为运行在 Docker 容器上面的实例,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机器就可以一键部署,大大简化了操作流程

1.1.3 总结

  • Docker 解决了 运行环境和配置问题软件容器 ,可以方便做持续集成并有助于整体发布的容器虚拟化技术。

1.2 容器 VS 虚拟机

1.2.1 容器发展简史

1645865632635-f4176df0-dea5-46a7-97e0-25ee644a03e7.png

1.2.2 传统虚拟化技术

  • 虚拟机(Virtual Machine)就是带环境安装的一种解决方案。
  • 它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 10 系统里面运行 Linux 系统 CentOS 7 。应用程序对此毫无感知,因为虚拟机看上去和真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了删除即可,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序、操作系统和硬件三者的逻辑不变。
  • 传统虚拟机技术基于安装在主操作系统上的虚拟机管理系统(如:VirtualBox 和 VMWare 等),可以创建虚拟机(虚拟各种硬件),在虚拟机上安装从操作系统,然后在从操作系统上安装部署各种应用。

1645865638553-75289ee8-c7f1-492d-a650-4b7d85a09d9f.png

  • 虚拟机的缺点:
    • ① 资源占用多。
    • ② 冗余步骤多。
    • ③ 启动慢。

1.2.3 容器虚拟化技术

  • 由于传统虚拟机的某些缺点,Linux 发展出了另外一种虚拟化技术:Linux 容器(Linux Containers,简称为 LXC)
  • Linux 容器是和系统其他部分隔离的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因此在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。
  • Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离。有了容器,就可以将软件运行的所有资源打包到一个隔离的容器中。容器和虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一的运行。

1645865647837-7f9b85c6-1098-48bc-88db-c66566518f9b.png

  • 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 运输软件。

1645865656649-9cf6c930-9711-4edd-9498-8ce2552ccb27.bmp

1.4 Docker 去哪下?

1.5 Docker 的优缺点

  • Docker 的优点:
    • ① Docker 让软件开发者和维护人员可以非常方便的启动应用程序以及将程序的依赖打包到一个容器中,然后启动 Docker 应用到支持 Docker 的系统平台中,可以很轻松的实现应用的移植性。
    • ② Docker 镜像中包含了应用运行环境和配置文件,所以 Docker 可以简化部署应用的工作,如:可以将 WEB 应用、后台应用(Java、Go 等)、数据库应用(MySQL 等)、Hadoop 集群、消息队列等都可以打包成一个个独立的 Docker 镜像来部署。
    • ③ 提高宿主机(裸金属服务器以及云虚拟机)的系统资源的利用率。
    • ……
  • Docker 的缺点:
    • ① 基本的 Docker 网络管理模式比较简单,主要是基于 Linux 系统的 namespace 进行隔离。
    • ② 和其它系统的网络连通性不够简单,如果使用自定义的地址网段,需要借助其他插件实现和其它网段的互通,提高了网络的整体复杂度。
    • ③ 容器中应用程序的日志不方便查看和收集。
    • ……

第二章:Docker 安装和卸载

2.1  前提说明

  • CentOS 7 安装 Docker:
    • Docker 并非是一个通用的容器工具,它依赖于已经存在并运行的 Linux 内核环境。
    • Docker 实际上是在已经运行的 Linux 下制造一个隔离的文件环境,因此它执行的效率几乎等同于所部署的 Linux 主机。
    • 因此,Docker 必须部署在 Linux 内核的系统上。如果其他系统想要部署 Docker 就必须要安装一个虚拟的 Linux 环境。

1645865664155-76d246f6-4577-4b3d-b8af-53b3c9bd2317.png

- 在 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

1682226692879-5fcd5bfd-4e2c-445b-95bc-0207ca1f6e18.gif

  • 查看 Linux 内核:
uname -sr

1682212802248-eb339fd2-cc69-409e-b221-de13c5733aa7.gif

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 文件,可以生成多个同时运行的容器实例。

1645865710027-3a476e58-5d40-45ff-9aa6-15c4c26417f4.png

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 来实现具体对容器进行的操作。

1645865859897-f5041af6-99df-4e7d-9dbf-e27974017d5a.png

2.4 Docker 基本实现原理

2.4.1 概述

  • Docker 主要通过如下三个方面来实现容器化:
    • ① 使用操作系统的 namespace 隔离系统资源技术,通过隔离 网络PID 进程系统信号量文件系统挂载主机名域名,来实现在同一宿主机系统中,运行不同的容器,并且每个容器之间是 相互隔离,运行互不干扰
    • ② 使用操作系统的 cgroups 系统资源配额功能,限制资源包括:CPU内存(Memory)、块设备(Blkio)、网络(Network)。
    • ③ 通过 OverlayFS 数据存储技术,实现容器 镜像 的物理存储和新建 容器 存储。

2.4.2 namespace 6 项隔离 (资源隔离)

  • 当一台物理主机(宿主机)运行容器的时候,为了避免容器所需系统资源之间的相干扰。Docker 就利用了操作系统的隔离技术 -- namespace ,来实现在同一个操作系统中,不同容器之间的资源可以独立运行。
  • Linux 中的 namespace 是 Linux 系统提供的一种资源隔离技术,可以实现系统资源隔离的列表如下:
namespace 系统调用参数 隔离内容
UTS CLONE_NEWUTS 主机和域名。
IPC CLONE_NEWIPC 信号量、消息队列和共享内存。
PID CLONE_NEWPID 进程编号。
Network CLONE_NEWNET 网络设备、网络栈、端口等。
Mount CLONE_NEWNS 挂载点(文件系统)。
User CLONE_NEWUSER 用户和用户组。
  • 示例:查看系统资源隔离
# 查找进程
ps aux | grep ssh

1682087875569-c64053a4-9288-4523-adb7-dfe6ba2d95d5.png

# 查找 namespace
ls -lah /proc/1294/ns/

1682087932800-d2f09b7b-7ee6-4f3b-882d-df6026251a05.png

2.4.3 cgroups 资源限制

  • 在操作系统解决了 资源相互隔离 的问题之后,还需要解决 资源限制 的问题,即避免在同一个操作系统中,防止有些资源消耗较大的容器,将整个物理机器(宿主机)的硬件资源(如:CPU、内存等)占满。
  • 在 Linux 系统中 cgropus 能够限制的资源列表如下:
子系统 功能
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 中生成的数据包。
  • 示例:查看系统实现的资源限制
cat /proc/cgroups

1682088150307-f515be12-fb97-48c5-9c1e-659412e412c7.png

2.4.3 OverlayFS

  • OverlayFS 是一种堆叠文件系统,它依赖并建立在其它的文件系统之上,如:ext4fs 、xfs 等,但是 OverlayFS 并不直接参与磁盘空间结构的划分,仅仅将原来系统文件中的文件和目录进行 "合并"一起 的功能,最终给用户展示"合并"的文件是在同一级目录 的现象,这就是联合挂载技术,相对于 AUFS(Docker 1.12 之前使用的存储技术),OverlayFS 速度更快,实现更为简单。
  • Linux 内核为 Docker 提供的 OverlayFS 驱动有两种:Overlay 和 Overlay2 。其中,Overlay2 是相对于 Overlay 的一种改进,在 Inode 利用率方面比 Overlay 更为高效。但是, Overlay 有环境的要求:Docker 版本是 17.06.02 + ,并且 宿主机文件系统需要是 EXT4 或 XFS 格式

2.4.4 OverlayFS 的实现方式

  • OverlayFS 通过三个目录:lower 目录、upper 目录、以及 work 目录来实现的。其中,lower 目录可以是多个,upper 目录可以进行读写操作的目录,而 work 目录为工作基础目录,挂载后内容会被清空,并且在使用过程中其内容用户是不可见的,最后联合挂载完成之后给用户呈现的统一视图就被称为 merged 目录。

1682129866528-d73cb77a-4821-4380-b3cb-2780e8813c9b.png

  • 示例:演示 OverlayFS 挂载操作
# 创建文件夹
mkdir /lower{1..3}
mkdir /upper /work /merged

1682131659038-619f1c4b-5b4d-4804-8f7d-9d2b375180f0.gif

# 挂载文件系统
mount -t overlay overlay -o lowerdir=/lower1:/lower2:/lower3,upperdir=/upper,workdir=/work /merged

1682131695592-7bdf808a-605f-423a-bfae-b42f9a0de3cd.gif

# 查看挂载
mount | grep merged

1682131736597-f5d870bb-72ea-4413-bbae-0a95b7b351f9.gif

# 向 /upper 目录中写入文件
touch /upper/upper.txt
# 查看 /merged 中是否存在
ls -lah /merged

1682131766832-878c9f8b-86b5-4dd4-bcb2-8d056d18f913.gif

# 在 /merged 中写入文件,查看是否存储到了 /upper
touch /merged/d.txt
ls -lah /upper
ls -lah /lower*

1682131819302-2fb9cf47-5d03-465c-b75d-0d356bf8de12.gif

# 如果没有 upper 层,那么 merged 是只读的
umount /merged
mount -t overlay overlay -o lowerdir=/lower1:/lower2:/lower3 /merged
touch /merged/c.txt

1682131856917-25146dfb-f943-4fbf-8e26-8f9eca8e96f8.gif

2.4.5 总结

  • 在操作系统中,可以根据宿主机的资源情况,创建不同应用和不同数量的容器;每个容器的 CPU、内存(Memory)、网络(Network)都是由系统的内核 -- namespace 进行隔离的,相互之间没有影响。
  • 为了防止某个正在运行的容器大量占用宿主机的系统资源(CPU、内存、网络),那么将由操作系统的 cgropus 进行资源限制(防止独占)。
  • 容器运行的基础是镜像,并且新容器的运行也是需要存储支持,在 Docker 中使用 OverlayFS 来解决这一问题。

注意:Docker 默认镜像容器 存储的位置是 /var/lib/docker/overlay2

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

1682218747006-98c1c050-2713-4d4d-88de-59ab5de1edde.gif

2.5.3 更新系统(选做)

  • 切换国内源:
cp -a /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
wget -O /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo
yum clean all
yum makecache

1682213361339-af556141-6afd-4deb-8101-e9815bd871c3.gif

  • 安装 EPEL 并切换国内源:
yum install epel-release -y
cp -a /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup
mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup
sed -i "s/#baseurl/baseurl/g" /etc/yum.repos.d/epel.repo
sed -i "s/metalink/#metalink/g" /etc/yum.repos.d/epel.repo
sed -i "s@https\?://download.fedoraproject.org/pub@https://repo.huaweicloud.com@g" /etc/yum.repos.d/epel.repo

1682213422600-92005178-4d03-4171-9d7f-1b040f5c66c3.gif

  • 更新系统:
yum -y update

1682213540446-88edc867-0609-4d2e-bad5-ff04bbcd21ed.gif

2.5.4 升级内核(选做)

  • 查看当前系统的版本:
cat /etc/redhat-release

1682213936777-72906174-2e47-4a22-9e36-417e2fea26f1.gif

  • 查看当前系统的内核以及内核的启动顺序:
# 查看当前系统内核
uname -sr
# 查看启动顺序
yum install -y grub2-pc
grub2-editenv list
# 查看可用内核版本及启动顺序
sudo awk -F\' '$1=="menuentry " {print i++ " : " $2}' /boot/grub2/grub.cfg

1682214633877-c65bdcba-5126-4b39-b8dc-45a68904192e.gif

  • 在 CentOS 7.x 上启用 ELRepo 仓库,并切换为清华源:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm
sed -i "s/mirrorlist=/#mirrorlist=/g" /etc/yum.repos.d/elrepo.repo
sed -i "s#elrepo.org/linux#mirrors.tuna.tsinghua.edu.cn/elrepo#g" /etc/yum.repos.d/elrepo.repo

1682214135964-e2107580-0671-439d-9790-f134b75edcc2.gif

  • 查看可用的系统内核相关包:
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available

1682214180617-6a502bda-d254-4c1d-81f9-85155479951f.gif

  • 安装长期支持的内核版本:
yum -y --enablerepo=elrepo-kernel install kernel-lt

1682214276863-5878e7e2-ec31-4ab2-a58c-e3dacddc77b8.gif

  • 设置默认的启动项
# 查看启动项
cat /etc/default/grub
# 设置默认的启动项
sed -i 's/^GRUB_DEFAULT=saved$/GRUB_DEFAULT=0/' /etc/default/grub
# 查看启动项
cat /etc/default/grub

1682214853819-017d8de9-c6a3-4e90-91e0-582cb3d78208.gif

  • 重新创建内核配置:
grub2-mkconfig -o /boot/grub2/grub.cfg

1682214387873-5c9de17f-f782-4d98-9e4c-ee0cb8aa8599.gif

  • 重启系统:
reboot

1682214432237-c81af9ee-8e46-49b7-bd97-3fafb483c051.gif

  • 查看当前系统的内核:
# 查看当前系统内核
uname -sr
# 查看可用内核版本及启动顺序
sudo awk -F\' '$1=="menuentry " {print i++ " : " $2}' /boot/grub2/grub.cfg

1682214941780-212d5d1d-169a-4c0a-9057-57bb57f34f4c.gif

2.5.5 关闭 SELinux

  • 命令:
# 查看 SELinux 是否开启
getenforce
# 查看 SELinux 是否开启
cat /etc/selinux/config
# 永久关闭 SELinux ,需要重启
sed -i 's/enforcing/disabled/' /etc/selinux/config
# 关闭当前会话的 SELinux ,重启之后无效
setenforce 0
# 查看 SELinux 是否开启
cat /etc/selinux/config

1682215709768-26975306-d925-4a4a-9c2d-300426a24075.gif

2.5.6 关闭 swap 分区

  • 命令:
# 查看 swap 分区是否存在
free -h
# 关闭当前会话的 swap ,重启之后无效
swapoff -a
# 永久关闭 swap ,需要重启
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 查看 swap 分区是否存在
free -h

1682215737633-b159ece6-f931-4de6-8fb2-e3543fe4ca16.gif

2.5.7 卸载旧版本

  • 命令:
yum remove docker \
          docker-client \
          docker-client-latest \
          docker-common \
          docker-latest \
          docker-latest-logrotate \
          docker-logrotate \
          docker-engine

1682215007007-d22d905c-ff15-44c3-8b02-bab4d66b539f.gif

2.5.8 yum 安装 gcc 相关

  • 命令:
yum -y install gcc gcc-c++

1682215052990-ee374671-3b52-4c53-99c9-9315aaf9a184.gif

2.5.9 安装所需要的软件包

  • 命令:
yum install -y yum-utils device-mapper-persistent-data lvm2

1682215094000-b110d20c-16fa-41c6-86f6-9728c61d0344.gif

2.5.10 设置 stable 镜像仓库

  • 命令:
# 官方源
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
# aliyun 源
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

1682215222874-8a90c601-d81c-4fbe-b741-ac9592cf33b6.gif

2.5.11 更新 yum 软件包索引

  • 命令:
yum makecache fast

1682215259550-08f0dfae-c976-4891-a29e-e7b3547c59de.gif

2.5.12 查看存储库中 Docker 的版本

  • 命令:
yum list docker-ce --showduplicates | sort -r

1682215315209-eed7fd91-db91-4506-941e-98f84231d161.gif

2.5.13 安装 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-1:20.10.9-3.el7.x86_64 \
            containerd.io

1682215498809-64f3c8d9-649b-407e-a2c0-70c0f10fb28c.gif

:::color4 温馨提示:最新版本的 Docker 已经集成了 docker buildx 和 docker compose 功能,只需要输入如下的命令即可:

:::

yum -y install docker-ce \
    docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

2.5.14 启动 Docker

  • 命令:
# 启动 Docker 并设置开机自启
systemctl enable --now docker

1682215798054-6c0d11ce-f25b-4155-9966-7ff404a40662.gif

2.5.15 验证 Docker 是否安装成功

  • 命令:
docker version
systemctl status docker

1682215872944-08c02e0e-e37a-4287-8228-857936e68fbb.gif

2.5.16 阿里云镜像加速

  • 命令:
sudo mkdir -pv /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
  "exec-opts": ["native.cgroupdriver=systemd"], 
  "registry-mirrors": [
    "https://du3ia00u.mirror.aliyuncs.com",
    "https://docker.lixd.xyz"
  ],
  "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

1682216154291-71513719-95b1-4b82-9299-50ffaaa546e2.gif

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 -y 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 容器只需要几秒钟。

1645865973571-9bc48797-017d-4755-950b-59e26a97a004.png

第三章:Docker 常用命令

3.1 帮助启动类命令

3.1.1 启动 Docker

  • 命令:
systemctl start docker

1682216324879-02024537-af4b-4206-9ed9-6efd6377e04c.gif

3.1.2 停止 Docker

  • 命令:
systemctl stop docker

1682216355695-8ff84663-ddbd-4e9b-ba8e-483aa63fa9d3.gif

3.1.3 重启 Docker

  • 命令:
systemctl restart docker

1682216387397-0a6b038d-c8ed-4522-b2b2-84ffd8826014.gif

3.1.4 查看 Docker 状态

  • 命令:
systemctl status docker

1682216418238-dfdf9378-d5c5-4e98-9cd1-b2f6071dffd3.gif

3.1.5 开机自动启动 Docker

  • 命令:
systemctl enable docker

1682216446725-b4e39947-d0db-4e4e-ad78-028d6978f44b.gif

3.1.6 查看 Docker 概要信息

  • 命令:
docker info

1682216487957-7d0063e6-88c7-4ad8-bc85-3a1f63634754.gif

3.1.7 查看 Docker 总体帮助文档

  • 命令:
docker --help

1682216536163-7c64646c-4533-4527-a352-5724b25a5292.gif

3.1.8 查看 Docker 命令帮助文档

  • 命令:
docker 具体命令 --help

1682216577417-c0a99ce7-4f98-4cbd-b8f5-c8e6253907ba.gif

3.2 镜像命令

3.2.1 列出本地主机上的镜像

  • 命令:
docker images [-qa]
  • 参数:
    • -q:只列出镜像 ID 。
    • -a:列出所有镜像,包括历史镜像。

注意:在 Docker 中镜像名称 + TAG = 镜像 ID ,容器名称 = 容器 ID 。

  • 示例:
docker images

1682216634688-dcdb80f6-9a40-4e6f-95dc-6a40b08569cc.gif

温馨提示:

  • 同一个仓库中可以有多个 tag 版本,代表这个仓库的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
  • 如果不知道一个镜像的版本标签,比如:只是用了 ubuntu,Docker 将默认使用 ubuntu:latest 镜像。

3.2.2 搜索镜像

  • 命令:
docker search 镜像名称
  • 示例:
docker search redis

1682216677056-d47f3f20-a1ad-43cf-969b-865893a84c77.gif

温馨提示:在实际使用中,还是直接去 Docker Hub 中搜素镜像,该命令使用的并不是很频繁!!!

3.2.3 拉取镜像

  • 命令:
docker pull 镜像名称[:TAG]

注意:没有 TAG 就表示 latest 。

  • 示例:
docker pull mysql:5.7

1682216812223-4630699c-6b2f-4930-845f-955d08cd51df.gif

3.2.4 查看镜像、容器、数据卷所占的空间

  • 命令:
docker system df
  • 示例:
docker system df

1682216864427-a589df82-616d-4479-800e-b826caa086dc.gif

3.2.5 删除镜像

  • 命令:删除某个镜像
docker rmi 镜像名称|镜像ID
  • 命令:强制删除某个镜像
docker rmi -f 镜像名称|镜像ID
  • 命令:强制删除所有的镜像
docker rmi -f $(docker images -qa)
  • 示例:
# 拉取镜像
docker pull ubuntu
docker pull mysql:5.7
# 删除镜像
docker rmi ubuntu
docker rmi mysql:5.7

1682217018941-bdd95dc0-c1b4-42d5-b09f-9f157dcb1b78.gif

  • 示例:
# 根据镜像 id 删除强制镜像
docker rmi -f 镜像id

1682217243929-ba4526bc-0442-41d4-ae45-e33026461db8.gif

  • 示例:
# 强制删除所有镜像
docker rmi -f $(docker images -qa)

1682217366084-8e5f2659-dab3-48d9-ae89-df3ef158e87f.gif

3.3 容器命令

3.3.1 前提说明

  • 有镜像才能创建容器,这是根本前提,本次以 ubuntu 为例演示。
  • 拉取 ubuntu :
docker pull ubuntu:20.04

1682227513087-3a79d089-1653-4092-bbc8-61710cd813e8.gif

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:20.04 /bin/bash

1682227636623-d4e1011a-4905-428c-bf81-687f9ed9ba3b.gif

3.3.3 列出当前所有正在运行的容器

  • 命令:
docker ps [-qa]
  • 参数:

    • -a:累出当前所有正在运行的容器 + 历史上运行过的容器。
    • -q:只显示容器编号。
  • 示例:

docker ps

1682227675500-2ffc4653-4729-4e2b-8a6e-eb61a85be633.gif

3.3.4 退出容器

  • ① exit :run 进容器,exit 退出,容器停止。
  • ② ctrl + p + q:run 进容器,ctrl + p + q 退出,容器不停止。

  • 示例:

exit

1682227772964-46d1e36d-e232-4e64-82b7-3348149ce41d.gif

  • 示例:
ctrl + p + q

1682227821268-353dd554-a984-4de7-88da-e8d95f878afd.gif

3.3.5 启动已停止的容器

  • 命令:
docker start 容器名称或容器ID
  • 示例:
docker start ubuntu

1682227891012-330d73ac-8334-4ef0-8497-caeaa60a1fe9.gif

3.3.6 重启容器

  • 命令:
docker restart 容器名称或容器ID
  • 示例:
docker restart ubuntu

1682227935861-509b7415-60f7-47f1-a22c-a4eecaa179c7.gif

3.3.7 停止容器

  • 命令:
docker stop 容器名称或容器ID
  • 示例:
docker stop ubuntu

1682227993117-2ccf0700-bfc2-470f-aa1c-673dd23a8fed.gif

3.3.8 强制停止容器

  • 命令:
docker kill 容器名称或容器ID
  • 示例:
docker kill ubuntu

1682228036860-931151fc-1828-47bb-9124-2c5697213366.gif

3.3.9 删除已停止的容器

  • 命令:
docker rm 容器名称或容器ID
  • 命令:一次强制删除多个容器
docker rm -f $(docker ps -qa)
docker ps -qa | xargs docker rm -f
  • 示例:
docker rm -f ubuntu

1682228088037-a1138b33-c8a2-4272-bcc3-3d0eac48e12b.gif

  • 示例:
docker rm -f $(docker ps -qa)

1682228217231-d9ea3f1f-2983-479f-b90f-193356eece95.gif

3.3.10 实验

3.3.10.1 前提说明

  • 本次以 Redis 6.0.8 镜像作为演示。

3.3.10.2 拉取镜像

  • 命令:
docker pull redis:6.0.8

1682228298298-5eea19ff-51ac-4290-947c-be859b943efc.gif

3.3.10.3 启动守护式容器

  • 在大部分场景下,我们希望 Docker 的服务是在后台运行的,我们可以通过 -d 指定容器的后台运行模式。
  • 命令:
docker run -d 容器名
  • 示例:启动 ubuntu 容器,以守护式方式
docker run -d ubuntu:20.04

1682228395022-883e6adb-fbc0-4c54-b156-b6140fc6ccfe.gif

温馨提示:如果用 docker ps 查看,会发现容器已经退出了,这是因为 Docker 容器后台运行的时候,必须有一个前台的进程 ,这个是 Docker 的机制问题:如果容器中运行的命令不是一直挂起的命令(比如:top、tail 等),当容器以守护式方式启动就会退出容器;当然如果是命令行模式,表示有交互默认,Docker 也会认为是前台进行的方式启动,不会将容器杀死。

  • 示例:以交互式方式启动 redis 容器:
docker run -it redis:6.0.8 /bin/bash

1682228444071-a37d5b33-73d8-444d-b6bd-cbe8f681f75b.gif

  • 示例:以守护式启动 redis 容器
docker run -d redis:6.0.8

1682228486763-fa57981e-4234-4df0-b95c-6a4a5e5f879e.gif

3.3.10.4 查看容器日志

  • 命令:
docker logs [-f] 容器名称|容器ID
  • 示例:
docker logs -f redis

1682228544103-bc897804-608c-4522-b545-c9047269a16d.gif

3.3.10.5 查看容器内运行的进程

  • 命令:
docker top 容器名称|容器ID
  • 示例:
docker top redis

1682228604095-a8032420-9d0d-4c06-a474-ee84588a25ab.gif

3.3.10.6 查看容器内部细节

  • 命令:
docker inspect 容器名称|容器ID
  • 示例:
docker inspect redis

1682228685212-80928f11-0170-499f-be49-8a05302aacd1.gif

3.3.10.7 进入正在运行的容器并以命令行交互

  • 命令:
docker exec -it 容器名称|容器ID [COMMAND]

注意:使用 exec 时,当 exit 退出容器时,不会导致容器终止。

  • 示例:
docker exec -it redis /bin/bash

1682228742908-e64dadb2-476c-4c9b-b043-3573fbc44091.gif

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 以  /.  结束:源文件夹里面的内容复制到目标里面。
        • 自动创建文件夹不会做递归。需要把父文件夹手动创建。
  • 示例:

docker cp redis:/data/a.txt .

1682229237884-5a4292dd-33f2-4a64-8608-5284c0ada05c.gif

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

1682229371276-f91dd626-3bf9-480d-9454-9236600c2ef8.gif

3.4 总结

1645866304881-3ad95646-2ad1-4ad3-bad9-e7982585fa5e.png

命令 描述
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

1682229558265-311722da-972c-43a6-91e6-86f81e9b17b7.gif

  • 其实,我们也可以通过如下的命令来查看镜像构建(build)历史信息:
docker history tomcat

1682229658484-df166515-99d4-48f1-bf22-89ebe8d54425.gif

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,没有父镜像),可以制作各种具体的应用镜像。

1645866319073-4af4cc81-e73d-4c85-9098-92416cffcef3.png

  • 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

  • 示例:证明 Docker 使用的存储驱动是 Overlay2

docker info | grep -E "Storage Driver|Server Version"

1682144065080-3d37b19f-77aa-44c6-afc6-ff7a60532ceb.png

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 等。

1645866324342-1eb7ba9f-7414-4116-9132-3588abe74828.png

  • 『问』平时我们安装进虚拟机的 CentOS 都是 4G 以上,为什么Docker 才 200+ MB?

1682229774689-17cb2b45-16a2-4654-9a43-8427882ed31a.png

  • 『答』对于一个精简的 OS ,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用的宿主机的 kernel ,自己只需要提供 rootfs 就可以了。由此可见对于不同的 Linux 发行版,bootfs 基本是一致的,rootfs 会有所差别,因为不同的发行版可以共用 bootfs 。

4.1.5 为什么 Docker 镜像要采用这种分层结构?

  • 镜像分层最大的一个好处就是共享资源,方便复制迁移。
  • 比如:多个镜像都是从相同的 base 镜像构建而来,那么 Docker 只需要在磁盘中保存一份 base 镜像,同时内存中也只是加载一份 base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。

4.2 Docker 镜像的理解

  • 写时复制,用时分配:Docker 镜像层都是只读的,容器层是可写的
  • 当容器启动的时候,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层之下的都叫做镜像层。
  • 所有对容器的改动,无论添加、删除还是修改文件都只会发生在容器层中,只有容器层是可写的,容器层下面的所有镜像层都是只读的。

1645866339467-45af26c2-5c91-44bf-8d2d-ee468d3e9490.png

4.3 使用 commit 制作镜像

  • 需求:在 ubuntu 镜像(官方镜像)中添加 vim 命令,安装制作为新的镜像。
  • 命令:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:TAG
  • 示例:
  • ① 拉取 ubuntu 镜像到本地:
docker pull ubuntu:20.04

1682229950665-a8514396-ebb9-42b9-a368-77890e500c79.gif

  • ② 运行 ubuntu 镜像,查看是否携带 vim 命令:
docker run -it --name="ubuntu" ubuntu:20.04 /bin/bash
vim a.txt

1682229994712-040bcb3c-2fb1-4395-adbf-6acd8816ed61.gif

  • ③ 在连接互联网的情况下,在容器内部安装 vim :
# 更新包管理器
apt-get update -y
# 安装 vim 命令
apt-get -y install vim

1682230113529-035a255d-2b6c-4a5f-bc14-324dfbcea752.gif

  • ④ 安装完成后,commit 新的镜像:
docker commit -m="安装有vim的ubuntu镜像" -a="许大仙" ubuntu xudaxian/ubuntu

1682230197222-f44eb882-2809-493c-a0d4-cc8db4d25f8f.gif

  • ⑤ 启动新的镜像,并进行测试:
docker run -it --name="xudaxian-ubuntu" xudaxian/ubuntu /bin/bash
vim a.txt

1682230257736-4dfc4656-6f4a-4875-ba15-ee1fcfc91db1.gif

4.4 总结

  • Docker 中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似于 Java 中继承一个 Base 基础类,然后自己按需扩展。
  • 新的镜像是从 base 镜像一层一层的叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

1645866436217-7861dec7-0e79-44ca-9591-c406d0eb7520.png

第五章:本地镜像发布到阿里云

5.1 本地镜像发布到阿里云流程

1645866469075-e5acf904-ba63-473e-8a38-f7bfd491532c.png

5.2 镜像的生成方法

  • ① 基于当前容器创建镜像,使用 docker commit 命令。
  • ② 基于 Dockerfile 文件。

5.3 本地镜像推送到阿里云

5.3.1 创建仓库镜像

  • 选择控制台,进入容器镜像服务。

1645866474152-042920ce-35e1-4ef6-85e6-6f0deca1e666.png

  • 选择个人实例:

1645866479804-163b79d9-ee36-491e-868d-caec6dcdbd99.png

  • 命名空间:

1645866488898-c2d3b3fd-6396-486a-9c54-98fbaa69e4a4.png

  • 镜像仓库:

1645866499169-530f1a61-3da2-44bc-88d8-f223aba1645b.png

1645866503685-4ef0adca-78c7-4d38-a830-2c1d9b3acd82.png

1645866508081-a473b94c-eae8-4793-b0f5-6e86cd3a0a26.png

1645866523162-6f4b86eb-b211-4d33-b269-254565d8fd65.png

5.3.2 将镜像推送到阿里云:

  • 登录阿里云:
docker login --username=**** registry.cn-shanghai.aliyuncs.com

1682230775808-e00bca5d-49af-45ae-9282-48ed8a8df505.gif

  • 查看镜像,并给镜像打标签:
docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/命名空间/xudaxian-ubuntu:[镜像版本号]

1682230931713-e70dcd65-d4ff-481c-84a0-6de75352d74d.gif

  • 推送镜像:
docker push registry.cn-shanghai.aliyuncs.com/xudaxian/xudaxian-ubuntu:1.0

1682230995103-28f4a605-025e-4e6c-b891-eb70960832a1.gif

5.4 将阿里云上的镜像下载到本地

  • 删除本地镜像:
docker system prune -af

1682231055500-697c2976-48ee-4de3-8332-3390059b6545.gif

  • 下载镜像到本地:
docker pull registry.cn-shanghai.aliyuncs.com/xudaxian-test/xudaxian-ubuntu:1.0

1682231096120-920082ed-3006-47c7-856a-193c9069670f.gif

第六章:本地镜像发布到私有库

6.1 本地镜像发布到私有库流程

1645866572429-044bf9e8-190d-47a5-96f2-8dc0054b7d87.png

6.2 Docker Registry

  • Docker Registry 是官方提供的工具,可以用于构建私有镜像仓库。

6.3 将本地镜像推送到私有库

  • 下载 Docker Registry 镜像:
docker pull registry

1682231231047-27b9f449-f5e1-4b11-932d-9e5f817aa0a9.gif

  • 运行Docker Registry 私有库 ,相当于本地有个私有的 Docker Hub:
docker run --name=registry -d \
    -p 5000:5000  \
    -v /var/registry/:/tmp/registry \
    --privileged=true \
    registry

注意:默认情况,仓库被创建在容器的 /var/lib/registry 目录下,建议自行用容器卷映射,方便于宿主机联调。

1682231282984-ef1f9838-d0d2-4af8-9473-fed979e10169.gif

  • curl 验证私服库上有什么镜像:
 curl -XGET http://127.0.0.1:5000/v2/_catalog

1682231317387-8f9353b1-fd1c-41b7-94cc-9549c9a05a56.gif

  • 命令:将镜像打标签
docker tag 镜像:Tag Host:Port/Repository:Tag
  • 示例:
docker pull ubuntu
docker tag ubuntu 192.168.68.10:5000/xudaxian-ubuntu:1.0

1682231488186-c42eabca-4327-415a-8d15-fd15a946cf76.gif

  • 修改配置文件以支持 Docker 受信私有仓库:
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "exec-opts": ["native.cgroupdriver=systemd"], 
  "registry-mirrors": [
    "https://du3ia00u.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com",
    "https://registry.docker-cn.com",
    "https://docker.mirrors.sjtug.sjtu.edu.cn"
  ],
  "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",
  "insecure-registries":["192.168.68.10:5000"]
}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker

1682231597754-995b96dd-26f1-445e-b1eb-4e2d88b30c04.gif

  • 将本地镜像推送到私有库:
docker push 192.168.68.10:5000/xudaxian-ubuntu:1.0

1682231692960-06235deb-15ee-42a4-b1c8-d4b544af610a.gif

  • curl 验证私服库上有什么镜像:
curl -XGET http://127.0.0.1:5000/v2/_catalog

1682231729455-1b8c3675-cb70-46bb-afd8-05397b56ae06.gif

第七章: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:20.04

1682232000256-e060b188-bdbf-48a8-a3f9-f5af8bbb5286.gif

  • 查看数据卷是否挂载成功:
docker inspect 容器ID|容器名称
  • 示例:
docker inspect ubuntu

1682232062801-7a2371f3-abe9-4f57-aca8-85e37ee8a552.gif

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 制作镜像的时候,尽量选择镜像带有 alpineslim 后缀的,因为这种类型的镜像的体积相对而言比较小,更易于构建和传输。

8.2 安装 MySQL

  • 搜索镜像:
docker search mysql

1682232135624-afd16424-927a-4a73-96e4-16464b09a464.gif

  • 拉取镜像:
docker pull mysql:5.7

1682232196591-1f8a32fa-b804-4b2d-8765-f3073b1fa30a.gif

  • 查看镜像:
docker images

1682232237645-24c208ca-8257-47dd-ae68-c2b1180d99de.gif

  • 启动容器:
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

1682232271032-782b7c71-f0cc-4e78-81e8-7b51e6492fee.gif

8.3 安装 Tomcat

  • 搜索镜像:
docker search tomcat

1682232346385-89170ef6-53b8-46c7-a31c-f87746df9b12.gif

  • 拉取镜像:
docker pull billygoo/tomcat8-jdk8

1682232409774-f25d1454-3e9a-4cfe-89bd-bb2bcfad453a.gif

  • 查看镜像:
docker images

1682232433542-c216f37d-b937-4912-b976-04947d42f80a.gif

  • 启动容器:
docker run -d \
    -p 8080:8080 \
    --name tomcat8 \
    billygoo/tomcat8-jdk8

1682232480897-c7abea96-54e7-4c6c-a75d-60aab8d5e010.gif

8.4 安装 Redis

  • 搜索镜像:
docker search redis

1682232629371-6662a18e-7451-44fa-a6ce-dd9037dbfa3f.gif

  • 拉取镜像:
docker pull redis:6.0.8

1682232662327-f5141141-0e47-4778-988c-3330276ccc1d.gif

  • 查看镜像:
docker images

1682232686712-b59aabda-1241-48c0-a690-5407782d202a.gif

  • 启动容器:
docker run -d \
    -p 6379:6379 \
    --name=redis \
    -v /var/redis/data:/data \
    redis:6.0.8 redis-server --appendonly yes --requirepass "123456"

1682232938172-3b9bea23-147f-4fe2-a622-d110b731e83e.gif

  • 使用配置文件启动 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

8.5 安装 GitLab

注意:GitLab 需要的内存 6G+。

8.5.1 手动安装

  • ① 安装和配置必须的依赖项:
sudo yum install -y curl policycoreutils-python openssh-server perl
sudo systemctl enable sshd
sudo systemctl start sshd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo systemctl reload firewalld
  • ② 配置 GitLab 软件源镜像:
curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash
  • ③ 安装:
# EXTERNAL_URL 配置的是安装 GitLab 的主机地址;当然,也可以使用 http://xxx.com
sudo EXTERNAL_URL="https://gitlab.example.com" yum install -y gitlab-jh
  • ④ 访问 GitLab 实例并登录:除非您在安装过程中指定了自定义密码,否则将随机生成一个密码并存储在 /etc/gitlab/initial_root_password 文件中(出于安全原因,24 小时后,此文件会被第一次 gitlab-ctl reconfigure 自动删除,因此若使用随机密码登录,建议安装成功初始登录成功之后,立即修改初始密码)。使用此密码和用户名 root 登录。
  • ⑤ GitLab 常用命令:
gitlab-ctl start # 启动所有 GitLab 组件
gitlab-ctl stop  # 停止所有 GitLab 组件
gitlab-ctl restart  # 重启所有 GitLab 组件
gitlab-ctl status   # 查看服务状态
gitlab-ctl reconfigure # 启动服务
vi /etc/gitlab/gitlab.rb # 修改默认的配置文件
gitlab-ctl tail  # 查看日志

8.5.2 Docker 安装 GitLab

  • 安装命令:
export GITLAB_HOME=/srv/gitlab
sudo docker run --detach \
  --hostname gitlab.example.com \
  --publish 443:443 --publish 80:80 --publish 22:22 \
  --name gitlab \
  --restart always \
  --volume $GITLAB_HOME/config:/etc/gitlab \
  --volume $GITLAB_HOME/logs:/var/log/gitlab \
  --volume $GITLAB_HOME/data:/var/opt/gitlab \
  --shm-size 256m \
  registry.gitlab.cn/omnibus/gitlab-jh:latest
  • 访问 GitLab URL,并使用用户名 root 和来自以下命令的密码登录:
sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

注意:密码文件将在 24 小时后的第一次重新配置运行中自动删除。

8.6 安装 SonarQube

  • 需要在 Linux 主机执行如下的命令,以便 Docker 主机配置符合 ElasticSearch 生产模式要求和文件描述符配置:
sysctl -w vm.max_map_count=524288
sysctl -w fs.file-max=131072
ulimit -n 131072
ulimit -u 8192
  • 安装:
vim docker-compose.yaml
version: "3"

services:
  sonarqube:
    image: sonarqube:lts-community
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql:
  postgresql_data:
docker compose build --force-rm --no-cache \
        && docker compose up -d

注意:

  • 最新版本的 Docker 中已经集成了 Docker Compose 命令了,只需要在安装 Docker 的同时,安装 docker-compose-plugin 插件即可,而无需再通过二进制的形式安装 docker-compose 了。
  • 默认的用户名和密码分别是 admin/admin

第九章:其他

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 守护进程启动时就已经停止了的容器。

更新: 2024-07-01 02:08:26
原文: https://www.yuque.com/fairy-era/yg511q/lb7t23

Comments