1.容器简介
1.什么是linux容器
Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。
更加详细地来说,请您假定您在开发一个应用。您使用的是一台笔记本电脑,而且您的开发环境具有特定的配置。其他开发人员身处的环境配置可能稍有不同。
您正在开发的应用依赖于您当前的配置,还要依赖于某些特定文件。与此同时,您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。
您希望尽可能多在本地模拟这些环境,而不产生重新创建服务器环境的开销。
因此,您要如何确保应用能够在这些环境中运行和通过质量检测,并且在部署过程中不出现令人头疼的问题,也无需重新编写代码和进行故障修复?答案就是使用容器。
容器可以确保您的应用拥有必需的配置和文件,使得这些应用能够在从开发到测试、再到生产的整个流程中顺利运行,而不出现任何不良问题。这样可以避免危机,做到皆大欢喜。
虽然这只是简化的示例,但在需要很高的可移植性、可配置性和隔离的情况下,我们可以利用 Linux 容器通过很多方式解决难题。无论基础架构是在企业内部还是在云端,或者混合使用两者,容器都能满足您的需求。
2.容器不就是虚拟化吗
是,但也不竟然。我们用一种简单的方式来思考一下:
虚拟化使得许多操作系统可同时在单个系统上运行。
容器则可共享同一个操作系统内核,将应用程序与系统其他部分隔离开。
图 - 普通虚拟化技术和Docker的对比
这意味着什么?首先,让多个操作系统在单个虚拟机监控程序上运行以实现虚拟化,并不能达成和使用容器同等的轻量级效果。事实上,在仅拥有容量有限的有限资源时,您需要能够可以进行密集部署的轻量级应用。Linux 容器可从单个操作系统运行,在所有容器中共享该操作系统,因此应用和服务能够保持轻量级,并行快速运行。
docker与Openstack的对比
3.容器发展简史
我们现在称为容器技术的概念最初出现在 2000 年,当时称为 FreeBSD jail,这种技术可将 FreeBSD 系统分区为多个子系统(也称为 Jail)。Jail 是作为安全环境而开发的,系统管理员可与企业内部或外部的多个用户共享这些 Jail。
Jail 的目的是让进程在经过修改的 chroot (更改某个进程所能看到的根目录,即将某进程限制在指定目录中,保证该进程只能对该目录及其子目录的文件有所动作,从而保证整个服务器的安全。 )环境中创建,而不会脱离和影响整个系统 — 在 chroot 环境中,对文件系统、网络和用户的访问都实现了虚拟化。尽管 Jail 在实施方面存在局限性,但最终人们找到了脱离这种隔离环境的方法。
但这个概念非常有吸引力。
2001年,通过 Jacques Gélinas 的 VServer 项目,隔离环境的实施进入了 Linux 领域。正如 Gélinas 所说,这项工作的目的是“在高度独立且安全的单一环境中运行多个通用Linux 服务器 [sic]。” 在完成了这项针对 Linux 中多个受控制用户空间的基础性工作后,Linux 容器开始逐渐成形并最终发展成了现在的模样。
2.Docker简介
1.什么是docker
Docker是PaaS 提供商 dotCloud 开源的一个基于 LXC (LXC是Linux原生支持的容器技术,可以提供轻量化的虚拟化,docker提供LXC的高级封装,发展标准的配置方法)的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源。Docker是通过内核虚拟化技术(namespace以及cgroups等)来提供容器的资源隔离与安全保障。由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机( VM)额外的操作系统开销,提高资源利用率。
Docker是使用Go语言编写的一个程序运行、测试、交付的开放平台,Docker被设计为能够使你快速地交付应用。在Docker中,你可以将你的程序分为不同的基础部分,对于每一个基础部分都可以当做一个应用程序来管理。Docker能够帮助你快速地测试、快速地编码、快速地交付,并且缩短你从编码到运行应用的周期。Docker使用轻量级的容器虚拟化平台,并且结合工作流和工具,来帮助你管理、部署你的应用程序。Docker在其核心,Docker实现了让几乎任何程序都可以在一个安全、隔离的容器中运行。安全和隔离可以使你可以同时在机器上运行多个容器。Docker容器轻量级的特性,意味着可以得到更多的硬件性能。
2.Docker的组成和架构详解
Docker 主机(Host):一个物理机或虚拟机,用于运行Docker服务进程和容器。
Docker服务端(Server):Docker守护进程,运行docker容器。
Docker客户端(Client):客户端使用docker命令或其他工具调用docker API。
Docker仓库(Registry):保存镜像的仓库,类似于git或svn这样的版本控制系统。
Docker镜像(Images):镜像可以理解为创建实例使用的模板。
Docker容器(Container):容器是从镜像生成对外提供服务的一个或一组服务。
统一的官方仓库:https://hub.docker.com/
Docker原理:建立-->传送-->运行
通过Docker Hub或者自己的Docker仓库分享Docker镜像, 从Docker镜像创建Docker容器, 在容器里运行应用程序。
Docker组件:镜像(Image)、容器(Container)、仓库(Repository)
Docker架构:C/S架构
-> Docker使用客户端-服务器(client-server)架构模式。
-> Docker 客户端会与Docker守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布你的 Docker 容器。
-> Docker 客户端和守护进程可以运行在同一个系统上,当然也可以使用Docker客户端去连接一个远程的 Docker 守护进程。
-> Docker 客户端和守护进程之间通过socket或者RESTful API进行通信。
Docker守护进程
如上图所示,Docker守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是通过 Docker 客户端间接和其通信。
Docker客户端
Docker 客户端,实际上是 docker 的二进制程序,是主要的用户与 Docker 交互方式。它接收用户指令并且与背后的 Docker 守护进程通信,如此来回往复。
Docker内部
要理解Docker内部构建,需要理解以下三种部件:
Docker 镜像 - Docker Images
Docker 仓库 - Docker Registry
Docker 容器 - Docker Containers
Docker镜像是Docker容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新 的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。
Docker仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker 仓库是 Docker 的分发部分。
Docker容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。
libcontainer
Docker 从 0.9 版本开始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系统的交互图如下:
3.Docker镜像是如何工作的
Docker镜像是Docker容器运行时的只读模板,每一个镜像由一系列的层(layers)组成;Docker使用UnionFS(联合文件系统)来将这些层联合到单独镜像中,UnionFS文件系统允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。
正因为有了这些层(layers)的存在,Docker才会如此的轻量。当你改变了一个Docker镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新的层被添加或升级了。所以你不用重新发布整个镜像,只需要升级。层使得分发Docker镜像变得简单和快速。
每个镜像都是从一个基础的镜像开始的,比如ubuntu,一个基础的Ubuntu镜像,或者是Centos,一个基础的Centos镜像。你可以使用你自己的镜像作为新镜像的基础,例如你有一个基础的安装了Nginx的镜像,你可以使用该镜像来建立你的Web应用程序镜像。(Docker通常从Docker Hub获取基础镜像)
Docker镜像从这些基础的镜像创建,通过一种简单、具有描述性的步骤,我们称之为 指令(instructions)。每一个指令会在镜像中创建一个新的层,指令可以包含这些动作:
-> 运行一个命令。
-> 增加文件或者文件夹。
-> 创建一个环境变量。
-> 当运行容器的时候哪些程序会运行。
这些指令存储在Dockerfile文件中。当你需要建立镜像的时候,Docker可以从Dockerfile中读取这些指令并且运行,然后返回一个最终的镜像。
4.Docker仓库的用处
Docker仓库是Docker镜像的存储仓库。可以推送镜像到Docker仓库中,然后在Docker客户端,可以从Docker仓库中搜索和拉取镜像。
5.Docker容器是如何工作的
一个Docker容器包含了一个操作系统、用户添加的文件和元数据(meta-data)。每个容器都是从镜像建立的,镜像告诉Docker容器内包含了什么,当容器启动时运行什么程序,还有许多配置数据。Docker镜像是只读的,当Docker运行一个从镜像建立的容器,它会在镜像顶部添加一个可读写的层,应用程序可以在这里运行。
6.Docker 技术是否与传统的 Linux 容器相同?
不相同。Docker 技术最初是基于 LXC 技术构建(大多数人都会将这一技术与“传统的” Linux 容器联系在一起),但后来它逐渐摆脱了对这种技术的依赖。
就轻量级虚拟化 这一功能来看,LXC 非常有用,但它无法提供出色的开发人员或用户体验。除了运行容器之外,Docker 技术还具备其他多项功能,包括简化用于构建容器、传输镜像以及控制镜像版本的流程。
传统的Linux 容器使用 init 系统来管理多种进程。这意味着,所有应用程序都作为一个整体运行。与此相反,Docker 技术鼓励应用程序各自独立运行其进程,并提供相应工具以实现这一功能。这种精细化运作模式自有其优势。
7.Docker容器运行时会做哪些事情?
使用docker命令时,Docker客户端都告诉Docker守护进程运行一个容器。
# docker run -i -t ubuntu /bin/bash
可以来分析这个命令,Docker客户端使用docker命令来运行,run参数表明客户端要运行一个新的容器。
Docker客户端要运行一个容器需要告诉Docker守护进程的最小参数信息是:
-> 这个容器从哪个镜像创建,这里是ubuntu,基础的Ubuntu镜像。
-> 在容器中要运行的命令,这里是/bin/bash,在容器中运行Bash shell。
那么运行这个命令之后在底层发生了什么呢?按照顺序,Docker做了这些事情:
-> 拉取ubuntu镜像:Docker检查ubuntu镜像是否存在,如果在本地没有该镜像,Docker会从Docker Hub下载。如果镜像已经存在,Docker会使用它来创建新的容器。
-> 创建新的容器:当Docker有了这个镜像之后,Docker会用它来创建一个新的容器。
-> 分配文件系统并且挂载一个可读写的层:容器会在这个文件系统中创建,并且一个可读写的层被添加到镜像中。
-> 分配网络/桥接接口:创建一个允许容器与本地主机通信的网络接口。
-> 设置一个IP地址:从池中寻找一个可用的IP地址并且服加到容器上。
-> 运行你指定的程序:运行指定的程序。
-> 捕获并且提供应用输出:连接并且记录标准输出、输入和错误让你可以看到你的程序是如何运行的。
由此就可以拥有一个运行着的Docker容器了!从这里开始你可以管理你的容器,与应用交互,应用完成之后,可以停止或者删除你的容器。
8.docker的目标和用途
Docker用途:简单配置、代码流水线管理、开发效率、应用隔离、服务器整合、调试能力、多租户、快速部署
Docker可以快速交付应用程序
Docker可以为你的开发过程提供完美的帮助。Docker允许开发者在本地包含了应用程序和服务的容器进行开发,之后可以集成到连续的一体化和部署工作流中。
举个例子,开发者们在本地编写代码并且使用Docker和同事分享其开发栈。当开发者们准备好了之后,他们可以将代码和开发栈推送到测试环境中,在该环境进行一切所需要的测试。从测试环境中,你可以将Docker镜像推送到服务器上进行部署。
Docker可以让开发和拓展更加简单
Docker的以容器为基础的平台允许高度可移植的工作。Docker容器可以在开发者机器上运行,也可以在实体或者虚拟机上运行,也可以在云平台上运行。Docker的可移植、轻量特性同样让动态地管理负载更加简单。你可以用Docker快速地增加应用规模或者关闭应用程序和服务。Docker的快速意味着变动几乎是实时的
Docker可以达到高密度和更多负载
Docker轻巧快速,它提供了一个可行的、符合成本效益的替代基于虚拟机管理程序的虚拟机。这在高密度的环境下尤其有用。例如,构建你自己的云平台或者PaaS,在中小的部署环境下同样可以获取到更多的资源性能。
Docker改变了什么?
-> 面向产品:产品交付
-> 面向开发:简化环境配置
-> 面向测试:多版本测试
-> 面向运维:环境一致性
-> 面向架构:自动化扩容
9.docker底层技术介绍
命名空间 [Namespaces]
什么是namespaces?
namespace 是 linux 内核提供的特性,为虚拟化而生,是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中。那么内核资源有哪些呢,或者说docker容器化技术用了哪些namespaces技术呢,下面我来一 一介绍下。
=> pid namespace:使用在进程隔离(Process ID)
不同用户的进程就是通过pid namespace隔离开的,且不同 namespace 中可以有相同 PID。
具有以下特征:
-> 每个namespace中的pid是有自己的pid=1的进程(类似 /sbin/init 进程,一般是内核完成初始化之后的第一个进程init。)
-> 每个 namespace 中的进程只能影响自己的同一个 namespace 或子 namespace 中的进程
-> 因为 /proc 包含正在运行的进程,因此在 container 中的 pseudo-filesystem (伪文件系统)的 /proc 目录只能看到自己namespace 中的进程
-> 因为 namespace 允许嵌套,父 namespace 可以影响子 namespace 的进程,所以子 namespace 的进程可以在父namespace中看到,但是具有不同的 pid
=> mnt namespace:使用在管理挂载点(Mount)
类似
chroot(更改root目录,就是更改根目录),将一个进程放到一个特定的目录执行。mnt namespace
允许不同namespace的进程看到的文件结构不同,这样每个namespace 中的进程所看到的文件目录就被隔离开了。同 chroot
不同,每个 namespace 中的 container 在 /proc/mounts 的信息只包含所在namespace的mount
point。
=> net namespace:使用在进程网络接口(Networking)
网络隔离是通过
net namespace 实现的, 每个 net namespace 有独立的 network devices, IP addresses,
IP routing tables, /proc/net 目录。这样每个 container 的网络就能隔离开来。 docker 默认采用
veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge 连接在一起。
=> uts namespace:使用在隔离内核和版本标识 (Unix Timesharing System)
UTS ("UNIX Time-sharing System") namespace 允许每个 container 拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。
=> ipc namespace:使用在管理进程间通信资源 (InterProcess Communication)
container
中进程交互还是采用 Linux 常见的进程间交互方法 (interprocess communication - IPC),
包括常见的信号量、消息队列和共享内存。然而同 VM 不同,container 的进程间交互实际上还是 host 上具有相同 pid
namespace 中的进程间交互,因此需要在IPC资源申请时加入 namespace 信息 - 每个 IPC 资源有一个唯一的 32bit
ID。
=> user namespace:使用在管理空户空间
每个 container 可以有不同的 user 和 group id, 也就是说可以以 container 内部的用户在 container 内部执行程序而非 Host 上的用户。
有了以上6种namespace从进程、网络、IPC、文件系统、UTS 和用户角度的隔离,一个 container 就可以对外展现出一个独立计算机的能力,并且不同container从OS层面实现了隔离。然而不同 namespace 之间资源还是相互竞争的,仍然需要类似ulimit 来管理每个container所能使用的资源。
资源配额 [cgroups]
Docker还使用到了cgroups技术来管理群组。使应用隔离运行的关键是让它们只使用你想要的资源。这样可以确保在机器上运行的容器都是良民(good multi-tenant citizens)。群组控制允许Docker分享或者限制容器使用硬件资源。例如,限制指定的容器的内容使用。
cgroups实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup 目录下新建一个文件夹即可新建一个 group,在此文件夹中新建 task 文件,并将 pid 写入该文件,即可实现对该进程的资源控制。具体的资源配置选项可以在该文件夹中新建子 subsystem ,{子系统前缀}.{资源项} 是典型的配置方法, 如 memory.usageinbytes 就定义了该 group 在 subsystem memory 中的一个内存限制选项。另外,cgroups 中的 subsystem 可以随意组合,一个 subsystem 可以在不同的 group 中,也可以一个 group 包含多个 subsystem - 也就是说一个 subsystem。
=> memory
内存相关的限制
=> cpu
在
cgroup 中,并不能像硬件虚拟化方案一样能够定义 CPU 能力,但是能够定义 CPU 轮转的优先级,因此具有较高 CPU
优先级的进程会更可能得到 CPU 运算。 通过将参数写入 cpu.shares ,即可定义改 cgroup 的 CPU 优先级 -
这里是一个相对权重,而非绝对值
=> blkio
block IO 相关的统计和限制,byte/operation 统计和限制 (IOPS 等),读写速度限制等,但是这里主要统计的都是同步 IO
=> devices
设备权限限制
Docker 联合文件系统
联合文件系统(UnionFS)是用来操作创建层的,使它们轻巧快速。Docker使用UnionFS提供容器的构造块。Docker可以使用很多种类的UnionFS包括AUFS, btrfs, vfs, and DeviceMapper。
Docker 容器格式
Docker连接这些组建到一个包装中,称为一个 container format(容器格式)。默认的容器格式是libcontainer。Docker同样支持传统的Linux容器使用LXC。在未来,Docker也许会支持其它的容器格式,例如与BSD Jails 或 Solaris Zone集成。
3.安装Docker
环境说明
#我们这里准备两台节点进行测试 [root@linux-test-no ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [root@linux-test-no ~]# uname -r 3.10.0-693.el7.x86_64 [root@linux-test-no ~]# hostname -I 172.31.46.38 [root@centos2-no ~]# hostname -I 172.31.46.78
在两个节点上都进行操作
[root@centos2-no ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo [root@centos2-no ~]# sed -i 's#download.docker.com#mirrors.ustc.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo [root@centos2-no ~]# yum install docker-ce -y
修改在docker01配置:
#修改启动文件,监听远程端口
[root@linux-test-no ~]# vim /usr/lib/systemd/system/docker.service
[root@linux-test-no ~]# systemctl daemon-reload [root@linux-test-no ~]# systemctl enable docker.service Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service. [root@linux-test-no ~]# systemctl restart docker.service
#检查是否启动
[root@linux-test-no ~]# ps -ef
在docker2进行测试
[root@centos2-no ~]# docker -H 172.31.46.38 info Client: Debug Mode: false Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 19.03.12 Storage Driver: overlay2
1.Docker基础命令操作
查看docker相关信息
[root@linux-test-no ~]# docker version Client: Docker Engine - Community Version: 19.03.12 API version: 1.40 Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:46:54 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.12 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:45:28 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
配置docker镜像加速
vi /etc/docker/daemon.json { "registry-mirrors": ["https://registry.docker-cn.com"] }
2.启动第一个容器
[root@linux-test-no ~]# docker run -d -p 80:80 nginx
参数说明
参数 |
说明 |
run |
创建并运行一个容器 |
-d |
放入后台 |
-p |
端口映射 |
nginx |
镜像名称 |
3.Docker镜像生命周期
4.docker镜像相关操作
1.搜索官方仓库镜像
[root@linux-test-no ~]# docker search centos NAME DESCRIPTION STARS OFFICIAL AUTOMATED centos The official build of CentOS. 6104 [OK] ansible/centos7-ansible Ansible on Centos7 132 [OK] consol/centos-xfce-vnc Centos container with "headless" VNC session… 117 [OK] jdeathe/centos-ssh OpenSSH / Supervisor / EPEL/IUS/SCL Repos - … 115 [OK] centos/systemd systemd enabled base container. 86 [OK]
列表说明
参数 |
说明 |
NAME |
镜像名称 |
DESCRIPTION |
镜像说明 |
STARS |
点赞数量 |
OFFICIAL |
是否是官方的 |
AUTOMATED |
是否是自动构建的 |
2.获取镜像
根据镜像名称拉取镜像
[root@linux-test-no ~]# docker pull centos Using default tag: latest latest: Pulling from library/centos 6910e5a164f7: Pull complete Digest: sha256:4062bbdd1bb0801b0aa38e0f83dece70fb7a5e9bce223423a68de2d8b784b43b Status: Downloaded newer image for centos:latest docker.io/library/centos:latest
查看当前主机镜像列表
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 8cf1bfb43ff5 5 days ago 132MB centos latest 831691599b88 5 weeks ago 215MB
列表参数说明
REPOSITORY 镜像仓库
TAG 标签
IMAGE ID 镜像ID
CREATED 创建时间
VIRTUAL SIZE 镜像大小
拉第三方镜像方法
docker pull index.tenxcloud.com/tenxcloud/httpd
docker pull 仓库服务器:端口/项目名称/镜像名称:tag(版本)号
3.导出镜像
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 8cf1bfb43ff5 5 days ago 132MB centos latest 831691599b88 5 weeks ago 215MB #导出镜像 [root@linux-test-no ~]# docker image save centos > docker-centos.tar.gz [root@linux-test-no ~]# ll total 443940 -rw-r--r-- 1 root root 478 Jul 13 18:00 add-memberof.ldif -rw-------. 1 root root 1367 Mar 18 2019 anaconda-ks.cfg -rw-r--r-- 1 root root 342 Jul 13 18:08 base.ldif -rw-r--r-- 1 root root 868 Jul 13 17:29 changedomain.ldif -rw-r--r-- 1 root root 120 Jul 13 16:23 changepwd.ldif -rw-r--r-- 1 root root 686 Jul 15 15:32 derby.log -rw-r--r-- 1 root root 222584320 Jul 27 11:31 docker-centos.tar.gz
4.删除镜像
[root@linux-test-no ~]# docker image rm centos:latest #红色字体为我们要删除的镜像,centos为镜像名称,latest为镜像标签。 Untagged: centos:latest Untagged: centos@sha256:4062bbdd1bb0801b0aa38e0f83dece70fb7a5e9bce223423a68de2d8b784b43b Deleted: sha256:831691599b88ad6cc2a4abbd0e89661a121aff14cfa289ad840fd3946f274f1f Deleted: sha256:eb29745b8228e1e97c01b1d5c2554a319c00a94d8dd5746a3904222ad65a13f8 [root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 8cf1bfb43ff5 5 days ago 132MB
5.导入镜像
[root@linux-test-no ~]# docker image load -i docker-centos.tar.gz #红色字体为你要导入的镜像 eb29745b8228: Loading layer [==================================================>] 222.6MB/222.6MB Loaded image: centos:latest [root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 8cf1bfb43ff5 5 days ago 132MB centos latest 831691599b88 5 weeks ago 215MB
6.查看镜像的详细信息
[root@linux-test-no ~]# docker image inspect centos #红色字体为要查看的镜像名称
7.手动将容器保存为镜像
#我们这里基于docker官方centos 6.8镜像进行测试,默认我们从官方的下载的os镜像没有安装任何服务,就连最基础的sshd服务都不会有。所以我们无法从外部通过ssh直接连接容器。 [root@linux-test-no ~]# docker pull centos:6.8 [root@linux-test-no ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES #启动一个centos6.8的镜像,在容器中安装sshd服务,并修改系统密码 [root@linux-test-no ~]# docker run -it -p 1022:22 centos:6.8 /bin/bash [root@f94fe91f659e /]# yum install openssh-server -y #chpasswd是批量修改用户密码的命令,使用格式如下,我们这里把root密码修改为123456 [root@f94fe91f659e /]# echo "root:123456" |chpasswd #启动ssd服务 [root@f94fe91f659e /]# /etc/init.d/sshd start #查看容器的ip地址,我们看到地址为172.17.0.2 [root@f94fe91f659e /]# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:16583 errors:0 dropped:0 overruns:0 frame:0 TX packets:14133 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:40026232 (38.1 MiB) TX bytes:970789 (948.0 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b) #我们这个时候新开一个终端,在宿主机本地测试通过ssh连接容器,输入密码,发现测试成功 [root@linux-test-no ~]# ssh 172.17.0.2 The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established. RSA key fingerprint is SHA256:bsUbjHkMxqvOdix+HKXAcemrm3ImCvxYs8Ozwq5bXI4. RSA key fingerprint is MD5:6e:f5:d2:b2:27:81:7d:7f:1d:73:1a:2f:e4:68:14:df. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '172.17.0.2' (RSA) to the list of known hosts. root@172.17.0.2's password: [root@f94fe91f659e ~]#
#这里面如果希望不从宿主机上连接此容器,从别的机器连接此容器,只需连接的时候指定宿主机的地址和容器上的22端口映射到宿主机的端口就行了。
将容器提交为镜像
[root@linux-test-no ~]# docker commit -p -a "qingbai" -m "centos6.8-sshd" f94fe91f659e centos6-ssh #容器提交的基本语法为docker commit [选项] 容器名或容器ID [镜像名[:标签]] 上面-p的作用是在提交的时候,将容器暂停。 -a的作用是指明提交镜像的作者 -m的作用是提交时的说明文字 所以上面的命令的作用就是以容器ID为f94fe91f659e的容器为基础,提交为镜像centos6-ssh,我这里在设镜像名的时候没有指定标签,默认就会帮我们设为latest,如果要设标签的话, 只需要在容器名后面加上冒号加标签,如(centos6-ssh:v1)并在提交过程中暂停容器,指明提交作者为qingbai,并附上镜像说明centos6.8-sshd #我们查看本地镜像仓库,发现镜像已经生成 [root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE centos6-ssh latest 58486de03672 20 seconds ago 342MB nginx latest 8cf1bfb43ff5 10 days ago 132MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB
使用新的镜像启动容器
#sshd -D 表示已后台后台守护进程方式运行sshd服务 [root@linux-test-no ~]# docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D bbb78fad8aba3a62447e834020e42d6d524e14d1ce05180548b2c8f01d184841
对新镜像启动的容器进行测试,看是否生效
[root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bbb78fad8aba centos6-ssh:latest "/usr/sbin/sshd -D" 22 seconds ago Up 22 seconds 0.0.0.0:1122->22/tcp strange_franklin [root@linux-test-no ~]# docker exec -it bbb78fad8aba /bin/bash [root@bbb78fad8aba /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 86: eth0@if87: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever [root@bbb78fad8aba /]# exit #测试发现,新镜像生成的容器中默认加了sshd服务。 [root@linux-test-no ~]# ssh 172.17.0.2 root@172.17.0.2's password: [root@bbb78fad8aba ~]#
5.容器的日常管理
1.容器的起/停和查看
最简单的运行一个容器
[root@linux-test-no ~]# docker run nginx
创建容器,两步走(不常用)
[root@linux-test-no ~]# docker create centos:latest /bin/bash #这条语句的意思就是通过centos:latest镜像创建容器,并不运行 8d9578c38a6f2b8c4bebc4f81c56d3670067a5824b26db1da9444b78237d913d [root@linux-test-no ~]# docker ps -a #这条语句的意思是查看显示所有的容器,包括未运行的 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d9578c38a6f centos:latest "/bin/bash" 3 seconds ago Created wonderful_saha [root@linux-test-no ~]# docker start 8d9578c38a6f #启动一个容器,后面跟的是上面容器的CONTAINER ID 8d9578c38a6f [root@linux-test-no ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d9578c38a6f centos:latest "/bin/bash" 51 seconds ago Exited (0) 7 seconds ago
快速启动容器的方法
[root@linux-test-no ~]# docker run centos:latest /usr/bin/sleep 20 #这条语句的意思是直接通过centos:latest镜像创建容器并运行,
并执行/usr/bin/sleep 20这个命令
现在基本上通过docker run来创建运行容器,它背后其实包含独立的两步,一步是docker create 创建容器,另一步是docker start启动容器。
通过上面的步骤,我们发现docker start启动容器后,docker ps去看,容器显示几秒前退出,并不在运行,这是因为,容器内的第一个进程必须
一直处于运行的状态,否则这个容器,就会处于退出状态!
查看正在运行的容器(下面两条命令都行)
[root@linux-test-no ~]# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abc685cb2007 centos:latest "/usr/bin/sleep 50" 4 seconds ago Up 3 seconds sleepy_jones [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES abc685cb2007 centos:latest "/usr/bin/sleep 50" 7 seconds ago Up 7 seconds sleepy_jones
查看你容器详细信息/ip
[root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 988a3716e9bb centos:latest "/usr/bin/sleep 200" 4 seconds ago Up 3 seconds keen_mcnulty [root@linux-test-no ~]# docker container inspect 988a3716e9bb #通过这条命令就可以看到容器的详细信息 [ { "Id": "988a3716e9bbeaa0f23d4fbe43d17c3189641026be5a13a98989a14f0cb457b1", "Created": "2020-07-27T07:51:22.925441099Z", "Path": "/usr/bin/sleep", "Args": [ "200"
.....
查看你所有的容器(包括未运行的)
[root@linux-test-no ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 988a3716e9bb centos:latest "/usr/bin/sleep 200" 26 minutes ago Exited (0) 22 minutes ago keen_mcnulty abc685cb2007 centos:latest "/usr/bin/sleep 50" 28 minutes ago Exited (0) 27 minutes ago sleepy_jones 35bdf2a164b0 centos:latest "/usr/bin/sleep 40" 29 minutes ago Exited (0) 28 minutes ago recursing_burnell 2eb97fa49c18 centos:latest "/usr/bin/sleep 20" About an hour ago Exited (0) About an hour ago awesome_rhodes 71fdafc25dc6 centos:latest "/bin/bash" About an hour ago Exited (0) About an hour ago
停止容器(下面两个命令都行)
[root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0caba1282af5 centos:latest "/usr/bin/sleep 200" 10 seconds ago Up 9 seconds romantic_mestorf [root@linux-test-no ~]# docker stop 0caba1282af5 0caba1282af5 或 [root@linux-test-no ~]# docker container kill 0caba1282af5
2.进入容器的方法
启动时进去方法
[root@linux-test-no ~]# docker run -it nginx:latest /bin/bash #参数:-it 可交互终端 root@7b960ee8d35b:/#
退出/离开容器同时按住
ctrl,p,q三个按键可以做到退出容器但不关闭,docker ps查看有
同时按住ctrl+d退出容器且关闭容器,docker ps查看无
启动后进入容器的方法
启动一个docker
[root@linux-test-no ~]# docker run -it centos:latest [root@1961edb8d554 /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 09:21 pts/0 00:00:00 /bin/bash root 14 1 0 09:21 pts/0 00:00:00 ps -ef
1.使用attach命令可以进入正在运行的容器,使用此方法类似于vnc,操作会在各个容器界面显示。如下
2.exec进入容器方法(推荐使用)
[root@linux-test-no ~]# docker exec -it 7b960ee8d35b /bin/bash #-it参数是创建一个新的终端,此方法表述在已运行的容器id为7b960ee8d35b的容器中开启一个交互式的终端
root@7b960ee8d35b:/#
exec方法进入已运行的容器和attach方法不一样,会单独建立一个终端,就是不会像attach一样,所有操作会在所有使用attach进入的界面同步显示。
此方法进入按ctrl+d键退出,只会退出终端,并不会同步关闭容器,而attach通过ctrl+d键退出终端,会同步关闭容器。
3.删除所有容器
[root@linux-test-no ~]# docker rm -f `docker ps -a -q` #-f表示强制删除容器,包括正在运行的容器,要删除单独的容器,把后面的红体字部分改成容器id.
4.启动时进行端口映射
-p参数端口映射
[root@linux-test-no ~]# docker run -d -p 88:80 nginx:latest #-d参数表示后台运行容器,并返回容器ID;这条命令的意思表示本地的88端口映射到容器的80端口。
不同指定映射方法
参数 |
说明 |
-p hostPort:containerPort |
端口映射 -p 8080:80 |
-p ip:hostPort:containerPort |
配置监听地址 -p 10.0.0.100:8080:80 (本地指定ip和指定端口映射到容器指定端口) |
-p ip::containerPort |
随机分配端口 -p 10.0.0.100::80 (本地指定IP和本地随机端口映射到容器指定端口) |
-p hostPort:containerPort:udp |
指定协议 -p 8080:80:tcp (本地指定端口和容器指定端口和指定协议,默认为tcp) |
-p 81:80 –p 443:443 |
一次性映射多个端口 |
随机映射
docker run -P (大P)# 需要镜像支持
查看指定容器已映射的端口
[root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 16d0a0cfe9b9 nginx:latest "/docker-entrypoint.…" 15 minutes ago Up 15 minutes 0.0.0.0:88->80/tcp charming_joliot [root@linux-test-no ~]# docker port 16d0a0cfe9b9 80/tcp -> 0.0.0.0:88
5.自定义容器名称
[root@linux-test-no ~]# docker run -it --name nginx-test nginx:latest #--name参数为通过镜像启动容器时指定容器名称,nginx-test就是指定的容器名,指定
容器名称的时候要唯一,不能起两个同样名称的容器
6.Docker数据卷的管理
Docker数据持久化:
容器在运行期间产生的数据是不会写在镜像里面的,重新用此镜像启动新的容器就会初始化镜像,会加一个全新的读写入层来保存数据。如果想做到数据持久化,Docker提供数据卷(Data volume)或者数据容器卷来解决问题,另外还可以通过commit提交一个新的镜像来保存产生的数据。
Docker Volume数据卷可以实现:
-> 绕过“拷贝写”系统,以达到本地磁盘IO的性能,(比如运行一个容器,在容器中对数据卷修改内容,会直接改变宿主机上的数据卷中的内容,所以是本地磁盘IO的性能,而不是先在容器中写一份,最后还要将容器中的修改的内容拷贝出来进行同步。)
-> 绕过“拷贝写”系统,有些文件不需要在docker commit打包进镜像文件。
-> 数据卷可以在容器间共享和重用数据
-> 数据卷可以在宿主和容器间共享数据
-> 数据卷数据改变是直接修改的
-> 数据卷是持续性的,直到没有容器使用它们。即便是初始的数据卷容器或中间层的数据卷容器删除了,只要还有其他的容器使用数据卷,那么里面的数据都不会丢失。
docker 数据卷的使用场景
从上面的介绍我们看出,docker内部数据持久化,做的不太好,一般容器内产生的数据会随着容器的的消失而消失。所以一般我们为了保存一些重要数据,会使用docker数据卷。docker数据卷一般会在以下场景使用。
1.日志输出
2.静态web页面
3.应用配置文件
4.多容器间目录或文件共享
1.挂载本地指定目录
#下面命令的意思,通过nginx:latest镜像创建容器,并在容器内部创建数据卷/usr/share/nginx/html,此目录可存在,可不存在,如不存在则会自动创建,然后指定此数据卷挂载宿主
机目录/iflytek/data1下面。此目录也可不存在,届时会自动创建。如果不指定宿主机目录,则数据卷会默认挂载宿主机的一个目录。默认在/var/lib/docker/volumes目录下
数据卷后
面跟的ro表示,创建的数据卷设为容器内只读,如果不指定,默认是读写。
[root@linux-test-no ~]# docker run -d -p 80:80 -v /iflytek/data1:/usr/share/nginx/html:ro nginx:latest
容器内站点目录: /usr/share/nginx/html
在宿主机写入数据,查看
[root@linux-test-no ~]# echo "test1" > /iflytek/data1/index.html [root@linux-test-no ~]# curl 172.31.46.38:80 test1
进入容器,尝试往数据卷内写入数据
[root@linux-test-no ~]# docker exec -it 2984edf77b32 /bin/bash root@2984edf77b32:/# cd /usr/share/nginx/html/ root@2984edf77b32:/usr/share/nginx/html# ls index.html root@2984edf77b32:/usr/share/nginx/html# cat index.html #这里我们看到数据卷和宿主机的文件已完成同步。 test1 root@2984edf77b32:/usr/share/nginx/html# echo "test1.1" > index.html #我们尝试往数据卷内写入数据,发现写不进去,这是因为我们开通创建数据卷的时候设为只读了。 bash: index.html: Read-only file system
一个宿主机目录可以同时挂载多个容器内的数据卷,这就启到了共享卷的作用。
2.创建数据卷容器,并挂载它
#这里我没指定宿主机的目录,所以这里只会在容器内创建一个数据卷,如果你想创建多个数据卷,你只需在命令里,再加一个-v后面跟你要创建的数据卷名称就可以了,这个时候此容器就可以
被理解为数据卷容器,数据卷会默认在宿主机生成一个目录。一般即便是删除了初始的数据卷容器,或是删除挂载了初始化数据卷容器的容器,但只要是有容器在使用该数据卷,那么它里面的数
据就不会丢失!(除非是没有容器在使用它们)
[root@linux-test-no ~]# docker run -d -p 8081:80 -v /usr/share/nginx/html nginx:latest 360a4cbff9e19ca681372d403ab930a2b6a66a8e6b499ed0176f0b076e3216d5 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 360a4cbff9e1 nginx:latest "/docker-entrypoint.…" 22 seconds ago Up 22 seconds 0.0.0.0:8081->80/tcp zealous_archimedes 2984edf77b32 nginx:latest "/docker-entrypoint.…" 36 minutes ago Up 36 minutes 0.0.0.0:80->80/tcp suspicious_rubin
#这里inspect表示显示容器的详细信息,我们会在详细信息里看到如下一段,其中source后面为我们创建数据卷的挂载的宿主机目录,Destination后面就是数据卷的地址
[root@linux-test-no ~]# docker inspect 360a4cbff9e1 。。。。。。 "Mounts": [ { "Type": "volume", "Name": "ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435", "Source": "/var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data", "Destination": "/usr/share/nginx/html", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], 。。。。。。
#一般如果没有改数据卷的默认目录的话,也可以通过下面命令直接查到,这后面的360a4cbff9e1是你的容器ID
[root@linux-test-no ~]# docker inspect 360a4cbff9e1 |grep /var/lib/docker/volumes
"Source": "/var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data",
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
360a4cbff9e1 nginx:latest "/docker-entrypoint.…" 35 minutes ago Up 35 minutes 0.0.0.0:8081->80/tcp zealous_archimedes
2984edf77b32 nginx:latest "/docker-entrypoint.…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp suspicious_rubin
#往数据卷内写入测试数据,测试其他容器挂载数据卷容器中的数据卷会不会生效。
[root@linux-test-no ~]# echo "test1.1" > /var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data/index.html
#下面的命令意思是创建容器nginx-test1.1,挂载360a4cbff9e1容器中的数据卷,--volumes-from后面填的是你要挂载的数据卷容器的ID或者容器名,--rm参数的作用是退出容器后,删除
容器。
[root@linux-test-no ~]# docker run -it -p 8082:80 --rm --volumes-from 360a4cbff9e1 --name nginx-test1.1 nginx:latest /bin/bash
#现在我们进到容器里来,我们看到360a4cbff9e1容器中的数据卷已被挂载,数据已同步过来了。
root@013f376bef15:/# cat /usr/share/nginx/html/index.html
test1.1
3.创建卷后挂载
Docker 新版本中引入了 docker volume 命令来管理 Docker volume。
使用默认的
'local'
driver 创建一个volume数据卷
#下面的命令就是查看容器上已有的数据卷
[root@linux-test-no ~]# docker volume ls DRIVER VOLUME NAME #创建数据卷的命令如下,--name后面跟你要创建的数据卷名,他会默认在数据卷目录下创建一个你指定的数据卷名称,就是他会在/var/lib/docker/volumes下生成一个数据卷test1。
[root@linux-test-no ~]# docker volume create --name test1 test1 [root@linux-test-no ~]# docker volume ls DRIVER VOLUME NAME local test1 [root@linux-test-no ~]# ls /var/lib/docker/volumes/ metadata.db test1 #下面的命令里中用户挂载了我们刚刚创建的数据卷test1,挂载已有数据卷的操作就是-v跟的是你要挂载的数据卷名称和你容器中的目录,这样就挂载成功了。其实如果你-v后面的宿主机目录
填写的是一个不存在的相对路径,而不是绝对路径的话,他也会默认的数据卷目录下帮你自动创建一个数据卷并命名为你填写的相对路径,就算此数据卷默认不存在。例如如果-v后面跟的是
test3:/volune 这里test3数据卷不存在,系统会默认帮你在默认的数据卷目录下创建一个test3数据卷。就是相当于省去了docker volume create步骤。
[root@linux-test-no ~]# docker run -d -p 8081:80 --name test1 -v test1:/volume nginx:latest 3de69cb9aa75a06d4cca8bb0dc78e435514381b0049a8f16301e027c173fe62c [root@linux-test-no ~]# docker inspect test1 |grep /var/lib/docker/volumes "Source": "/var/lib/docker/volumes/test1/_data",
#上面的命令结果就是test1数据卷对应在本机上的目录
/var/lib/docker/volumes/test1/_data
挂载给容器内的
/volume
目录
4.备份数据卷和恢复
#我们先创建一个容器test1,包含一个数据卷/test1
[root@linux-test-no iflytek]# docker run -it -p 8081:80 --name test1 -v /test1 nginx:latest /bin/bash root@d0d32aa5ab4b:/# cd /test1 #测试往数据卷里写入数据
root@d0d32aa5ab4b:/test1# mkdir test1.1 root@d0d32aa5ab4b:/test1# ls test1.1 #开始进行数据卷的备份操作,启动一个新的容器并且从你要备份的数据卷容器中挂载卷,然后挂载当前目录到容器中为backup,并备份
test1
卷中所有的数据为
test
.
tar
,执行完成之后删除
容器--rm
,此时备份就在当前的目录下,名为
test
.
tar。
[root@linux-test-no iflytek]# docker run --rm --volumes-from test1 -v $(pwd):/backup nginx:latest tar cvf /backup/test.tar /test1 tar: Removing leading `/' from member names /test1/ /test1/test1.1/ [root@linux-test-no iflytek]# ls data1 data2 data3 data4 lost+found test.tar
#总结就是备份数据卷就是先创建一个容器,并挂载要备份的容器数据卷,再挂载数据卷(
pwd
):
/backup
目录到容器
/bakcup
,在容器中执行要备份
的数据目录(我这里是test1)
到
/backup
,
也就是备份到宿主机$(pwd
):
/backup
目录。
#下面我们来演示怎么恢复数据卷,恢复给另外的容器
[root@linux-test-no iflytek]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0d32aa5ab4b nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (0) 2 hours ago test1
#我们这里把之前的test1容器删除掉
[root@linux-test-no iflytek]# docker rm -f d0d32aa5ab4b
d0d32aa5ab4b
[root@linux-test-no iflytek]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAM
#我们这里启动一个test2容器,并创建test1数据卷。新容器创建时挂载的数据卷路径最好是和之前备份的数据卷路径一致,要不然只能恢复一部分数据。列如老的数据卷容器里有
test1和test2数据卷,然后我们启动新容器创建数据卷的时候,只创建了test1数据卷,那么恢复的时候也只会恢复test1,不会恢复test2。不过这也不是绝对的,这个看你备份
的时候备份哪些卷,比如我们在老数据卷容器中只备份了test1卷没有备份test2卷,那新容器就算挂载了test2卷,恢复也没数据。
[root@linux-test-no iflytek]# docker run -p 8081:80 -it -v /test1 --name test2 nginx:latest /bin/bash
#这里我们发现现在新创建的test1数据卷里没有任何东西
root@f5164f9124b2:/# ls /test1
root@f5164f9124b2:/#
#这个时候我们可以在开一个终端来做恢复数据卷的操作,我们需要先cd到存放我们备份文件所在的目录,然后执行恢复操作,如下,下面的命令的意思是创建一个新的临时容器并挂载我们要恢复数据卷
的数据卷容器test2,这个时候新建的容器中就会有挂载test2中的数据卷test1,然后在把宿主机本地的目录挂载临时容器中的backup数据卷,然后在本地目录下的备份文件也就是backup下面的
备份文件进行解压缩到根下面,因为一开始我们备份的时候是直接备份/test1的,数据解压缩的话,就会把数据恢复到test1下面,正好之前我们挂载了test2中的数据卷test1。所以数据就恢复到test
2数据卷容器中的test1下面去了,这就达到了恢复数据卷的效果
[root@linux-test-no ~]# cd /iflytek
[root@linux-test-no iflytek]# docker run --rm --volumes-from test2 -v $(pwd):/backup nginx:latest tar xvf /backup/test.tar -C /
test1/
test1/test1.1/
#这个时候我们再新创建的数据卷容器test2里,查看数据卷有没有恢复,我们发现数据卷已恢复
root@f5164f9124b2:/# ls /test1
test1.1
root@f5164f9124b2:/#
#上面我们演示的是恢复到其他容器,恢复到同一个容器其实意思一样,我们只需要改--volumes-from后面跟的值就可以了。
5.容器数据卷的管理
---------------------
本文著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
来源地址:https://www.php.cn/docker/456656.html
来源:php中文网(www.php.cn)
© 版权声明:转载请附上原文链接!
---------------------
本文著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
来源地址:https://www.php.cn/docker/456656.html
来源:php中文网(www.php.cn)
© 版权声明:转载请附上原文链接!
---------------------
本文著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
来源地址:https://www.php.cn/docker/456656.html
来源:php中文网(www.php.cn)
© 版权声明:转载请附上原文链接!
---------------------
本文著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
来源地址:https://www.php.cn/docker/456656.html
来源:php中文网(www.php.cn)
© 版权声明:转载请附上原文链接!
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。无主的数据卷可能会占据很多空间,要清理会很麻烦
1.列出所有数据卷
[root@linux-test-no iflytek]# docker volume ls
DRIVER VOLUME NAME
local 5fe072dd48041e24d2424e75f6281a4ccd9ca925d62ec74be83326eb6a1918f7
local 6c1bc17941dfa0f924f64ec67eac02dd4208625ebfebadf46304403f641d5620
local 58b1e859ee8bb76f92de82b9a2f8b72cbbf018777291e741fb47bc66882a5d19
使用--filter dangling=true 过滤 不在使用的数据卷
[root@linux-test-no iflytek]# docker volume ls --filter dangling=true DRIVER VOLUME NAME local 6c1bc17941dfa0f924f64ec67eac02dd4208625ebfebadf46304403f641d5620 local 58b1e859ee8bb76f92de82b9a2f8b72cbbf018777291e741fb47bc66882a5d19
2.创建一个数据卷,可以设置,--name,--path,--mode。 也可以不用
拥有一切自动生成的参数
[root@linux-test-no iflytek]# docker volume create
3.删除一个数据卷
[root@linux-test-no iflytek]# docker volume rm 后面跟VOLUME NAME(卷名)
4.严禁把容器正在使用的数据卷和绑定挂载的数据卷删除(删除数据卷的时候可以通过下面命令进行删除)
docker volume ls --filter dangling=true #这个是过滤掉不在使用的数据卷,然后你可以选择性删除 docker volume ls --filter dangling=true | grep local |awk '{print $2}'|xargs docker volume rm #这个是删除所有不在使用的数据卷
6.容器数据卷的总结
通过上面的介绍我们知道什么是数据卷,什么是数据卷容器,但有的同学可能会问,这上面的挂载本地指定目录,创建数据卷容器并挂载它,还有创建卷后挂载都有什么区别呢。下面我来介绍一下
1.挂载本地指定目录,顾名思义,就是我们可以指定数据卷的的宿主机挂载目录,这一般在下面场景中会用到,就是现在生成一个大文件,我发现默认的数据卷目录空间不太够了,所以这个时候我们就需要指定数据卷的宿主机挂载目录,这个有一个小缺点就是宿主机挂载目录不唯一,以后管理起来可能不太方便
2.创建数据卷容器并挂载它,主要起的是保证这个数据卷可以一直提供服务,不会造成数据丢失。但是如果一个数据卷被创建出来后,如果没有任何容器去使用他,那么此数据卷就会丢失,我所说的丢失不是讲数据真的没了。只是当我们再次创建同名数据卷的时候,并不会找回以前的数据卷里的数据,但这个也不是绝对的。其实造成这个现状的原因是当我们通过-v参数创建数据卷的时候,默认会在默认的数据卷目录/var/lib/docker/volumes/创建一个目录,不过这个目录名是不规则的(为了好解释,我们之间取这个目录名为123),在容器内部如果我们创建数据卷的时候没有指定宿主机目录,那么容器的内部逻辑就会把你创建的数据卷默认挂这个123。所以只要有容器用这个数据卷,数据卷就会一直挂着这个123。但是如果没有容器在使用这个数据卷了,那挂载就会自动断开。因为这个目录名是不规则的,所以我们在数据卷层面就会认为此数据卷丢失了,当我们在创建一个同名的数据名时候,内部不会在挂载123,可能去挂载另一个456了。但是123目录会还在,只要你不删除它。所以我上面讲的找不会数据不是绝对的,就是因为你记性好,真的记住了这个不规则的目录名,所以当我们要找回数据的时候,只需指定数据卷挂载宿主机上这个不规则的目录名就行了。
3.因为有上面2的情况,所以我们可以先创建数据卷,然后在进行挂载。通俗易懂就是我把上面的不规则目录名规范化了,就算后面数据卷没容器使用,数据也能再轻易找回来。
其实上面使用数据卷的三种方法,总结起来就是挂载本地指定目录可以防止空间不足,缺点是挂载不在一个目录下,管理起来不太方便。然后创建卷后挂载是创建数据卷容器并挂载它的升级版,更推荐使用,优点是挂载都在一个目录下,管理起来更方便点。缺点是可能造成空间压力。
4.容器数据卷如果我们挂载的时候,宿主机目录是空的,然后关联到一个容器的目录,如果容器内的目录下默认是有文件的,那么启动的容器,会默认已宿主机目录为准,就是会清空
容器内被关联的目录下的文件或目录。
7.Dockerfile自动构建docker镜像
DockerFile 可以说是一种可以被 Docker 程序解释的脚本, DockerFile 是由一条
条的命令组成的,每条命令对应 linux 下面的一条命令, Docker 程序将这些
DockerFile 指令再翻译成真正的 linux 命令,其有自己的书写方式和支持的命
令, Docker 程序读取 DockerFile 并根据指令生成 Docker 镜像,相比手动制作镜
像的方式, DockerFile 更能直观的展示镜像是怎么产生的,有了 DockerFile,当
后期有额外的需求时,只要在之前的 DockerFile 添加或者修改响应的命令即可
重新生成新的 Docke 镜像,避免了重复手动制作镜像的麻烦
1.Dockerfile指令集
dockerfile主要组成部分:
基础镜像信息 FROM centos:6.8
制作镜像操作指令RUN yum insatll openssh-server -y
容器启动时执行指令 CMD ["/bin/bash"]
dockerfile常用指令:
FROM 这个镜像的妈妈是谁?(指定基础镜像)
MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)
RUN 你想让它干啥(在命令前面加上RUN即可)
ADD 给它点创业资金(COPY文件,会自动解压)
WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)
VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)
EXPOSE 它要打开的门是啥(指定对外的端口)
CMD 奔跑吧,兄弟!(指定容器启动后的要干的事情)
2.创建一个Dockerfile
[root@linux-test-no ~]# cd /opt/ #这里建议目录结构按照业务类型或系统类型等方式划分,方便后期镜像比较多的时候 进行分类。不过只是建议,具体你想把dockerfile文件放到哪里看你自己 [root@linux-test-no opt]# mkdir dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} -pv [root@linux-test-no opt]# cd dockerfile/system/centos/ [root@linux-test-no centos]# pwd /opt/dockerfile/system/centos #编写dockerfile,生成的镜像的时候会在执行命令的当前目录查找 Dockerfile 文件, 所以名称不可写错, 而且 D 必须大写 Dockerfile文件中第一行,必须是 From xxx (xxx 是基础镜像) ,下面每一行指定有什么用,上面已经讲过了,不用再解释了。
[root@linux-test-no centos]# vim Dockerfile FROM centos:6.8 RUN yum install openssh-server -y RUN echo "root:123456" |chpasswd RUN /etc/init.d/sshd start CMD ["/usr/sbin/sshd","-D"]
3.通过dockerfile文件构建docker镜像
[root@linux-test-no centos]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE centos6-ssh latest 58486de03672 18 hours ago 342MB nginx latest 8cf1bfb43ff5 10 days ago 132MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #下面命令中,-t 为镜像标签打标签并指定镜像名, . 表示当前路径。因为我们要构建镜像的Dockerfile在本地目录下,所以我们用了. 如果需要的dockerfile文件不在本地目录下,而是
在其他目录下,我们则需要把.换成指定的其他目录。
[root@linux-test-no centos]# docker image build -t centos6.8-ssh:test1 .
#测试发现我们通过Dockerfile文件构建的docker镜像成功。
[root@linux-test-no ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos6.8-ssh test1 922e349f2760 About an hour ago 342MB
centos6-ssh latest 58486de03672 19 hours ago 342MB
nginx latest 8cf1bfb43ff5 11 days ago 132MB
centos latest 831691599b88 6 weeks ago 215MB
centos 6.8 82f3b5f3c58f 16 months ago 195MB
#测试使用自构建的镜像启动成功
[root@linux-test-no ~]# docker run -d -p 2022:22 centos6.8-ssh:test1
2e2a32d93d8bd82e88eb83fa93ae1fc2841d46885b25c6027bf5d58b4604dd44
8.Docker中的镜像分层
Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
1.Docker镜像为什么分层
镜像分层最大的一个好处就是共享资源。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如/etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。这就是容器 Copy-on-Write 特性。
2 .可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
3.容器层的细节说明
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
文件操作的
文件操作 |
说明 |
添加文件 |
在容器中创建文件时,新文件被添加到容器层中。 |
读取文件 |
在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。 |
修改文件 |
在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。 |
删除文件 |
在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。(只是记录删除操作) |
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
9.容器间的互联
容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式。
该系统会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。
容器间的互联分为同宿主机下不同容器间的互联,同一网段下不同宿主机下容器的互联,不同网段下不同宿主机下容器的互联。
1.同宿主机下不同容器间的互联
同宿主下不同容器间的互联,现在基本上采用docker run --link的方式进行,下面我来进行演示。
docker run --link可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。
--link的格式:
--link <name or id>:alias
其中,name和id是源容器的name和id,alias是源容器在link下的别名。
别名的作用就是自定义的容器名称可能后期会发生变化,那么一旦名称发生变化,程序之间也要随之发生变化,比如程序通过容器名称进行服务调用,但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用,每次都进行更改的话又比较麻烦, 因此可以使用自定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可
[root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES #创建并启动测试源容器test1
[root@linux-test-no ~]# docker run -d -it --name test1 centos:6.8 655769f1e67fb292111837508f798beec2d07926e5cb65d0048420a3566e028c [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 655769f1e67f centos:6.8 "/bin/bash" 6 minutes ago Up 6 minutes test1
#创建并启动名为test2的接收容器,并把该容器和名为test1,别名设为test1.1的容器链接起来。其中test1是源容器名,test1.1是我们为源容器设的别名。
接收容器可以通过源容器名或者源容器的别名进行链接
[root@linux-test-no ~]# docker run -t -i --name test2 --link test1:test1.1 centos:6.8 /bin/bash
#测试发现接收容器可以通过源容器名进行链接。
[root@4a7a77ebc5e7 /]# ping test1
PING test1.1 (172.17.0.2) 56(84) bytes of data.
64 bytes from test1.1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.484 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=3 ttl=64 time=0.078 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=4 ttl=64 time=0.070 ms
^C
--- test1.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3167ms
rtt min/avg/max/mdev = 0.060/0.173/0.484/0.179 ms
#测试发现接收容器可以通过别名进行链接。
[root@4a7a77ebc5e7 /]# ping test1.1
PING test1.1 (172.17.0.2) 56(84) bytes of data.
64 bytes from test1.1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.085 ms
#查看接收容器的地址为172.17.0.3
[root@4a7a77ebc5e7 /]# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 b) TX bytes:0 (0.0 b)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[root@linux-test-no ~]# docker exec -it test1 /bin/bash
#查看源容器的为172.17.0.2,由此确认,通过link链接后,接收容器可以通过容器名和别名链接源容器
[root@655769f1e67f /]# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1362 (1.3 KiB) TX bytes:672 (672.0 b)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[root@655769f1e67f /]# ping test2
ping: unknown host test2
#源容器可以通过地址和接收容器链接
[root@655769f1e67f /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.476 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.061 ms
总结
在--link标签下,接收容器就是通过设置环境变量和更新/etc/hosts文件来获取源容器的信息,并与之建立通信和传递数据的。
10.docker私有仓库(registry)
Docker Registry 作为 Docker 的核心组件之一负责镜像内容的存储与分发,客户
端的 docker pull 以及 push 命令都将直接与 registry 进行交互,最初版本的 registry
由 Python 实现,由于设计初期在安全性,性能以及 API 的设计上有着诸多的缺陷,
该版本在 0.9 之后停止了开发,由新的项目 distribution(新的 docker register 被称为
Distribution)来重新设计并开发下一代 registry,新的项目由 go 语言开发,所有的
API,底层存储方式,系统架构都进行了全面的重新设计已解决上一代 registry 中存在
的问题, 2016 年 4 月份 rgistry 2.0 正式发布, docker1.6 版本开始支持 registry 2.0,
而八月份随着 docker 1.8 发布, docker hub 正式启用 2.1 版本 registry 全面替代之
前版本 registry,新版 registry 对镜像存储格式进行了重新设计并和旧版不兼容,
docker 1.5 和之前的版本无法读取 2.0 的镜像,另外, Registry 2.4 版本之后支持了
回收站机制,也就是可以删除镜像了,在 2.4 版本之前是无法支持删除镜像的,所以
如果你要使用最好是大于 Registry2.4 版本的。
本部分将介绍通过官方提供的 docker registry 镜像来简单搭建一套本地私有仓库环境。
这种容器私服有点像nexus,就是maven私服,你理解了maven私服就理解了容器私服。
1.创建一个普通的仓库
#查看本地镜像中是否有registry镜像,这里我们看没有
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE centos6.8-ssh test1 922e349f2760 22 hours ago 342MB centos6-ssh latest 58486de03672 40 hours ago 342MB nginx latest 8cf1bfb43ff5 11 days ago 132MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #下载registry镜像。
[root@linux-test-no ~]# docker pull registry
#基于registry镜像创建容器私有仓库,--restart=always的作用是让此容器随着docker服务的重启而重启,这样的启动方式适合与一些监控程序,跟着机器一起启动,出问题也会自动重启。
在上面我们介绍数据卷的时候我们讲过,容器内的数据一般会随着容器的消失而消失,所以我们为了让私库内的镜像不消失,所以一般我们会通过-v参数挂载一个宿主机目录,/var/lib/registry
目录是registry容器内存放镜像的默认目录。
[root@linux-test-no ~]# docker run -d -p 5000:5000 --restart=always --name qingbai_registry -v /iflytek/my_registry:/var/lib/registry registry:latest
7d1aba329d0cdc6a084efd646c8e3e59930e50ba93dca3ec40ed43f31554db24
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d1aba329d0c registry:latest "/entrypoint.sh /etc…" 45 seconds ago Up 45 seconds 0.0.0.0:5000->5000/tcp qingbai_registry
4a7a77ebc5e7 centos:6.8 "/bin/bash" 13 hours ago Up 12 hours test2
655769f1e67f centos:6.8 "/bin/bash" 13 hours ago Up 13 hours
#Docker从1.3.X之后,与docker registry交互默认使用的是https,然而此处搭建的私有仓库只提供http服务,
所以我们需要在docker的客户机(即上传镜像到私有仓库里或从私有仓库下载镜像的客户机
)
上修改以下配置文件。使其支持http服务,不然我们后续使用的时候会报错。
[root@linux-test-no ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["172.31.46.38:5000"] 这里是我们要加的行,里面地址填的是私有仓库所在服务器的地址。
}
[root@linux-test-no ~]# systemctl restart docker.service
#修改完配置后,重启docker服务,让修改生效,我们发现我们上面--restart=always参数起了作用,registry随着docker服务的重启而重启了。
不过这里用--restart=always参数的时候我们需要注意一点,如果我们不想要这个容器了,我们不能通过平常的docker rm 和docker stop命令,因为通过这些命令删除
不掉容器,还可能出现其他问题,而是需要更新 restart 的状态。例如:docker update --restart=no nginx:latest 这样之后, 这个容器就不会在自动启动了。最
后我们就可以通过传统方式删除容器。
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d1aba329d0c registry:latest "/entrypoint.sh /etc…" 9 minutes ago Up 3 minutes 0.0.0.0:5000->5000/tcp qingbai_registry
测试上传镜像到私库和从私库上拉镜像
#查看本地现有镜像
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6-ssh latest 58486de03672 43 hours ago 342MB nginx latest 8cf1bfb43ff5 12 days ago 132MB registry latest 2d4f4b5309b1 6 weeks ago 26.2MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #开始上传镜像到私有仓库,我们这里需要先给要上传的镜像打个tag,格式如下,centos6.8-ssh:test1为我们要上传的镜像名和tag号,172.31.46.38:5000为我们要传的私库地址,
/后面是你要在私库里把这个镜像重新取的名字和tag号。
[root@linux-test-no ~]# docker tag centos6.8-ssh:test1 172.31.46.38:5000/centos6.8-ssh:test1 #我们看到本地多了一个镜像172.31.46.38:5000/centos6.8-ssh这个就是我们打的tag
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE 172.31.46.38:5000/centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6-ssh latest 58486de03672 43 hours ago 342MB nginx latest 8cf1bfb43ff5 12 days ago 132MB registry latest 2d4f4b5309b1 6 weeks ago 26.2MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #开始上传镜像,push后面跟的就是我们的上面打的tag
[root@linux-test-no ~]# docker push 172.31.46.38:5000/centos6.8-ssh
#我们通过下面的命令查看私库里现在有哪些镜像
[root@linux-test-no ~]# curl -XGET http://172.31.46.38:5000/v2/_catalog
{"repositories":["centos6.8-ssh"]}
#我们这里测试把本地刚刚上传的镜像删除,然后再从私库里下载回来
[root@linux-test-no ~]# docker image rm centos6.8-ssh:test1
Untagged: centos6.8-ssh:test1
[root@linux-test-no ~]# docker image rm 172.31.46.38:5000/centos6.8-ssh:test1
#我们这里看到刚刚打的tag镜像和源镜像已删除。
[root@linux-test-no ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
centos6-ssh latest 58486de03672 43 hours ago 342MB
nginx latest 8cf1bfb43ff5 12 days ago 132MB
registry latest 2d4f4b5309b1 6 weeks ago 26.2MB
centos latest 831691599b88 6 weeks ago 215MB
centos 6.8 82f3b5f3c58f 16 months ago 195MB
#我们现在测试从私库里拉我们刚刚上传的镜像,
[root@linux-test-no ~]# docker pull 172.31.46.38:5000/centos6.8-ssh:test1
#测试成功,我们在本地看到了此镜像。这样,我们就完成了私库的搭建,也就可以在同一局域网内的其他机器上,从该私有仓库中pull下来该镜像。
[root@linux-test-no ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
172.31.46.38:5000/centos6.8-ssh test1 922e349f2760 26 hours ago 342MB
centos6-ssh latest 58486de03672 44 hours ago 342MB
nginx latest 8cf1bfb43ff5 12 days ago 132MB
registry latest 2d4f4b5309b1 6 weeks ago 26.2MB
centos latest 831691599b88 6 weeks ago 215MB
centos 6.8 82f3b5f3c58f 16 months ago 195MB
2.带basic(用户名和密码)认证的仓库
上面我们创建的仓库,有一个安全风险,就是任何人都可以上传镜像和拉取镜像。所以为了安全,容器仓库会设为basic认证的仓库。那么带basic认证的仓库
怎么配置呢,如下。
1.安装加密工具
[root@linux-test-no ~]# yum install httpd-tools -y
2.设置认证密码
[root@linux-test-no ~]# mkdir /opt/registry-var/auth/ -p [root@linux-test-no ~]# htpasswd -Bbn clsn 123456 > /opt/registry-var/auth/htpasswd
3.启动容器,在启动时传入认证参数
#这里我们基于上面的普通仓库进行操作
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d1aba329d0c registry:latest "/entrypoint.sh /etc…" 7 hours ago Up 7 hours 0.0.0.0:5000->5000/tcp qingbai_registry
#这里我们需要先把容器的restart状态改变,让其不随docker服务的重启而重启
[root@linux-test-no ~]# docker update --restart=no qingbai_registry
qingbai_registry
#然后我们重启docker进行验证,关闭上面已在运行的仓库。
[root@linux-test-no ~]# systemctl restart docker
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#开始启动带basic认证的仓库,下面前一面一个-v是把我们在宿主机上创建的认证目录和容器内的认证目录关联,让仓库运行的时候可以读取我们在宿主机上创建的用户名和密码并进行验证。
下一个-v是把仓库容器中的镜像存放目录映射到宿主机上,-e REGISTRY_AUTH_HTPASSWD_PATH后面填认证文件所在的目录。因为我上面用户名和密码放在htpasswd文件下,所以我这里填写
/auth/htpasswd
[root@linux-test-no ~]# docker run -d -p 5000:5000 -v /opt/registry-var/auth/:/auth/ -v /iflytek/my_registry:/var/lib/registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry 996e778baea4c6b913397c4a902f520355c4ad6bc62beb1cead22bfb201032cd
4.使用验证用户测试
#登陆用户
[root@linux-test-no ~]# docker login 172.31.46.38:5000 Username: clsn Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded #推送镜像到仓库
[root@linux-test-no ~]# docker push 172.31.46.38:5000/centos:6.8 The push refers to repository [172.31.46.38:5000/centos] ad337ac82f03: Layer already exists 6.8: digest: sha256:3e472cabf40e9beee56affc1fdce0e897dadc4e6063c00cd16bcbdbd3ba96864 size: 529
#认证文件保存位置
[root@linux-test-no ~]# cat .docker/config.json
{
"auths": {
"172.31.46.38:5000": {
"auth": "Y2xzbjoxMjM0NTY="
}
},
"HttpHeaders": {
"User-Agent": "Docker-Client/19.03.12 (linux)"
}
}
11.docker-compose编排工具
当在宿主机启动较多的容器时候, 如果都是手动操作会觉得比较麻烦而且容器出错,这个时候推荐使用 docker 单机编排工具 docker compose, Docker Compose
是 docker 容器的一种编排服务, docker compose 是一个管理多个容器的工具,比如可以解决容器之间的依赖关系, 就像启动一个 web 就必须得先把数据库服务
先启动一样, docker compose 完全可以替代 docker run 启动容器。
1.安装docker-compose
#下载pip软件
[root@linux-test-no ~]# yum install -y python2-pip
#下载docker-compose
[root@linux-test-no ~]# pip install --upgrade pip
[root@linux-test-no ~]# pip install docker-compose
#下载docker-compose之前建议开启国内pip下载,另下载过程中可能会报错,报错解决方法参考下面博客
https://www.cnblogs.com/felixqiang/p/11946644.html
#查看docker-compose版本
[root@linux-test-no ~]# docker-compose version
/usr/lib64/python2.7/site-packages/cryptography/__init__.py:39: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.
CryptographyDeprecationWarning,
docker-compose version 1.26.2, build unknown
docker-py version: 4.2.2
CPython version: 2.7.5
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
国内开启pip下载加速:https://developer.aliyun.com/mirror/pypi?spm=a2c6h.13651102.0.0.3e221b11i6opDK
[root@linux-test-no ~]# mkdir ~/.pip/ [root@linux-test-no ~]# cat > ~/.pip/pip.conf << 'EOF' > [global] > index-url = https://mirrors.aliyun.com/pypi/simple/ > [install] > trusted-host=mirrors.aliyun.com > EOF
2.编排启动容器
1.创建文件目录
#目录可以在任意目录, 推荐放在有意义的位置。 [root@linux-test-no ~]# mkdir /opt/my_wordpress/ [root@linux-test-no ~]# cd /opt/my_wordpress/ [root@linux-test-no my_wordpress]#
2.编写编排文件启动单个容器
#编排文件是一个 yml 格式的配置文件,因此要严格注意前后的缩进和格式,不然通过编排文件启动容器的时候会有各种问题。
[root@linux-test-no my_wordpress]# vim docker-compose.yml web1: #这里是填容器的id,每一个容器都可以设自己的id image: nginx:latest #这里写镜像名,表示从哪个镜像启动,如果镜像本地不存在,会自动去仓库拉 expose: #这里表示开放什么端口,这里可写可不写,对应下面的prots。 - 80 - 443 volumes: #这里表示挂载数据卷 - /iflytek/data1:/usr/share/nginx/html restart: always
container_name: nginx-web1 #这里指定启动后的容器名 ports: #这里表示映射的端口号 - "80:80" - "443:443" [root@linux-test-no my_wordpress]# cat /iflytek/data1/index.html #这里准备测试web界面 test1
[root@linux-test-no my_wordpress]# docker-compose up #通过docker-compose文件前台启动容器,如果想后台的话,只需执行docker-compose up -d,还有启动命令一定要在
docker-compose文件所在目录执行
#刚刚因为我们是前台启动的,所以我们这里重新开一个端口看容器是否启动和测试web能否访问,结果如下,我们发现docker-compose启动成功
[root@linux-test-no ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f2919530ece nginx:latest "/docker-entrypoint.…" 14 minutes ago Up 14 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-web1
996e778baea4 registry "/entrypoint.sh /etc…" 28 hours ago Up 28 hours 0.0.0.0:5000->5000/tcp musing_yalow
[root@linux-test-no ~]# curl 172.31.46.38:80
test1
3.编写编排文件启动多个容器
#编排文件如下,通过下面我们看出,启动几个容器,就写几个容器ID名就行了,然后在容器ID下面写上你自己启动时要配置的参数
[root@linux-test-no my_wordpress]# vim docker-compose.yml web1: image: nginx:latest expose: - 80 - 443 volumes: - /iflytek/data1:/usr/share/nginx/html restart: always container_name: nginx-web1 ports: - "80:80" - "443:443" web2: image: nginx:latest expose: - 80 - 443 volumes: - /iflytek/data2:/usr/share/nginx/html restart: always container_name: nginx-web2 ports: - "81:80" - "4443:443" [root@linux-test-no my_wordpress]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 996e778baea4 registry "/entrypoint.sh /etc…" 28 hours ago Up 28 hours [root@linux-test-no my_wordpress]# cat /iflytek/data2/index.html test2.web2
#通过docker-compose编排文件后台启动容器
[root@linux-test-no my_wordpress]# docker-compose up -d
#测试发现docker-compose编排文件启动多容器成功。
[root@linux-test-no my_wordpress]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0b55534de6da nginx:latest "/docker-entrypoint.…" 44 seconds ago Up 42 seconds 0.0.0.0:81->80/tcp, 0.0.0.0:4443->443/tcp nginx-web2
187305da8f7a nginx:latest "/docker-entrypoint.…" 44 seconds ago Up 42 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-web1
996e778baea4 registry "/entrypoint.sh /etc…" 29 hours ago Up 29 hours 0.0.0.0:5000->5000/tcp musing_yalow
[root@linux-test-no my_wordpress]# curl 172.31.46.38:80
test1
[root@linux-test-no my_wordpress]# curl 172.31.46.38:81
test2.web2
12.Docker镜像加速配置
国内下载国外的镜像有时候会很慢,因此可以更改 docker 配置文件添加一个加
速器, 可以通过加速器达到加速下载镜像的目的。
1.获取加速地址
浏览器打开 http://cr.console.aliyun.com, 注册或登录阿里云账号,点击左侧的
镜像加速器, 将会得到一个专属的加速地址, 而且下面有使用配置说明:
2.生成配置文件
按阿里官方的操作手册,我们在本地生成配置文件
[root@gitlab ~]# mkdir -p /etc/docker [root@gitlab ~]# sudo tee /etc/docker/daemon.json <<-'EOF' > { > "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"] > } > EOF { "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"] } [root@gitlab ~]# cat /etc/docker/daemon.json { "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"] }
3.重启docker服务
[root@gitlab ~]# systemctl daemon-reload
[root@gitlab ~]# systemctl restart docker
13.Docker网络类型
docker的逻辑网络图如下
Docker 服务安装完成之后,默认在每个宿主机会生成一个名称为 docker0 的网卡
其 IP 地址都是 172.17.0.1/16,并且会生成三种不能类型的网络,如下
[root@gitlab ~]# ifconfig docker0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:4b:88:44:4e txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 #这个命令是看容器的网络列表的
[root@gitlab ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 17d7ac9c1b55 bridge bridge local 8391899dee5d host host local 3aa485e206ff none null local
1.docker的网络类型
Bridge默认docker网络隔离基于网络命名空间,在物理机上创建docker容器时会为每一个docker容器分配网络命名空间,并且把容器IP桥接到物理机的虚拟网桥上。
2.为容器配置none类型网络(就是不为容器配置网络功能)
此模式下创建容器是不会为容器配置任何网络参数的,如:容器网卡、IP、通信路由等,全部需要自己去配置,所以极少使用。
#指定容器启动时用的网络类型是需在启动参数里加上--net=后面跟你要指定的类型网络。
[root@linux-test-no ~]# docker run -it --name net_none --net=none centos:latest /bin/bash #验证,我们刚刚指定了none类型网络,我们现在进容器发现容器中并没有配置任何网络功能。
[root@b61605f1ceb5 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever
3.为容器配置Container类型网络(就是与其他容器共享网络配置)
此模式和host模式很类似,只是此模式创建容器共享的是其他容器的IP和端口而不是物理机,此模式容器自身是不会配置网络和端口,创建此模式容器进去后,你会发现里边的IP是你所指定的那个容器IP并且端口也是共享的,因此这个容器的端口不能和被指定容器的端口冲突, 但是新容器其它还是互相隔离的,如进程等。
#起一个测试的被共享网络的测试容器。
[root@linux-test-no ~]# docker run -it -d --name test1 centos:latest /bin/bash 556135e167bd6849ff98ee23e2eab079245a1f0baeb16d76a67cf98970461a38 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 556135e167bd centos:latest "/bin/bash" 8 seconds ago Up 7 seconds test1 [root@linux-test-no ~]# docker exec -it test1 /bin/bash #查看网络配置
[root@556135e167bd /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever #起一个Container类型网络的容器,格式为--net=container:后面跟你要指定的容器名或容器ID
[root@linux-test-no ~]# docker run -it -d --name net_container --net=container:test1 centos:latest /bin/bash 3868b33234b30acdde241abe2fe48990d187813e4239f38cc58e9c79c292b5ff [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3868b33234b3 centos:latest "/bin/bash" 3 seconds ago Up 3 seconds net_container 556135e167bd centos:latest "/bin/bash" 9 minutes ago Up 9 minutes test1 [root@linux-test-no ~]# docker exec -it net_container /bin/bash #查看网络配置是否和测试容器一样
[root@556135e167bd /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
4.使用宿主机网络
启动的容器如果指定了使用 host 模式,那么新创建的容器不会创建自己的虚拟
网卡,而是直接使用宿主机的网卡和 IP 地址, 因此在容器里面查看到的 IP 信息
就是宿主机的信息,访问容器的时候直接使用宿主机 IP+容器端口即可,不过容
器的其他资源们必须文件系统、 系统进程等还是和宿主机保持隔离。
此模式的网络性能最高,但是各容器之间端口不能相同, 适用于运行容器端口比
较固定的业务。
这个模式认为是不安全的。
#我们先看一下宿主机的网络配置
[root@linux-test-no ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether fa:16:3e:75:0f:be brd ff:ff:ff:ff:ff:ff inet 172.31.46.38/24 brd 172.31.46.255 scope global dynamic eth0 valid_lft 39286sec preferred_lft 39286sec inet6 fe80::f816:3eff:fe75:fbe/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:62:93:42:75 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:62ff:fe93:4275/64 scope link valid_lft forever preferred_lft forever 123: veth38cafa1@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP link/ether 86:33:44:5f:8f:bb brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::8433:44ff:fe5f:8fbb/64 scope link valid_lft forever preferred_lft forever #看下宿主机的系统,等下有用
[root@linux-test-no ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) #启动一个host类型网络的容器,启动格式为加一个启动参数--net=host
[root@linux-test-no ~]# docker run -it --name net_host --net=host centos:latest /bin/bash #我们现在已经进容器了,看网络配置,和宿主机一样。这里可能会有人问,你这明明在宿主机上,怎么讲进容器了,我们看下面
[root@linux-test-no /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether fa:16:3e:75:0f:be brd ff:ff:ff:ff:ff:ff inet 172.31.46.38/24 brd 172.31.46.255 scope global dynamic eth0 valid_lft 39175sec preferred_lft 39175sec inet6 fe80::f816:3eff:fe75:fbe/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:62:93:42:75 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:62ff:fe93:4275/64 scope link valid_lft forever preferred_lft forever 123: veth38cafa1@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 86:33:44:5f:8f:bb brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::8433:44ff:fe5f:8fbb/64 scope link valid_lft forever preferred_lft forever #看到这里我们发现,我们是进到容器里了,因为宿主机系统和容器系统不一样。出现这样的原因是我们启动的时候指定的是host类型网络,这是host类型网络的特性
[root@linux-test-no /]# cat /etc/redhat-release CentOS Linux release 8.2.2004 (Core)
5.Docker跨主机通信之macvlan(一般用的比较少)
macvlan的逻辑图如下
我们这里测试在两台宿主机上进行容器通过macvlan的链接的测试
#以下操作是在宿主机1上做的
#使用下面的命令在宿主机上创建名为mcv1的macvlan网络。 -d指定创建的网络类型为什么,类似于加了一个什么网络驱动。
--subnet 指定macvlan网络所在的网络,一般填写宿主机所在的网络,--gateway指定网关,一般为宿主机网关。-o parent指定用来分配macvlan网络的物理网卡,因为macvlan创建的时候,
需要关联一个物理网卡才行。
[root@linux-test-no ~]# docker network create -d macvlan --subnet 172.31.46.0/24 --gateway 172.31.46.1 -o parent=eth0 mcv1 ceede34b513e7e1e5376e7f0b4ac90ef591467558a188d1035d8dd1060bc777f #查看我们的docker网络类型,发现生成了一个macvlan类型网络的macv1。
[root@linux-test-no ~]# docker network ls NETWORK ID NAME DRIVER SCOPE e6d919586ae3 bridge bridge local 79232f7835db host host local ceede34b513e mcv1 macvlan local 58d353d474cd none null local #这里我们还需要把我们macvlan关联的物理网卡开启混杂模式,不然可能出现ping不通的情况。
混杂模式(Promiscuous Mode)是指一台机器能够接收所有经过它的数据流,而不论其目的地址是否是他
[root@linux-test-no ~]# ip link set eth0 promisc on #启动一个容器c1,通过--network指定使用什么类型网络,我们这里是名为mcv1的macvlan类型网络。--ip指定容器内的地址,防止容器地址自动分配,导致冲突
[root@linux-test-no ~]# docker run -itd --name c1 --ip=172.31.46.101 --network mcv1 centos:latest 489ad6f309b9772d7327ccf732f3c3575a43390ac02a0a18ac1be12c76faae77 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 489ad6f309b9 centos:latest "/bin/bash" 43 seconds ago Up 42 seconds c1 3868b33234b3 centos:latest "/bin/bash" 39 hours ago Up 39 hours net_container 556135e167bd centos:latest "/bin/bash" 39 hours ago Up 39 hours test1 #我们进到我们刚刚创建的容器中,查看地址是否是我们指定的
[root@linux-test-no ~]# docker exec -it c1 /bin/bash [root@489ad6f309b9 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 124: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether 02:42:ac:1f:2e:65 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.31.46.101/24 brd 172.31.46.255 scope global eth0 valid_lft forever preferred_lft forever #以下操作是在宿主机2上进行的操作
#这里执行的步骤和宿主机1上一样,也是类似起一个macvlan的驱动。驱动名要和宿主机1一样都指定成mcv1
[root@gitlab ~]# docker network create -d macvlan --subnet 172.31.46.0/24 --gateway 172.31.46.1 -o parent=eth0 mcv1 f0e34200bed181a1a626bc3a214f86111ab87fbb8d5ed37f6948a1685d4190f8 [root@gitlab ~]# docker network ls NETWORK ID NAME DRIVER SCOPE b25338243647 bridge bridge local 8391899dee5d host host local f0e34200bed1 mcv1 macvlan local 3aa485e206ff none null local #然后我们这里把我们在宿主机2上配置了macvlan驱动的物理网卡设为混杂模式,从上面我们看出,我们起macvlan驱动的时候,指定的是eth0网卡
[root@gitlab ~]# ip link set eth0 promisc on #启动一个容器C2,指定我们要使用的名为mcv1的macvlan类型网络,这里因为我们是要和宿主机1下的c1容器通信,所以我们要在一个macvlan通道macv1下。
[root@gitlab ~]# docker run -itd --name c2 --ip=172.31.46.102 --network mcv1 centos:latest 5659b8fd85155a1d35f423597eb90658c5fe6e6ebab737980894babca336219a [root@gitlab ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5659b8fd8515 centos:latest "/bin/bash" 2 seconds ago Up 1 second c2 [root@gitlab ~]# docker exec -it c2 /bin/bash [root@5659b8fd8515 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 5: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether 02:42:ac:1f:2e:66 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.31.46.102/24 brd 172.31.46.255 scope global eth0 valid_lft forever preferred_lft forever
使用--filter dangling=true 过滤 不在使用的数据卷
---------------------
本文著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
来源地址:https://www.php.cn/docker/456656.html
来源:php中文网(www.php.cn)
© 版权声明:转载请附上原文链接!