docker学习笔记——基础篇

Docker进阶:网络篇 - 至安 - 博客园 (cnblogs.com)

Docker-概述

学习资源

最好的资源在官网!

Docker官方:

视频教程:

历史

2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司。

这家公司主要提供基于PaaS的云计算技术服务。具体来说,是和LXC有关的容器技术。

后来,dotCloud公司将自己的容器技术进行了简化和标准化,并命名为——Docker。

Docker技术诞生之后,并没有引起行业的关注。而dotCloud公司,作为一家小型创业企业,在激烈的竞争之下,也步履维艰。

正当他们快要坚持不下去的时候,脑子里蹦出了“开源”的想法。

什么是“开源”?开源,就是开放源代码。也就是将原来内部保密的程序源代码开放给所有人,然后让大家一起参与进来,贡献代码和意见。

有的软件是一开始就开源的。也有的软件,是混不下去,创造者又不想放弃,所以选择开源。自己养不活,就吃“百家饭”嘛。

2013年3月,dotCloud公司的创始人之一,Docker之父,28岁的Solomon Hykes正式决定,将Docker项目开源。 不开则已,一开惊人。

越来越多的IT工程师发现了Docker的优点,然后蜂拥而至,加入Docker开源社区。

Docker的人气迅速攀升,速度之快,令人瞠目结舌。

开源当月,Docker 0.1 版本发布。此后的每一个月,Docker都会发布一个版本。到2014年6月9日,Docker 1.0 版本正式发布。

此时的Docker,已经成为行业里人气最火爆的开源技术,没有之一。甚至像Google、微软、Amazon、VMware这样的巨头,都对它青睐有加,表示将全力支持。

Docker和容器技术为什么会这么火爆?说白了,就是因为它“轻”。

在容器技术之前,业界的网红是虚拟机。虚拟机技术的代表,是VMWare和OpenStack。

相信很多人都用过虚拟机。虚拟机,就是在你的操作系统里面,装一个软件,然后通过这个软件,再模拟一台甚至多台“子电脑”出来。

在“子电脑”里,你可以和正常电脑一样运行程序,例如开QQ。如果你愿意,你可以变出好几个“子电脑”,里面都开上QQ。“子电脑”和“子电脑”之间,是相互隔离的,互不影响。

虚拟机属于虚拟化技术。而Docker这样的容器技术,也是虚拟化技术,属于轻量级的虚拟化。

虚拟机虽然可以隔离出很多“子电脑”,但占用空间更大,启动更慢,虚拟机软件可能还要花钱(例如VMWare)。

而容器技术恰好没有这些缺点。它不需要虚拟出整个操作系统,只需要虚拟一个小规模的环境(类似“沙箱”)。

它启动时间很快,几秒钟就能完成。而且,它对资源的利用率很高(一台主机可以同时运行几千个Docker容器)。此外,它占的空间很小,虚拟机一般要几GB到几十GB的空间,而容器只需要MB级甚至KB级。

正因为如此,容器技术受到了热烈的欢迎和追捧,发展迅速。

docker 理念

Docker是基于Go语言实现的云开源项目。

Docker的主要目标是“Build,Ship and Run Any App , Anywhere”,也就是通过对应用组件的封装、分 发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。

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

什么是虚拟化技术

什么是虚拟化

在计算机技术中,虚拟化(Virtualization)是一种资源管理技术。它是将计算机的各种实体资源,如:服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以用更好的方式来利用这些资源。

虚拟化的目的是为了在同一个主机上运行多个系统或应用,从而提高系统资源的利用率,并带来降低成本、方便管理和容错容灾等好处。

虚拟化技术分类

从实现形式来分,虚拟化技术可分为基于硬件的虚拟化和基于软件的虚拟化。

硬件虚拟化

硬件虚拟化就是硬件物理平台本身提供了对特殊指令的截获和重定向的支持。支持虚拟化的硬件,也是一些基于硬件实现软件虚拟化技术的关键。在基于硬件实现软件虚拟化的技术中,在硬件是实现虚拟化的基础,硬件(主要是CPU)会为虚拟化软件提供支持,从而实现硬件资源的虚拟化。

支持虚拟化的硬件有:

  • Intel-VT-(Intel Virtualization Technology),Intel公司为解决纯软件虚拟化解决方案在可靠性、安全性和性能上的不足而引进的技术。它可以让一个CPU工作起来像多个CPU在并行运行,从而使得在一部电脑内同时运行多个操作系统成为可能
  • AMD-V-(AMD Virtualization),是AMD公司的虚拟化技术。它是对x86处理器系统架构的一组硬件扩展和硬件辅助虚拟化技术,可以简化纯软件的虚拟化解决方案,改进VMM(虚拟机监视器)的设计,更充分地利用硬件资源,提高服务器和数据中心的虚拟化效率

软件虚拟化

软件虚拟化就是利用软件技术,在现有的物理平台上实现对物理平台访问的截获和模拟。在软件虚拟化技术中,有些技术不需要硬件支持,如:QEMU;而有些软件虚拟化技术,则依赖硬件支持,如:VMware、KVM。

对软件虚拟化进行细分,又可以分为以下几类:

  • 完全虚拟化:(Full Virtualization)虚拟机模拟完整的底层硬件环境和特权指令的执行过程,使客户机操作系统可以独立运行。支持完全虚拟化的软件有:Parallels Workstation、VirtualBox、Virtual Iron、Oracle VM、Virtual PC、Virtual Server、Hyper-V、VMware Workstation、QEMU等
  • 硬件辅助虚拟化:(Hardware-assisted Virtualization)是指通过硬件辅助支持模拟运行环境,使客户机操作系统可以独立运行,实现完全虚拟化的功能。支持硬件辅助虚拟化的软件有:Linux KVM、VMware Workstation、VMware Fusion、Virtual PC、Xen、VirtualBox、Parallels Workstation等
  • 部分虚拟化:(Partial Virtualization)只针对部分硬件资源进行虚拟化,虚拟机模拟部分底层硬件环境,特别是地址空间。这样的环境支持资源共享和线程独立,但是不允许建立独立的客户机操作系统。
  • 平行虚拟化:(Para-Virtualization)虚拟机不需要模拟硬件,而是将部分硬件接口以软件的形式提供给客户机操作系统。如:早期的Xen。
  • 操作系统层虚拟化:(OS-level virtualization)这种技术将操作系统内核虚拟化,可以允许使用者空间软件实例被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运行。这个软件实例,也被称为是一个容器(containers)、虚拟引擎(Virtualization engine)、虚拟专用服务器(virtual private servers)。每个容器的进程是独立的,对于使用者来说,就像是在使用自己的专用服务器。 Docker容器技术就是属于操作系统层虚拟化的范畴

