Docker学习笔记
现在学习的教程:尚硅谷Docker实战教程(docker教程天花板)(共13H24Mins)
介绍相关
基本介绍
Docker 是一种用于开发、交付和运行应用程序的开源平台,它采用了容器化技术。以下是 Docker 的一些详细介绍:
1.容器化技术
容器化是一种虚拟化形式,允许将应用程序及其所有依赖项打包到一个容器中。这个容器包含了应用程序的代码、运行时、系统工具、库以及依赖项,形成了一个独立的执行单元。容器可以在任何支持 Docker 的环境中运行,而不受底层系统的影响。
2.Docker 架构
Docker 的架构包括以下关键组件:
-
Docker Daemon: 运行在主机上的守护进程,负责管理容器的创建、运行和停止等操作。
-
Docker Client: 与 Docker Daemon 进行交互的命令行工具或图形用户界面。
-
Docker Registry: 存储 Docker 镜像的仓库,可以是公共的如 Docker Hub,也可以是私有的。
-
Docker 镜像: 包含应用程序及其依赖项的只读模板。镜像可以用来创建容器。
-
容器: 通过镜像创建的运行实例,是一个独立的、可执行的应用程序单元。
3.Docker 的优势
-
一致性: 由于容器包含了应用程序及其所有依赖项,可以确保应用程序在不同环境中的一致性,避免了“在我的机器上可以运行”这种问题。
-
轻量级: 容器与虚拟机相比更轻量级,因为它们共享主机系统的内核,不需要额外的操作系统。
-
可移植性: Docker 容器可以在任何支持 Docker 的环境中运行,使应用程序更易于移植和部署。
-
快速部署: 由于容器启动快速,可以在几秒钟内部署新的容器实例。
-
灵活性: Docker 提供了灵活的工具和 API,允许开发人员根据需要自定义容器环境。
4.Docker 使用
使用 Docker 的基本步骤包括:
-
编写 Dockerfile: Dockerfile 是一个文本文件,包含了构建 Docker 镜像所需的指令。
-
构建镜像: 使用
docker build
命令基于 Dockerfile 构建镜像。 -
运行容器: 使用
docker run
命令基于镜像创建并运行容器。 -
发布镜像: 将镜像推送到 Docker Registry,以便其他人可以使用。
-
部署应用程序: 在目标环境中使用 Docker 运行容器,部署应用程序。
5.Docker Compose
Docker Compose 是一个工具,允许使用一个 YAML 文件定义多容器 Docker 应用程序的服务、网络和卷等配置。通过简化配置,Docker Compose 简化了多容器应用程序的管理和部署。
总的来说,Docker 提供了一种方便、一致、可移植的方式来打包、交付和运行应用程序,是现代软件开发和部署的重要工具之一。
Docker的作用
Docker 的主要作用在于简化应用程序的开发、交付和部署过程,提供一种轻量、灵活、可移植的容器化解决方案。以下是 Docker 的主要作用:
-
容器化应用程序: Docker 允许开发人员将应用程序及其所有依赖项打包到一个容器中。这个容器包含了应用程序的代码、运行时、系统工具、库以及依赖项,形成了一个独立的执行单元。容器化使得应用程序能够在不同环境中以相同的方式运行,避免了由于环境差异而导致的问题。
-
一致性和可重复性: Docker 提供了一致性和可重复性,确保应用程序在不同开发、测试和生产环境中的一致性。开发人员可以在他们的开发机器上构建和测试容器,然后将相同的容器部署到生产环境中。
-
快速部署: Docker 容器可以在几秒钟内启动,相比传统的虚拟机更为快速。这使得开发人员和运维团队能够更快速地部署新的应用程序实例,响应变化和需求。
-
资源利用率: Docker 容器共享主机系统的内核,相比传统虚拟机更为轻量级。这导致更高的资源利用率,允许在同一台物理机上运行更多的容器实例。
-
环境隔离: 每个 Docker 容器都运行在独立的用户空间,具有自己的文件系统、进程空间和网络空间。这提供了良好的隔离性,使得容器之间互不影响。
-
跨平台和云平台兼容: Docker 容器可以在任何支持 Docker 的环境中运行,无论是开发人员的本地机器、测试环境还是云平台。这种跨平台性使得应用程序更易于迁移和部署。
-
简化配置和管理: Docker 使用 Dockerfile 来定义镜像的构建过程,以及使用 Docker Compose 来管理多容器应用程序的服务配置。这简化了配置和管理复杂应用程序的过程。
-
微服务架构支持: Docker 容器适用于微服务架构,允许将应用程序拆分成小而独立的服务单元。每个服务可以在一个独立的容器中运行,简化了开发、测试和部署过程。
总体而言,Docker 提供了一种现代化、高效的软件开发和部署方式,使得团队能够更迅速、灵活地交付和运行应用程序。
为什么会有docker出现
假定您在开发一个尚硅谷的谷粒商城,您使用的是一台笔记本电脑而且您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件。此外,您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。您希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销。请问? 您要如何确保应用能够在这些环境中运行和通过质量检测?并且在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复?
答案就是使用容器。Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案—–==系统平滑移植,容器虚拟化技术==。
环境配置相当麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。

之前在服务器配置一个应用的运行环境,要安装各种软件,就拿尚硅谷电商项目的环境来说,Java/RabbitMQ/MySQL/JDBC驱动包等。安装和配置这些东西有多麻烦就不说了,它还不能跨平台。假如我们是在 Windows 上安装的这些环境,到了 Linux 又得重新装。况且就算不跨操作系统,换另一台同样操作系统的服务器,要移植应用也是非常麻烦的。
传统上认为,软件编码开发/测试结束后,所产出的成果即是程序或是能够编译执行的二进制字节码等(java为例)。而为了让这些程序可以顺利执行,开发团队也得准备完整的部署文件,让维运团队得以部署应用程式,开发需要清楚的告诉运维部署团队,用的全部配置文件+所有软件环境。不过,即便如此,仍然常常发生部署失败的状况。
Docker的出现使得Docker得以打破过去「程序即应用」的观念。透过镜像(images)将作业系统核心除外,运作应用程式所需要的系统环境,由下而上打包,达到应用程式跨平台间的无缝接轨运作。
代码即应用 —> 镜像即应用。
Docker理念
Docker是基于Go语言实现的云开源项目。
Docker的主要目标是“Build, Ship and Run Any App, Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行”。

Linux容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。**将应用打成镜像,通过镜像成为运行在Docker容器上面的实例,而 Docker容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。**只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
容器与虚拟机比较
2023.12.03
容器发展简史


传统虚拟机技术
虚拟机(virtual machine)就是带环境安装的一种解决方案。
它可以在一种操作系统里面运行另一种操作系统,比如在Windows10系统里面运行Linux系统CentOS7。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。
Win10 | WMWare | Centos7各种cpu、内存网络额配置+各种软件 | 虚拟机实例 |
---|
传统虚拟机技术基于安装在主操作系统上的虚拟机管理系统(如:VirtualBox和VMWare等),创建虚拟机(虚拟出各种硬件),在虚拟机上安装从操作系统,在从操作系统中安装部署各种应用。

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

Docker 容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统虚拟机则是在硬件层面实现虚拟化。与传统的虚拟机相比,Docker 优势体现为启动速度快、占用体积小。
对比

比较了 Docker 和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
能干嘛
一次构建、随处运行
更快速的应用交付和部署
传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。
更便捷的升级和扩缩容
随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。
更简单的系统运维
应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。
更高效的计算资源利用
Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。
应用场景

Docker借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地,Docker 将这个模型运用到自己的设计中,唯一不同的是:集装箱运输货物,而 Docker 运输软件。
下载地址
docker官网:http://www.docker.com
Docker Hub官网: https://hub.docker.com/
安装
Docker 并非是一个通用的容器工具,它依赖于已存在并运行的 Linux 内核环境。
Docker 实质上是在已经运行的 Linux 下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的 Linux 主机。
因此,Docker 必须部署在 Linux 内核的系统上。如果其他系统想部署 Docker 就必须安装一个虚拟 Linux 环境。

在 Windows 上部署 Docker 的方法都是先安装一个虚拟机,并在安装 Linux 系统的的虚拟机中运行 Docker。
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上, 要求系统为64位、Linux系统内核版本为 3.8以上,这里选用Centos7.x
查看自己的内核
uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
|
|

安装步骤
官方安装文档:https://docs.docker.com/engine/install/centos/
-
确定你是CentOS7及以上版本
-
卸载旧版本
https://docs.docker.com/engine/install/centos/
-
yum安装gcc相关
1 2
yum -y install gcc yum -y install gcc-c++
需要保证,CentOS7能上外网。
-
安装需要的软件包
官网要求

执行命令
|
|
- 设置stable镜像仓库
**【大坑】**不要直接使用官网的镜像仓库
|
|
容易出错:
- [Errno 14] curl#35 - TCP connection reset by peer
- [Errno 12] curl#35 - Timeout
【推荐】使用国内的镜像
|
|
成功截图:

- 更新yum软件包索引
|
|
- 安装DOCKER CE
|
|

成功截图:

- 启动docker
|
|
- 测试
|
|
成功截图:
docker version

docker run hello-world

- 卸载
|
|
阿里云镜像加速
https://promotion.aliyun.com/ntms/act/kubernetes.html
-
注册一个属于自己的阿里云账户(可复用淘宝账号)
-
获得加速器地址连接
-
登陆阿里云开发者平台
-
点击控制台
-
选择容器镜像服务
-
获取加速器地址
-
-
粘贴脚本直接执行
1 2 3 4 5 6 7 8
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://8oj2kl3i.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
run的功能
启动Docker后台容器(测试运行 hello-world)
|
|

输出这段提示以后,hello world就会停止运行,容器自动终止。
run干了什么?

为什么Docker比VM虚拟机快
(1)docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
(2)docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。


Docker的基本组成
镜像(image)
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。
相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。

