Docker笔记

文章目录

  • 1.docker为什么会出现
  • 2.docker是什么
  • 3.传统虚拟机和容器的对比
    • 3.1虚拟机
    • 3.2容器虚拟化技术
    • 3.3两者对比
    • 3.4为什么Docker会比VM虚拟机快?
  • 4.docker能干嘛
  • 6.docker的应用场景
  • 7.docker三要素
    • 一:镜像(Image)
    • 二:容器(Container)
    • 三:仓库(Repository)
  • 8.docker工作原理
  • 9.docker平台架构图解
  • 10.docker的安装
  • 11.阿里云镜像加速配置
  • 12.docker常用命令
    • 12.1帮助启动类命令
    • 12.2镜像命令
  • 13.3容器命令
  • 14.docker镜像
    • 14.1是什么
    • 14.2分层的镜像
    • 14.3镜像的底层原理(联合文件系统)
    • 14.4镜像加载原理
    • 14.5为什么docker镜像使用分层结构
    • 14.6docker镜像commit操作案例
    • 14.7在阿里云推送/拉取镜像
    • 14.8阿里云私有库
    • 14.9创建私有仓库
      • 14.9.1下载镜像docker registry
      • 14.9.2运行私有库Registry
      • 14.9.3创建一个新镜像, ubuntu安装ifconfig命令
      • 14.9.4修改配置文件使之支持http(修改进程守护配置文件,设置docker允许推动镜像)
      • 14.9.5重启私有仓库
      • 14.9.6将镜像推送到私服库
      • 14.9.7查看当前私服库中的镜像
  • 15.容器数据卷
    • 15.1是什么
    • 15.2能干嘛
    • 15.3为容器添加数据卷
    • 15.4容器卷ro和rw的读写规则
    • 15.5容器卷之间的继承
  • 16.docker下常规软件安装
    • 16.1Tomcat
    • 16.2MySQL
    • 16.3Redis
  • 17.搭建MySQL主从复制
  • 18.redis集群搭建
    • 18.1分布式储存—哈希取余算法
    • 18.2分布式储存—一致性哈希算法
    • 18.3分布式储存—哈希槽算法
    • 18.4redis分片集群扩缩容配置案例架构
      • 18.4.1分片集群搭建
      • 18.4.2主节点哈希槽范围说明
      • 18.4.3主从容错
      • 18.4.4主从扩容
      • 18.4.5主从缩容
  • 19.Dockerfile
    • 19.1是什么
    • 19.2Dockerfile内容基础知识
    • 19.3docker执行Dockerfile的大致流程
    • 19.4docker镜像、docker容器、Dockerfile
    • 19.5DockerFile常用保留字指令
    • 19.6使用Dockerfile实现自定义镜像
    • 19.7虚悬镜像
  • 20.docker微服务实战
    • 20.1将jar包部署到docker容器上
  • 21.docker网络
    • 21.1是什么
    • 21.2docker启动与不启动时的网络情况
    • 21.3docker网络的相关命令
    • 21.4**能干嘛**
    • 21.5docker网络模式
      • 21.5.1docker网络模式分类
      • 21.5.2bridge模式
      • 21.5.3host网络模式
      • 21.5.4none网络模式
      • 21.5.5container网络模式
      • 21.5.6自定义网络模式
      • 21.5.7link连接网络模式
    • 21.6docker网络底层ip和容器的映射变化
  • 22.Docker-compose容器编排
    • 22.1是什么
    • 22.2能干嘛
    • 22.3Docker-Compose的安装
    • 22.4Docker-Compose的常用命令
    • 22.5Docker-Compose核心概念
    • 22.6Docker-Compose的使用步骤
    • 22.7不使用Compose编排存在的问题
    • 22.7使用Compose编排微服务
  • 23.docker轻量级可视化工具Protainer
    • 23.1Protainer是什么
    • 23.2Protainer安装
    • 23.3在Protainer中安装Nginx
  • 24.docker重量级监视工具CIG
    • 24.2CIG监控
    • 24.3使用Compose搭建CIG监控平台
    • 24.4 Grafana配置

Docker笔记_第1张图片

1.docker为什么会出现

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

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

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

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

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

2.docker是什么

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

docker基于Linux内核,仅包含业务运行所需的runtime环境。

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

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

Docker笔记_第2张图片

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

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

3.1虚拟机

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

Docker笔记_第3张图片

虚拟机的缺点:

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

3.2容器虚拟化技术

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

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

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

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

Docker笔记_第4张图片=

3.3两者对比

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

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

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

Docker笔记_第5张图片

3.4为什么Docker会比VM虚拟机快?

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

Docker容器的本质就是一个进程。

4.docker能干嘛

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

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

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

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

三:更简单的系统运维

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

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

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

6.docker的应用场景

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

Docker笔记_第6张图片

7.docker三要素

Docker笔记_第7张图片

一:镜像(Image)

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

二:容器(Container)

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

  • Docker利用容器独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。
  • 最小配置的Linux环境。
  • 类似于Java中使用类模板创建的类实例。

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

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

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

三:仓库(Repository)

  • Docker仓库是集中存放镜像文件的场所。
  • 仓库分为公开仓库和私有仓库两种。
  • 最大的公开仓库是Docker官方的Docker Hub:https://hub.docker.com/

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

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