几种虚拟化技术

虚拟化是通过软件的方式模拟实体服务器,其初衷是为了解决“一种应用占用一台服务器”模式所带来的服务器数量剧增的问题,从而降低数据中心复杂度,简化管理难度。在虚拟化的发展过程中,出现过以下主要虚拟化技术或产品:

  • Xen - 由剑桥大学开发的,一款开源的虚拟机监视器。采用ICA协议,它通过一种叫做准虚拟化的技术来获取高性能,甚至在一些与传统虚拟技术极度不友好的架构上(如:x86),Xen也有极佳的表现。Xen属于半虚拟化的技术,所以其性能损失非常小。Xen没有指令翻译,其或者使用使能理解和翻译虚拟操作系统发出的未修改指令的CPU(即:完全虚拟化);或者修改操作系统,使它发出的指令最优化,便于在虚拟化环境中执行(即:准虚拟化)。
  • KVM - KVM是一个Linux kernel模块,可以使用modprobe来加载KVM,加载后还需要通过其他工具创建虚拟机。KVM是一个全虚拟化的解决方案,但需要CPU支持虚拟化功能。相比Xen来说,KVM可以更加方便的整合进Linux内核,但它还需要其它虚拟化软件(如:QEMU)才能实现虚拟化功能
  • LXC - 即:Linux Container,Linux容器,是一种轻量级的虚拟化的手段。它可以提供轻量级的虚拟化,以隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。容器会有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。
  • OpenVZ - 是SWsoft公司开发的开源软件,是该公司Virtuozzo软件的基础产品,是基于Linux平台的操作系统级服务器虚拟化解决方案。通过OpenVZ,可以在单个物理服务器上创建多个相互隔离的虚拟专用服务器(VPS)并以最大的效率共享硬件和管理资源。其上运行虚拟服务器被称为VPS(Virtual Private Serve),每个VPS的运行环境和独立服务器完全一致。OpenVZ基于Linux系统内核及作业系统提供操作系统级虚拟化,在虚拟化过程中资源消耗非常小,官方宣称约1-2%。
  • Hyper-V - 是微软件推出的一种虚拟化技术,可以采用半虚拟化或全虚拟的方式创建虚拟机。虽然它可以创建Windows或Linux操作系统,但其本身只能运行在Windows系统下,使用范围较为有限
  • Oracle VM - Oracle推出的服务器虚拟化软件,基于开源的Xen技术,包括Oracle VM Server和Oracle VM Manager两部分。
  • VMWare - 是一家非常出名虚拟化软件公司,其产品涵盖服务器、桌面等各种虚拟化领域,如:VMware Workstation - 是一款桌面虚拟机软件,可以在一台实体机器上模拟完整的网络环境,并可运行多个Windows、DOS、Linux或Mac系统,是非常好的开发、测试、部署解决方案。从技术角度来说,VMware Workstation是一款完全虚拟化产品,可借助硬件辅助在不修改用户操作系统的情况下完整虚拟化操作系统。
  • VMware ESX Server - 是一款适用于任何系统环境的企业级的虚拟机软件,可以认为是VMware Server的升级版。相比VMware Workstation来说,其功能更加强大,可以用于构建高伸缩和高可靠企业级服务器,并可实现远程管理、高级资源管理控制等高级功能。

Docker虚拟化

什么是Docker?

Docker是一个开源的应用容器引擎,它让开发者可以打包他们的应用以及依赖到一个可移植的容器中,然后发布到安装了任何 Linux 发行版本的机器上。Docker基于LXC来实现类似VM的功能,可以在更有限的硬件资源上提供给用户更多的计算资源。与同VM等虚拟化的方式不同,LXC不属于全虚拟化、部分虚拟化或半虚拟化中的任何一个分类,而是一个操作系统级虚拟化。

Docker是直接运行在宿主操作系统之上的一个容器,使用沙箱机制完全虚拟出一个完整的操作,容器之间不会有任何接口,从而让容器与宿主机之间、容器与容器之间隔离的更加彻底。每个容器会有自己的权限管理,独立的网络与存储栈,及自己的资源管理能,使同一台宿主机上可以友好的共存多个容器。

Docker借助Linux的内核特性,如:控制组(Control Group)、命名空间(Namespace)等,并直接调用操作系统的系统调用接口。从而降低每个容器的系统开销,并实现降低容器复杂度、启动快、资源占用小等特征。

Docker能干什么?

  • 简化配置

这是Docker公司宣传的Docker的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。

  • 代码流水线(Code Pipeline)管理

前一个场景对于管理代码的流水线起到了很大的帮助。代码从开发者的机器到最终在生产环境上的部署,需要经过很多的中间环境。而每一个中间环境都有自己微小的差别,Docker给应用提供了一个从开发到上线均一致的环境,让代码的流水线变得简单不少。

  • 提高开发效率

这就带来了一些额外的好处:Docker能提升开发者的开发效率。详细一点的例子,可以参考Aater在DevOpsDays Austin 2014大会或者是DockerCon上的演讲。

不同的开发环境中,我们都想把两件事做好。一是我们想让开发环境尽量贴近生产环境,二是我们想快速搭建开发环境。

理想状态中,要达到第一个目标,我们需要将每一个服务都跑在独立的虚拟机中以便监控生产环境中服务的运行状态。然而,我们却不想每次都需要网络连接,每次重新编译的时候远程连接上去特别麻烦。这就是Docker做的特别好的地方,开发环境的机器通常内存比较小,之前使用虚拟的时候,我们经常需要为开发环境的机器加内存,而现在Docker可以轻易的让几十个服务在Docker中跑起来。

  • 隔离应用

有很多种原因会让你选择在一个机器上运行不同的应用,比如之前提到的提高开发效率的场景等。