容器(container)
1.从面向对象角度
Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
2.从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库(repository)
仓库(Repository)是集中存放镜像文件的场所。
类似于
Maven仓库,存放各种jar包的地方; github仓库,存放各种git项目的地方; Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。 最大的公开仓库是 Docker Hub(https://hub.docker.com/),存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等。
小总结
需要正确的理解仓库/镜像/容器这几个概念:
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
image文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
- 镜像文件
image 文件生成的容器实例,本身也是一个文件,称为镜像文件。
- 容器实例
一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们 的容器。
- 仓库
就是放一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了。
Docker工作原理
Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
- 用户是使用 Docker Client与 Docker Daemon 建立通信,并发送请求给后者。
- Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Cient 的请求。
- Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
- Job 的运行过程中,当需要容器境像时,则从 Docker Registry 中下载像,并通过像管理驱动 Graph driver 将下载像以 Grah 的形式存储。
- 当需要为 Docker创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
- 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Exec driver 来完成。
- Libcontainer 是一项独立的容器管理包,Netwok driver 以及 Exec diver 都是通过 Libcontainer 来实现具体对容器进行的操作。

Docker常用命令
帮助启动类命令
启动docker:
|
|
停止docker:
|
|
重启docker:
|
|
查看docker状态:
|
|
开机启动:
|
|
查看docker概要信息:
|
|
查看docker总体帮助文档:
|
|
查看docker命令帮助文档:
|
|
镜像命令
docker images
列出本地主机上的镜像

各个选项说明:
REPOSITORY:表示镜像的仓库源 TAG:镜像的标签版本号 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小
同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。 如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。
OPTIONS说明:
-a :列出本地所有的镜像(含历史映像层) -q :只显示镜像ID。
docker search
|
|
docker search
命令用于在 Docker Hub 或其他 Docker 镜像仓库中搜索 Docker 镜像。以下是该命令的详细介绍:
语法
|
|
参数
--filter , -f
: 根据提供的过滤条件过滤输出结果。--format
: 指定输出的格式。--limit
: 限制返回的结果数量。--no-trunc
: 不截断输出。
示例
-
基本搜索:
1
docker search ubuntu
这会在 Docker Hub 中搜索包含 “ubuntu” 关键字的所有镜像。
-
使用过滤条件:
1
docker search --filter stars=3 ubuntu
上述命令会在 Docker Hub 中搜索获得至少 3 星的 “ubuntu” 相关的镜像。
-
限制结果数量:
1
docker search --limit=5 ubuntu
该命令将返回 Docker Hub 中前五个与 “ubuntu” 相关的镜像。
-
指定输出格式:
1
docker search --format "table {{.Name}}\t{{.Description}}" ubuntu
该命令将按表格格式输出镜像的名称和描述。
注意事项
TERM
参数是搜索关键字,可以是镜像的名称、描述或其他相关信息。- 默认情况下,
docker search
命令会搜索 Docker Hub,但你也可以在 TERM 后面加上镜像仓库地址进行搜索。
这就是 docker search
命令的基本介绍和一些常用的选项。通过这个命令,你可以方便地查找和浏览 Docker Hub 上的各种镜像。
docker pull
|
|
docker pull
命令用于从 Docker 镜像仓库中拉取指定的 Docker 镜像到本地系统。以下是该命令的详细介绍:
语法
|
|
参数
--all-tags , -a
: 拉取仓库中的所有标签。--disable-content-trust
: 禁用镜像内容的信任(Content Trust)。
示例
-
拉取指定仓库和标签的镜像:
1
docker pull ubuntu:20.04
上述命令将拉取 Docker Hub 上的
ubuntu
仓库中的20.04
标签对应的镜像。 -
拉取仓库中的所有标签:
1
docker pull --all-tags ubuntu
该命令将拉取 Docker Hub 上
ubuntu
仓库中的所有标签对应的镜像。
注意事项
NAME
参数是要拉取的镜像的仓库名称。TAG
参数是要拉取的具体标签,可以是镜像的版本号等。- 如果未提供标签信息,将默认拉取仓库中的
latest
标签的镜像。 DIGEST
参数是使用 SHA256 哈希值指定的镜像内容摘要。
通过 docker pull
命令,你可以方便地从 Docker 镜像仓库中获取所需的镜像,并在本地系统中建立对这些镜像的拷贝。这是在创建和运行容器之前常见的一步。
docker system df
docker system df
命令用于显示 Docker 系统的磁盘使用情况。该命令会提供关于镜像、容器和卷占用的磁盘空间信息。以下是该命令的详细介绍:
语法
|
|
参数
--format
: 指定输出的格式。
示例
-
查看系统磁盘使用情况:
1
docker system df
该命令将显示关于镜像、容器和卷占用的磁盘空间信息。
-
指定输出格式:
1
docker system df --format "table {{.Type}}\t{{.TotalCount}}\t{{.Size}}\t{{.UsedByImages}}\t{{.UsedByContainers}}\t{{.UsedByVolumes}}"
上述命令将按表格格式输出磁盘使用情况的各个字段。
输出字段解释
TYPE
: 表示磁盘使用的类型,包括 “Images”(镜像)、“Containers”(容器)和"Volumes"(卷)。TOTAL COUNT
: 表示总数,即相应类型的总数量。SIZE
: 表示相应类型占用的总磁盘空间。USED BY IMAGES
: 表示被镜像占用的磁盘空间。USED BY CONTAINERS
: 表示被容器占用的磁盘空间。USED BY VOLUMES
: 表示被卷(Volumes)占用的磁盘空间。
注意事项
docker system df
主要用于检查 Docker 的磁盘使用情况,帮助用户了解哪些部分占用了磁盘空间。docker system df
不接受太多的选项,主要用于显示信息。
通过运行 docker system df
,你可以迅速了解 Docker 系统中各个组件占用的磁盘空间,这对于管理和维护 Docker 环境是很有帮助的。
docker rmi
|
|
docker rmi
命令用于删除本地系统上的一个或多个 Docker 镜像。以下是该命令的详细介绍:
语法
|
|
参数
--force , -f
: 强制删除正在使用的镜像。--no-prune
: 不移除未被任何容器引用的镜像。
示例
-
删除单个镜像:
1
docker rmi ubuntu:20.04
上述命令将删除本地系统上的
ubuntu:20.04
镜像。可以根据镜像名字或ID对镜像进行删除。
-
删除多个镜像:
1
docker rmi ubuntu:20.04 alpine:latest
该命令将删除本地系统上的
ubuntu:20.04
和alpine:latest
镜像。 -
强制删除正在使用的镜像:
1
docker rmi -f ubuntu:20.04
通过使用
-f
选项,你可以强制删除正在被容器使用的镜像。 -
不移除未被任何容器引用的镜像:
1
docker rmi --no-prune ubuntu:20.04
该命令将删除指定的镜像,但不会移除未被任何容器引用的镜像。
-
删除本地系统上的所有 Docker 镜像
如果你想删除本地系统上的所有 Docker 镜像,可以使用一些命令行工具的组合来实现。请注意,这是一个慎重的操作,因为这将删除本地系统上的所有镜像,包括正在运行的容器的基础镜像。
以下是一个使用命令行工具(Linux/Unix 系统)来删除本地所有 Docker 镜像的示例:
1
docker rmi $(docker images -q)
这个命令的步骤解释如下:
docker images -q
:该命令列出所有镜像的 ID。-q
选项表示只返回镜像的 ID。docker rmi $(docker images -q)
:该命令使用$()
将docker images -q
的输出作为参数传递给docker rmi
,从而删除所有这些镜像。
请注意,这种方法不会删除正在运行的容器,因为镜像在容器中运行时是被使用的。如果需要删除运行中的容器,首先需要停止这些容器。(可以加上
-f
来强制删除正在使用的镜像)docker rmi $(docker images -q)
和docker rmi $(docker images -qa)
:这两个命令都是用来删除本地系统上的 Docker 镜像,但它们的区别在于选择要删除的镜像的方式。
-
docker rmi $(docker images -qa)
:-qa
选项返回所有镜像的 ID,包括悬空(dangling)的镜像。- 这将删除本地系统上的所有镜像,包括被引用和悬空的镜像。
1
docker rmi $(docker images -qa)
-
docker rmi $(docker images -q)
:-q
选项返回所有镜像的 ID,但不包括悬空(dangling)的镜像。- 这将删除本地系统上的所有非悬空的镜像,即被容器引用的镜像。
1
docker rmi $(docker images -q)
注意事项
- 如果要删除的镜像正在被运行的容器使用,通常需要停止相关容器或使用
-f
选项强制删除。 - 当你删除一个镜像时,Docker 将尝试从本地系统上删除该镜像的所有版本。如果有其他镜像的层被共享,这可能会导致其他镜像也受到影响。
- 使用
docker rmi
命令时,你可以指定一个或多个镜像的名称或 ID 进行删除。
通过 docker rmi
命令,你可以在本地系统上删除不再需要的 Docker 镜像,从而释放磁盘空间并清理环境。
悬空镜像
悬空镜像(dangling images)是指在本地 Docker 系统中存在但没有与任何标签关联的镜像。这些镜像通常是构建其他镜像过程中生成的中间层(intermediate layer),或者是由于删除标签而导致没有标签关联的镜像。
悬空镜像不被任何容器或其他镜像直接引用,因此它们可能被认为是不再需要的中间结果。这些镜像占用磁盘空间,但由于没有标签,很难直接引用它们。
使用 docker images
命令时,悬空镜像通常会显示为 <none>
或者 <none> <none>
,表示缺少仓库名和标签。以下是一些示例:
|
|
你可以使用 docker images -f "dangling=true"
命令来查找悬空镜像:
|
|
为了清理悬空镜像,可以使用 docker image prune
命令:
|
|
或者,如果你希望仅删除悬空镜像,而不删除其他不被使用的镜像,你可以使用以下命令:
|
|
请注意,在执行类似删除操作之前,请确保你了解这将删除哪些镜像,并且确保没有任何需要保留的数据。
容器命令
有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)
下载ubuntu镜像
|
|
docker run
要新建并启动一个新的 Docker 容器,你可以使用 docker run
命令。以下是该命令的详细说明:
语法
|
|
参数
-
--detach , -d
: 在后台运行容器。 -
--name
: 指定容器的名称。 -
--interactive , -i
: 保持标准输入 (stdin) 打开(以交互模式运行容器),通常与-t
一起使用。 -
--tty , -t
: 为容器重新分配一个伪终端,通常与-i
一起使用。 -
--publish , -p
: 将容器的端口映射到主机。-P
:将容器内部的端口映射到主机上的随机端口。
-
--volume , -v
: 将主机目录挂载到容器内。 -
--env , -e
: 设置环境变量。 -
--rm
: 在容器退出时自动删除容器。
示例
-
运行一个基本的容器:
1
docker run ubuntu
上述命令将以默认配置从 Docker Hub 拉取并运行 Ubuntu 镜像。
-
在后台运行容器:
1
docker run -d nginx
该命令将在后台运行一个 Nginx 容器。
-
指定容器名称:
1
docker run --name my_container ubuntu
上述命令将为容器指定名称为
my_container
。 -
映射端口:
1
docker run -p 8080:80 nginx
该命令将容器的 80 端口映射到主机的 8080 端口。
-
挂载卷:
1
docker run -v /host/path:/container/path ubuntu
该命令将主机上的
/host/path
目录挂载到容器内的/container/path
目录。 -
设置环境变量:
1
docker run -e MYSQL_ROOT_PASSWORD=mysecretpassword mysql
该命令将设置 MySQL 容器的
MYSQL_ROOT_PASSWORD
环境变量。 -
交互式终端:
1
docker run -it centos /bin/bash
该命令将以交互式模式运行 Centos容器,并打开 Bash 终端。
使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
参数说明:
-i: 交互式操作。 -t: 终端。 centos : centos 镜像。 /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。 要退出终端,直接输入 exit。
-
自动删除容器:
1
docker run --rm ubuntu
该命令将在容器退出时自动删除容器。
注意事项
IMAGE
参数是要使用的镜像的名称。COMMAND
和ARG...
参数是在容器内部执行的命令和参数。- 如果不提供
--detach
(-d)选项,容器将在前台运行,你将看到容器的输出。 - 运行容器时,可以根据需要使用其他选项和参数以满足特定的需求,例如资源限制、网络配置等。
以上是使用 docker run
命令创建和启动 Docker 容器的基本示例。根据你的具体需求,你可能需要使用更多选项和参数。
docker run -d
在 Docker 中,docker run -d
命令用于在后台模式(detached mode)运行容器,即使容器的主进程结束,容器也会继续运行。以下是该命令的详细说明:
语法
|
|
参数
--detach , -d
: 在后台运行容器。--name
: 指定容器的名称。--publish , -p
: 将容器的端口映射到主机。--volume , -v
: 将主机目录挂载到容器内。--env , -e
: 设置环境变量。--restart
: 设置容器的重启策略。
注意事项
IMAGE
参数是要使用的镜像的名称。COMMAND
和ARG...
参数是在容器内部执行的命令和参数。- 在后台模式下运行容器时,容器的输出通常不会直接显示在终端上。可以使用
docker logs
命令查看容器的输出。
docker run -d
允许你在后台运行容器,适用于那些不需要交互式输入的应用程序。通过使用其他选项和参数,你可以自定义容器的行为,例如端口映射、卷挂载、环境变量设置等。
使用镜像centos:latest以 后台模式 启动一个容器
|
|
问题:然后docker ps -a 进行查看, 会发现容器已经退出。
很重要的要说明的一点:Docker容器后台运行,就必须有一个前台进程。
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如:
|
|
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀因为他觉得他没事可做了。
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有交互操作,不要中断。
前台交互式启动和后台守护式启动
前台交互式启动和后台守护式启动是 Docker 容器启动方式的两种主要模式,它们之间有一些关键的区别。
前台交互式启动(Foreground Interactive Mode):
- 在前台交互式模式下启动容器时,容器的主进程通常是一个交互式的 Shell 或其他交互式应用程序。
- 容器启动后,它会占用当前终端,并等待用户输入。
- 用户可以与容器的主进程进行交互,执行命令、查看输出等。
- 当容器的主进程终止时,容器也将终止。
示例:
1
docker run -it ubuntu /bin/bash
在这个例子中,容器以交互式 Shell 的方式启动,用户可以在容器内执行命令。
后台守护式启动(Background Daemon Mode):
- 在后台守护式模式下启动容器时,容器的主进程通常是一个守护进程,例如 Web 服务器、数据库服务器等。
- 容器启动后,主进程在后台运行,不会占用当前终端。
- 用户可以继续使用终端,而容器的主进程会在后台持续运行。
- 容器的终止不会直接影响当前终端。
示例:
1
docker run -d nginx
在这个例子中,Nginx 作为后台守护进程启动,不会占用当前终端,而是在后台运行提供 Web 服务。
关键区别:
- **交互性:**前台模式通常用于需要用户交互的场景,例如调试、测试等。后台模式适用于长期运行的服务,如 Web 服务器、数据库等。
- **占用终端:**前台模式占用当前终端,后台模式不会占用当前终端,允许用户继续在终端中执行其他操作。
- **容器终止:**前台模式下,容器的终止会导致当前终端的退出;后台模式下,容器的终止不会直接影响当前终端。
选择使用哪种启动模式取决于你的应用程序的性质和需求。
docker ps
docker ps
命令用于列出运行中的 Docker 容器。以下是该命令的详细说明:
语法
|
|
参数
--all , -a
:显示所有容器,包括已停止的。--latest , -l
:显示最近创建的容器。--last int , -n
:显示最近n个创建的容器。--quiet , -q
:以静默模式显示容器的 ID。
示例
-
列出运行中的容器:
1
docker ps
该命令将显示所有当前正在运行的 Docker 容器的基本信息,包括容器 ID、名称、状态、端口映射等。
-
列出所有容器,包括已停止的:
1
docker ps -a
该命令将显示所有容器,包括已停止的容器。
-
只显示容器的 ID:
1
docker ps -q
该命令将以静默模式(只显示容器 ID)显示正在运行的容器。
输出字段解释
docker ps
命令的输出包含以下字段:
CONTAINER ID
: 容器的唯一标识符。IMAGE
: 使用的镜像。COMMAND
: 容器启动时执行的命令。CREATED
: 容器创建的时间。STATUS
: 容器的运行状态。PORTS
: 容器的端口映射信息。NAMES
: 容器的名称。
注意事项
- 如果不提供任何选项,
docker ps
将只显示正在运行的容器。 - 使用
-a
选项将显示所有容器,包括已停止的。 - 使用
-q
选项将以静默模式显示容器的 ID。 - 如果容器已经停止,
STATUS
列将显示停止的时间,例如 “Exited (0) 5 minutes ago”。
docker ps
命令是 Docker 中一个常用的命令,它允许你查看当前正在运行的容器以及容器的基本信息。这对于管理和监控 Docker 容器非常有帮助。
退出容器
在 Docker 中,有几种方式可以退出容器。以下是一些常见的退出容器的方式:
-
正常退出容器:
- 在容器内执行
exit
命令,或者按下Ctrl + D
键。 - 示例:
1
exit
- 在容器内执行
-
使容器后台运行
-
使用
Ctrl + P + Q
组合键可以从正在运行的容器中脱离(detach),而不终止容器的运行。这意味着容器将继续在后台运行,但你会返回到宿主机的命令行界面。脱离容器后,你仍然可以使用
docker attach
命令重新进入容器的交互模式。1
docker attach <container_id_or_name>
-
-
后台运行容器时,停止容器:
- 如果容器是在后台运行的,可以使用
docker stop
命令来停止容器。 - 示例:
1
docker stop <container_id_or_name>
- 如果容器是在后台运行的,可以使用
-
容器运行完任务后自动退出:
- 如果容器执行的任务完成后就自动退出,可以在
docker run
命令中使用--rm
选项,这会在容器退出时自动删除容器。 - 示例:
1
docker run --rm my_image
- 如果容器执行的任务完成后就自动退出,可以在
-
强制退出容器:
- 如果容器不响应,可以使用
docker kill
命令来强制退出容器。 - 示例:
1
docker kill <container_id_or_name>
- 如果容器不响应,可以使用
-
使用
docker-compose down
命令:- 如果容器是通过 Docker Compose 启动的,可以使用
docker-compose down
命令来停止并删除相关的容器。 - 示例:
1
docker-compose down
- 如果容器是通过 Docker Compose 启动的,可以使用
请根据你的具体需求选择适当的方式退出容器。正常退出容器和停止容器的方式是最常用的,但在某些情况下可能需要使用强制退出等方式。
docker start
docker start
命令用于启动已停止的容器。以下是该命令的详细介绍:
语法
|
|
参数
--attach , -a
: 连接到正在运行的容器。--detach-keys
: 覆盖分离键的默认值。--interactive , -i
: 保持标准输入 (stdin) 打开。--stop-timeout
: 等待容器停止的超时时间。
示例
-
启动一个已停止的容器:
1
docker start my_container
该命令将启动名为
my_container
的已停止容器。 -
后台启动容器:
1
docker start -d my_container
该命令将在后台启动名为
my_container
的已停止容器。 -
启动并连接到容器:
1
docker start -ai my_container
该命令将启动并连接到名为
my_container
的容器。使用-ai
选项可以同时保持标准输入 (stdin) 打开。
注意事项
CONTAINER
参数是指定要启动的容器的名称或容器的 ID。- 如果容器是以交互模式(例如,使用
-i
选项)启动的,你可以使用docker attach
命令连接到容器的标准输入、输出和错误流。 - 如果容器是以后台模式启动的,你可以使用
docker logs
命令查看容器的日志。
通过 docker start
命令,你可以重新启动之前停止的容器,无论是以交互模式还是后台模式运行。此命令提供了一种灵活的方式来管理容器的生命周期。
docker restart
docker restart
命令用于重启运行中或已停止的容器。该命令将停止容器并立即重新启动它。以下是该命令的详细介绍:
语法
|
|
参数
--time , -t
: 指定在容器停止之前的超时时间。
示例
-
重启一个运行中的容器:
1
docker restart my_container
该命令将重启名为
my_container
的运行中容器。 -
重启多个容器:
1
docker restart container1 container2
该命令将同时重启名为
container1
和container2
的容器。 -
带超时时间的重启:
1
docker restart -t 30 my_container
该命令将在重启容器之前等待 30 秒。
注意事项
CONTAINER
参数是指定要重启的容器的名称或容器的 ID。- 使用
docker restart
会在容器停止之后立即重新启动,这可能导致服务中断。 - 如果容器处于停止状态,
docker restart
将启动它;如果容器处于运行状态,将先停止再启动。
docker restart
提供了一种方便的方式来重新启动容器,无论其当前状态如何。在某些情况下,重启容器可能是更新配置或应用程序更改的一种简便方式。请确保了解容器内应用程序的行为,以便在重启过程中不会造成数据丢失或其他问题。
docker stop
docker stop
命令用于停止运行中的容器。这个命令发送一个信号给容器,通知它停止运行,然后容器会执行相应的停止操作。以下是该命令的详细介绍:
语法
|
|
参数
--time , -t
: 指定容器在被强制停止之前的超时时间,单位为秒。
示例
-
停止一个运行中的容器:
1
docker stop my_container
该命令将停止名为
my_container
的运行中容器。 -
停止多个容器:
1
docker stop container1 container2
该命令将同时停止名为
container1
和container2
的容器。 -
带超时时间的停止:
1
docker stop -t 30 my_container
该命令将在停止容器之前等待 30 秒,允许容器执行一些清理操作。
注意事项
CONTAINER
参数是指定要停止的容器的名称或容器的 ID。- 使用
docker stop
会尽量优雅地通知容器停止运行,允许容器执行一些清理工作。如果容器内的应用程序支持优雅关闭,可以在这个过程中完成善后工作。 - 如果容器在超时时间内没有正常停止,将被强制停止。
- 如果不指定超时时间,默认使用 Docker 配置中的超时值。
通过 docker stop
命令,你可以控制容器的生命周期,安全地停止容器以及执行一些清理操作。在一些情况下,可能需要等待容器执行一些任务再停止,这时可以使用 -t
选项指定一个合适的超时时间。
docker kill
docker kill
命令用于强制停止运行中的容器。与 docker stop
不同,docker kill
不会发送优雅停止的信号,而是直接终止容器的进程。以下是该命令的详细介绍:
语法
|
|
参数
--signal , -s
: 指定要发送给容器的信号,默认为SIGKILL
。
示例
-
强制停止一个运行中的容器:
1
docker kill my_container
该命令将强制停止名为
my_container
的运行中容器。 -
强制停止多个容器:
1
docker kill container1 container2
该命令将同时强制停止名为
container1
和container2
的容器。 -
指定信号强制停止:
1
docker kill -s SIGTERM my_container
该命令将使用
SIGTERM
信号强制停止容器。默认为SIGKILL
。
注意事项
CONTAINER
参数是指定要强制停止的容器的名称或容器的 ID。- 使用
docker kill
将直接终止容器的进程,不会给容器执行清理工作的机会。 - 可以使用
-s
选项指定要发送的信号。常用的信号包括SIGTERM
(15)和SIGKILL
(9)。 - 如果不指定信号,默认使用
SIGKILL
。
使用 docker kill
是在容器无法通过正常方式停止时的一种手段。这通常用于处理无响应的或者需要立即停止的情况,但应谨慎使用,因为它可能导致数据丢失或其他问题。
docker rm
docker rm
命令用于删除一个或多个已经停止的容器。以下是该命令的详细介绍:
语法
|
|
参数
--force , -f
: 强制删除运行中的容器。--link
: 删除容器间的连接。--volumes , -v
: 删除与容器关联的卷。
示例
-
删除一个已停止的容器:
1
docker rm my_container
该命令将删除名为
my_container
的已停止容器。 -
删除多个已停止的容器:
1
docker rm container1 container2
该命令将同时删除名为
container1
和container2
的已停止容器。 -
强制删除运行中的容器:
1
docker rm -f running_container
该命令将强制删除名为
running_container
的运行中容器。 -
删除容器及关联的卷:
1
docker rm -v my_container
该命令将删除名为
my_container
的容器,并删除与之关联的卷。
注意事项
CONTAINER
参数是指定要删除的容器的名称或容器的 ID。- 如果容器正在运行,通常需要停止容器后才能删除。
- 使用
-f
选项可以强制删除正在运行的容器。 - 使用
-v
选项可以删除容器关联的卷。卷是容器内的持久化存储,使用-v
选项可以同时删除这些卷。
通过 docker rm
命令,你可以清理已停止的容器,释放资源,并在需要时删除与之相关的卷。请谨慎使用 -f
选项,因为它将强制删除正在运行的容器,可能导致数据丢失。
docker logs
docker logs
命令用于查看容器的日志输出。该命令允许你检查容器内的标准输出(stdout)和标准错误输出(stderr)。以下是该命令的详细说明:
语法
|
|
参数
--details
: 显示更多的容器日志详细信息。--follow , -f
: 实时跟踪容器的日志输出。--since
: 仅显示自指定日期或时间以来的日志。--tail
: 仅显示指定行数的日志。--timestamps , -t
: 显示时间戳。--until
: 仅显示到指定日期或时间的日志。
示例
-
查看容器的日志:
1
docker logs my_container
该命令将显示名为
my_container
的容器的日志输出。 -
实时跟踪容器的日志:
1
docker logs -f my_container
该命令将实时跟踪名为
my_container
的容器的日志输出。 -
显示容器日志的详细信息:
1
docker logs --details my_container
该命令将显示名为
my_container
的容器的详细日志信息。 -
显示指定行数的日志:
1
docker logs --tail 10 my_container
该命令将显示名为
my_container
的容器的最后 10 行日志。 -
显示自指定日期或时间以来的日志:
1
docker logs --since "2022-01-01T00:00:00" my_container
该命令将显示名为
my_container
的容器从指定日期或时间以来的日志。
注意事项
CONTAINER
参数是指定要查看日志的容器的名称或容器的 ID。- 使用
-f
选项可以实时跟踪容器的日志输出,类似于tail -f
命令。 - 使用
--details
选项可以显示更多的容器日志详细信息,例如容器的标签、ID 等。 - 使用
--timestamps
选项可以显示日志中的时间戳。
docker logs
是一个非常有用的命令,特别是在调试和监视容器时。通过查看容器的日志输出,你可以了解容器内部的运行情况,发现问题并进行排查。
docker top
docker top
命令用于显示 Docker 容器内运行的进程信息,类似于 Linux 中的 top
命令。以下是该命令的详细说明:
语法
|
|
参数
CONTAINER
: 指定要查看进程信息的容器的名称或容器的 ID。ps OPTIONS
: 可选参数,传递给容器内的ps
命令的选项。
示例
|
|
这个命令将显示名为 my_container
的容器内运行的进程信息。
|
|
这个命令将显示名为 my_container
的容器内运行的详细进程信息,类似于 Linux 中的 ps aux
。
注意事项
CONTAINER
参数是指定要查看进程信息的容器的名称或容器的 ID。ps OPTIONS
是可选参数,可以传递给容器内的ps
命令的选项。这允许你自定义输出的格式和内容。
docker top
提供了一种查看容器内运行进程的快速方式。这对于监视容器中运行的进程和调试容器问题很有帮助。
docker inspect
docker inspect
命令用于检查 Docker 对象的详细信息,包括容器、镜像、卷等。该命令返回一个 JSON 格式的输出,包含有关指定对象的各种属性和配置信息。以下是该命令的详细说明:
语法
|
|
参数
OPTIONS
: 可选参数,可以用来自定义输出的格式、选择要显示的字段等。NAME|ID
: 指定要检查的 Docker 对象的名称或 ID。
示例
-
检查容器的详细信息:
1
docker inspect my_container
这个命令将返回名为
my_container
的容器的详细信息。 -
检查镜像的详细信息:
1
docker inspect my_image
这个命令将返回名为
my_image
的镜像的详细信息。 -
检查多个对象的详细信息:
1
docker inspect my_container my_image
这个命令将同时返回名为
my_container
的容器和名为my_image
的镜像的详细信息。 -
使用格式化输出:
1
docker inspect --format='{{.NetworkSettings.IPAddress}}' my_container
这个命令将以特定格式输出名为
my_container
的容器的 IP 地址。
注意事项
NAME|ID
参数是指定要检查的 Docker 对象的名称或 ID。可以同时指定多个对象。- 使用
--format
选项可以自定义输出的格式。可以使用 Go 模板语法指定要显示的字段。 docker inspect
返回的是一个包含详细信息的 JSON 格式文本,因此可以通过解析 JSON 获取感兴趣的信息。
docker inspect
是一个非常强大的命令,可以用来深入了解 Docker 对象的内部配置和状态。它在调试、监控和自动化脚本中都非常有用。
docker exec
docker exec
命令用于在运行中的容器内部执行命令。通过这个命令,你可以进入容器的命名空间,以交互或非交互的方式执行特定的命令。以下是该命令的详细说明:
语法
|
|
参数
OPTIONS
: 可选参数,用于自定义执行命令的行为,例如设置工作目录、指定用户等。CONTAINER
: 指定要在其中执行命令的容器的名称或 ID。COMMAND
: 要在容器内执行的命令。ARG...
: 可选参数,传递给容器内执行的命令的参数。
示例
-
进入容器的 Shell:
1
docker exec -it my_container /bin/bash
这个命令将以交互式方式进入名为
my_container
的容器的 Bash Shell。 -
在容器内执行命令:
1
docker exec my_container ls -l
这个命令将在名为
my_container
的容器内执行ls -l
命令。 -
指定工作目录执行命令:
1
docker exec -w /app my_container ls -l
这个命令将在名为
my_container
的容器内的/app
目录中执行ls -l
命令。 -
以非交互方式执行命令:
1
docker exec my_container echo "Hello, Docker!"
这个命令将在名为
my_container
的容器内执行echo
命令,输出 “Hello, Docker!",但不进入交互式 Shell。
注意事项
CONTAINER
参数是指定要在其中执行命令的容器的名称或容器的 ID。- 使用
-it
选项可以以交互式方式进入容器。如果要执行非交互命令,可以省略这个选项。 - 可以通过
-w
选项指定在容器内执行命令时的工作目录。 - 使用
docker exec
不会改变容器的状态,即容器仍然在运行中。 - 在容器中执行的命令会继承容器的环境和配置。
通过 docker exec
,你可以方便地在运行中的容器内执行命令,而无需停止和启动容器。这对于调试、查看容器内部状态以及执行一次性任务非常有用。
docker attach
docker attach
命令用于附加到正在运行的容器的标准输入、输出和错误流(STDIN/STDOUT/STDERR)。这个命令可以使你与容器的主进程建立交互式的连接。需要注意的是,使用 docker attach
会绑定到容器的主进程,而不会创建新的 Shell。
语法
|
|
参数
OPTIONS
: 可选参数,用于自定义附加操作的行为,例如选择 STDIN 是否绑定到终端。CONTAINER
: 指定要附加的容器的名称或容器的 ID。
示例
|
|
这个命令将附加到名为 my_container
的容器,与容器内的主进程建立交互连接。
注意事项
- 使用
docker attach
会附加到容器内的主进程,并且当前终端将与容器的 STDIN/STDOUT/STDERR 流相连。 - 当容器的主进程结束时,
docker attach
也会随之结束,返回到原始终端。 - 如果容器的主进程是一个 Shell,那么你会直接进入到这个 Shell,并与其进行交互。
- 如果容器的主进程是一个守护进程或者一个不希望用户交互的服务,使用
docker attach
可能不太合适。在这种情况下,更推荐使用docker exec
来执行需要的命令。 - 使用
CTRL + P
和CTRL + Q
可以在不终止容器的情况下从docker attach
中退出。
总体而言,docker attach
是一种在运行中的容器中建立交互连接的方式,但它有一些使用上的限制,因此在一些场景下可能不如 docker exec
灵活。
docker exec
和 docker attach
的区别:
docker exec
和 docker attach
是两个不同的命令,它们在与容器的交互方式上有一些重要的区别。
docker exec
命令:
-
**功能:**用于在运行中的容器内部执行命令,而不需要进入容器的交互式 Shell。
-
**使用场景:**适用于执行一次性任务、查看容器内部状态、调试等操作。
-
示例:
1
docker exec -it my_container /bin/bash
-
注意事项:
docker exec
允许你在容器内部执行任何命令,而不仅仅是 Shell。- 可以在容器内指定工作目录、设置环境变量等。
- 使用
docker exec
不会改变容器的状态,容器仍然在运行。
docker attach
命令:
-
**功能:**用于附加到正在运行的容器的标准输入、输出和错误流,与容器的主进程建立交互连接。
-
**使用场景:**适用于需要与容器的主进程直接进行交互的场景。
-
示例:
1
docker attach my_container
-
注意事项:
docker attach
会直接附加到容器的主进程,并且当前终端与容器的 STDIN/STDOUT/STDERR 流相连。- 如果容器的主进程是一个 Shell,你将进入到这个 Shell 中。
- 当容器的主进程结束时,
docker attach
也会结束,返回到原始终端。 - 使用
CTRL + P
和CTRL + Q
可以在不终止容器的情况下从docker attach
中退出。
区别总结:
attach 直接进入容器启动命令的终端,不会启动新的进程。用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程。用exit退出,不会导致容器的停止。
推荐使用
docker exec
命令,因为退出容器终端,不会导致容器的停止。
docker cp
docker cp
命令用于在本地文件系统和运行中的容器之间复制文件或目录。这个命令允许你从主机系统复制文件到容器内,或从容器内复制文件到主机系统。以下是该命令的详细说明:
语法
|
|
参数
OPTIONS
: 可选参数,用于自定义复制操作的行为,例如递归复制、设置权限等。CONTAINER
: 指定容器的名称或容器的 ID。SRC_PATH
: 指定要复制的文件或目录的路径。对于从主机到容器的复制,这是主机上的路径;对于从容器到主机的复制,这是容器内的路径。DEST_PATH
: 指定目标路径。对于从主机到容器的复制,这是容器内的路径;对于从容器到主机的复制,这是主机上的路径。SRC_PATH|-
和DEST_PATH|-
表示标准输入或标准输出。
示例
-
从主机到容器复制文件:
1
docker cp file.txt my_container:/path/in/container/
这个命令将本地主机上的
file.txt
复制到名为my_container
的容器内的/path/in/container/
目录。 -
从容器到主机复制文件:
1
docker cp my_container:/path/in/container/file.txt /local/path/on/host/
这个命令将容器内的
/path/in/container/file.txt
复制到本地主机上的/local/path/on/host/
目录。 -
从主机到容器复制目录:
1
docker cp my_directory my_container:/path/in/container/
这个命令将本地主机上的
my_directory
目录复制到名为my_container
的容器内的/path/in/container/
目录。 -
从容器到主机复制目录:
1
docker cp my_container:/path/in/container/my_directory /local/path/on/host/
这个命令将容器内的
/path/in/container/my_directory
目录复制到本地主机上的/local/path/on/host/
目录。 -
从容器复制到标准输出:
1
docker cp my_container:/path/in/container/file.txt -
这个命令将容器内的
/path/in/container/file.txt
文件的内容输出到标准输出。
注意事项
CONTAINER
参数是指定容器的名称或容器的 ID。- 复制操作是从本地主机到容器或从容器到本地主机,不能直接在容器之间复制。
- 可以使用
-L
选项递归地复制目录和子目录。 - 使用
SRC_PATH|-
和DEST_PATH|-
可以将文件内容输出到标准输出或从标准输入读取内容进行复制。
docker cp
是一个方便的命令,使得在主机和容器之间复制文件和目录变得容易。这对于将文件复制到运行中的容器以及从容器中提取文件很有用。
导入和导出
Docker 提供了 docker export
和 docker import
命令,用于导出和导入容器的文件系统快照,使得容器可以在不同的环境中共享。
1.导出容器
docker export
命令用于将容器的文件系统快照打包为一个 tar 归档文件。以下是该命令的基本语法:
|
|
CONTAINER
: 指定要导出的容器的名称或容器的 ID。container.tar
: 指定导出的文件保存的路径。
示例:
|
|
2.导入容器
docker import
命令用于从 tar 归档文件或标准输入流中创建一个新的镜像。这个命令允许你将文件系统快照导入为 Docker 镜像。以下是该命令的详细介绍:
语法
|
|
参数
OPTIONS
: 可选参数,用于自定义导入操作的行为,例如设置标签、指定工作目录等。file|URL|-
: 指定导入的 tar 归档文件的路径、URL 地址或者从标准输入读取。REPOSITORY[:TAG]
: 指定新创建的镜像的仓库名称和标签。
示例
-
从本地文件导入:
1
docker import my_container_exported.tar my_imported_image
这个命令将
my_container_exported.tar
文件导入为名为my_imported_image
的新镜像。 -
从 URL 导入:
1
docker import http://example.com/my_image.tar my_imported_image
这个命令将通过 URL
http://example.com/my_image.tar
导入镜像为名为my_imported_image
。 -
从标准输入导入:
1
cat my_container_exported.tar | docker import - my_imported_image
这个命令将通过标准输入流导入 tar 文件,并创建名为
my_imported_image
的新镜像。
注意事项
- 如果未指定仓库名称和标签,新创建的镜像将被赋予随机生成的唯一 ID。
docker import
导入的镜像是不包含历史记录的。如果需要完整的历史记录,可以考虑使用docker commit
命令。- 这种方式导入的镜像是基础镜像,没有元数据信息,例如启动配置、网络配置等。在导入后,你可能需要通过
docker run
进行额外的配置。
总体而言,docker import
是一个简便的方式,可以从 tar 归档文件或标准输入导入文件系统快照,并创建一个新的 Docker 镜像。
总的来说,docker export
和 docker import
是简单而有效的方式,可以在不同的 Docker 环境中分享和传递容器的文件系统快照。
常用命令汇总