8.docker工作原理

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

Docker笔记_第9张图片

9.docker平台架构图解

Docker笔记_第10张图片

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

Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从容器接收命令并管理运行在主机上的容器。Docker运行的基本流程为:

  • 用户是使用Docker ClientDocker 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来实现具体对容器进行的操作。

Docker笔记_第11张图片

10.docker的安装

Docker官网

Docker Hub官网

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

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

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

Docker笔记_第12张图片

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

cat /etc/redhat- release:查看版本
uname -r:查看内核

查看自己虚拟机的内核:

Docker笔记_第13张图片

卸载

  1. 关闭服务 systemctl stop docker
  2. 使用yum删除docker引擎 yum remove docker-ce docker-ce-cli containerd.io
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

旧版本的Docker引擎包可能叫做:dockerdocker-engine。
新版本的Docker引擎包叫做:docker-ce

  1. 删除镜像、容器、卷、自定义配置等文件 rm -rf /var/lib/docker rm -rf /var/lib/containerd

开始安装:

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

yum -y install gcc
yum -y install gcc-c++

二:安装需要的软件包

yum install -y yum-utils

三:配置Docker的资源库地址(安装镜像仓库)

  • 官方地址:(比较慢,不推荐)
# 在yum资源库中添加docker资源库 
  yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

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

  • 阿里云镜像地址:
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

四:创建缓存(可选)(更新yum软件包索引)

yum makecache fast

五:安装docker引擎

安装最新版本的Docker引擎、Docker客户端:

# docker-ce是Docker引擎,docker-ce-cli是客户端
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

安装指定版本:

# 查询版本列表
yum list docker-ce --showduplicates | sort -r

# 指定版本安装17.09.0.ce版
# sudo yum install docker-ce- docker-ce-cli- containerd.io docker-compose-plugin
sudo yum install docker-ce-17.09.0.ce docker-ce-cli-17.09.0.ce containerd.io docker-compose-plugin

六:启动docker

如果没有启动Docker引擎,那么执行 docker version查看版本号时,只能看到 Client: Docker Engine(Docker引擎客户端)的版本号。
启动Docker引擎:

# 新版本的Docker就是一个系统服务,可以直接使用启动系统服务方式启动
systemctl start docker

# 此时查看docker版本,可以看到Server: Docker Engine(Docker引擎)版本号
docker version

Docker笔记_第14张图片

docker run hello-world

Docker笔记_第15张图片

11.阿里云镜像加速配置

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

登录阿里云,进入 工作台 -> 容器镜像服务 -> 镜像工具 -> 镜像加速器。

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker

12.docker常用命令

12.1帮助启动类命令

命令 说明
启动docke 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
查看版本号 docker version

12.2镜像命令

命令 说明
docker images [options]
-a:列出本地的所有镜像 (包括历史镜像)
-q:只显示镜像ID
列出主机上的所有镜像●REPOSITORY:表示镜像的仓库源
TAG:镜像的标签,版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小

同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
如果不指定TAG版本,那么Docker将默认使用 :latest 镜像,即最后一次更新。

命令 说明
docker search 镜像名 [options]
–limit 数量
搜索某个镜像NAME:镜像名称。
●DESCRIPTION:镜像描述。
●Stars:点赞数量。
●OFFIVIAL:是否为官方认证。
●AUTOMATED:是否是自动构建的。
默认在Docker hub中进行搜索
docker pull 镜像名 等价于:docker pull 镜像名称:latest / 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 system df

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

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

    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)/ xargs docker rm 一次性删除多个容器实例
docker logs 容器ID 查看容器日志
docker top 容器ID 查看容器内运行的进程
docker inspect 容器ID 查看容器内部的细节
docker exec -it 容器ID bashShell /docker attach 容器ID 进入正在运行的容器并以命令行交互
- exec和attach的区别
●attach:进入容器中启动命令终端,不会启动新的进程,使用exit会导致容器的退出。
●exec:在容器中打开新的终端,可以启动新的进程,使用exit只会退出当前终端,不会退出容器。
推荐使用exec
docker cp 容器ID:容器路径 主机路径 从容器内拷贝文件到主机上
docker export 容器ID > 文件名.tar 导出容器为一个tar文件
`cat 文件名.tar docker import - 镜像用户/镜像名:镜像版本`

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

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

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

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

新建/启动容器

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同时使用;
  • -it:启动交互式容器 (前台有伪终端,等待交互)
  • -P: 随机端口映射,大写P
  • -p: 指定端口映射,小写p
  • -p 主机端口:docker容器端口

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

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

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

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

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

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

docker ps [OPTIONS]

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

14.docker镜像

14.1是什么

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

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

14.2分层的镜像

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

Docker笔记_第16张图片

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

UnionFS(联合文件系统)

  • Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。

  • **Union 文件系统是 Docker 镜像的基础。**镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

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

