• docker详解(尚硅谷阳哥)


    文章目录


    查看源图像

    该文章已同步收录到我的博客网站,欢迎浏览我的博客网站,xhang’s blog

    1.docker为什么会出现

    一款产品从开发到上线,一般都会有开发环境,测试环境,运行环境

    如果有一个环境中某个软件或者依赖版本不同了,可能产品就会出现一些错误,甚至无法运行。比如开发人员在windows系统,但是最终要把项目部署到linux。如果存在不支持跨平台的软件,那项目肯定也无法部署成功。

    这就产生了开发和运维人员之间的矛盾。开发人员在开发环境将代码跑通,但是到了上线的时候就崩了。还要重新检查操作系统,软件,依赖等版本,这大大降低了效率。造成了搭环境一两天,部署项目两分钟的事件。

    docker的出现就能解决以上问题:

    开发人员把环境配置好,将需要运行的程序包运行成功,然后把程序包和环境一起打包给运维人员,让运维人员部署就可以了。这大大提高了项目上线的效率。

    2.docker简介

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

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

    image.png

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

    docker简介总结:

    解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。docker基于Linux内核,仅包含业务运行所需的runtime环境。

    3.传统虚拟机和容器的对比

    3.1虚拟机

    虚拟机是可以在一种操作系统里面运行另一种操作系统,比如在Windows10系统里面运行Linux系统CentOS7。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。

    image.png

    虚拟机的缺点:

    1. 启动慢
    2. 资源占用多
    3. 冗余步骤多

    3.2容器虚拟化技术

    由于前面虚拟机存在某些缺点,Linux发展出了另一种虚拟化技术:

    Linux容器(Linux Containers,缩写为 LXC)

    Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。

    Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。

    image.png=

    3.3两者对比

    • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;

    • 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

    • 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。

    4.docker的作用

    一:更快速的应用交付和部署

    传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。

    二:更便捷的升级和扩缩容

    随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。

    三:更简单的系统运维

    应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。

    四:更高效的计算资源利用

    Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。

    6.docker的应用场景

    docker借鉴了标准集装箱的概念。标准集装箱是将货物运往世界各地,docker将这个模型运用到自己的设计当中,唯一不同的是:集装箱运送货物,而docker运输软件。

    image-20221006102616735

    7.docker三要素

    image.png

    一:镜像(Image)

    Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。

    二:容器(Container)

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

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

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

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

    三:仓库(Repository)

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

    仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub(https://hub.docker.com/),存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云 等
    image-20221006121520224

    8.docker工作原理

    Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说到的集装箱。

    image.png

    9.docker平台架构图解

    Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。

    Docker运行的基本流程为:

    • 用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
    • Docker Daemon作为Docker架构中的主体部分,首先提供Docker Server的功能使其可以接受Docker Client的请求。
    • Docker Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
    • Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动Graph driver将下载镜像以Graph的形式存储。
    • 当需要为Docker创建网络环境时,通过网络管理驱动Network driver创建并配置Docker容器网络环境。
    • 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过Exec driver来完成。
    • Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。

    img

    10.docker的安装

    Docker官网

    Docker并非是一个通用的容器工具,它依赖于已存在并运行的Linux内核环境。

    Docker实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的Linux主机。

    因此,Docker必须部署在Linux内核的系统上。如果其他系统想部署Docker就必须安装一个虚拟 Linux环境。

    image-20221006104041904

    要求系统为64位、Linux系统内核版本为 3.8以上

    查看自己虚拟机的内核:

    image-20221006120107538

    开始安装:

    一:搭建gcc环境(gcc是编程语言译器)

    yum -y install gcc
    yum -y install gcc-c++
    
    • 1
    • 2

    二:安装需要的软件包

    yum install -y yum-utils
    
    • 1

    三:安装镜像仓库

    官网上的是

    image-20221006132500216

    但是因为docker的服务器是在国外,所以有时候从仓库中下载镜像的时候会连接被拒绝或者连接超时的情况,所以可以使用阿里云镜像仓库

    yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
    • 1

    四:更新yum软件包索引

    yum makecache fast
    
    • 1

    五:安装docker引擎

    yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
    
    • 1

    六:启动docker

    systemctl start docker
    
    • 1

    查看docker服务

    image-20221006133740030

    查看docker版本信息

    docker version
    
    • 1

    image-20221006134009284

    docker run hello-world
    
    • 1

    image-20221006134430175

    11.阿里云镜像加速配置

    为了提高镜像的拉取、发布的速度,可以配置阿里云镜像加速

    image-20221006134917410

    查看加速器地址

    在这里插入图片描述

    在CentOS下配置镜像加速器

    在这里插入图片描述

    mkdir -p /etc/docker
    tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["https://8pfzlx7j.mirror.aliyuncs.com"]
    }
    EOF
    systemctl daemon-reload
    systemctl restart docker
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    输出这段提示以后,hello world就会停止运行,容器自动终止。

    run干了什么?

    image.png

    12.为什么docker比vm虚拟机更快

    (1)docker有着比虚拟机更少的抽象层

    由于docker不需要Hypervisor(虚拟机监视器)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

    (2)docker利用的是宿主机的内核,而不需要加载操作系统OS内核

    当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。

    image.png

    image.png

    13.docker常用命令

    13.1帮助启动类命令

    • 启动docker: systemctl start docker

    • 停止docker: systemctl stop docker

    • 重启docker: systemctl restart docker

    • 查看docker状态: systemctl status docker

    • 开机启动: systemctl enable docker

    • 查看docker概要信息: docker info

    • 查看docker总体帮助文档: docker --help

    • 查看docker命令帮助文档: docker 具体命令 --help

    13.2镜像命令

    命令说明
    docker images列出主机上的所有镜像
    docker search 镜像名搜索某个镜像
    docker pull 镜像名 / docker pull 镜像名 [:TAG]不指定版本,默认是最新版本/指定镜像版本
    docker system df查看镜像/容器/数据卷所占的空间
    docker rmi 镜像名/镜像ID删除镜像
    docker rmi -f 镜像名/镜像ID强制删除镜像
    docker rmi -f 镜像名1:TAG 镜像名2:TAG删除多个镜像
    docker rmi -f $(docker images -qa)删除docker引擎中的全部镜像
    curl -XGET http://私有仓库主机ip:端口/v2/镜像名称/tags/list查看私有仓库指定镜像所有版本
    • 列出主机上的所有镜像:docker images

    image-20221006143017481

    各个选项说明:
    REPOSITORY:表示镜像的仓库源
    TAG:镜像的标签版本号
    IMAGE ID:镜像ID
    CREATED:镜像创建时间
    SIZE:镜像大小
     同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
    如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
    OPTIONS说明:
    -a :列出本地所有的镜像(含历史映像层)
    -q :只显示镜像ID。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 搜索某个镜像: search 镜像名`

    image-20221006143856893

    各个选项说明:
    NAME:镜像名称
    DESCRIPTION:镜像说明
    STARS:点赞数量
    OFFICAL:是否是官方的
    AUTOMATED:是否是自动构建的
    OPTIONS说明:
    --limit : 只列出N个镜像,默认25个
    docker search --limit 5 redis
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20221006144112829

    • 下载镜像:

      docker pull 镜像名 不指定版本,默认是最新版本

      docker pull 镜像名 [:TAG] 指定镜像版本

    image-20221006151136781

    image-20221006151855515

    • 查看镜像/容器/数据卷所占的空间 docker system df

    各个选项说明:
    TYPE:类型(镜像、容器、数据卷)
    TOTAL:总数
    SIZE:大小
    RECLAIMABLE:伸缩性
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20221006151321253

    • 删除镜像

      docker rmi 镜像名/镜像ID

      强制删除镜像

      docker rmi -f 镜像名/镜像ID

      删除多个镜像

      docker rmi -f 镜像名1:TAG 镜像名2:TAG

      删除docker引擎中的全部镜像

      docker rmi -f $(docker images -qa)

    image-20221006151630262

    删除带版本的镜像

    image-20221006152834652

    • 查看私有仓库指定镜像所有版本

      curl -XGET http://私有仓库主机ip:端口/v2/镜像名称/tags/list

    image-20221007162625237

    面试题:谈谈docker虚悬镜像是什么?

    仓库名、标签都是的镜像,俗称虚悬镜像dangling image

    image-20221007095110216

    13.3容器命令

    命令说明
    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]新建/启动容器
    docker run -it IMAGE [COMMAND] [ARG...]启动交互式容器
    docker run --name=容器名 IMAGE [COMMAND] [ARG...]新建指定名字的容器
    docker run -d IMAGE [COMMAND] [ARG...]为容器开启守护进程
    docker ps [OPTIONS]列出当前正在运行的所有容器
    exit退出容器,容器停止
    快捷键ctrl+p+q退出容器,容器不停止
    docker start 容器ID或者容器名启动已停止运行的容器
    docker restart 容器ID或者容器名重启容器
    docker stop 容器ID或者容器名停止容器
    docker kill 容器ID或容器名强制停止容器
    docker rm 容器ID删除已停止的容器:
    docker rm -f 容器名/容器ID强制删除正在运行的容器
    docker rm -f $(docker ps -a -q) 一次性删除多个容器实例
    docker logs 容器ID查看容器日志
    docker top 容器ID查看容器内运行的进程
    docker inspect 容器ID查看容器内部的细节
    docker exec -it 容器ID bashShell进入正在运行的容器并以命令行交互
    docker cp 容器ID:容器路径 主机路径从容器内拷贝文件到主机上
    docker export 容器ID > 文件名.tar导出容器为一个tar文件
    `cat 文件名.tardocker import - 镜像用户/镜像名:镜像版本`

    docker命令中/bin/bash的作用是:

    docker中必须要保持一个进程的运行,要不然整个容器启动后就会马上kill itself,这个/bin/bash就表示启动容器后启动bash。

    有镜像才能创建容器, 这是根本前提(下载一个CentOS或者ubuntu镜像演示)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2VIyzu0k-1667213295628)(Docker.assets/1658129060820-e3bbad90-56b9-44d7-971b-305557ab2ed9.png)]

    image-20221006155016710

    • 新建/启动容器

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

      启动交互式容器

      docker run -it IMAGE [COMMAND] [ARG...]

      新建指定名字的容器

      docker run --name=容器名 IMAGE [COMMAND] [ARG...]

      为容器开启守护进程

      docker run -d IMAGE [COMMAND] [ARG...]

    OPTIONS说明(常用):有些是一个减号,有些是两个减号
    --name="容器新名字":为容器指定一个名称;
    -d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
    -i:以交互模式运行容器,通常与 -t 同时使用;
    -t:为容器重新分配一个伪输入终端,通常与 -i同时使用;也即启动交互式容器(前台有伪终端,等待交互)-P: 随机端口映射,大写P
    -p: 指定端口映射,小写p
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    启动交互式容器-it表示启动带命令行交互的伪终端

    image-20221006155558072

    新建指定的名字的容器

    image-20221006161531221

    image-20221006161622200

    启动守护式容器(让容器在后台运行)

    在大部分的场景下,我们希望 docker 的服务是在后台运行的, 我们可以过 -d 指定容器的后台运行模式

    在后台开启一个容器后,再查询当前运行中的容器,发现并没有。

    很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程

    容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。

    这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start。但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀因为他觉得他没事可做了。所以,最佳的解决方案是将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有交互操作,别中断.

    前台启动redis服务

    image-20221006174506158

    后台启动redis服务

    image-20221006174742899

    • 列出当前正在运行的所有容器:docker ps [OPTIONS]

    OPTIONS说明(常用):
    -a :列出当前所有正在运行的容器+历史上运行过的
    -l :显示最近创建的容器。
    -n:显示最近n个创建的容器。
    -q :静默模式,只显示容器编号。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    创建一个新的虚拟机实例,查看当前容器的运行情况

    image-20221006160319654

    image-20221006160412104

    • 退出容器,容器停止:

      exit

      退出容器,容器不停止

      快捷键ctrl+p+q

    • 启动已停止运行的容器:docker start 容器ID或者容器名

    • 重启容器:docker restart 容器ID或者容器名

    • 停止容器:docker stop 容器ID或者容器名

    • 强制停止容器:docker kill 容器ID或容器名

    • 删除已停止的容器:

      docker rm 容器ID

      强制删除正在运行的容器

      docker rm -f 容器名/容器ID

      一次性删除多个容器实例

      docker rm -f $(docker ps -a -q)

      docker ps -a -q | xargs docker rm

    • 查看容器日志:docker logs 容器ID

    查看redis的日志信息

    image-20221006214915182

    • 查看容器内运行的进程:docker top 容器ID

    可以看到redis容器中当前只有一个进程:redis-sercer

    image-20221006215315989

    • 查看容器内部的细节:docker inspect 容器ID

    image-20221006215520135

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

      方式1(推荐方式):

      docker exec -it 容器ID bashShell

      方式2:

      docker attach 容器ID

    方式1:

    image-20221006220739584

    方式2:

    image-20221006220852384

    • 从容器内的文件拷贝到主机上:docker cp 容器ID:容器路径 主机路径

    将容器下/opt目录下的test.txt文件cp到主机上

    image-20221007091534832

    image-20221007091850001

    • 将容器以压缩包的形式导出到当前路径下:docker export 容器ID > 压缩文件名.tar

    image-20221007092635830

    • 从tar包中的内容创建一个新的文件系统再导入为镜像:

      cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本

    image-20221007095352712

    image-20221007095258345

    使用刚刚解压的镜像创建一个容器,查看容器中是否有test.txt文件。

    image-20221007100054307

    14.docker镜像

    14.1镜像的概念

    是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。

    只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。

    14.2分层的镜像

    以我们的pull为例,在下载的过程中我们可以看到docker的镜像是在一层一层的下载

    image-20221007101532092

    14.3镜像的底层原理(联合文件系统)

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

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

    14.4镜像加载原理

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

    bootfs(引导文件系统)主要包含bootloader和kernel(Linux内核), 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等等。

    image.png

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

    image.png

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

    14.5为什么docker镜像使用分层结构

    镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。

    比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;

    同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

    Docker镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

    所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

    image.png

    Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。

    新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层

    img

    14.6docker镜像commit操作案例

    • docker commit 提交容器副本使之成为一个新的镜像:

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

    测试:在tomcat安装vim

    image-20221007110109385

    安装vim

    apt-get update
    apt-get -y install vim
    
    • 1
    • 2

    image-20221007132055336

    image-20221007132606745

    14.7在阿里云推送/拉取镜像

    image.png

    image-20221007133532797

    image-20221007133627900

    image-20221007133932740

    阿里云镜像仓库提供的对应的命令:

    image-20221007134421230

    image-20221007135035796

    image-20221007135054813

    测试:

    删除本地镜像,从阿里云仓库中拉取

    image-20221007135512048

    14.8阿里云私有库

    Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。

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

    14.9创建私有仓库

    一:下载镜像docker registry

    docker pull registry
    
    • 1

    image-20221007144731642

    二:运行私有库Registry

    docker run -d -p 5000:5000  -v /docker-xha/tomcat-vim/:/opt/registry --privileged=true registry
    
    
    • 1
    • 2

    image-20221007145449184

    三:创建一个新镜像,tomcat安装ifconfig命令

    image-20221007152529792

    docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
    docker commit -m="ifconfig cmd add" -a="xha" 749a08193a53 tomcat-ifconfig:1.1
    
    • 1
    • 2

    image-20221007152843896

    已经提交的镜像:

    image-20221007152956116

    四:验证提交的镜像能够使用ifconfig

    image-20221007153856525

    五:查看私服库上有什么镜像

    curl -XGET http://主机ip:5000/v2/_catalog
    
    • 1

    当前私服库上没有任何镜像

    image-20221007154223413

    六:将新镜像修改符合私服规范的Tag

    docker tag tomcat-ifconfig:1.1 192.168.26.135:5000/tomcat-ifconfig:1.1
    
    • 1

    image-20221007154912950

    七:修改进程守护配置文件,设置docker允许推动镜像

    "insecure-registries": ["192.168.26.135:5000"]
    
    • 1

    image-20221007160501425

    重启docker服务

    image-20221007160531795

    八:重启私有仓库

    docker run -d -p 5000:5000  -v /命名空间/仓库名称/:/opt/registry --privileged=true registry
    
    • 1

    九:将镜像推送到私服库

    image-20221007161511190

    十:查看当前私服库中的镜像

    curl -XGET http://主机ip:5000/v2/_catalog
    
    • 1

    image-20221007161605701

    十一:拉取私服库中的镜像

    docker pull 主机ip:端口号/镜像名:版本号
    
    • 1

    image-20221007161921402

    查看docker中的所有镜像

    image-20221007162100582

    利用此镜像新建容器,并测试ifconfig命令

    image-20221007162304698

    15.容器数据卷

    15.1容器数据卷概述

    卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性数据卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。

    数据卷会将docker容器内的数据保存进宿主机的磁盘中,运行一个带有容器卷存储功能的容器实例。

    15.2容器数据卷的特点

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

    15.3为容器添加数据卷

    docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
    
    • 1

    选项解释:

    –privileged=true的作用是允许目录挂载

    -v 是挂载硬盘

    image-20221007180335767

    查看数据卷是否挂载成功:

    dokcer inspect 容器id
    
    • 1

    image-20221007181135798

    容器和宿主机之间数据共享:

    在容器中编辑文件:

    image-20221007181949448

    在宿主机的同一路径下查看文件:

    image-20221007182039394

    在宿主机中编辑文件:

    image-20221007182129985

    查看容器中查看文件:

    image-20221007182207374

    实现了容器和宿主机之间的数据共享

    即使容器停止了,在宿主机操作数据卷,等到容器重新启动了也能实现数据共享

    15.4容器卷ro和rw的读写规则

    一:ro即read only,容器只能读

    docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro --name:容器名 镜像名
    
    • 1

    image-20221007183529559

    创建的实例:

    image-20221007183610831

    使用主机进行文件的修改和读取,并在容器中进行读写操作。

    image-20221007184643896

    15.5容器卷之间的继承

    第一个容器1完成和宿主机的映射

    image-20221007185846974

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

    docker run -it  --privileged=true --volumes-from 父类  --name:容器名 镜像名
    
    • 1

    image-20221007190206840

    16.docker下常规软件安装

    16.1Tomcat

    说明:由于较新版的tomcat需要删除/usr/local/tomcat目录下的webapps文件,并将webapps.dist重命名为webapp。所以推荐下载旧版的tomcat。

    步骤:

    1. docker hub上面查找tomcat镜像(这里采用8.0.53版本)

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

    3. docker images查看是否有拉取到的tomcat

    4. 使用tomcat镜像创建容器实例

    报错就重启一下docker服务

    docker run -d -p 8080:8080 --name t1 tomcat:8.0.53
    
    • 1

    tomcat服务启动成功

    image-20221007200126913

    16.2MySQL

    一:简单版本

    1. docker hub上面查找mysql镜像(这里采用8.0.19版本)
    2. 使用mysql8.0.19镜像创建容器(也叫运行镜像)
    docker run -p 主机端口号:容器端口 -e MYSQL_ROOT_PASSWORD=密码 -d mysql:版本
    
    • 1

    image-20221007202728418

    1. 进入mysql

    image-20221007202841774

    4.测试:查看数据库,创建数据库

    image-20221007203549953

    6.查看docker容器下mysql的字符集编码

    show variables like 'character%'
    
    • 1

    image-20221007204330382

    5.在本机采用可视化工具连接测试

    image-20221007203751609

    二:实战版本

    1. 创建mysql容器实例

    ​ 为了防止数据丢失和误删问题,采用数据卷的形式实现数据备份:

    docker run -d -p 3306:3306 --privileged=true \
    -v /opt/mysql/log:/var/log/mysql \
    -v /opt/mysql/data:/var/lib/mysql \
    -v /opt/mysql/conf:/etc/mysql/conf.d \
    -e MYSQL_ROOT_PASSWORD=xu.123456 \
    --name mysql \
    mysql:8.0.19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20221007210640746

    1. 在主机的配置文件目录下新建mysql的配置文件my.cnf

    image-20221007211047324

    设置mysql字符编码为utf-8

    [client]
    default_character_set=utf8
    [mysqld]
    collation_server = utf8_general_ci
    character_set_server = utf8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 重启mysql容器实例
    docker restart 容器ID
    
    • 1

    image-20221007211401972

    1. 重新启动容器,重新查看mysql的字符集编码

      show variables like 'character%'
      
      • 1

    image-20221007215721251

    16.3Redis

    1. 拉取redis镜像

    image-20221007230141926

    1. 获取redis的配置文件

    ​ redis配置文件官网Redis configuration | Redis

    1. 创建存放redis配置文件的目录,创建redis.conf文件,写入配置信息

    image-20221007231811179

    1. 修改配置文件内容

      • 添加redis密码(requirepass)
      • 修改bind为0.0.0.0(任何机器都能够访问)
      • 为了避免和docker中的-d参数冲突,将后台启动设置为no(daemonize no)
      • 关闭保护模式(protected-mode no)
      • 开启AOF持久化(appendonly yes)
    2. 使用redis镜像创建容器实例

      docker run -d -p 6379:6379 \
      --name redis --privileged=true \
      -v /opt/redis/redis.conf:/etc/redis/redis.conf \
      -v /opt/redis/data:/data \
      redis:6.0.8
      
      • 1
      • 2
      • 3
      • 4
      • 5

      image-20221008093209067

    3. 进入容器,并启动redis客户端

    image-20221008093325824

    1. 退出容器,redis容器依旧运行。

    image-20221008095233338

    17.搭建MySQL主从复制

    1. 首先安装好MySQL镜像
    2. 创建主节点MySQL实例对象,主机端口号为3307,容器内端口号为3306
    docker run -p 3307:3306 \
    --name mysql-master \
    -v /opt/mysql-master/log:/var/log/mysql \
    -v /opt/mysql-master/data:/var/lib/mysql \
    -v /opt/mysql-master/conf:/etc/mysql/conf.d \
    -e MYSQL_ROOT_PASSWORD=root  \
    -d mysql:8.0.19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 进入/opt/mysql-master/conf目录下新建my.cnf
    [mysqld]
    ## 设置server_id,同一局域网中需要唯一
    server_id=101 
    ## 指定不需要同步的数据库名称
    binlog-ignore-db=mysql  
    ## 开启二进制日志功能
    log-bin=mall-mysql-bin  
    ## 设置二进制日志使用内存大小(事务)
    binlog_cache_size=1M  
    ## 设置使用的二进制日志格式(mixed,statement,row)
    binlog_format=mixed  
    ## 二进制日志过期清理时间。默认值为0,表示不自动清理。
    expire_logs_days=7  
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
    ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 修改完配置后重启master容器实例
    docker restart mysql-master
    
    • 1
    1. 进入主节点mysql-master容器实例,进入数据库
    docker exec -it 主节点容器实例 /bin/bash
    mysql -u root -proot
    
    • 1
    • 2
    1. master容器实例内创建数据同步用户并授予权限

      CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
      ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
      GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
      
      • 1
      • 2
      • 3

    image-20221008102651407

    1. 创建从节点MySQL容器实例对象,主机端口号为3308,容器内端口号为3306
    docker run -p 3308:3306 \
    --name mysql-slave \
    -v /opt/mysql-slave/log:/var/log/mysql \
    -v /opt/mysql-slave/data:/var/lib/mysql \
    -v /opt/mysql-slave/conf:/etc/mysql/conf.d \
    -e MYSQL_ROOT_PASSWORD=root  \
    -d mysql:8.0.19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20221008103056282

    1. 进入/opt/mysql-slave/conf目录下新建my.cnf
    [mysqld]
    ## 设置server_id,同一局域网中需要唯一
    server_id=102
    ## 指定不需要同步的数据库名称
    binlog-ignore-db=mysql  
    ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
    log-bin=mall-mysql-slave1-bin  
    ## 设置二进制日志使用内存大小(事务)
    binlog_cache_size=1M  
    ## 设置使用的二进制日志格式(mixed,statement,row)
    binlog_format=mixed  
    ## 二进制日志过期清理时间。默认值为0,表示不自动清理。
    expire_logs_days=7  
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
    ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062  
    ## relay_log配置中继日志
    relay_log=mall-mysql-relay-bin  
    ## log_slave_updates表示slave将复制事件写进自己的二进制日志
    log_slave_updates=1  
    ## slave设置为只读(具有super权限的用户除外)
    read_only=1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. 修改完配置后重启slave实例
    docker restart mysql-slave
    
    • 1
    1. 在主节点数据库查看主从同步状态
    show master status;
    
    • 1

    获取到File和Position

    image-20221008104944052

    1. 进入从节点,配置主从复制
    change master to master_host='宿主机ip', master_user='slave', master_password='123456', 
    master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=1030, master_connect_retry=30;
    
    • 1
    • 2

    主从复制参数说明:

    master_host:主数据库的IP地址;

    master_port:主数据库的运行端口;

    master_user:在主数据库创建的用于同步数据的用户账号;

    master_password:在主数据库创建的用于同步数据的用户密码;

    master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数

    master_log_pos:指定从数据库从哪个位置开始复制数据,通过主数据的状态,获取Position参数

    master_connect_retry:连接失败重试的时间间隔,单位为秒。

    1. 在从节点数据库中查看主从同步状态
    show slave status \G;
    
    • 1

    image-20221008110143618

    1. 在从节点数据库开启主从同步
    start slave;
    
    • 1

    image-20221008114906432

    1. 在从节点数据库再次查看主从同步状态是否变为Yes
    show slave status \G;
    
    • 1

    image-20221008125226283

    1. 主从复制测试

    主节点新建数据库,创建表,插入数据,然后在从节点中进行查看。

    从节点数据库查询查看:

    image-20221008125125783

    18.redis集群搭建

    18.1分布式储存—哈希取余算法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9bKbNAlH-1667213295650)(https://imagebed-xuhuaiang.oss-cn-shanghai.aliyuncs.com/typora/image-removebg-preview%20(3)].png)

    hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。

    优点:

    简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。

    缺点:

    原来规划好的节点,进行扩容或者缩容就比较困难,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌。

    18.2分布式储存—一致性哈希算法

    一致性哈希算法为了解决分布式缓存数据变动和映射问题。目的是当服务器个数发生变动时, 尽量减少影响客户端到服务器的映射关系

    算法构建一致性哈希环

    为了在节点数目发生改变时尽可能少的迁移数据,将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到临近的存储节点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。

    image.png

    优点

    加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。

    image.png

    缺点

    数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。

      1. image.png

    18.3分布式储存—哈希槽算法

    哈希槽(散列插槽)实质就是一个数组,数组[0,2^14 -1]形成hash slot空间。解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

    image__1_-removebg-preview

    一共有多少个hash槽

    一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

    哈希槽计算

    Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。

    image-20221008141447491

    redis cluster采用数据分片的哈希槽来进行数据存储和数据的读取。redis cluster一共有2^14(16384)个槽,所有的master节点都会有一个槽区比如0~1000,槽数是可以迁移的。master节点的slave节点不分配槽,只拥有读权限。但是注意在代码中redis cluster执行读写操作的都是master节点,并不是读是从节点,写是主节点。

    为什么是16384个槽?
    在握手成功后,两个节点之间会定期发送ping/pong消息,交换数据信息,在redis节点发送心跳包时需要把所有的槽信息放到这个心跳包里,以便让节点知道当前集群信息,在发送心跳包时使用char进行bitmap压缩后是2k(16384÷8÷1024=2kb),也就是说使用2k的空间创建了16k的槽数。
    虽然使用CRC16算法最多可以分配65535(2^16-1)个槽位,65535=65k,压缩后就是8k(8 * 8 (8 bit) * 1024(1k) = 8K),也就是说需要需要8k的心跳包,作者认为这样做不太值得;并且一般情况下一个redis集群不会有超过1000个master节点,所以16k的槽位是个比较合适的选择。

    • 如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
    • redis的集群主节点数量基本不可能超过1000个。集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。
    • 槽位越小,节点少的情况下,压缩率高

    18.4redis分片集群扩缩容配置案例架构

    18.4.1分片集群搭建

    1. 关闭防火墙,启动docker后台服务

    2. 新建6个redis镜像的容器实例形成6个redis主从节点

    docker run -d \
    --name redis-node-1 \
    --net host --privileged=true \
    -v /data/redis/share/redis-node-1:/data redis:6.0.8 \
    --cluster-enabled yes \
    --appendonly yes \
    --port 6381
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    命令选项详解:

    docker run:创建并运行docker容器实例;

    –name redis-node-6:容器名字;

    –net host:使用宿主机的IP和端口,默认;

    –privileged=true:获取宿主机root用户权限;

    -v /data/redis/share/redis-node-6:/data:容器卷,宿主机地址:docker内部地址;

    redis:6.0.8:redis镜像和版本号;

    –cluster-enabled yes:开启redis集群;

    –appendonly yes:开启持久化;

    –port 6386:redis端口号;

    image-20221008143516491

    1. 进入容器redis-node-1并为6台机器构建集群关系
    redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
    
    • 1

    命令选项详解:

    –cluster create:创建集群

    –cluster-replicas 1:表示每个主节点有一个从节点

    192.168.150.101:7001:主机ip和容器内redis端口

    三主三从,由于一个redis集群只有16384个插槽

    所以主节点6381的插槽范围是[0-5460]

    所以主节点6381的插槽范围是[5461-10922]

    所以主节点6381的插槽范围是[10923-16384]

    image-20221008150746483

    1. 查看集群状态

    采用命令查看帮助手册

    redis-cli --cluster help
    
    • 1

    image-20221008161558000

    查看集群状态:

    cluster nodes
    
    • 1

    6385是从节点,主节点是0e,即6383.
    6386是从节点,主节点是aa,即6381.
    6384是从节点,主节点是5b,即6382.

    image-20221008152910844

    18.4.2主节点哈希槽范围说明

    因为当存入k-v键值对时,redis会对key进行crc16算法得出一个值,然后对16384取余,得出的结果位于哪个主节点的哈希槽范围中就存入哪个主节点。

    redis-cli -p 主节点端口
    
    • 1

    image-20221008160228927

    所以在连接redis集群的时候要添加参数“-c”表示以集群的形式连接redis,这样能实现在主节点之间实现切换。

    redis-cli -c -p 主节点端口
    
    • 1

    image-20221008160512593

    查看当前集群状态

    redis-cli --cluster check 主机ip:容器中redis端口
    
    • 1

    image-20221008161940529

    18.4.3主从容错

    ​ 当主节点宕机之后,它的从节点会转换为主节点。

    image-20221008165204209

    测试,停止主节点6381,查看其和它的从节点6386的状态

    ​ 6381连接失败,其从节点6386变为主节点。

    image-20221008163933306

    ​ 恢复之前的主节点6381,查看其和主节点6386的状态

    6381变为从节点,6386还是主节点。

    image-20221008164100825

    18.4.4主从扩容

    在原来的3主3从得基础上扩容到4主4从

    1. 根据redis镜像新建两个容器实例,对应的端口号分别是6387、6388
    docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
    
    • 1

    image-20221008170110903

    1. 将新增的6387节点作为master节点添加到redis集群中

    ​ 查看帮助

    redis-cli --cluster help
    
    • 1

    image-20221008170459273

    将6387节点作为主节点添加到集群当中

    redis-cli --cluster add-node new_host:new_port existing_host:existing_port
    
    • 1

    image-20221008170930151

    1. 查看集群状态

    可以看到新加入的主节点 并没有分配哈希槽位

    image-20221008171239444

    1. 重新分配哈希槽位

    image-20221008172015743

    1. 再次查看集群状态

       可以发现为新节点分配的哈希槽位并不是连续的,其哈希槽位是由原来的每一个主节点分配的。
      
      • 1

    image-20221008181009836

    1. 添加新节点6388作为主节点6387的从节点
    redis-cli --cluster add-node 192.168.26.135:6388 192.168.26.135:6387 --cluster-slave --cluster-master-id ee499e33ad50ffaf84d4ed95a39625c49dc1ae4b
    
    • 1

    image-20221008182421651

    18.4.5主从缩容

    使6387和6388主从节点下线

    1. 查看6387和6388的节点ID

    2. 将6388从节点从主节点上删除

    3. 将主节点的哈希槽位清空并重新分配槽位给master1

    image-20221008184347879

    1. 删除空槽位的主节点
    redis-cli --cluster del-node 192.168.26.135:6387 ee499e33ad50ffaf84d4ed95a39625c49dc1ae4b
    
    • 1

    19.Dockerfile

    19.1Dockerfile简介

    Dockerfile reference | Docker Documentation

    Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本

    image.png

    构建Docker镜像的步骤:

    1. 编写Dockerfile文件
    2. docker build 命令构建镜像
    3. docker run 镜像 运行容器实例

    19.2Dockerfile内容基础知识

    1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
    2. 指令按照从上到下,顺序执行
    3. #表示注释
    4. 每条指令都会创建一个新的镜像层并对镜像进行提交

    19.3docker执行Dockerfile的大致流程

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

    19.4docker镜像、docker容器、Dockerfile

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

    • Dockerfile是软件的原材料
    • Docker镜像是软件的交付品
    • Docker容器则可以认为是软件镜像的运行态,即依照镜像运行的容器实例

    Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

    image.png

    1. Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
    2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
    3. Docker容器,容器是直接提供服务的。

    19.5DockerFile常用保留字指令

    • FROM

    基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from

    • MAINTAINER

    ​ 镜像维护者的姓名和邮箱地址

    • RUN

    容器构建时需要运行的命令

    • EXPOSE

    当前容器对外暴露出的端口

    • WORKDIR

    指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

    • USER

    ​ 指定该镜像以什么样的用户去执行,如果都不指定,默认是root

    • ENV

    用来在构建镜像过程中设置环境变量

    ​ 这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;

    ​ 也可以在其它指令中直接使用这些环境变量。

    ​ 比如:WORKDIR $MY_PATH

    • ADD

    将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包

    • COPY

    类似ADD,拷贝文件和目录到镜像中。

    ​ 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

    • VOLUME

    容器数据卷,用于数据保存和持久化工作

    • CMD

    指定容器启动后的要干的事情

    • ENTRYPOINT

    也是用来指定一个容器启动时要运行的命令

    ​ 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作 参数送给 ENTRYPOINT 指令指定的程序。

    19.6使用Dockerfile实现自定义镜像

    自定义镜像需求:具备vim+ifconfig+jdk8环境

    1. 创建文件夹myfile,并将jdk压缩包传到当前目录下

    image-20221008221532808

    1. 创建Dockerfile文件,编辑内容
    FROM centos:7
    MAINTAINER xha<2533694604@qq.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    #安装vim编辑器
    RUN yum -y install vim
    #安装ifconfig命令查看网络IP
    RUN yum -y install net-tools
    #安装java8及lib库
    RUN yum -y install glibc.i686
    RUN mkdir /usr/local/java
    #ADD 是相对路径jar,把jdk-8u341-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
    ADD jdk-8u341-linux-x64.tar.gz /usr/local/java/
    #配置java环境变量
    ENV JAVA_HOME /usr/local/java/jdk1.8.0_341
    ENV JRE_HOME $JAVA_HOME/jre
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
    ENV PATH $JAVA_HOME/bin:$PATH
    
    EXPOSE 80
    
    CMD echo $MYPATH
    CMD echo "success--------------ok"
    CMD /bin/bash
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    注意:centos版本指定为7 centos:7

    image-20221008222254771

    1. 构建镜像
    docker build -t centosjava8:1.0 .
    
    • 1

    构建完成:

    image-20221008223304651

    查看创建的镜像

    image-20221008223558311

    1. 运行镜像
    docker run -it 镜像ID /bin/bash
    
    • 1

    image-20221008224041659

    19.7虚悬镜像

    仓库名和版本号都为的就是虚悬镜像

    image-20221008224814393

    查看所有的虚悬镜像

    docker image ls -f dangling=true
    
    • 1

    删除所有虚悬镜像

    docker image prune
    
    • 1

    20.docker微服务实战

    20.1将jar包部署到docker容器上

    1. 创建新目录,将jar包放在该目录下

    image-20221009093812151

    1. 编写Dockerfile文件
    #基础镜像使用java
    FROM java:8
    # 作者
    MAINTAINER xha
    # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
    VOLUME /tmp
    # 将jar包添加到容器中并更名
    ADD docker_test-0.0.1-SNAPSHOT.jar dockertest.jar
    # 运行jar包
    RUN bash -c 'touch /dockertest.jar'
    ENTRYPOINT ["java","-jar","/dockertest.jar"]
    #暴露8090端口作为微服务
    EXPOSE 8090
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    image-20221009093746461

    1. 构建镜像

    在当前目录下构建镜像

    docker build -t dockertest:1.0 .
    
    • 1

    镜像构建成功

    image-20221009094209016

    image-20221009094226784

    1. 运行镜像
    docker run -d -p 8090:8090 镜像ID
    
    • 1
    1. 测试项目接口

    image-20221009094334057

    21.docker网络

    21.1docker网络是什么

    Docker启动时会在主机上自动创建一个docker0网桥,即一个Linux网桥。容器借助网桥和主机或者其他容器进行通讯。

    21.2docker启动与不启动时的网络情况

    一:不启动docker时

    image-20221009095714013

    • ens33是宿主机ip

    可以发现是在同一网段

    image-20221009100216738

    • lo是回环链路网络
    • virbr0

    当选择虚拟化相关的服务后,启动网卡时就会有一个网桥连接的私网地址virbr0网卡(有一个固定的ip地址192.168.122.1),是做虚拟网桥使用的,其作用是连接虚拟机上的虚拟网卡,提供NAT访问外网的功能。

    二:启动docker时

    ​ 会产生一个名为docker0的虚拟网桥

    image-20221009100823090

    21.3docker网络的相关命令

    查看docker网络的相关命令

    docker network --help
    
    • 1
    命令说明
    docker network ls查看网络
    docker network create 网络名创建网络
    docker network connect 网络名为容器连接到网络
    docker network disconnect 网络名断开容器的网络
    docker network inspect 网络名查看网络源数据
    docker network rm 网络名字删除网络
    docker network prune删除所有无用的网络

    21.4docker网络的作用

    • 容器间的互联和通信以及端口映射

    • 容器IP变动时候可以通过服务名直接网络通信而不受到影响

    21.5docker网络模式

    21.5.1docker网络模式分类

    网络模式简介
    bridge为每一个容器分配、设置IP等,并将容器连接到一个docker0虛拟网桥,默认为该模式
    host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
    none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP 等。
    container新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等。

    21.5.2bridge网络模式

    Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间。宿主机和容器之间、容器与容器之间可以通过网桥docer0(bridge)相互通信

    image-20221009114027019

    查看bridge网桥

    docker network inspect bridge
    
    • 1
    image-20221009114624965

    使用tomcat镜像创建两个容器,宿主机端口分别是8081和8082,容器端口都是8080

    image-20221009115505373

    进入容器t1,查看网络模式

    162:eth0@if163 有eth0

    image-20221009120129133

    进入容器t2,查看网络模式

    164:eth0@if165 有eth0

    image-20221009120406227

    在宿主机查看网络模式

    163:veth@if162 有veth

    165:veth@if164 有veth

    image-20221009120535691

    综上可以看出,容器内都有一个网络模式和网桥进行相连,实现和宿主机两两匹配验证。

    21.5.3host网络模式

    容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。

    image-20221009132204235

    在之前搭建redis分片集群的时候,各个redis主从节点使用的网络模式就是host

    image-20221009132613993

    可以发现各个主从节点并没有对应的端口,即指定端口并没有意义,而是和宿主机公用ip和端口号。

    image-20221009132722275

    使用host网络模式创建tomcat镜像

    docker run -d -p 8083:8080 --network=host --name t3 tomcat:8.0.53
    
    • 1

    image-20221009133725316

    查看容器是否有端口

    image-20221009133809629

    查看容器的网络模式,可以发现没有ip

    image-20221009134017741

    查看宿主机和容器的ip信息,可以发现是一模一样的,即容器使用的是宿主机的ip和端口

    image-20221009134258214

    image-20221009134305926

    21.5.4none网络模式

    在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo需要我们自己为Docker容器添加网卡、配置IP等。

    21.5.5container网络模式

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

    image-20221009135306812

    测试:

    创建一个tomcat容器,再创建第二个tomcat容器,创建第二个容器的时候指定使用第一个tomcat容器的网络配置。

    docker run -d -p 8084:8080 --name t4 tomcat:8.0.19
    docker run -d -p 8085:8080 --network container:t4 --name t5 tomcat:8.0.53
    
    • 1
    • 2

    但是会提示端口号冲突,因为两台tomcat公用8080端口。

    image-20221009140451708

    21.5.6自定义网络模式

    一:使用刚刚创建的两个tomcat镜像容器实例t1和t2,在容器内部首先进行ping对方的ip

    发现可以ping通

    image-20221009142320302

    二:但是当按照服务名ping时发现没有ping通

    image-20221009142532707

    三:自定义网络模式

    docker多个容器之间的集群规划要使用服务名,因为ip是会变动,使用自定义网络模式能够使用服务名进行通信

    1. 创建网络,默认模式是bridge(网桥)模式
    docker network create 网络名
    
    • 1

    image-20221009143102120

    1. 创建两个容器实例,并使用自定义的网络模式
    docker run -d -p 8081:8080 --network myselfnet --name t1 tomcat:8.0.19
    
    • 1

    image-20221009143631425

    测试使用服务名ping

    image-20221009145219292

    21.6docker网络底层ip和容器的映射变化

    docker容器内部的ip是有可能是会发生变化的

    使用同一镜像创建两个容器实例,并查看网络信息

    docker inspect 容器ID
    
    • 1

    第一个容器

    image-20221009111810871

    第二个容器

    image-20221009111916231

    删除第二个容器,再创建一个容器,查看ip

    image-20221009112457128

    可以发现当第二个容器被停止之后,创建的第三个容器的ip与第二个相同。

    22.Docker-compose容器编排

    22.1Docker-compose的定义

    Docker-Compose就是容器编排,负责实现对Docker容器集群的快速编排

    Docker-Compose可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器

    22.2Docker-Compose的作用

    ==docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来。==但是这样我们又面临了一个问题?

    如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样工作量会和大。所以docker官方给我们提供了docker-compose多服务部署的工具

    例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。

    Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)

    可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题

    22.3Docker-Compose的安装

    Docker-Compose官网:Docker Desktop | Docker Documentation

    image-20221009152219405

    安装命令:

    DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} 
    
    mkdir -p $DOCKER_CONFIG/cli-plugins 
    
    curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
    
    chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20221009161047213

    打印版本号,查看是否成功

    docker compose version
    
    • 1

    image-20221009161123920

    22.4Docker-Compose的常用命令

    命令说明
    docker-compose -h查看帮助
    docker-compose up启动所有docker-compose服务
    docker-compose up -d启动所有docker-compose服务并后台运行
    docker-compose down停止并删除容器、网络、卷、镜像
    docker-compose exec yml里面的服务id进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
    docker-compose ps展示当前docker-compose编排过的运行的所有容器
    docker-compose top展示当前docker-compose编排过的容器进程
    docker-compose logs yml里面的服务id查看容器输出日志
    docker-compose config检查配置
    docker-compose config -q检查当前路径下的compose.yml文件配置,有问题才有输出
    docker-compose restart重启服务
    docker-compose start启动服务
    docker-compose stop停止服务

    22.5Docker-Compose核心概念

    image-20221009160142219

    22.6Docker-Compose的使用步骤

    • 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件

    • 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。

    • 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线

    22.7不使用Compose编排存在的问题

    1. 不使用Compose部署项目的方式是分别启动mysql服务、redis服务和微服务镜像文件,部署完成
    2. 存在的问题
    • 先后顺序要求固定,先mysql+redis才能微服务访问成功

    • 多个run命令…

    • 容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错, 要么生产IP写死(可以但是不推荐),要么通过服务调用

    22.7使用Compose编排微服务

    1. 编写docker-compose.yml文件

      在vim模式下 :set paste粘贴的文本数据不会乱

      #compose版本
      version: "3"  
       
      #微服务项目	
      services:
        microService:
      #微服务镜像  
          image: zzyy_docker:1.6
          container_name: ms01
          ports:
            - "6001:6001"
      #数据卷
          volumes:
            - /app/microService:/data
          networks: 
            - atguigu_net 
          depends_on: 
            - redis
            - mysql
            
      #redis服务
        redis:
          image: redis:6.0.8
          ports:
            - "6379:6379"
          volumes:
            - /app/redis/redis.conf:/etc/redis/redis.conf
            - /app/redis/data:/data
          networks: 
            - atguigu_net
          command: redis-server /etc/redis/redis.conf
       
       #mysql服务
        mysql:
          image: mysql:5.7
          environment:
            MYSQL_ROOT_PASSWORD: '123456'
            MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
            MYSQL_DATABASE: 'db2021'
            MYSQL_USER: 'zzyy'
            MYSQL_PASSWORD: 'zzyy123'
          ports:
             - "3306:3306"
          volumes:
             - /app/mysql/db:/var/lib/mysql
             - /app/mysql/conf/my.cnf:/etc/my.cnf
             - /app/mysql/init:/docker-entrypoint-initdb.d
          networks:
            - atguigu_net
          command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
       
       #创建自定义网络
      networks: 
         atguigu_net: 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
    2. 修改微服务项目,将映射的ip修改为服务名

    ​ 将SpringBoot项目的配置文件中mysql和redis的ip更改为项目名。之后打包成jar包,在docker中编写Dockerfile文件,构建镜像。

    1. 检查当前目录下compose.yml文件是否有语法错误
    docker compose config -q
    
    • 1
    1. 启动所有docker-compose服务并后台运行
    docker compose up -d
    
    • 1

    image-20221009173718073

    23.docker轻量级可视化工具Protainer

    23.1Protainer是什么

    Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

    23.2Protainer安装

    Docker and Kubernetes Management | Portainer

    1. 拉取portainer
    docker pull portainer/portainer
    
    • 1
    1. 根据portainer镜像创建容器实例

    restart=always表示即使重启docker服务,Protainer容器依旧存在。

    docker run -d -p 9000:9000 --name portainer \
    --restart=always \ 
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /www/portainer/data:/data \
    portainer/portainer
    
    • 1
    • 2
    • 3
    • 4
    • 5

    查看容器实例

    image-20221009180719447

    1. 访问宿主机ip加protainer端口号

    输入密码

    image-20221009180906699 image-20221009181052635

    image-20221009181252455

    可以查看到镜像、容器、网络等等。

    image-20221009181308692

    23.3在Protainer中安装Nginx

    1. 添加nginx容器

    image-20221009182314493

    1. nginx镜像拉取成功,nginx容器创建成功

    image-20221009182432614

    1. 访问80端口查看nginx服务是否正常启动

    image-20221009182632031

    24.docker重量级监视工具CIG

    24.1原生命令监控容器的详细信息

    docker status
    
    • 1

    image-20221009183711805

    问题:

    通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。

    但是,docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能

    24.2CIG监控

    CIG分别表示:CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表

    image-20221009220100275

    • CAdvisor是一个容器资源监控工具包括容器的内存,CPU,网络IO,磁盘I0等监控。

    • InfluxDB是用Go语言编写的一个开源分布式时序、 事件和指标数据库,无需外部依赖。

    • Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括

    24.3使用Compose搭建CIG监控平台

    1. 新建cig目录,在目录下创建docker-compose.yml文件,实现容器编排。
    version: '3.1'
     
    volumes:
      grafana_data: {}
     
    services:
     influxdb:
      image: tutum/influxdb:0.9
      restart: always
      environment:
        - PRE_CREATE_DB=cadvisor
      ports:
        - "8083:8083"
        - "8086:8086"
      volumes:
        - ./data/influxdb:/data
     
     cadvisor:
      image: google/cadvisor
      links:
        - influxdb:influxsrv
      command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
      restart: always
      ports:
        - "8080:8080"
      volumes:
        - /:/rootfs:ro
        - /var/run:/var/run:rw
        - /sys:/sys:ro
        - /var/lib/docker/:/var/lib/docker:ro
     
     grafana:
      user: "104"
      image: grafana/grafana
      user: "104"
      restart: always
      links:
        - influxdb:influxsrv
      ports:
        - "3000:3000"
      volumes:
        - grafana_data:/var/lib/grafana
      environment:
        - HTTP_USER=admin
        - HTTP_PASS=admin
        - INFLUXDB_HOST=influxsrv
        - INFLUXDB_PORT=8086
        - INFLUXDB_NAME=cadvisor
        - INFLUXDB_USER=root
        - INFLUXDB_PASS=root
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    1. 检查docker-compose.yml文件是否有错误
    docker-compose config -q
    
    • 1
    1. 后台启动docker-compose服务
    docker-compose up -d
    
    • 1
  • 相关阅读:
    解决Visio和office365安装兼容问题
    诚意满满的前端面试总结
    Xcode 15下,包含个推的项目运行时崩溃的处理办法
    入门学习之社会工程学
    【gradle】通过 toml 管理 classifier 的写法
    SpringMVC中异常处理详解
    基于docker实现JMeter分布式压测
    Java工具库——Commons IO的50个常用方法
    网络工程师的网络安全之路:应对威胁与保障数据
    本地部署 zeppelin 0.10.1
  • 原文地址:https://blog.csdn.net/qq_52030824/article/details/127621158