我们经常需要考虑两点,一是因为要降低成本而进行服务器整合,二是将一个整体式的应用拆分成松耦合的单个服务(译者注:微服务架构)。如果你想了解为什么松耦合的应用这么重要,请参考Steve Yege的这篇论文,文中将Google和亚马逊做了比较。

  • 整合服务器 正如通过虚拟机来整合多个应用,Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本。由于没有多个操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比虚拟机提供更好的服务器整合解决方案。
  • 调适能力

Docker提供了很多的工具,这些工具不一定只是针对容器,但是却适用于容器。它们提供了很多的功能,包括可以为容器设置检查点、设置版本和查看两个容器之间的差别,这些特性可以帮助调试Bug。你可以在《Docker拯救世界》的文章中找到这一点的例证。

  • 多租户

另外一个Docker有意思的使用场景是在多租户的应用中,它可以避免关键应用的重写。我们一个特别的关于这个场景的例子是为IoT(物联网)的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。

使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于Docker环境的启动速度和其高效的diff命令。

  • 快速部署

在虚拟机之前,引入新的硬件资源需要消耗几天的时间。Docker的虚拟化技术将这个时间降到了几分钟,Docker只是创建一个容器进程而无需启动操作系统,这个过程只需要秒级的时间。这正是Google和Facebook都看重的特性。

你可以在数据中心创建销毁资源而无需担心重新启动带来的开销。通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。

Docker的基本组成

仓库,镜像,容器的关系(这是官网的图)

img

  • 镜像(image)

Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。 就好似 Java 中的 类和对象,类就是镜像,容器就是对象!

  • 容器(container)

Docker 利用容器(Container)独立运行一个或一组应用。容器是用镜像创建的运行实例。

它可以被启动、开始、停止、删除。每个容器都是相互隔离的,保证安全的平台。

可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等) 和运行在其中的应用程序

容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。

  • 仓库(repository)

仓库(Repository)是集中存放镜像文件的场所。

仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓 库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式

最大的公开仓库是 Docker Hub(https://hub.docker.com/),存放了数量庞大的镜像供用户下载。 国内的公开仓库包括阿里云 、网易云 等

小结:

Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个 可交付的运行环境,这个打包好的运行环境就似乎 image镜像文件。只有通过这个镜像文件才能生 成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。 同一个 image 文件,可以生成多个同时运行的容器实例。

image 文件生成的容器实例,本身也是一个文件,称为镜像文件

一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例, 也就是我们的容器

至于仓库,就是放了一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候从仓库中拉下来 就可以了

Docker和虚拟机的区别?

虚拟机Virtual Machine与容器化技术(代表Docker)都是虚拟化技术,两者的区别在于虚拟化的程度不同。

基本对比

img

  • 虚拟机
    • 基础设施(Infrastructure)。它可以是你的个人电脑,数据中心的服务器,或者是云主机。
    • 主操作系统(Host Operating System)。你的个人电脑之上,运行的可能是MacOS,Windows或者某个Linux发行版。
    • 虚拟机管理系统(Hypervisor)。利用Hypervisor,可以在主操作系统之上运行多个不同的从操作系统。类型1的Hypervisor有支持MacOS的HyperKit,支持Windows的Hyper-V以及支持Linux的KVM。类型2的Hypervisor有VirtualBox和VMWare。
    • 操作系统(Guest Operating System)。假设你需要运行3个相互隔离的应用,则需要使用Hypervisor启动3个从操作系统,也就是3个虚拟机。这些虚拟机都非常大,也许有700MB,这就意味着它们将占用2.1GB的磁盘空间。更糟糕的是,它们还会消耗很多CPU和内存。
    • 各种依赖。每一个从操作系统都需要安装许多依赖。如果你的的应用需要连接PostgreSQL的话,则需要安装libpq-dev;如果你使用Ruby的话,应该需要安装gems;如果使用其他编程语言,比如Python或者Node.js,都会需要安装对应的依赖库。
  • Docker容器
    • 主操作系统(Host Operating System)。所有主流的Linux发行版都可以运行Docker。对于MacOS和Windows,也有一些办法运行Docker。
    • Docker守护进程(Docker Daemon)。Docker守护进程取代了Hypervisor,它是运行在操作系统之上的后台进程,负责管理Docker容器。
    • 各种依赖。对于Docker,应用的所有依赖都打包在Docker镜像中,Docker容器是基于Docker镜像创建的。
    • 应用。应用的源代码与它的依赖都打包在Docker镜像中,不同的应用需要不同的Docker镜像。不同的应用运行在不同的Docker容器中,它们是相互隔离的。

虚拟机是在物理资源层面实现的隔离,相对于虚拟机,Docker是你APP层面实现的隔离,并且省去了虚拟机操作系统(Guest OS)),从而节省了一部分的系统资源;Docker守护进程可以直接与主操作系统进行通信,为各个Docker容器分配资源;它还可以将容器与主操作系统隔离,并将各个容器互相隔离。虚拟机启动需要数分钟,而Docker容器可以在数毫秒内启动。由于没有臃肿的从操作系统,Docker可以节省大量的磁盘空间以及其他系统资源。

虚拟机与容器docker的区别,在于vm多了一层guest OS,虚拟机的Hypervisor会对硬件资源也进行虚拟化,而容器Docker会直接使用宿主机的硬件资源

下面我们采用形象的比喻区分两者的隔离级别

  • 服务器:比作一个大型的仓管基地,包含场地与零散的货物——相当于各种服务器资源。
  • 虚拟机技术:比作仓库,拥有独立的空间堆放各种货物或集装箱,仓库之间完全独立——仓库相当于各种系统,独立的应用系统和操作系统。
  • Docker:比作集装箱,操作各种货物的打包——将各种应用程序和他们所依赖的运行环境打包成标准的容器,容器之间隔离。

虚拟技术对比

  • 隔离性

在于隔离性上面,由于vm对操作系统也进行了虚拟化,隔离的更加彻底。而Docker共享宿主机的操作系统,隔离性较差。

  • 运行效率

由于vm的隔离操作,导致生成虚拟机的速率大大低于容器Docker生成的速度,因为Docker直接利用宿主机的系统内核。比如openstack能够以10台/min的速度创建虚拟机,而docker可以做到在几秒钟之内创建大量容器,它们的启动速度是在数量级上的差距。