14.4镜像加载原理

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

  • bootfs(引导文件系统)主要包含bootloaderkernel(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镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

    所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。

    只有容器层是可写的,容器层下面的所有镜像层都是只读的。

Docker笔记_第17张图片

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

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

Docker笔记_第18张图片

14.6docker镜像commit操作案例

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

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

测试:在ubuntu安装vim

image-20221007110109385

安装vim

apt-get update
apt-get -y install vim

image-20221007132055336

Docker笔记_第19张图片

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

Docker笔记_第20张图片

  1. 阿里云 -> 容器镜像服务

    Docker笔记_第21张图片

  2. 命名空间(类似于包名)

    Docker笔记_第22张图片

  3. 镜像仓库

    Docker笔记_第23张图片

    Docker笔记_第24张图片

  4. 生成窗口以后,会提供一系列命令

      ```
      docker login --username=每个人自己的用户名 registry.cn-hangzhou.aliyuncs.com
      docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/wuqiyong/docker_study:[镜像版本号]
      docker push registry.cn-hangzhou.aliyuncs.com/wuqiyong/docker_study:[镜像版本号]
      ```
    

    image.png

  5. 拉取阿里云中的镜像

docker pull registry.cn-hangzhou.aliyuncs.com/wuqiyong/docker_study:[镜像版本号]

14.8阿里云私有库

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

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

14.9创建私有仓库

14.9.1下载镜像docker registry

docker pull registry

Docker笔记_第25张图片

Docker笔记_第26张图片

14.9.2运行私有库Registry

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

Docker笔记_第27张图片

14.9.3创建一个新镜像, ubuntu安装ifconfig命令

  1. 从Hub上下载ubuntu镜像到本地并成功运行

  2. 原始的Ubuntu镜像是不带着ifconfig命令的

    Docker笔记_第28张图片

  3. 外网连通的情况下,安装ifconfig命令并测试通过

    docker容器内执行上述两条命令:apt-get update apt-get install net-tools

Docker笔记_第29张图片

Docker笔记_第30张图片

  1. 安装完成后,commit我们自己的新镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
docker commit -m="ifconfig cmd add" -a="xha" 749a08193a53 tomcat-ifconfig:1.1

Docker笔记_第31张图片

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

Docker笔记_第32张图片

  1. curl验证私服库上有什么镜像
curl -XGET http://主机ip:5000/v2/_catalog

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

image.png

  1. 将新镜像zzyyubuntu:1.2修改符合私服规范的Tag

    按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
    自己host主机IP地址,填写自己的,不要粘贴错误。
    使用命令 docker tag 将zzyyubuntu:1.2 这个镜像修改为192.168.111.162:5000/zzyyubuntu:1.2

    docker tag  zzyyubuntu:1.2  192.168.111.162:5000/zzyyubuntu:1.2
    

    Docker笔记_第33张图片

14.9.4修改配置文件使之支持http(修改进程守护配置文件,设置docker允许推动镜像)

Docker笔记_第34张图片

别无脑照着复制,registry-mirrors 配置的是国内阿里提供的镜像加速地址,不用加速的话访问官网的会很慢。
2个配置中间有个逗号 ','别漏了,这个配置是json格式的。
vim命令新增如下红色内容:vim /etc/docker/daemon.json

{
  "registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"],
  "insecure-registries": ["192.168.111.162:5000"]
}

重启docker服务restart docker.service

上述理由:docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====> 修改完后如果不生效,建议重启docker。

14.9.5重启私有仓库

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

14.9.6将镜像推送到私服库

docker push 192.168.111.162:5000/zzyyubuntu:1.2

Docker笔记_第35张图片

14.9.7查看当前私服库中的镜像

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

Docker笔记_第36张图片

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

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

Docker笔记_第37张图片

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

docker run -it 镜像ID /bin/bash

Docker笔记_第38张图片

15.容器数据卷

添加属性打卡权限
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可

为什么?

  • 因为目录挂载的情况被默认为不安全的行为,也即使用该参数以后,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。

15.1是什么

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

一句话:有点类似我们Redis里面的rdb和aof文件。

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

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

15.2能干嘛

将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。为了能保存数据在docker中我们使用卷。

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

15.3为容器添加数据卷

  • 直接命令添加
    docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名

    选项解释:

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

    -v 是挂载硬盘
    Docker笔记_第39张图片

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

    dokcer inspect 容器id
    

    Docker笔记_第40张图片

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

    1. docker修改,主机同步获得 。
    2. 主机修改,docker同步获得。
    3. docker容器stop,主机修改,docker容器重启看数据是否同步。

    Docker笔记_第41张图片

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

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

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

  • ro即read only,容器只能读
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro --name:容器名 镜像名
  • rw即read write,容器读写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名

15.5容器卷之间的继承

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

docker run -it  --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu

Docker笔记_第42张图片

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

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

Docker笔记_第43张图片

16.docker下常规软件安装

  1. 搜索镜像
  2. 拉取镜像
  3. 查看镜像
  4. 启动镜像 - 服务端口映射
  5. 停止容器
  6. 移除容器

16.1Tomcat

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

步骤:

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

    docker search tomcat

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

    docker pull tomcat

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

    docker images tomcat

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

    docker run -it -p 8080:8080 tomcat

    -p 小写,主机端口:docker容器端口
    -P 大写,随机分配端口
    -i 交互
    -t 终端
    -d 后台

报错就重启一下docker服务

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

报错

Docker笔记_第44张图片

解决

  • 可能没有映射端口或者没有关闭防火墙
  • 把webapps.dist目录换成webapps