|
|
Docker镜像
镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
分层的镜像
Docker 使用分层的文件系统结构来构建镜像。每个镜像都是由多个只读层(Layer)组成的。这种分层的设计有几个重要的优势:
-
**镜像复用:**由于每个层都是只读的,当多个镜像共享相同的层时,可以节省存储空间。如果两个镜像大部分层相同,它们只需要存储不同的那一层。
-
**层的缓存:**当构建镜像时,Docker 使用缓存来提高构建速度。如果之前的构建已经包含了某一层,那么在后续构建中可以直接使用缓存,而不必重新下载或创建。
-
**分层的可读性和可写性:**容器运行时可以在镜像的顶部添加一个可写的层,该层包含容器运行时的文件系统修改。这使得容器可以在只读的基础镜像上运行,并且容器的变化都可以保存在可写的层中,而不影响基础镜像。
一个典型的 Docker 镜像由多个层组成,每个层都代表一个文件系统的快照。当你运行一个容器时,Docker 将这些层堆叠在一起,形成一个容器的文件系统。当你对容器进行修改时,这些修改将保存在一个新的可写层中。
例如,一个包含基础 Ubuntu 操作系统的 Docker 镜像可能由以下层组成:
- **基础镜像层:**包含 Ubuntu 操作系统的文件系统。
- **软件包安装层:**包含通过
apt-get
安装的软件包。 - **应用程序层:**包含你的应用程序和相关文件。
这样的分层结构使得 Docker 镜像更加灵活、可共享,也方便了版本控制和镜像管理。
联合文件系统
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
ChatGPT的解答:
Docker 中的联合文件系统是指通过联合挂载(Union Mounting)将多个只读文件系统层叠在一起,形成一个单一的文件系统视图。这种联合文件系统的设计是为了支持 Docker 镜像的分层结构,以提供镜像的复用、缓存和高效的文件系统操作。
Docker 使用联合文件系统的主要目的是将不同的文件系统层合并为一个单一的文件系统,同时保留每个层的只读特性。这使得容器可以在只读的基础镜像上运行,并在一个可写的层中保存容器运行时的文件修改。以下是联合文件系统的一些关键特点:
-
**只读层:**每个 Docker 镜像层都是只读的。这包括基础镜像和通过
Dockerfile
中的指令添加的每一层。 -
**联合挂载:**Docker 使用联合挂载技术将多个只读层堆叠在一起,形成一个单一的文件系统。这种堆叠的方式允许容器看到一个统一的文件系统视图。
-
**可写层:**在容器运行时,Docker 会在联合文件系统的顶部添加一个可写的层,用于保存容器运行时的文件修改。这个可写层是容器的文件系统的一部分,但它不会影响底层的只读层。
-
**分层的镜像:**Docker 镜像由多个分层组成,每个分层都包含文件系统的快照。这种分层结构允许 Docker 镜像的高度可复用和可共享。
-
**缓存和速度:**联合文件系统提供了文件系统的缓存机制,当构建镜像时,如果之前的构建已经包含了某一层,Docker 可以直接使用缓存,而不必重新下载或创建。
总的来说,Docker 中的联合文件系统是一个关键的技术,使得 Docker 镜像能够实现轻量、高效、可共享的特性。这种联合文件系统的设计是 Docker 实现容器化的关键之一。
Docker镜像加载原理
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev,/proc,/bin,/etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
分层结构的原因
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像; 同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的。 当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