因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。

  • 资源利用率

在资源利用率上虚拟机由于隔离更彻底,因此利用率也会相对较低。

因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。比如对于本次实验的平台,实际的CPU架构是2块物理CPU。

参考文章

感谢大佬的辛苦整理,节省了大量时间

https://note.oddfar.com/pages/09f2eb/

Docker-安装

环境说明

我们使用的是 CentOS 7 (64-bit)

Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。

查看自己的内核:

用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型 等)。

uname -r

查看版本信息:

cat /etc/os-release

安装步骤

官网安装参考手册:https://docs.docker.com/engine/install/centos/

  1. yum安装gcc相关环境(需要确保虚拟机可以上外网 )

    yum update
    yum -y install gcc
    yum -y install gcc-c++
    
  2. 卸载旧版本

    sudo yum remove docker \
                      docker-client \
                      docker-client-latest \
                      docker-common \
                      docker-latest \
                      docker-latest-logrotate \
                      docker-logrotate \
                      docker-engine
    
  3. 安装需要的软件包

    sudo yum install -y yum-utils
    
  4. 设置镜像仓库

    官网(国外):

    sudo yum-config-manager \
        --add-repo \
        https://download.docker.com/linux/centos/docker-ce.repo
    

    阿里云(推荐):

    sudo yum-config-manager \
        --add-repo \
    	http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
  5. 更新yum软件包索引

    yum makecache fast
    
  6. 安装 Docker CE

    yum install docker-ce docker-ce-cli containerd.io
    
  7. 启动 Docker

    #开机自启
    systemctl enable docker
    #启动
    systemctl start docker
    

    至此,已经安装完

  • 查看版本

    docker version
    
  • 查看安装的镜像

    docker images
    
  • 测试运行hello

    docker run hello-world
    

也可以参考这篇安装文档 https://blog.csdn.net/lms279151398/article/details/114649713

卸载docker

systemctl stop docker
yum -y remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

踩坑记录

Docker服务启动报错:Job for docker.service failed because the control process exited with error

是因为 xfsprogs 版本太低了。

yum update xfsprogs

感谢大佬提供的解决方案https://www.cnblogs.com/FoChen/p/8708932.html

Docker-常用命令

帮助命令

docker version # 显示 Docker 版本信息。
docker info # 显示 Docker 系统信息,包括镜像和容器数。
docker --help # 帮助

镜像命令

Docker Hub 官方镜像仓库

查看镜像

docker images

列出本地主机上的所有镜像

参数 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像id
CREATED 镜像创建时间
SIZE 镜像大小

同一个仓库源可以有多个 TAG,代表这个仓库源的不同版本,我们使用 REPOSITORY:TAG 定义不同的镜像,docker默认使用 lastest 镜像!

docker search

搜索镜像: docker search 某个镜像的名称 ,对应DockerHub仓库中的镜像

docker search mysql

列出收藏数不小于指定值的镜像,例如

docker search mysql --filter=stars=1000

  • NAME: 镜像仓库源的名称
  • DESCRIPTION: 镜像的描述
  • OFFICIAL: 是否 docker 官方发布
  • STARS: 类似 Github 里面的 star,表示点赞、喜欢的意思。
  • AUTOMATED: 自动构建。

也通过Docker Hub 进行查找https://hub.docker.com

下载镜像

docker pull

不写tag,默认是latest

docker pull mysql

指定版本下载

docker pull mysql:5.7

镜像仓库中需有该版本

删除镜像

docker rmi

docker rmi -f 镜像id # 删除单个
docker rmi -f 镜像名:tag 镜像名:tag # 删除多个

删除全部

docker rmi -f $(docker images -qa)

容器命令

启动容器

docker run [OPTIONS] IMAGE [COMMAND][ARG...]

常用参数说明

参数 说明
--name 给容器指定一个名字 之后再对容器操作,可以用这个name,相当于“别名”
-d 后台方式运行容器,并返回容器的id
-i 以交互模式运行容器,通过和 -t 一起使用
-t 给容器重新分配一个终端,通常和 -i 一起使用
-P 随机端口映射(大写)
-p 指定端口映射(小写),一般可以有四种写法

示例:

#启动一个容器,使用centos进行用交互模式启动容器,在容器内执行/bin/bash命令
docker run -it centos /bin/bash

退出容器:exit

容器查看

docker ps [OPTIONS]

常用参数说明

参数 说明
-a 列出当前所有正在运行的容器 + 历史运行过的容器
-l 显示最近创建的容器
-n=? 显示最近n个创建的容器
-q 静默模式,只显示容器编号。

退出容器

指令 说明
exit 容器停止退出
ctrl+P+Q 容器不停止退出

启动停止容器

指令 说明
docker start (容器id or 容器名) 启动容器
docker restart (容器id or 容器名) 重启容器
docker stop (容器id or 容器名) 停止容器
docker kill (容器id or 容器名) 强制停止容器

docker rundocker start的区别

  • docker run 只在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器时,只需要使用命令docker start即可。
    docker run相当于执行了两步操作:将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start)。
  • docker start的作用是,重新启动已存在的镜像。也就是说,如果使用这个命令,我们必须事先知道这个容器的ID,或者这个容器的名字,我们可以使用docker ps找到这个容器的信息。

删除容器

指令 说明
docker rm 容器id 删除指定容器
docker rm -f $(docker ps -aq) 删除所有容器
docker ps -a -q|xargs docker rm 删除所有容器

后台启动容器

docker run -d 容器名

启动centos,使用后台方式启动,例如:

docker run -d centos

问题: 使用docker ps 查看,发现容器已经退出了!

解释:Docker容器后台运行,就必须有一个前台进程,容器运行的命令如果不是那些一直挂起的命 令,就会自动退出。

比如,你运行了nginx服务,但是docker前台没有运行应用,这种情况下,容器启动后,会立即自杀,因为他觉得没有程序了,所以最好的情况是,将你的应用使用前台进程的方式运行启动。

清理停止的容器

清理停止的容器:

docker container prune

image-20210604202728156

查看日志

docker logs -f -t --tail n 容器id