先成功启动tomcat

Docker笔记_第45张图片

查看webapps 文件夹查看为空

Docker笔记_第46张图片

免修改版说明

docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8

Docker笔记_第47张图片

16.2MySQL

一:简单版本

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

image-20221007202728418

  1. 进入mysql

Docker笔记_第48张图片

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

Docker笔记_第49张图片

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

show variables like 'character%'

Docker笔记_第50张图片

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

Docker笔记_第51张图片

二:实战版本

  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 \
-e MYSQL_ROOT_PASSWORD=密码 \
--name mysql \
mysql:8.0.19
  • 上述命令的含义:
    • docker run:在docker中启动一个容器实例
    • -d:该容器在后台运行
    • -p 3306:3306:容器与主机映射端口为, 3306(主机端口,即外部连接mysql使用的端口号): 3306(容器端口)
    • --privileged=true :添加容器对宿主机的属性打卡权限
    • -v /opt/mysql/log:/var/log/mysql:将容器/var/log/mysql目录下的数据,备份到主机的 /mysqldata/mysql/log目录下
    • -v /opt/mysql/data:/var/lib/mysql:将容器/var/lib/mysql目录下的数据,备份到主机的 /mysqldata/mysql/data目录下
    • -v /opt/mysql/conf:/etc/mysql:将容器/etc/mysql目录下的数据,备份到主机的 mysqldata/mysql/conf目录下
    • -e MYSQL_ROOT_PASSWORD=root:设置当前mysql实例的密码为root
    • --name mysql:容器运行后的名称
    • mysql:5.7:需要运行的容器名称以及版本号

image-20221007210640746

  1. 在主机的配置文件目录下新建mysql的配置文件my.cnf,通过容器卷同步给mysql容器实例

Docker笔记_第52张图片

设置mysql字符编码为utf-8

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

image-20221007211401972

  1. 重新启动容器,重新查看mysql的字符集编码
show variables like 'character%'

Docker笔记_第53张图片

16.3Redis

  1. 拉取redis镜像
//拉取最新版本
docker pull redis
//拉取指定版本
docker pull redis:6.0.8

  1. 获取redis的配置文件

redis配置文件官网Redis configuration | Redis

  1. 创建存放redis配置文件的目录,创建redis.conf文件,写入配置信息
    1. 将一个redis.conf文件模板拷贝进/redis目录下
    2. redis目录下修改redis.conf文件
      image-20221007231811179修改文件中以下配置项:
1.将bind 127.0.0.1 -::1注释掉
# bind 127.0.0.1 -::1
2.将 appendonly no 设置成yes,开启redis数据持久化 
 appendonly yes  
3.将  requirepass foobared 解开注释,设置密码
 requirepass root
4.以下两项配置可选(如果不需要从外部连接,可不进行配置,以下配置有风险,请谨慎配置)
保护模式:如果设置为yes,那么只允许我们在本机的回环连接,其他机器无法连接,即外部无法连接,此处关闭
protected-mode no 
将bind 127.0.0.1注释掉,此项配置的作用是服务绑定监听本机的哪个ip
# bind 127.0.0.1
  1. 修改配置文件内容

    • 添加redis密码(requirepass)
    • 修改bind为0.0.0.0(任何机器都能够访问)
    • 为了避免和docker中的-d参数冲突,将后台启动设置为no(daemonize no)
    • 关闭保护模式(protected-mode no)
    • 开启AOF持久化(appendonly yes)
      修改完毕后的完整redis.conf文件如下:
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
#bind 127.0.0.1

protected-mode no

port 6379

tcp-backlog 511

requirepass root

timeout 0

tcp-keepalive 300

daemonize no

supervised no

pidfile /var/run/redis_6379.pid

loglevel notice

logfile ""

databases 30

always-show-logo yes

save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename dump.rdb

dir ./

replica-serve-stale-data yes

replica-read-only yes

repl-diskless-sync no

repl-disable-tcp-nodelay no

replica-priority 100

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

appendonly yes

appendfilename "appendonly.aof"

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

aof-use-rdb-preamble yes

lua-time-limit 5000

slowlog-max-len 128

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

list-max-ziplist-size -2

list-compress-depth 0

set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

stream-node-max-bytes 4096
stream-node-max-entries 100

activerehashing yes

hz 10

dynamic-hz yes

aof-rewrite-incremental-fsync yes

rdb-save-incremental-fsync yes




  1. 使用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 \
    -d redis:6.0.8 redis-server /etc/redis/redis.conf\
    
    

    image-20221008093209067

  2. 进入容器,并启动redis客户端docker exec -it 运行着Rediis服务的容器ID redis-cli

image-20221008093325824

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. 进入/opt/mysql-master/conf目录下新建my.cnf

    vim 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

## relay_log配置中继日志
##relay_log=mall-mysql-relay-bin  
## log_slave_updates表示slave将复制事件写进自己的二进制日志
##log_slave_updates=1  
## slave设置为只读(具有super权限的用户除外)
##read_only=1

  1. 修改完配置后重启master容器实例
docker restart mysql-master
  1. 进入主节点mysql-master容器实例,进入数据库
docker exec -it mysql-master /bin/bash
mysql -u root -proot
  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. 创建从节点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

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. 修改完配置后重启slave实例
docker restart mysql-slave

  1. 在主节点数据库查看主从同步状态