创建新的镜像
docker commit命令
docker commit
命令用于创建一个新的镜像,该镜像是通过对容器的修改而生成的。具体而言,该命令将容器的文件系统和元数据保存为新的镜像。以下是docker commit
命令的基本语法和一些常见选项的详细介绍:
基本语法:
|
|
CONTAINER
:要提交为镜像的容器的ID或名称。REPOSITORY[:TAG]
:新镜像的名称和标签。如果省略标签,默认使用latest
。
选项(OPTIONS):
-
-a, --author
:指定新镜像的作者信息。1
docker commit -a "Author Name" CONTAINER [REPOSITORY[:TAG]]
-
-c, --change
:提交时应用的定制化配置。1
docker commit -c 'CMD ["nginx", "-g", "daemon off;"]' CONTAINER [REPOSITORY[:TAG]]
-
-m, --message
:为新镜像添加一条提交消息。1
docker commit -m "Commit message" CONTAINER [REPOSITORY[:TAG]]
-
--pause
:在提交时暂停容器,以确保容器文件系统的一致性。1
docker commit --pause CONTAINER [REPOSITORY[:TAG]]
示例:
|
|
请注意,使用docker commit
可以创建快照,但最好的做法是使用 Dockerfile 来定义容器镜像的构建步骤,以便能够重现镜像的构建过程和确保更好的可维护性。
案例演示
创建新的ubuntu镜像,使其具有 Vim 编辑器。
要创建一个新的 Ubuntu 镜像,并确保它具有 Vim 编辑器,你可以使用以下步骤:
-
创建一个基础容器:首先,运行一个基础的 Ubuntu 容器。
1
docker run -it --name my_ubuntu ubuntu
这将在交互模式下启动一个新的 Ubuntu 容器,并将其命名为
my_ubuntu
。 -
在容器中安装 Vim:进入容器,并在容器内使用 apt 安装 Vim。
1
docker exec -it my_ubuntu bash
在容器内部,运行以下命令安装 Vim:
1 2
apt update apt -y install vim
apt update
:更新本地软件包索引;apt -y install vim
:在Linux 系统上使用 APT 包管理器安装 Vim 文本编辑器。 -
退出容器:在容器内安装完 Vim 后,退出容器。
1
exit
-
提交容器为新镜像:使用
docker commit
命令将容器提交为新的镜像。1
docker commit -m="vim cmd add ok" -a="hollis" my_ubuntu ubuntu_with_vim:1.0
my_ubuntu
为当前容器的名称;ubuntu_with_vim:1.0
为新镜像的名称和版本号。 -
验证新镜像:您可以使用新创建的镜像运行一个容器,并验证是否安装了 Vim。
1
docker run -it --rm ubuntu_with_vim:1.0
在容器中,运行
vim --version
来确认 Vim 是否已安装。
这样,您就创建了一个新的 Ubuntu 镜像,并确保它包含了 Vim 编辑器。请注意,通过使用 Dockerfile 来定义镜像,您可以更好地记录镜像构建的步骤,以便更容易地重现和分享镜像。
总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。 新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