例子:我们启动 centos,并编写一段脚本来测试玩玩!最后查看日志

docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"

image-20210603174412524

查看日志:

docker logs 容器id
参数 说明
-t 显示时间戳
-f 打印最新的日志
--tail 数字显示多少条!
docker logs -tf --tail 10 87f5e5a2954e

image-20210603174510568

  • 停止运行
docker stop 容器id

image-20210603175026851

  • 查看正在运行容器的进程信息
docker top 容器id
  • 查看容器/镜像的元数据
docker inspect 容器id

image-20210603175638262

进入正在运行的容器

命令一:

docker exec -it 容器id /bin/bash

例如:

# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
# docker run -d centos /bin/sh -c "while true;do echo hello;sleep 1;done"
a9b967bdbc870bb039b69c76ddc3d3ce6aa87d57c51a8040e32224fb45576b28
# docker ps
a9b967bdbc87   centos    "/bin/sh -c 'while t…"   8 seconds ago   Up 7 seconds             upbeat_haibt
# docker exec -it a9b967bdbc87 /bin/bash
[root@a9b967bdbc87 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:01 ?        00:00:00 /bin/sh -c while true;do echo hello;sleep 1;done
root        37     0  0 10:02 pts/0    00:00:00 /bin/bash
root        59     1  0 10:02 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root        60    37  0 10:02 pts/0    00:00:00 ps -ef

退出容器终端,不会导致容器的停止

命令二:

docker attach 容器id

测试:

# docker images
centos        latest    300e315adb2f   5 months ago   209MB
# docker  run -it -d  centos /bin/bash
7f9ead6f906b3c691d29866236414e1808d194462ed0839c8ee5c947d731ed57
# docker ps
7f9ead6f906b   centos    "/bin/bash"   10 seconds ago   Up 9 seconds             nervous_mcclintock
# docker attach 7f9ead6f906b
# echo "hello"
hello
# exit
exit

区别 :

  • exec 是在容器中打开新的终端,并且可以启动新的进程
  • attach 直接进入容器启动命令的终端,不会启动新的进程

推荐大家使用 docker exec 命令,

常用命令总结

img_29

命令 官方说明 解释
attach Attach local standard input, output, and error streams to a running container 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile 通过 Dockerfile 定制镜像
commit Create a new image from a container's changes 提交当前容器为新的镜像
cp Copy files/folders between a container and the local filesystem 从容器中拷贝指定文件或者目录到宿主机中
create Create a new container 创建一个新的容器,同 run,但不启动容器
diff Inspect changes to files or directories on a container's filesystem 查看 docker 容器变化
events Get real time events from the server 从 docker 服务获取容 器实时事件
exec Run a command in a running container 在已存在的容器上运行命令
export Export a container's filesystem as a tar archive 导出容器的内 容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image 展示一个镜像形成历史
images List images 列出系统当前镜像
import Import the contents from a tarball to create a filesystem image 从 tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information 显示系统相关信息
inspect Return low-level information on Docker objects 查看容器详细信息
kill Kill one or more running containers 杀掉 指定 docker 容器
load Load an image from a tar archive or STDIN 从一个 tar 包中加载一 个镜像[对应 save]
login Log in to a Docker registry 登陆一个 docker 源服务器
logout Log out from a Docker registry 从当前 Docker registry 退出
logs Fetch the logs of a container 输出当前容器日志信息
pause Pause all processes within one or more containers 暂停容器
port List port mappings or a specific mapping for the container 查看映射端口对应的容器内部源端口
ps List containers 列出容器列表
pull Pull an image or a repository from a registry 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to a registry 推送指定镜像或者库镜像至docker源服务器
rename Rename a container 给一个容器改名
restart Restart one or more containers 重启运行的容器
rm Remove one or more containers 移除一个或者多个容器
rmi Remove one or more images 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container 创建一个新的容器并运行 一个命令
save Save one or more images to a tar archive (streamed to STDOUT by default) 保存一个镜像为一个 tar 包[对应 load]
search Search the Docker Hub for images 在 docker hub 中搜 索镜像
start Start one or more stopped containers 启动容器
stats Display a live stream of container(s) resource usage statistics 显示容器资源使用统计信息的实时信息
stop Stop one or more running containers 停止容器
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE 给源中镜像打标签
top Display the running processes of a container 查看容器中运行的进程信 息
unpause Unpause all processes within one or more containers 取消暂停容器
update Update configuration of one or more containers 更新容器配置
version Show the Docker version information 查看 docker 版本号
wait Block until one or more containers stop, then print their exit codes 截取容器停止时的退出状态值

练习

安装Tomcat

官网测试安装

docker run -it --rm tomcat:9.0
  • -it :交互模式
  • --rm:容器启动成功并退出以后容器就自动移除,一般在测试情况下使用!

1、下载tomcat镜像:

docker pull tomcat

2、启动

docker run -d -p 8080:8080 --name myTomcat tomcat

3、进入tomcat

docker exec -it tomcat /bin/bash

进入后发现,webapps 里什么也没有

# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work
# ls webapps
 

踩坑

报错

curl: (56) Recv failure: Connection reset by peer

解决方案: 重建docker0网桥,但出现错误原因不清楚

# 停止docker
systemctl stop docker
# 安装bridge-utils
yum install -y bridge-utils 
# 关闭docker0网桥
ip link set dev docker0 down
# 删除docker0网桥
brctl delbr docker0
# 添加docker0网桥
brctl addbr docker0
# 添加网桥信息
ip addr add 172.16.10.1/24 dev docker0
# 启动docker0网桥
ip link set dev docker0 up
# 查看网桥是否正常
ip addr
# 启动docker
systemctl restart docker

若部署一个 jsp 网站,需要把文件复制到容器里,非常麻烦。

我们可以通过“数据卷”技术,将容器内文件和我们 Linux 文件进行映射挂载

Docker - 镜像与仓库

Docker 镜像

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含 运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

Docker镜像加载原理

UnionFS (联合文件系统)

UnionFS 是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

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

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

典型的Linux文件系统由bootfsrootfs两部分组成

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

img_41

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

image-20210604172626563

对于一个精简的系统,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就可以了。由此可见对于不同的 linux 发行版, bootfs 基本是一 致的, rootfs 会有差别, 因此不同的发行版可以公用 bootfs。

分层理解

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!

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

最大的好处,莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层的方式可以通过 docker image inspect命令!

docker image inspect tomcat:latest

image-20210604174631340

所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

img_46

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了 一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。

img_47

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版本。

img_49

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统 一的文件系统。

Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

img_50

特点:

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!

提交镜像

docker commit 从容器创建一个新的镜像。

  • 语法:

    docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
    

测试

1、从Docker Hub 下载 tomcat 镜像到本地并运行

-it 交互终端 -p 端口映射

docker run -it -p 8080:8080 tomcat

2、访问地址

image-20210604183544250

docker启动官方tomcat镜像的容器,发现404是因为使用了加速器,而加速器里的 tomcat的webapps下没有root等文件!

[root@VM-0-6-centos ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED         STATUS         PORTS                                       NAMES
a8b6aff64fa3   tomcat    "catalina.sh run"   8 minutes ago   Up 8 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   silly_feynman
[root@VM-0-6-centos ~]# docker exec -it a8b6aff64fa3 /bin/bash
root@a8b6aff64fa3:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work

进入 tomcat 查看 cd 到 webapps 下发现全部空的,反而有个 webapps.dist 里有对应文件

root@a8b6aff64fa3:/usr/local/tomcat# cd webapps.dist
root@a8b6aff64fa3:/usr/local/tomcat/webapps.dist# ls
ROOT  docs  examples  host-manager  manager

我们可以 cp -r 复制文件到webapps下!

root@a8b6aff64fa3:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@a8b6aff64fa3:/usr/local/tomcat# cd webapps
root@a8b6aff64fa3:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

此时再次访问,则不是404

**3、提交修改后的镜像为 tomcat02 **

下次则可以直接启动这个

注意:commit的时候,容器的名字不能有大写,否则报错:invalid reference format

# docker commit -a="birdy" -m="new tomcat" a8b6aff64fa3 myTomcat2:1.1
sha256:620813976effbc8a7e36398a9b801891d1654dea37a50927b36a950ffe21a63b
[root@VM-0-6-centos ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
tomcat02              1.1       620813976eff   8 seconds ago   672MB

停止后再启动看看,首页可访问

[root@VM-0-6-centos ~]# docker stop a8b6aff64fa3
a8b6aff64fa3
[root@VM-0-6-centos ~]# docker run -it -p 8080:8080 tomcat02:1.1

Docker 仓库

DockerHub

注册dockerhub https://hub.docker.com/signup

1、登录

docker login -u oddfar

2、将镜像发布出去

[root@VM-0-6-centos logs]# docker push hello-world
Using default tag: latest
The push refers to repository [docker.io/library/hello-world]
f22b99068db9: Layer already exists 
errors:
denied: requested access to the resource is denied
unauthorized: authentication required

错误:请求的资源访问被拒绝

问题:本地镜像名无帐号信息,解决加 tag 即可

[root@VM-0-6-centos logs]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED             SIZE
hello-world           latest    d1165f221234   3 months ago        13.3kB
[root@VM-0-6-centos logs]# docker tag d1165f221234 oddfar/hello-world:1.0

oddfar 是我的用户名

3、再次push

[root@VM-0-6-centos logs]# docker push oddfar/hello-world:1.0

访问:https://hub.docker.com/ 可看到提交的镜像

image-20210606181526206

阿里云镜像服务

登录阿里云 -> 找到容器镜像服务 -> 创建命名空间 -> 创建镜像仓库

点击进入这个镜像仓库,可以看到所有的信息

image-20210606192542790

指令:

image-20210606204609437

测试:推送 hello-world

[root@VM-0-6-centos ~]# docker login --username=a_zhiyuan registry.cn-hangzhou.aliyuncs.com
[root@VM-0-6-centos ~]# docker tag d1165f221234 registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0
[root@VM-0-6-centos ~]# docker push registry.cn-hangzhou.aliyuncs.com/zhiyuan/study:1.0

提交成功

image-20210606204641884

数据卷

数据卷(Data Volume)

将应用和运行环境打包形成容器运行时,运行环境可以伴随着容器,但是我们对于数据的要求,是希望能够持久化!

为什么要有数据卷

想象一下,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这就太扯了!

Docker容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行不通的!

为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除而丢失了!

卷就是目录或者文件,存在一个或者多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性。

卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷。

特点:

  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止

一句话: 就是容器的持久化,以及容器间的继承和数据共享!

使用数据卷

方式一:直接使用命令来添加

在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里。

docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名

示例:

docker run -it -v /home/d-test:/home centos /bin/bash

查看数据卷是否挂载成功 docker inspect 容器id

#docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
05fa819084c9   centos    "/bin/bash"   20 seconds ago   Up 20 seconds             friendly_keller
#docker inspect 05fa819084c9

容器:

# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  s
# cd home
# ls
# touch test.java

主机:

# cd /home/d-test
# ls
test.java

方式二:Docker File 文件方式

DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。

1、编写DockerFile文件

我们在宿主机 /home 目录下新建一个 docker-test-volume文件夹

mkdir docker-test-volume

出于可移植和分享的考虑,之前使用的 -v 主机目录:容器目录 这种方式不能够直接在 DockerFile 中实现。

#创建DockerFile文件,内容如下
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "-------end------"
CMD /bin/bash

说明:在编写DockerFile文件中使用 VOLUME 来给镜像添加一个或多个数据卷

2、build生成镜像

build生成镜像,获得一个新镜像 test-centos,注意最后面有个 .

docker build -f /home/docker-test-volume/dockerfile1 -t test-centos .

查看自定义镜像

[root@localhost docker-test-volume]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
test-centos   latest    a5a71da7c1c2   About a minute ago   231MB

然后启动容器:

docker run -it test-centos /bin/bash

通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?

3、查看数据目录

我们在数据卷中新建一个文件

[root@93343e21a67b /]# cd dataVolumeContainer1
[root@93343e21a67b dataVolumeContainer1]# touch container.txt

查看下这个容器的信息

docker inspect 93343e21a67b
[root@VM-0-6-centos ~]# cd /var/lib/docker/volumes/7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788/_data
[root@VM-0-6-centos _data]# ls
container.txt

可以看到,本机上有了在容器中创建的文件

安装mysql测试

1、安装

docker pull mysql:5.7

2、启动容器

-e 为环境变量

mysql 的数据不应该放在容器内,应放主机内!

参考官方文档

docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

连接 mysql 并创建一个数据库

#进入容器
docker exec -it mysql01 bash

#登录mysql
mysql -P 3310 -u root -p
mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)

mysql> create database test;
Query OK, 1 row affected (0.00 sec)

image-20210605093027167

匿名和具名挂载

匿名挂载

-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

可通过命令 docker volume ls 查看挂载的列表

[root@VM-0-6-centos ~]# docker volume ls
DRIVER    VOLUME NAME
local     4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local     7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local     7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local     adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52

这些没指定名字的都是匿名挂载, -v 只写了容器内路径,并没写容器外路径

挂载目录是: /var/lib/docker/volumes/VOLUME-NAME/_data

匿名挂载的缺点,就是不好维护,不清楚目录挂载的是哪个容器

具名挂载

-v 卷名:/容器内路径

例如取名为 juming 来挂载

[root@VM-0-6-centos ~]# docker run -d -P --name nginx02 -v juming:/etc/nginx nginx
112f36599f077eada56197c22dd3b3a3eaba2e5bb38bf2cb19adc783163991e7
[root@VM-0-6-centos ~]# docker volume ls
DRIVER    VOLUME NAME
local     4d0221bc0d8b9e44fb2e878cd3efcacb9b4bd51c8e135d79c549f7a6345f3a24
local     7a1e6924fed1cc5ea6a386d9b2542c0ffc53fada1755bc7d09601274dff6ddd0
local     7adb0e2e33503b17abfd453fded4b0cd9d9e8b05e064d248dc47de0da6456788
local     adaa3053cb2ff95afc7bab51451f4b1167aa1b9056398ed44b0d4cae9580db52
local     juming

查看挂载的目录:docker volume VOLUME-NAME

[root@VM-0-6-centos ~]# docker volume inspect juming
[
    {
        "CreatedAt": "2021-06-05T16:32:10+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming/_data",
        "Name": "juming",
        "Options": null,
        "Scope": "local"
    }
]

挂载操作中,没指定目录名情况下,默认在 /var/lib/docker/volumes/ 目录

改变文件的读写权限

指定容器对我们挂载出来的内容的读写权限

docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx
  • ro: readonly 只读
  • rw: readwrite 可读可写

数据卷容器

上面提到主机和容器之间共享数据,那么如何实现容器和容器之间的共享数据呢?

命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器(Data Volume Container)

测试容器间传递共享

使用之前的镜像:test-centos,运行容器 docker01(父容器),docker02,docker03

他们都会具有容器卷 /dataVolumeContainer1/dataVolumeContainer2

1、先启动一个父容器docker01,然后在 dataVolumeContainer2 新增文件

[root@VM-0-6-centos _data]# docker run -it --name docker01 test-centos
[root@cd87cb3eb33b /]# ls -l
total 56
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Jun  5 08:56 dataVolumeContainer1
drwxr-xr-x   2 root root 4096 Jun  5 08:56 dataVolumeContainer2
............
[root@cd87cb3eb33b /]# cd dataVolumeContainer2
[root@cd87cb3eb33b dataVolumeContainer2]# touch docker01.txt

退出且不停止容器运行:ctrl+P+Q

2、创建docker02,docker03 让他们继承docker01

--volumes-from 父容器

可以看到 docker01 创建的文件存在

[root@VM-0-6-centos _data]# docker run -it --name docker02 --volumes-from docker01 test-centos
[root@f81238516f65 /]#  cd dataVolumeContainer2
[root@f81238516f65 dataVolumeContainer2]# ls
docker01.txt
[root@f81238516f65 dataVolumeContainer2]# touch docker02.txt

[root@VM-0-6-centos _data]# docker run -it --name docker03 --volumes-from docker01 test-centos
[root@c8c41a2a0831 /]# ls
bin  dataVolumeContainer1  dataVolumeContainer2  dev  etc  home  lib  lib64  lost+found  media	mnt  opt  proc	root  run  sbin  srv  sys  tmp	usr  var
[root@c8c41a2a0831 /]# cd dataVolumeContainer2
[root@c8c41a2a0831 dataVolumeContainer2]# ls
docker01.txt  docker02.txt

3、回到docker01发现可以看到 02 和 03 添加的共享文件

[root@VM-0-6-centos ~]#  docker attach docker01
[root@cd87cb3eb33b dataVolumeContainer2]# ls -l
total 0
-rw-r--r-- 1 root root 0 Jun  5 08:56 docker01.txt
-rw-r--r-- 1 root root 0 Jun  5 08:58 docker02.txt
-rw-r--r-- 1 root root 0 Jun  5 09:00 docker03.txt

删除 docker01 后 ,docker02 、 docker03 还可以正常共享数据

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。 存储在本机的文件则会一直保留!

DockerFile

我们要研究自己如何做一个镜像,而且我们写的微服务项目以及 springboot 打包上云部署,Docker就是最方便的。

微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。

流程:

开发应用 => DockerFile => 打包为镜像 => 上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动 运行

什么是 DockerFile

dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本

构建步骤:

1、编写DockerFile文件

2、docker build 构建镜像

3、docker run运行镜像

查看之前拉取的 centos :https://hub.docker.com/_/centos

点击版本查看Dockerfile 文件

FROM scratch
ADD centos-7-x86_64-docker.tar.xz /

LABEL \
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20201113" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-11-13 00:00:00+00:00"

CMD ["/bin/bash"]

DockerFile 构建过程

基础知识:

1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数

2、指令按照从上到下,顺序执行

3、# 表示注释

4、每条指令都会创建一个新的镜像层,并对镜像进行提交

流程:

  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似 docker commit 的操作提交一个新的镜像层
  4. Docker再基于刚提交的镜像运行一个新容器
  5. 执行dockerfile中的下一条指令直到所有指令都执行完成!

说明:

从应用软件的角度来看,DockerFile,docker镜像 与 docker容器 分别代表软件的三个不同阶段。

  • DockerFile 是软件的原材料 (代码)
  • Docker 镜像则是软件的交付品 (.apk)
  • Docker 容器则是软件的运行状态 (客户下载安装执行)

DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!

img_72

DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容 包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权 限控制)等等。

Docker镜像:Docker build DockerFile文件会产生一个Docker镜像,当运行 Docker 镜像时,会真正开始提供服务;

Docker容器:直接提供服务

DockerFile 指令

关键字 说明
FROM 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER 镜像维护者的姓名混合邮箱地址
RUN 容器构建时需要运行的命令
EXPOSE 当前容器对外保留出的端口
WORKDIR 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV 用来在构建镜像过程中设置环境变量
ADD 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY 类似ADD,拷贝文件和目录到镜像中!
VOLUME 容器数据卷,用于数据保存和持久化工作
CMD 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT 指定一个容器启动时要运行的命令!和CMD一样
ONBUILD 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD被触发

img_74

img_75

CMD 和 ENTRYPOINT 的区别

我们之前说过,两个命令都是指定一个容器启动时要运行的命令

  • CMD

    Dockerfile 中可以有多个CMD 指令,但只有最后一个生效,且CMD 会被 docker run 之后的参数替换!

  • ENTRYPOINT

    docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!

测试 CMD 命令

1、编写文件

[root@VM-0-6-centos dockerfile-test]# vim dockerfile-cmd-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-cmd-test
FROM centos 
CMD [ "ls", "-a" ]

2、构建并运行

docker build -f dockerfile-cmd-test -t cmdtest .

docker run cmdtest

image-20210606171411821

3、如果我们希望用 -l 列表展示信息,我们就需要加上 -l参数

[root@VM-0-6-centos dockerfile-test]#  docker run cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.

问题:我们可以看到可执行文件找不到的报错,executable file not found。

之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。

因此这里的 -l 替换了原来的 CMD,而不是添加在原来的 ls -a 后面。

而 -l 根本不是命令,所以自然找不到。

那么如果我们希望加入 -l这参数,我们就必须重新完整的输入这个命令:

docker run cmdtest ls -al

测试 ENTRYPOINT 命令

1、编写文件

[root@VM-0-6-centos dockerfile-test]# vim dockerfile-entrypoint-test
[root@VM-0-6-centos dockerfile-test]# cat dockerfile-entrypoint-test
FROM centos
ENTRYPOINT [ "ls", "-a" ]

2、构建并运行

docker build -f dockerfile-entrypoint-test -t entrypointtest .

docker run entrypointtest

3、测试 -l 参数,发现可以直接使用,这里就是一种追加

我们可以明显的知道 CMD 和 ENTRYPOINT 的区别了

docker run entrypointtest -l

image-20210606171953764

实战测试

CentOS

官方默认的 CentOS 的情况不支持 vimifconfig 指令,我们自己构建一个支持这些指令的镜像

1、编写文件

[root@VM-0-6-centos home]# cd dockerfile-test

[root@VM-0-6-centos dockerfile-test]# vim my-centos
#基础环境
FROM centos
#作者
MAINTAINER zhiyuan<oddfar@163.com>

#设置环境变量
ENV MYPATH /usr/local
#进入容器后的默认目录位置
WORKDIR $MYPATH

#安装vim等命令
RUN yum -y install vim
RUN yum -y install net-tools

#暴露端口
EXPOSE 80

#容器启动后自动执行的命令
CMD echo $MYPATH
CMD echo "----end-----"
CMD /bin/bash

2、构建镜像

命令最后有一个 . 表示当前目录

docker build -f my-centos -t mycentos:1.1 .

成功后:

image-20210606165936963

3、运行

docker run -it mycentos:1.1

测试后,可以看到,我们自己的新镜像已经支持 vim 和 ifconfig的命令了

  • 列出镜像的变更历史:

    docker history 镜像名\镜像id

Tomcat

步骤:

  • 将 JDK 和 tomcat 安装的压缩包拷贝/home/build 目录下
  • 新建一个 read.txt 文件
  • 新建一个 Dockerfile 文件
[root@VM-0-6-centos home]# cd build
[root@VM-0-6-centos build]# ls
apache-tomcat-9.0.46.tar.gz  Dockerfile  jdk-8u11-linux-x64.tar.gz  read.txt  tomcat

Dockerfile 内容

FROM centos

MAINTAINER birdy<test@qq.com>
#把宿主机当前上下文的read.txt拷贝到容器/usr/local/路径下
COPY read.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器指定目录下
ADD jdk-8u11-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.46.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#变量
ENV MYPATH /usr/local
#设置工作访问时候的WORKDIR路径,登录落脚点
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.46
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.46/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.46/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/bin/logs/catalina.out

构建镜像:

docker build -t diytomcat .

在此目录下默认构建 Dockerfile 文件,所以不需要带上文件名

启动:

docker run -d  -p 9090:8080 --name mydiytomcat -v /home/build/tomcat/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /home/build/tomcat/logs/:/usr/local/apache-tomcat-9.0.46/logs --privileged=true diytomcat

备注:Docker挂载主机目录Docker访问出现cannot open directory Permission denied

解决办法:在挂载目录后多加一个--privileged=true参数即可

写个测试网站扔到test目录:

WEB-INF/web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="true">

  <display-name>Test</display-name>

</web-app>

a.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
	Hello World!<br/>
	<% System.out.println("-------my docker tomcat-------");%>
</body>
</html>

查看日志:

[root@VM-0-6-centos tomcat]# cd logs
[root@VM-0-6-centos logs]# cat catalina.ou[t

image-20210606174533465

SpingBoot

1、使用 IDEA 构建一个 SpringBoot 项目

2、编写 Controller

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
	    return "hello,world";
    }
}

打包成 jar 包

3、构建镜像

将打包好的 jar 包拷贝到 Dockerfile 同级目录,编写 Dockerfile文件

FROM java:8

# 服务器只有dockerfile和jar在同级目录
COPY *.jar /app.jar

CMD ["--server.port=8080"]

# 指定容器内要暴露的端口
EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]

构建运行

# 构建镜像
docker build -t idea-ks .

# 运行
docker run -d -P --name idea-ks idea-ks

最后测试访问

posted @ 2021-11-11 11:15  至安  阅读(239)  评论(0编辑  收藏  举报