show master status;

获取到File和Position

image-20221008104944052

  1. 进入从节点,配置主从复制
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot

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;

主从复制参数说明:

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;

Docker笔记_第54张图片

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

image-20221008114906432

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

Docker笔记_第55张图片

  1. 主从复制测试

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

从节点数据库查询查看:

Docker笔记_第56张图片

18.redis集群搭建

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

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

优点:

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

缺点:

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

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

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

算法构建一致性哈希环

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

Docker笔记_第57张图片

优点

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

Docker笔记_第58张图片

缺点

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

Docker笔记_第59张图片

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

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

Docker笔记_第60张图片

一共有多少个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 之间的哈希槽,也就是映射到某个节点上。

Docker笔记_第61张图片

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

命令选项详解:

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

命令选项详解:

–cluster create:创建集群

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

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

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

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

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

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

Docker笔记_第62张图片

  1. 查看集群状态

采用命令查看帮助手册

redis-cli --cluster help

Docker笔记_第63张图片

查看集群状态:

cluster nodes

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

image-20221008152910844

18.4.2主节点哈希槽范围说明

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

redis-cli -p 主节点端口

Docker笔记_第64张图片

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

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

Docker笔记_第65张图片

查看当前集群状态

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

Docker笔记_第66张图片

18.4.3主从容错

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

Docker笔记_第67张图片

测试,停止主节点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

image-20221008170110903

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

查看帮助

redis-cli --cluster help

Docker笔记_第68张图片

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

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

Docker笔记_第69张图片

  1. 查看集群状态

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

image-20221008171239444

  1. 重新分配哈希槽位

Docker笔记_第70张图片

  1. 再次查看集群状态

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

Docker笔记_第71张图片

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

Docker笔记_第72张图片

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

19.Dockerfile

19.1是什么

Dockerfile reference | Docker Documentation

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

Docker笔记_第73张图片

构建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体系的基石。

Docker笔记_第74张图片

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

19.5DockerFile常用保留字指令

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

  • MAINTAINER- 镜像维护者的姓名和邮箱地址

  • RUN-容器构建时需要运行的命令(RUN是在 docker build时运行)
    两种格式

  1. shell格式

RUN yum -y install vim

image.png

  1. exec格式

Docker笔记_第75张图片

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

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

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

  • ENV-ENV MY_PATH /usr/mytest 用来在构建镜像过程中设置环境变量
    这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量。比如:WORKDIR $MY_PATH

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

  • COPY-类似ADD,拷贝文件和目录到镜像中。
    将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

COPY src dest
COPY ["src", "dest"]
:源文件或者源目录
:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

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

  • CMD-指定容器启动后的要干的事情
    Docker笔记_第76张图片
    注意:
    Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。
    参考官网Tomcat的dockerfile演示讲解:

官网最后一行命令

image.png

演示覆盖操作

image.png

它和前面RUN命令的区别
CMD是在docker run 时运行。
RUN是在 docker build 时运行。

  • ENTRYPOINT-也是用来指定一个容器启动时要运行的命令
    类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作 参数送给 ENTRYPOINT 指令指定的程序。
    命令格式和案例说明

命令格式:

image.png

ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。

当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成

image.png

案例如下:假设已通过 Dockerfile 构建了 nginx:test 镜像:

Docker笔记_第77张图片

Docker笔记_第78张图片

优点:在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

小总结

FROM            #基础镜像,一切从这里开始
MAINTAINER      #镜像是谁写的,姓名+邮箱
RUN             #镜像构建的时候需要执行的命令
ADD             #添加内容,
WORKDIR         #镜像的工作目录
VOLUME          #卷挂载的目录
EXPOSE          #暴漏端口配置,与docker run -p 宿主机端口:容器内端口 效果一样
CMD             #指定这个容器启动的时候要运行的命令,只有最后一个会生效
ENTRYPOINT      #指令这个容器启动的时候执行的命令 可以追加命令
ONBUILD         #当构建一个被继承的DockerFile时,会运行ONBUILD的指令,触发指令
COPY            #类似于ADD,将我们文件拷贝到镜像中
ENV             #构建的时候设置环境变量

Docker笔记_第79张图片

19.6使用Dockerfile实现自定义镜像

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

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

image-20221008221532808

  1. 创建Dockerfile文件,编辑内容
FROM centos:7
MAINTAINER xha<[email protected]>

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

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

Docker笔记_第80张图片

  1. 构建镜像docker build -t 新镜像名字:TAG .
docker build -t centosjava8:1.0 .

注意,上面TAG后面有个空格,有个点

构建完成:

Docker笔记_第81张图片

查看创建的镜像

Docker笔记_第82张图片

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

Docker笔记_第83张图片

再体会下UnionFS(联合文件系统)

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

Docker笔记_第84张图片

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

19.7虚悬镜像

仓库名和版本号都为的就是虚悬镜像,俗称dangling image

在构建或者删除镜像时可能由于一些错误导致出现虚悬镜像。例如:

# 构建时候没有镜像名、tag
docker build .

image-20221008224814393

查看所有的虚悬镜像

docker image ls -f dangling=true

删除所有虚悬镜像

docker image prune