创建新镜像的几种方式
在 Docker 中,生成新镜像的方法有多种,以下是一些常见的方式:
-
使用 Dockerfile:
-
创建一个包含构建指令的 Dockerfile 文件,定义镜像的构建步骤、依赖关系和配置。
-
使用
docker build
命令来基于 Dockerfile 构建新镜像。 -
示例:
1 2 3
# Dockerfile FROM ubuntu:latest RUN apt-get update && apt-get install -y vim
1
docker build -t my_ubuntu_with_vim .
-
-
使用容器快照(docker commit):
-
运行一个容器并在容器内进行修改。
-
使用
docker commit
命令基于修改后的容器生成新镜像。 -
示例:
1 2 3
docker run -it --name my_container ubuntu:latest # 在容器内安装 vim 或进行其他修改 docker commit my_container my_ubuntu_with_vim
-
-
导入和导出容器(docker export 和 docker import):
-
使用
docker export
将容器文件系统导出为 tar 文件。 -
使用
docker import
将导出的 tar 文件导入为新的镜像。 -
示例:
1 2 3 4
docker run -it --name my_container ubuntu:latest # 在容器内安装 vim 或进行其他修改 docker export my_container > my_container.tar docker import my_container.tar my_ubuntu_with_vim
-
-
使用已有镜像作为基础:
-
基于已有的镜像启动一个容器。
-
在容器内进行修改,然后使用
docker commit
生成新镜像。 -
示例:
1 2 3
docker run -it --name my_container ubuntu:latest # 在容器内安装 vim 或进行其他修改 docker commit my_container my_ubuntu_with_vim
-
无论使用哪种方法,建议优先使用 Dockerfile 来定义镜像的构建过程,因为这样更具有可维护性和可重复性。 Dockerfile 允许您清晰地描述镜像的配置和依赖关系,并且能够轻松地分享和复制镜像构建过程。
本地镜像发布到阿里云
流程

命名空间


创建镜像仓库



进入管理界面获得脚本