Dockerfile写一个

vim Dockerfile

from ubuntu
CMD echo 'action is success'

docker build .

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

Docker笔记_第85张图片

  1. 构建镜像

在当前目录下构建镜像

docker build -t dockertest:1.0 .

镜像构建成功

Docker笔记_第86张图片

image-20221009094226784

  1. 运行镜像
docker run -d -p 8090:8090 镜像ID

  1. 测试项目接口

Docker笔记_第87张图片

21.docker网络

21.1是什么

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

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

一:不启动docker时

Docker笔记_第88张图片

  • ens33是宿主机ip

可以发现是在同一网段

Docker笔记_第89张图片

  • lo是回环链路网络
  • virbr0

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

之前学习Linux安装,勾选安装系统的时候附带了libvirt服务才会生成的一个东西,如果不需要可以直接将libvirtd服务卸载,
yum remove libvirt-libs.x86_64

二:启动docker时

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

Docker笔记_第90张图片

21.3docker网络的相关命令

查看docker网络的相关命令

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

21.4能干嘛

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

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

21.5docker网络模式

21.5.1docker网络模式分类

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

bridge模式:使用–network bridge指定,默认使用docker0
host模式:使用–network host指定
none模式:使用–network none指定
container模式:使用–network container:NAME或者容器ID指定

21.5.2bridge模式

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

docker run的时候,没有指定–network的话,默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig就苦役看到docker0和自己create的network。

网桥docker0创建一对对等虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配:

整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫 veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫做 veth pair)。

每个容器实例内部也有一块网卡,容器内的网卡接口叫做eth0。

docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

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

Docker笔记_第91张图片

查看bridge网桥

docker network inspect bridge

Docker笔记_第92张图片

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

image-20221009115505373

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

162:eth0@if163 有eth0

Docker笔记_第93张图片

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

164:eth0@if165 有eth0

Docker笔记_第94张图片

在宿主机查看网络模式

163:veth@if162 有veth

165:veth@if164 有veth

Docker笔记_第95张图片

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

1: lo…

容器内的网卡为 eth0
@符号后面就是宿主机上对应的veth网卡的编号28
27: eth0@if28 …

在宿主机执行 ip addr 查看宿主机网卡信息:

每个veth都有个编号:vethXXXXXX

@符号后面对应就是容器内的eth0网卡编号27

28: vethXXXXXX@if27 …

21.5.3host网络模式

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行 NAT 转换。

容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network space。

容器将不会虚拟出自己的网卡,而是直接使用宿主机的 IP 和端口。

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

Docker笔记_第96张图片

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

Docker笔记_第97张图片

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

Docker笔记_第98张图片

如果在 docker run 命令中同时使用了 --network host 和 -p端口映射,例如:

使用host网络模式创建tomcat镜像
docker run -d -p 8083:8080 --network=host --name t3 tomcat:8.0.53

那么会出现一个警告:

WARNING: Published ports are discarded when using host network mode

image-20221009133725316

因为此时已经使用了host模式,本身就是直接使用的宿主机的IP和端口,此时的-p端口映射就没有了意义,也不会生效,端口号还是会以主机端口号为主。

正确做法是:不再进行-p端口映射,或者改用bridge模式

查看容器是否有端口

image-20221009133809629

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

Docker笔记_第99张图片

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

Docker笔记_第100张图片

Docker笔记_第101张图片

21.5.4none网络模式

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

21.5.5container网络模式

新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。

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

Docker笔记_第102张图片

测试:

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

docker run -d -p 8084:8080 --name t4 tomcat:8.0.19

# 指定和 t4 容器共享网络
docker run -d -p 8085:8080 --network container:t4 --name t5 tomcat:8.0.53

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

image-20221009140451708

测试:

docker run -it --name alpine1 alpine /bin/sh

# 指定和 alpine1 容器共享网络
docker run -it --netrowk container:alpine1 --name alpine2 alpine /bin/sh

此时使用 ip addr查看两台容器的网络,会发现两台容器的eth0网卡内的IP等信息完全相同。

如果关掉了alpine1容器,因为alpine2的网络使用的alpine1共享网络,所以关掉alpin1后,alpine2的eth0网卡也随之消失了。

21.5.6自定义网络模式

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

  • 容器 IP 变动时候可以通过服务名直接网络通信而不受影响。(类似Eureka,通过服务名直接互相通信,而不是写死IP地址)。

docker中还有一个 --link 进行容器网络互联,但是已经被标记为过时的,可能会在将来的版本中移除这个功能。推荐使用自定义网络替换link。

  • 自定义桥接网络(自定义网络默认使用的是桥接网络 bridge):

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

发现可以ping通

Docker笔记_第103张图片

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

image-20221009142532707

三:自定义网络模式

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

  1. 创建网络,默认模式是bridge(网桥)模式
docker network create 网络名
#查看网络列表 
docker network ls

Docker笔记_第104张图片

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

image-20221009143631425

测试使用服务名ping

# 安装ifconfig命令
yum install -y net-tools
# 安装ip addr命令
yum install -y iproute
# 安装ping命令
yum install -y iputils

# 直接ping容器名,不需要ping IP地址
ping 容器名

Docker笔记_第105张图片

21.5.7link连接网络模式

示例:

# 启动一台mysql容器
# --name 为容器指定一个别名
docker run --name mysql-matomo -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.28

# 启动另一个容器,通过--link连接到mysql容器
# --link 容器名称:本容器连接对方时的别名
docker run -d -p 8888:80 --link mysql-matomo:db --name matomo matomo:4.9.0

# 此时,在matomo容器中,便可以通过 db 这个hostname连接到mysql-matomo容器,而无须再通过ip
# 连接地址:db:3306

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

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

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

docker inspect 容器ID

第一个容器

Docker笔记_第106张图片

第二个容器

Docker笔记_第107张图片

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

Docker笔记_第108张图片

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

22.Docker-compose容器编排

22.1是什么

Docker-Compose就是容器编排,是Docker官方的开源项目, 负责实现对Docker容器集群的快速编排。

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

22.2能干嘛

docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来。

但是这样又面临了一个问题,如果需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样工作量会和大。

所以docker官方给我们提供了docker-compose多服务部署的工具

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

核心概念:

  • 服务(service):一个个应用容器实例
  • 工程(project):由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml中定义

Compose使用的三个步骤:

  1. 编写 Dockerfile 定义各个应用容器,并构建出对应的镜像文件
  2. 编写 docker-compose.yml,定义一个完整的业务单元,安排好整体应用中的各个容器服务
  3. 执行 docker-compose up 命令,其创建并运行整个应用程序,完成一键部署上线

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

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

22.3Docker-Compose的安装

Docker-Compose的版本需要和Docker引擎版本对应,可以参照官网上的对应关系。

Docker-Compose官网:Docker Desktop | Docker Documentation

Docker笔记_第109张图片

安装命令:

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-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose

# 添加权限
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose

卸载Compose:直接删除 docker-compose文件即可

image-20221009161047213

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

docker compose version

image-20221009161123920

22.4Docker-Compose的常用命令

执行命令时,需要在对应的docker-compose.yml文件所在目录下执行。

命令 说明
docker-compose -h 查看帮助
docker-compose up 启动所有docker-compose服务(类似 docker run)
docker-compose up -d 启动所有docker-compose服务并后台运行
docker-compose down 停止并删除容器、网络、卷、镜像(类似 docker stop + docker rm)
docker-compose rm 删除容器
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核心概念

Docker笔记_第110张图片

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: 
    
    
#docker-compose文件的版本,目前使用的是官网提供的最新版本3
version: "3"
#关于服务容器实例的配置 
services:
 #---------------第一个容器服务的配置-----------------------	
  microService: #自定义的服务名,可随意
    image: docket-test:1.1 #需要启动的docker容器名称及版本号
    container_name: ms01 #容器运行后的名称,相当于 --name命令
    build:#构建指定目录下的Dockerfile
      context: .
      dockerfile: Dockerfile
    ports: #启动后的端口映射
      - "6001:6001"
    volumes:#容器数据卷的映射配置,相当于参数命令 -v
      - /home/myfile/microService:/data #容器数据卷的映射路径
    networks: #自定义的网络配置相当于参数 --network
      - wf_net #自定义的网络,通过 docker network create命令创建
    depends_on: #image配置项启动前需要先启动的容器实例,也就是docket-test启动前 
      - redis #需要先启动 redis 和mysql,此处使用的是下面自定义的容器服务名
      - mysql
 #---------------第二个容器服务的配置-----------------------	
  redis:  #自定义的服务名,可随意
    image: redis:6.0.8  #需要启动的docker容器名称及版本号
    ports:
      - "6379:6379"  #启动后的端口映射
    volumes: #容器数据卷的映射配置,相当于参数命令 -v
      - /home/redis/redis.conf:/etc/redis/redis.conf
      - /home/redis/data:/data
    networks: #自定义的网络配置相当于参数 --network
      - wf_net 
    command: redis-server /etc/redis/redis.conf # 使用redis.conf运行redis
    
  #---------------第三个容器服务的配置-----------------------	
  mysql:#自定义的服务名,可随意
    image: mysql:5.7 #需要启动的docker容器名称及版本号
    environment:#环境配置
      MYSQL_ROOT_PASSWORD: 'root' #root用户的密码
      MYSQL_ALLOW_EMPTY_PASSWORD: 'no' #是否允许空密码
      MYSQL_DATABASE: 'docker-test' 
      MYSQL_USER: 'wangfei' #对mysql再配置一个用户名
      MYSQL_PASSWORD: 'wf123'#对mysql再配置一个m
    ports: #启动后的端口映射
       - "3306:3306"
    volumes: #容器数据卷的映射配置,相当于参数命令 -v
       - /app/mysql/db:/var/lib/mysql
       - /app/mysql/conf/my.cnf:/etc/my.cnf
       - /app/mysql/init:/docker-entrypoint-initdb.d
    networks: #自定义的网络配置相当于参数 --network
      - wf_net 
    command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
 
networks: #网络配置,此处相当于再此处创建网络
   wf_net: #相当于通过 docker network create命令创建一个wf_net网络

  1. 修改微服务项目,将映射的ip修改为服务名

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

  1. 检查当前目录下compose.yml文件是否有语法错误
docker compose config -q

  1. 启动所有docker-compose服务并后台运行