相关操作命令
1.登录阿里云Docker Registry
|
|
用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。
您可以在访问凭证页面修改凭证密码。
2.从Registry中拉取镜像
|
|
3.将镜像推送到Registry
|
|
请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。
4.选择合适的镜像仓库地址
从ECS推送镜像时,可以选择使用镜像仓库内网地址。推送速度将得到提升并且将不会损耗您的公网流量。
如果您使用的机器位于VPC网络,请使用 registry-vpc.cn-hangzhou.aliyuncs.com 作为Registry的域名登录。
5. 示例
使用"docker tag"命令重命名镜像,并将它通过专有网络地址推送至Registry。
|
|
使用 “docker push” 命令将该镜像推送至远程。
|
|
Docker私服库
介绍
Docker私服库(Registry)是用于存储和管理Docker镜像的服务器。它允许您在本地网络中创建和维护自己的Docker镜像仓库,以提高镜像的分发速度、安全性和可靠性。您可以搭建私有的Docker Registry来存储和分享自己的镜像,而不是依赖公共的Docker Hub。
以下是一些关于搭建和使用Docker私服库的一般步骤:
-
选择Registry: 选择要使用的Registry。Docker官方提供了一个开源的Registry,可以在GitHub上找到:Docker Registry。除此之外,还有一些第三方Registry,比如JFrog Artifactory、Harbor等。
-
安装Registry: 安装选定的Registry。如果选择Docker官方的Registry,可以按照其文档进行安装。如果选择其他Registry,可以参考相应的文档。
-
配置Registry: 配置Registry以满足您的需求。这可能包括设置访问控制、配置存储后端、启用TLS等。
-
启动Registry: 启动Registry服务。具体的启动命令取决于您选择的Registry。例如,使用Docker官方Registry的命令可能类似于:
1
docker run -d -p 5000:5000 --restart=always --name registry registry:2
这将在本地端口5000上启动一个Docker Registry容器。
-
推送和拉取镜像: 将本地构建的Docker镜像推送到私有Registry,然后从Registry中拉取镜像。推送和拉取的命令如下:
-
推送:
1 2
docker tag image_name:tag localhost:5000/image_name:tag docker push localhost:5000/image_name:tag
-
拉取:
1
docker pull localhost:5000/image_name:tag
请注意,这里的
localhost:5000
是Registry的地址,您需要替换为实际的地址。 -
通过搭建私有的Docker Registry,您可以更好地控制您的镜像,提高镜像的安全性和可靠性。此外,私有Registry还支持离线环境中的部署,使您能够在没有互联网连接的环境中使用Docker。
具体案例
创建新的ubuntu镜像,使其支持 ifconfig 命令,并推送到私有库中。
- 下载镜像Docker Registry


- 运行私有库Registry,相当于本地有个私有Docker hub
|
|
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调。

-
创建一个新镜像,ubuntu安装ifconfig命令
-
从Hub上下载ubuntu镜像到本地并成功运行
-
原始的Ubuntu镜像是不带着ifconfig命令的

- 外网连通的情况下,安装ifconfig命令并测试通过
docker容器内执行上述两条命令:
|
|


- 安装完成后,commit我们自己的新镜像
公式:docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
命令:在容器外执行,记得
|
|

-
启动我们的新镜像并和原来的对比
-
官网是默认下载的Ubuntu没有ifconfig命令;
-
我们自己commit构建的新镜像,新增加了ifconfig功能,可以成功使用。

- curl验证私服库上有什么镜像
|
|
可以看到,目前私服库没有任何镜像上传过。

- 将新镜像zzyyubuntu:1.2修改符合私服规范的Tag
按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
使用命令:docker tag
将zzyyubuntu:1.2
这个镜像修改为192.168.111.162:5000/zzyyubuntu:1.2
。
|
|
- 修改配置文件使之支持http

vim修改daemon.json文件:
|
|
在该文件中添加如下的内容:
|
|
2个配置中间有个逗号 ‘,‘别漏了,这个配置是json格式的。
修改之后的文件内容:

docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====> 修改完后如果不生效,建议重启docker。
- push推送到私服库
|
|

- 再次curl验证私服库上有什么镜像
|
|

- pull到本地并运行
|
|

|
|

容器数据卷
privileged=true
--privileged=true
是 Docker Run 命令的一个选项,用于在容器中开启特权模式。启用特权模式允许容器访问主机上的所有设备,并允许容器执行特权操作,这样可能会带来一些潜在的安全风险。
使用 --privileged=true
主要有以下几个作用:
-
设备访问: 特权模式允许容器访问主机上的所有设备。这对于与一些硬件相关的容器应用可能是必需的,但也会增加潜在的安全风险。
-
CAP_SYS_ADMIN 权限: 特权模式赋予容器拥有 Linux 的
CAP_SYS_ADMIN
权限,这是一个非常高的权限级别,容器将能够执行许多系统级别的操作。这包括挂载文件系统、修改网络配置等。 -
进程隔离: 特权模式关闭了容器内与主机之间的一些隔离性措施,使容器内的进程能够影响主机系统。
虽然在某些特殊情况下可能需要使用 --privileged=true
,但一般情况下,推荐避免使用它,因为这可能会增加容器的安全风险。如果有可能,最好使用更细粒度的权限设置,只开启容器真正需要的权限。
例如,如果您只需要容器访问某个设备,可以考虑使用 --device
选项,而不是开启整个特权模式。例如:
|
|
这将只授予容器对 /dev/sdX
设备的访问权限,而不是开启整个特权模式。
是什么
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
一句话:有点类似我们Redis里面的rdb和aof文件,将docker容器内的数据保存进宿主机的磁盘中。
能干嘛
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。 为了能保存数据在docker中我们使用卷。
特点:
- 数据卷可在容器之间共享或重用数据;
- 卷中的更改可以直接实时生效;
- 数据卷中的更改不会包含在镜像的更新中;
- 数据卷的生命周期一直持续到没有容器使用它为止。
数据卷案例
1.宿主vs容器之间映射添加容器卷
公式:docker run -it -v /宿主机目录:/容器内目录 ubuntu /bin/bash
命令:
|
|

2.查看数据卷是否挂载成功
|
|

3.容器和宿主机之间数据共享
- docker修改,主机同步获得;
- 主机修改,docker同步获得;
- docker容器stop,主机修改,docker容器重启看数据是否同步。

读写规则映射添加说明
读写(默认)


rw = read + write
|
|
默认同上案例,默认就是rw。
只读
容器实例内部被限制,只能读取不能写。
|
|

此时容器自己只能读取不能写。
此时如果宿主机写入内容,可以同步给容器内,容器可以读取到。
卷的继承和共享
容器1完成和宿主机的映射
|
|


容器2继承容器1的卷规则
|
|

这样,容器1、容器2和宿主机的数据卷就都是共享的了。
此时,即使容器1被关闭了,也不会影响容器2和宿主机之间的数据共享。当容器1被再次开启时,所有的数据都会根据宿主机中的数据同步更新。
Docker常规安装简介
总体步骤
- 搜索镜像
- 拉取镜像
- 查看镜像
- 启动镜像 — 服务端口映射
- 停止容器
- 移除容器
安装tomcat
搜索镜像
docker hub上面查找tomcat镜像
|
|

拉取镜像
从docker hub上拉取tomcat镜像到本地
|
|

查看镜像
docker images查看是否有拉取到的tomcat
|
|

启动镜像
使用tomcat镜像创建容器实例(也叫运行镜像)
|
|
-p 小写,主机端口:docker容器端口
-P 大写,随机分配端口
![]()
-i:交互
-t:终端
-d:后台
访问 tomcat 首页
问题

解决
可能方案1
可能没有映射端口或者没有关闭防火墙

可能方案2
把webapps.dist目录换成webapps
1.先成功启动tomcat

2.查看webapps 文件夹查看为空

免修改版说明
|
|

安装Mysql
docker hub上面查找mysql镜像

从docker hub上(阿里云加速器)拉取mysql镜像到本地
标签为5.7

使用mysql5.7镜像创建容器(也叫运行镜像)
命令出处,哪里来的?

简单版
使用mysql镜像
|
|

建库建表插入数据

外部Win10也来连接运行在dokcer上的mysql容器实例服务

问题
插入中文数据试试

为什么报错?
docker上默认字符集编码隐患
docker里面的mysql容器实例查看,内容如下:
|
|

删除容器后,里面的mysql数据如何办?
实战版
新建mysql容器实例
|
|

这个命令的作用是创建并运行一个MySQL容器,将MySQL的日志、数据和配置文件分别挂载到主机上的指定目录,使得这些数据在容器停止或删除时仍然保持持久化。同时,通过端口映射,允许通过主机的3306端口访问MySQL服务。容器的root密码也被设置为123456。
新建my.cnf
通过容器卷同步给 mysql 容器实例
|
|

重新启动mysql容器实例再重新进入并查看字符编码


再新建库新建表再插入中文测试


结论
之前的DB 无效
修改字符集操作+重启mysql容器实例
之后的DB 有效,需要新建
结论:docker安装完MySQL并run出容器后,建议请先修改完字符集编码后再新建mysql库-表-插数据。

注意事项
mysql 5.7需要修改数据库的字符编码集;
mysql 8.0,要在windows的 sqlyog 连接数据库,需要使用下面的命令:
1 2 3 4 5 6 7 8
#使用mysql数据库 USE mysql; #修改'root'@'localhost'用户的密码规则和密码 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的数据库密码'; #刷新权限 FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的数据库密码';
:这个命令的作用是将指定用户的认证方式更改为mysql_native_password
,并设置一个新的密码。因为在MySQL 8.0之前的版本中,MySQL使用mysql_native_password
插件作为默认的密码认证插件。然而,从MySQL 8.0版本开始,新的安装使用了更安全的caching_sha2_password
插件。如果你在使用旧版本的MySQL或者需要与某些应用程序或工具兼容,可能需要将用户的认证方式更改为
mysql_native_password
,并设置一个符合该插件要求的密码。如果要在windows的 sqlyog 连接安装在centos7虚拟机中的docker中的mysql,则需要将上面的
'root'@'localhost'
改为'root'@'%'
。
'root'@'localhost'
和'root'@'%'
的区别:这两条SQL语句的区别在于指定用户的连接来源不同,一个是’localhost’,另一个是’%’。
'root'@'localhost'
: 这表示你正在修改用户’root’,但是仅允许从本地主机(即数据库服务器所在的机器)连接。这意味着用户只能通过本地的MySQL服务连接,不能通过网络从远程主机连接。这通常用于提高安全性,因为它限制了对数据库的直接远程访问。
1
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的数据库密码';
'root'@'%'
: 这表示你正在修改用户’root’,允许从任何主机(包括远程主机)连接。使用’%‘通配符表示所有主机。这样的设置可能会增加一些安全风险,因为允许来自任何地方的连接,应慎重使用,并确保密码和其他安全设置足够强大。
1
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的数据库密码';
选择使用哪个取决于你的安全需求和数据库的访问需求。通常情况下,为了提高安全性,建议将访问限制为仅允许来自信任主机的连接。如果需要从任何地方连接,则必须确保使用强密码,并且其他安全措施得到了妥善配置。
赋予远程访问权限
|
|
安装redis
搜索镜像
|
|

拉取镜像
从docker hub上(阿里云加速器),拉取redis镜像到本地,标签为6.0.8。
|
|

查看镜像
|
|

设置容器卷映射
Docker挂载主机目录Docker访问出现 cannot open directory .: Permission denied 解决办法:在挂载目录后多加一个–privileged=true参数即可。
在CentOS宿主机下新建目录/app/redis
|
|

拷贝配置文件
将准备好的redis.conf文件放进/app/redis目录下
默认出厂的原始redis.conf: redis.conf.txt 。
/app/redis目录下修改redis.conf文件
-
开启redis验证 可选 requirepass 123
-
允许redis外地连接 必须
注释掉 # bind 127.0.0.1
-
daemonize no 必须 将daemonize yes注释起来或者 daemonize no设置,因为该配置和docker run中-d参数冲突,会导致容器一直启动失败。
-
开启redis数据持久化 appendonly yes 可选。
启动镜像
使用redis6.0.8镜像创建容器(也叫运行镜像)
|
|

测试redis-cli连接上来
|
|

请证明docker启动使用了我们自己指定的配置文件
修改前