docker compose up -d

Docker笔记_第111张图片

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

23.1Protainer是什么

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

Portainer分为开源社区版(CE版)和商用版(BE版/EE版)。

23.2Protainer安装

Docker and Kubernetes Management | Portainer

Portainer也是一个Docker镜像,可以直接使用Docker运行。

  1. 拉取portainer
# 旧版镜像地址为portainer/portainer,从2022年1月标记为过期
# 新版镜像地址为portainer/portainer-ce

docker pull portainer/portainer
  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

查看容器实例

image-20221009180719447

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

首次进来时,需要创建 admin 的用户名(默认admin)、密码(必须满足校验规则,例如portainer.io123)。

选择 local管理本地docker,即可看到本地Docker的详细信息,包括其中的镜像(images)、容器(containers)、网络(networks)、容器卷(volumes)、compose编排(stacks)等等。

输入密码

Docker笔记_第112张图片 Docker笔记_第113张图片

Docker笔记_第114张图片

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

Docker笔记_第115张图片

23.3在Protainer中安装Nginx

  1. 添加nginx容器

Docker笔记_第116张图片

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

image-20221009182432614

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

Docker笔记_第117张图片

24.docker重量级监视工具CIG

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

docker status

Docker笔记_第118张图片

问题:

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

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

24.2CIG监控

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

Docker笔记_第119张图片

  • CAdvisor是一个容器资源监控工具包括容器的内存,CPU,网络IO,磁盘I0等监控。同时提供了一个Web页面用于查看容器的实时运行状态。

    • CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过CAdvisor提供了很多数据集成接口,支持 InfluxDB、Redis、Kafka、Elasticsearch等集成,可以加上对应配置将监控数据发往这些数据库存储起来。

    • CAdvisor主要功能:

      • 展示Host和容器两个层次的监控数据

      • 展示历史变化数据

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

    • CAdvisor默认只在本机保存2分钟的数据,为了持久化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合存储 CAdvisor 的数据。而且 CAdvisor本身已经提供了InfluxDB的集成方法,在启动容器时指定配置即可。

    • InfluxDB主要功能:

      • 基于时间序列,支持与时间有关的相关函数(如最大、最小、求和等)

      • 可度量性,可以实时对大量数据进行计算

      • 基于事件,支持任意的事件数据

  • Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括InfluxDB、MySQL、Elasticsearch、OpenTSDB、Graphite等)和丰富的插件及模板功能,支持图表权限控制和报警。

    • Granfana主要功能:
      • 灵活丰富的图形化选项
      • 可以混合多种风格
      • 支持白天和夜间模式
      • 多个数据源

24.3使用Compose搭建CIG监控平台

  1. 新建cig目录,在目录下创建docker-compose.yml文件,实现容器编排。
version: '3.1'
 
volumes:
  grafana_data: {}
 
services:
 influxdb:
 	# tutum/influxdb 相比influxdb多了web可视化视图。但是该镜像已被标记为已过时
  image: tutum/influxdb:0.9
  restart: always
  environment:
    - PRE_CREATE_DB=cadvisor
  ports:
    - "8083:8083"	# 数据库web可视化页面端口
    - "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. 检查docker-compose.yml文件是否有错误
docker-compose config -q
  1. 后台启动docker-compose服务
docker-compose up -d

容器启动之后:

  1. 在浏览器打开InfluxDB数据库的页面: http://xxx.xxx.xxx.xxx:8083,使用命令查看当前数据库中的数据库实例:

    SHOW DATABASES

    查看其中是否自动创建了我们在配置文件中配置的 cadvisor 数据库实例

  2. 在浏览器打开CAdvisor页面:http://xxx.xxx.xxx.xxx8080/,查看当前docker中的cpu、内存、网络IO等统计信息

  3. 在浏览器打开Grafana页面:http://xxx.xxx.xxx.xxx:3000/,默认用户名密码是:admin/admin。

24.4 Grafana配置

添加数据源

Configuration(小齿轮)选项卡中,选择Data Sources,添加一个InfluxDB数据源:

  • name:自定义一个数据源名称,例如InfluxDB
  • Query Language:查询语言,默认InfluxQL即可
  • URL:根据compose中的容器服务名连接,http://influxdb:8086
  • database:我们在InfluxDB中创建的数据库实例,cadvisor
  • User:InfluxDB的默认用户,root
  • Password:root

保存并测试,可以连通即可

添加工作台

  1. 在Create(加号)选项卡中,选择创建 Dash Board工作台。右上角配置中可以配置创建出来的工作台的标题、文件夹等信息。

  2. 在创建出来的工作台中,选择Add panel中的Add a new panel添加一个新的面板。

    • 在右上角Time series(时序图)位置可以切换展示的图表样式(柱状图、仪表盘、表格、饼图等等)

    • 右侧边栏为该图表配置相关信息:标题、描述

    • 图表下方可以配置该图表展示的数据的查询语句,例如:

      • FROM:cpu_usage_total(Grafana会自动获取InfluxDB数据库中的元数据,可以直接选择对应表名)

      • WHERE:添加一个条件,container_name=cig-cadvisor-1

      • ALIAS:配置一个别名,CPU使用情况汇总

你可能感兴趣的:(J2EE,docker,运维,容器)