我们用的配置文件,数据库默认是16个。
修改后

宿主机的修改会同步给docker容器里面的配置。
记得重启服务。
测试redis-cli连接上来第2次

Docker复杂安装详说
安装Mysql主从复制
主从复制的介绍
MySQL的主从复制是一种数据库复制技术,用于将一个MySQL数据库服务器(主服务器)上的数据更改自动地复制到一个或多个其他MySQL服务器(从服务器)。这种复制机制使得从服务器上的数据能够保持与主服务器上的数据同步,从而提供了多种优势和用途,包括:
-
负载均衡: 可以将读取操作分布到多个服务器上,从而减轻主服务器的负载。主服务器负责处理写操作,而从服务器处理读操作,有效提高系统整体性能。
-
高可用性: 如果主服务器发生故障,可以快速切换到一个从服务器作为新的主服务器,从而保证数据库服务的可用性。这种架构可以提高系统的容错能力。
-
数据备份: 从服务器可以用作主服务器的实时备份。如果主服务器数据发生损坏或丢失,可以快速切换到一个从服务器,确保业务的连续性。
-
地理分布式数据: 可以将从服务器部署在不同的地理位置,实现数据的分布式存储和访问。这对于全球性的应用程序和服务非常有用。
-
数据分析和报告: 从服务器可以用于执行复杂的查询和数据分析,而不会影响主服务器的性能。这使得可以在从服务器上运行报表和分析任务,而不会干扰主服务器的正常运行。
实现MySQL主从复制的基本原理是,主服务器将所有的数据库更改记录在二进制日志(Binary Log)中,而从服务器连接到主服务器,读取这些二进制日志,并将其中的更改应用到自己的数据库中。这样就保持了主从服务器之间的数据一致性。
需要注意的是,MySQL主从复制并不是用于实时同步的方案,因此在极端情况下可能会出现一些延迟。此外,复制过程中需要确保网络稳定、权限设置正确,并且注意处理主从服务器之间的一些特殊情况,如主从服务器之间的同步错误等。
主从复制的原理
MySQL主从复制的原理基于二进制日志(Binary Log)的使用。以下是MySQL主从复制的基本工作原理:
-
主服务器记录二进制日志:
- 主服务器上的每个写操作(INSERT、UPDATE、DELETE等)都会被记录到二进制日志中。这些日志文件包含了对数据库进行更改的详细信息。
-
从服务器连接到主服务器:
- 从服务器连接到主服务器,并请求复制主服务器的数据。连接过程中,从服务器会提供一个唯一的标识符(
server-id
)以便主服务器识别。
- 从服务器连接到主服务器,并请求复制主服务器的数据。连接过程中,从服务器会提供一个唯一的标识符(
-
从服务器获取主服务器的二进制日志信息:
- 从服务器发送一个请求,主服务器将自己当前的二进制日志文件名和位置信息发送给从服务器。
-
从服务器将二进制日志应用到自己的数据库:
- 从服务器获取到二进制日志文件后,它会将这些日志文件中的操作逐一应用到自己的数据库上,确保数据的一致性。
-
主从服务器保持同步:
- 一旦从服务器追赶上主服务器的最新位置,就会保持同步。此时,主服务器上发生的任何更改都会实时地通过二进制日志传播到从服务器。
需要注意的是,这种复制机制并不是实时的。主从服务器之间可能存在一些延迟,这取决于网络延迟、从服务器的处理能力等因素。
此外,MySQL主从复制还支持两种复制线程:
- I/O 线程(I/O Thread): 负责从主服务器读取二进制日志文件。
- SQL 线程(SQL Thread): 负责执行从主服务器读取的二进制日志中的SQL语句,将更改应用到从服务器的数据库中。
通过这两个线程的协作,主从服务器能够有效地进行数据同步。在从服务器的复制过程中,还可以通过设置不同的复制模式,如异步复制或半同步复制,以满足不同的需求和性能要求。
主从复制的搭建
1.新建主服务器容器实例3307
|
|
mysql 8.0需要使用下面的命令:
1
docker run --privileged=true -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0
/mydata/mysql-master/conf:/etc/mysql —-»> /mydata/mysql-master/conf:/etc/mysql/conf.d
2.进入/mydata/mysql-master/conf目录下新建my.cnf
|
|
my.cnf内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=101 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能 log-bin=mall-mysql-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062
3.修改完配置后重启master实例
|
|
4.进入mysql-master容器
|
|
5.master容器实例内创建数据同步用户
|
|
注意:mysql 8.0 之前的版本中加密规则是mysql_native_password,而在mysql 8.0 之后,加密规则是caching_sha2_password,现在修改为mysql_native_password。
1
CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
6.新建从服务器容器实例3308
|
|
7.进入/mydata/mysql-slave/conf目录下新建my.cnf
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
[mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=102 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用 log-bin=mall-mysql-slave1-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062 ## relay_log配置中继日志 relay_log=mall-mysql-relay-bin ## log_slave_updates表示slave将复制事件写进自己的二进制日志 log_slave_updates=1 ## slave设置为只读(具有super权限的用户除外) read_only=1
8.修改完配置后重启slave实例
|
|
9.在主数据库中查看主从同步状态
|
|
10.进入mysql-slave容器
|
|
11.在从数据库中配置主从复制
|
|

主从复制参数说明:
master_host:主数据库的IP地址; master_port:主数据库的运行端口; master_user:在主数据库创建的用于同步数据的用户账号; master_password:在主数据库创建的用于同步数据的用户密码; master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数; master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数; master_connect_retry:连接失败重试的时间间隔,单位为秒。
12.在从数据库中查看主从同步状态
|
|

13.在从数据库中开启主从同步
|
|

14.查看从数据库状态发现已经同步

15.主从复制测试
主机新建库-使用库-新建表-插入数据
从机使用库-查看记录
可能存在的问题
所有的配置都正确,但Slave_IO_Running
始终为No
,可能是网络原因导致两个docker容器之间无法通信。
默认的bridge 网桥无法指定固定的ip,会导致mysql服务的ip不固定,最好配置为自定义网络。
配置自定义网络:
在 Docker 中配置自定义网络是为了让容器能够相互通信,而不依赖于宿主机的网络设置。以下是使用 Docker 配置自定义网络的一般步骤:
步骤:
创建自定义网络: 使用
docker network create
命令创建自定义网络。你可以为网络指定一个名称,例如my_network
:
1
docker network create my_network
这将创建一个名为
my_network
的自定义网络。运行容器并加入网络: 在启动容器时,通过
--network
选项将容器连接到自定义网络。例如:
1 2
docker run -d --name container1 --network my_network my_image1 docker run -d --name container2 --network my_network my_image2
这将创建两个容器
container1
和container2
,并将它们连接到my_network
网络中。
--network
可简写为--net
。验证网络连接: 在容器中执行网络连接测试,确保它们能够相互通信。你可以使用
ping
、telnet
或其他网络工具进行测试。使用自定义网络中的别名: Docker 允许你为容器在自定义网络中指定别名,这样它们可以使用别名进行通信。例如:
1
docker run -d --name container3 --network my_network --network-alias alias_name my_image3
在这个例子中,
container3
可以使用别名alias_name
来访问该容器。移除自定义网络: 如果需要,可以使用
docker network rm
命令来删除自定义网络:
1
docker network rm my_network
示例:
以下是一个完整的示例,展示如何使用自定义网络:
1 2 3 4 5 6 7 8 9 10 11 12 13
# 步骤1:创建自定义网络 docker network create my_network # 步骤2:运行容器并加入网络 docker run -d --name container1 --network my_network nginx docker run -d --name container2 --network my_network nginx # 步骤3:验证网络连接 docker exec -it container1 ping container2 # 步骤4:使用别名 docker run -d --name container3 --network my_network --network-alias alias_name nginx docker exec -it container1 ping alias_name
请注意,上述示例中使用的是
nginx
镜像,你可以根据你的实际情况替换为其他镜像。使用自定义网络有助于更好地组织容器,提高容器之间的隔离性,并方便容器之间的通信。
查看网络:
|
|
docker中mysql时区的问题:(2023.12.12补)
默认情况下,docker的时区采用的是UTC时区,比北京时间晚了8小时。在mysql中,字段使用CreateTime(自动获取当前时间插入)功能时,会出现晚8小时的情况。
如何解决?
先查看docker的系统时区
进入正在运行的 Docker 容器的 shell,并查看容器内的系统时区。
1
docker exec -it container_name /bin/bash
然后,在容器内部,执行以下命令查看系统时区:
1
cat /etc/timezone
或者,如果
/etc/timezone
文件不存在,你可以查看/etc/localtime
文件:
1
ls -l /etc/localtime
设置时区
进入容器后,可以使用以下命令设置时区:
1
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
这将通过符号链接将容器的
/etc/localtime
文件设置为指定的时区。在这个例子中,时区被设置为 ‘Asia/Shanghai’,你可以根据需要替换为其他时区。设置完成之后,重启docker容器即可。
分布式存储案例
1~2亿条数据需要缓存,请问如何设计这个存储案例
回答:单机单台100%不可能,肯定是分布式存储,用redis如何落地?
一般业界有3种解决方案:
哈希取余分区

2亿条记录就是2亿个k,v,我们单机不行,必须要分布式多机,假设有3台机器构成一个集群,用户每次读写操作都是根据公式: hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。
缺点:
原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。
某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌。
一致性哈希算法分区
一致性Hash算法背景
一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。
提出一致性Hash解决方案,目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。
3大步骤:
-
算法构建一致性哈希环
一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。
它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模。而一致性Hash算法是对 2^32 取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:
整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到 2^32-1 ,也就是说0点左侧的第一个点代表2^32-1, 0和 2^32-1 在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。
-
服务器IP节点映射
将集群中各个IP节点映射到环上的某一个位置。 将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
-
key落到服务器的落键规则
当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。 如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:
根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。
优点:
-
一致性哈希算法的容错性
假设Node C宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据,并且这些数据会转移到D进行存储。
-
一致性哈希算法的扩展性
数据量增加了,需要增加一台节点NodeX,X的位置在A和B之间,那收到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可, 不会导致hash取余全部数据重新洗牌。
缺点:
-
一致性哈希算法的数据倾斜问题 一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如,系统中只有两台服务器:
哈希槽分区
为什么会出现?
为了解决一致性哈希算法的数据倾斜问题。哈希槽实质就是一个数组,数组[0,2^14 -1]形成hash slot空间。
能干什么?
解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。
哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
有多少个hash槽?
一个集群只能有16384个槽,编号0到16383(0到2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
哈希槽计算
Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上。


3主3从redis集群配置
关闭防火墙+启动docker后台服务
|
|
新建6个docker容器redis实例
|
|
命令参数说明:
docker run
:创建并运行docker容器实例;--name redis-node-6
:容器名字;--net host
:使用宿主机的IP和端口,默认;--privileged=true
:获取宿主机root用户权限;-v /data/redis/share/redis-node-6:/data
:容器卷,宿主机地址:docker内部地址;-redis:6.0.8
:redis镜像和版本号;--cluster-enabled yes
:开启redis集群;--appendonly yes
:开启持久化;--port 6386
:redis端口号。
如果运行成功,效果如下:

进入容器redis-node-1并为6台机器构建集群关系
进入容器
|
|
构建主从关系
注意,进入docker容器后才能执行下一命令,且注意自己的真实IP地址。
|
|
--cluster-replicas 1
:表示为每个master创建一个slave节点。


链接进入6381作为切入点,查看集群状态
|
|


主从容错切换迁移案例
数据读写存储
启动6机构成的集群并通过exec进入
|
|
对6381新增两个key
|
|

防止路由失效加参数-c并新增两个key
|
|
这里加入参数-c,表示cluster,意为进入三台机器组成的redis集群而不是redis-node-1这一台机器。

查看集群信息
|
|

容错切换迁移
主6381和从机切换,先停止主机6381
|
|
6381主机停了,对应的真实从机上位。
6381主机停了,对应的真实从机上位
再次查看集群信息
|
|

6381宕机了,6385上位成为了新的master。
备注:本次脑图笔记6381为主下面挂从6385。 每次案例下面挂的从机以实际情况为准,具体是几号机器就是几号。
先还原之前的3主3从
|
|
中间需要等待一会儿,docker集群重新响应。 主从机器分配情况以实际情况为准。

查看集群状态
|
|

主从扩容案例
新建6387、6388两个节点+新建后启动+查看是否8节点
|
|
进入6387容器实例内部
|
|
将新增的6387节点(空槽号)作为master节点加入原集群
|
|
6387 就是将要作为master新增节点 6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群


检查集群情况第1次
|
|

重新分派槽号
|
|
这里的主机地址和端口号写集群中的任意一台即可。


检查集群情况第2次
|
|

槽号分派说明
为什么6387是3个新的区间,以前的还是连续?
重新分配成本太高,所以前3家各自匀出来一部分,从6381/6382/6383三个旧节点分别匀出1364个坑位给新节点6387。

为主节点6387分配从节点6388
命令:redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
|
|
e4781f644d4a4e4d4b4d107157b9ba8144631451——-这个是6387的编号,按照自己实际情况
检查集群情况第3次
|
|


主从缩容案例
目的:6387和6388下线
先删从节点,然后将主节点的槽号清空,最后删除主节点。
检查集群情况1获得6388的节点ID
|
|

将6388删除,从集群中将4号从节点6388删除
命令:redis-cli --cluster del-node ip:从机端口 从机6388节点ID
|
|

|
|
检查一下发现,6388被删除了,只剩下7台机器了。

将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
|
|



检查集群情况第二次
|
|
4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了,不然要输入3次,一锅端。
将6387删除
命令:redis-cli --cluster del-node ip:端口 6387节点ID
|
|

检查集群情况第三次
|
|

DockerFile解析
是什么
概述
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

官网
https://docs.docker.com/engine/reference/builder/
构建三步骤
- 编写Dockerfile文件;
- docker build命令构建镜像;
- docker run依镜像运行容器实例。
DockerFile构建过程解析
Dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数;
- 指令按照从上到下,顺序执行;
- #表示注释;
- 每条指令都会创建一个新的镜像层并对镜像进行提交。
Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器;
- 执行一条指令并对容器作出修改;
- 执行类似docker commit的操作提交一个新的镜像层;
- docker再基于刚提交的镜像运行一个新容器;
- 执行dockerfile中的下一条指令直到所有指令都执行完成。
小总结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
- Dockerfile是软件的原材料;
- Docker镜像是软件的交付品;
- Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例。
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

1.Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2.Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
3.Docker容器,容器是直接提供服务的。
DockerFile常用保留字指令
参考tomcat8的dockerfile入门:https://github.com/docker-library/tomcat
FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from。
MAINTAINER
镜像维护者的姓名和邮箱地址。
RUN
容器构建时需要运行的命令
两种格式:
-
shell格式
如:
RUN yum -y install vim
-
exec格式
RUN是在 docker build时运行。
EXPOSE
当前容器对外暴露出的端口。
WORKDIR
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点。
USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root。
ENV
用来在构建镜像过程中设置环境变量。
ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,
比如:WORKDIR $MY_PATH
。
ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY
类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
COPY src dest
或COPY ["src", "dest"]
<src源路径>:源文件或者源目录 <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
VOLUME
容器数据卷,用于数据保存和持久化工作。
CMD
指定容器启动后的要干的事情。
CMD 指令的格式和 RUN 相似,也是两种格式:
- shell 格式:
CMD<命令>
- exec 格式:
CMD [”可执行文件”, "参数1”, “参数2”...]
- 参数列表格式:
CMD["参数1”, “参数2”...]
。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
注意
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。
参考官网Tomcat的dockerfile演示讲解
官网最后一行命令

我们演示自己的覆盖操作

CMD和前面RUN命令的区别
CMD是在docker run 时运行,RUN是在 docker build时运行。
ENTRYPOINT
也是用来指定一个容器启动时要运行的命令。
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
命令格式:
|
|
ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。
当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成:<ENTRYPOINT>"<CMD>"
案例如下:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
|
|
也就是说,当指定了ENTRYPOINT后,docker run
会执行Dockerfile文件中的ENTRYPOINT
和CMD
内容。具体如下:
Docker命令 | docker run nginx:test | docker run nginx:test -c /etc/nginx/new.conf |
---|---|---|
实际执行命令 | nginx -c /etc/nginx/nginx.conf | nginx -c /etc/nginx/new.conf |
优点
在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
注意
如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
小总结

案例
自定义镜像mycentosjava8
要求
Centos7镜像具备vim+ifconfig+jdk8
JDK的下载镜像地址:https://www.oracle.com/java/technologies/downloads/#java8

https://mirrors.yangxingzhen.com/jdk/
编写
编写Dockerfile文件,内容如下:
|
|

Dockerfile的首字母D必须要大写。
构建
|
|


注意,上面TAG后面有个空格,有个点。
运行
|
|
Docker网络
是什么
docker不启动,默认网络情况

docker启动后,网络情况

会产生一个名为docker0的虚拟网桥。
查看docker网络模式命令:docker network ls
。
常用基本命令
help

创建网络
|
|
查看网络
|
|
网络详情
查看某个网络的详细信息
|
|
删除网络
|
|
案例
|
|

能干嘛
容器间的互联和通信以及端口映射。
容器IP变动时候可以通过服务名直接网络通信而不受到影响。
网络模式
总体介绍
bridge模式:使用–network bridge指定,默认使用docker0;
host模式:使用–network host指定;
none模式:使用–network none指定;
container模式:使用–network container:NAME或者容器ID指定。
容器实例内默认网络IP生产规则
说明
1.先启动两个ubuntu容器实例

2.docker inspect 容器ID or 容器名字

3.关闭u2实例,新建u3,查看ip变化

结论
docker容器内部的ip是有可能会发生改变的,所以我们一般使用docker名字而不是docker的网络IP(这时候就需要自定义的网络,详见后面的自定义网络)。
案例说明
bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
|
|

|
|

案例
1.Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2.docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址。
3.网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
- 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
- 每个容器实例内部也有一块网卡,每个接口叫eth0;
- docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。

|
|
两两匹配验证

host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
案例
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
|
|

问题: docke启动时总是遇见标题中的警告 原因: docker启动时指定–network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告, 并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。 解决: 解决的办法就是使用docker的其他网络模式,例如–network=bridge,这样就可以解决问题,或者不指定 ip端口映射。
正确写法:
|
|
查看网络情况
|
|

没有设置-p的端口映射了,如何访问启动的tomcat83??
http://宿主机IP:8080/
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的, 所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
none
在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡、配置IP等。
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)。
|
|
进入容器内部查看
|
|

在容器外部查看
|
|

container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。

使用Alpine 作为演示的镜像
Alpine Linux 是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。
|
|
运行结果,验证共用搭桥

假如此时关闭alpine1,再看看alpine2
|
|

|
|

自定义网络
|
|
上述成功启动并用docker exec进入各自容器实例内部
【问题】
按照IP地址ping是OK的


按照服务名ping结果???


现在存在的问题是:只能按照ip地址进行互相访问,不能通过容器名,这在实际使用中会极不方便。
所以我们可以考虑使用自定义网络,让两个docker容器都处于同一个自定义网络中,这样就可以通过容器名直接进行网络访问。
案例如下:
自定义桥接网络,自定义网络默认使用的是桥接网络bridge。
新建自定义网络
|
|

新建容器加入上一步新建的自定义网络
|
|
|
|


问题结论
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)。
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 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。

Docker-compose容器编排
是什么
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。
Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
能干嘛
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具。
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
去哪下
官网:https://docs.docker.com/compose/compose-file/compose-file-v3/
官网下载:https://docs.docker.com/compose/install/
安装步骤
|
|

卸载步骤

Compose核心概念
一文件:docker-compose.yml
两要素:
- 服务(service):一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器。
- 工程(project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件;
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线。
Compose常用命令
|
|
Compose编排微服务
改造升级微服务工程docker_boot
以前的基础版

SQL建表建库
|
|
改POM
|
|
写YML
|
|
主启动
|
|
业务类
config配置类
RedisConfig
|
|
SwaggerConfig
|
|
新建entity
User
|
|
UserDTO
|
|
新建mapper
新建接口UserMapper
|
|
src\main\resources路径下新建mapper文件夹并新增UserMapper.xml
|
|
新建service
|
|
新建controller
|
|
mvn package命令将微服务形成新的jar包并上传到Linux服务器/mydocker目录下
编写Dockerfile
|
|
构建镜像
|
|
不用Compose
单独的mysql容器实例
新建mysql容器实例
|
|
进入mysql容器实例并新建库db2021+新建表t_user
|
|
|
|
单独的redis容器实例
|
|
微服务工程
|
|
上面三个容器实例依次顺序启动成功
|
|

swagger测试
|
|
存在的问题
上面成功了,有哪些问题?
-
先后顺序要求固定,先mysql+redis才能微服务访问成功
-
多个run命令……
-
容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错,要么生产IP写死(可以但是不推荐),要么通过服务调用。
使用Compose
服务编排,一套带走,安排
编写docker-compose.yml文件
|
|
第二次修改微服务工程docker_boot
写YML
|
|
通过服务名访问,IP无关。
mvn package命令将微服务形成新的jar包并上传到Linux服务器/mydocker目录下
编写Dockerfile
|
|
构建镜像
|
|
启用docker-compose
|
|


进入mysql容器实例并新建库db2021+新建表t_user
|
|
|
|
最后,测试通过。
关停
|
|

Portainer
Docker轻量级可视化工具Portainer
是什么
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
安装
官网:https://www.portainer.io/
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
步骤
docker命令安装
|
|

第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
用户名,直接用默认admin
密码记得8位,随便你写

设置admin用户和密码后首次登陆

选择local选项卡后本地docker详细信息展示

上一步的图形展示,能想得起对应命令吗?

高级容器监控
Docker容器监控之CAdvisor+InfluxDB+Granfana
原生命令
|
|

docker stats命令的结果:

是什么
容器监控3剑客:CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
CAdvisor

InfluxDB

Granfana

总结

具体操作
compose容器编排,一套带走
新建目录

新建3件套组合的docker-compose.yml
|
|
启动docker-compose文件
|
|


查看三个服务容器是否启动
|
|

测试
浏览cAdvisor收集服务,http://ip:8080/
第一次访问慢,请稍等;
cadvisor也有基础的图形展现功能,这里主要用它来作数据采集。
浏览influxdb存储服务,http://ip:8083/
浏览grafana展现服务,http://ip:3000
ip+3000端口的方式访问,默认帐户密码(admin/admin);
配置步骤:
配置数据源
![]()
选择influxdb数据源
![]()
配置细节
![]()
![]()
![]()
配置面板panel
![]()
![]()
![]()
![]()
![]()
![]()
到这里cAdvisor+InfluxDB+Grafana容器监控系统就部署完成了。