Docker-应用容器

安装Docker

  • 官网

    官网(): https://www.docker.com/

    centos(): https://docs.docker.com/engine/install/centos/

    选择Linux() 选择对应系统安装()
  • 卸载旧版本

    1
    2
    3
    4
    5
    6
    7
    8
    sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
  • 下载关于Docker 的依赖环境

    1
    yum install -y yum-utils  device-mapper-persistent-data  lvm2
  • 设置镜像仓库

    1
    2
    3
    yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    # 选择一个
    sudo yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
  • 安装docker

    1
    2
    3
    4
    # 更新 yum 软件包索引
    yum makecache fast
    # 安装最新版本
    sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 启动docker 并设置开机自动启动

    1
    2
    3
    4
    5
    # 启动
    systemctl start docker
    # 设置开机自启
    systemctl enable docker

  • 配置镜像加速

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 可以通过修改daemon配置文件/etc/docker/daemon.json 来使用加速器
    sudo mkdir -p /etc/docker

    # 添加国内镜像【sudo开始复制一直到 EOF 结束】
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
    "registry-mirrors":[
    "https://eyy45bvx.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com",
    "https://registry.aliyuncs.com",
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn"
    ]
    }
    EOF

    # 重新加载 daemon 配置
    sudo systemctl daemon-reload
    # 重启 docker
    sudo systemctl restart docker
    • 可以获取自己的阿里云地址

      • 登录阿里云

      • 进入控制台

      • 搜索[容器镜像服务](https://cr.console.aliyun.com/cn-hangzhou/instances)

        获取镜像加速器地址
  • 查看镜像加速是否生效

    1
    docker info
    加速生效
  • 测试环境

    1
    docker run hello-world
  • 输出

    测试环境
    成功安装Docker

卸载Docker

  • 查看运行状态

    1
    systemctl status docker 
  • 停止服务

    1
    2
    3
    systemctl stop docker
    # 出现如下,使用该命令
    sudo systemctl stop docker.socket
    停止
  • 查看yum 安装的docker 文件包

    1
    yum list installed | grep docker
    已下载列表
  • 删除所有安装的docker 文件包

    1
    2
    3
    4
    # 查看
    rpm -qa|grep docker
    # 删除列出的文件
    yum -y remove xxx
    删除
  • 删除docker 镜像

    1
    rm -rf /var/lib/docker

中央仓库

  1. Docker 官方的中央仓库: 这个仓库是镜像最全的,但是下载速度较慢https://hub.docker.com/

  2. 国内镜像网站: 网易蜂巢,daoCloud...

    1
    2
    https://c.163yun.com/hub#/home
    http://hub.daocloud.io (推荐使用,速度加载较快)
  3. 在公司内部会采用私服的方式拉取镜像(添加相关配置)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 编辑 | 新建该配置文件
    vim /etc/docker/daemon.json
    # 添加如下信息
    {
    "registry-mirrors": ["https://register.docker-cn.com"],
    # 私服
    "insecure-registries": ["ip:port"]
    }
    # 重新启动两个服务
    systemctl daemon-reload
    systemctl restart docker

镜像的操作

  • 拉取环境

    1
    2
    3
    4
    5
    6
    # http://hub.daocloud.io/ 在此处搜索
    # 拉取镜像到本地
    docker pull 镜像名称[:tag]

    # Eg
    docker pull daocloud.io/library/tomcat:8.0.45
    • 拉取流程

      拉取所需环境
    • 拉取过程

      拉取过程

Run-流程

  • 流程

    docker run 的 run 流程

Docker-常用命令

帮助启动类命令
  • 启动

    1
    systemctl start docker
  • 停止

    1
    systemctl stop docker
  • 重启

    1
    systemctl restart docker
  • 查看状态

    1
    systemctl status docker
  • 开机启动

    1
    systemctl enable docker
  • 查看docker 概要信息

    1
    docker info
  • 查看docker 总体帮助命令

    1
    docker --help
  • 查看docker 命令帮助文档

    1
    docker 具体命令 --help
镜像命令
  • 列出本地主机上的镜像

    1
    2
    3
    4
    5
    docker images -[options]

    options:
    -a: 列出本地所有的镜像(含历史映像层)
    -q: 只显示镜像 ID
    查看全部本地的镜像
    • REPOSITORY: 表示镜像的仓库源

    • TAG: 镜像的标签版本号

    • IMAGE ID: 镜像ID

    • CREATED: 镜像创建时间

    • SIZE: 镜像大小

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

      如果你不指定一个镜像的版本标签,例如你只使用ubuntu,docker 将默认使用ubuntu:latest 镜像

  • 搜索某个镜像

    1
    2
    3
    docker search 某个镜像名称
    # Eg: 查看排名前 5 的
    docker search --limit 5 redis
    信息
    参数 说明
    NAME 镜像名称
    DESCRIPTION 镜像说明
    STARS 点赞数
    OFFICIAL 是否是官方的
    AUTOMA 是否是自动构建的
  • 拉取某个镜像

    1
    2
    3
    docker pull 某个镜像名称[:TAG]
    # 没有 TAG 就是最新版,等价于如下
    docker pull 镜像名称:latest
  • 查看占用空间

    1
    docker system df 镜像/容器/数据卷所占用的空间
    空间信息
  • 删除镜像

    1
    2
    3
    4
    5
    6
    7
    8
    # 删除单个, -f 参数可以强制删除
    docker rmi 某个镜像名字id

    # 删除多个
    docker rmi -f 镜像名1:TAG 镜像名2:TAG

    # 删除全部
    docker rmi -f $(docker images -qa)
    删除前与删除后
  • 镜像导出与导入

    1
    2
    3
    4
    5
    6
    # 将本地镜像导出
    docker save -o 导出的路径 镜像id
    # 加载本地的镜像文件
    docker load -i 镜像文件
    # 修改镜像名称
    docker tag 镜像id 新镜像名称:版本
    使用流程
  • 面试题: 谈谈docker 虚悬镜像是什么?

    • 虚悬镜像指的是

      仓库名、标签都是<none> 的镜像,俗称虚悬镜像(dangling image)

    • 长什么样

      虚悬镜像,需要删除掉
容器命令
  • 拉取ubuntu 镜像

    1
    docler pull ubuntu
  • 新建+启动容器

    • 启动交互式容器(前台命令行)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # 简单操作
      docker run 镜像标识 | 镜像名称[:tag]

      # 可以直接拉取并启动
      docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像的标识|镜像名称[:tag]

      # -d: 代表后台运行容器
      # --name: 容器名称 =>指定容器的名称

      # -i: 以交互模式运行容器,通常与 -t 同时使用
      # -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
      docker run -it ubuntu bash
      # 退出
      exit
      # -p: 宿主机端口:容器端口 => 为了映射当前 Linux 的端口和容器的端口
  • 退出

    • exit: run 进去容器,exit 退出,容器停止

      容器自动关闭
    • ctrl+p+q: run 进去容器,ctrl+p+q 退出,容器不停止

      容器未停止
  • 查看正在运行的容器

    1
    2
    3
    docker ps [-qa]
    # -a: 查看全部的容器,包括没有运行的
    # -q: 只查看容器的标识
    测试
  • 启动已停止运行的容器

    1
    docker start 容器id/或者容器名
    使用容器id进行启动或关闭
  • 停止容器

    1
    docker stop 容器id/或者容器名
  • 强制停止容器

    1
    docker kill 容器id/或者容器名
  • 删除已停止的容器

    1
    2
    3
    4
    # 删除单个
    docker rm 容器id
    # 一次性删除多个容器实例
    docker rm -f $(docker ps -qa)
    删除多个已停止容器
  • 查看容器的日志

    1
    2
    docker logs -f 容器id
    # -f: 可以滚动查看日志的最后几行
  • 进入正在运行的容器并以命令行交互

    • 方式一

      1
      2
      3
      4
      5
      6
      docker exec -it 容器id(CONTAINER ID)  bash
      # Eg: 进入 Tomcat
      docker exec -it fb0 bash

      # 退出容器内部
      exit
      进入容器内的Tomcat
    • 方式二

      1
      docker attach 容器id
    • 两者的区别

      • exec【推荐】是在容器中打开新的终端,并且可以启动新的进程,exit 退出,不会导致容器的停止
      • attach: 直接进入容器启动命令的终端,不会启动新的进程,exit 退出,会导致容器的停止
  • 查看容器内部细节

    1
    docker inspect 容器id
  • 从容器内拷贝文件到主机上

    • 容器 到 主机

    • 命令

      1
      2
      3
      docker cp 容器id:容器内路径 目的主机路径
      # Eg: 将 容器 tmp 目录内的文件备份到宿主机
      docker cp bc7c957b6662:/tmp ./cp-tmp.txt
      文件备份
  • 导入和到导出容器

    • export: 导出容器的内容六作为一个tar 归档文件

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

    • 案例

      1
      2
      # 导出
      docker export 容器id > 文件名.tar
      1
      2
      3
      4
      # 导入
      cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
      # Eg:
      cat ubuntu.tar | docker import - coderitl/ubuntu:latest
      导入与导出

Docker-镜像

  • 镜像

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

  • 分层的镜像

    一个镜像的下载是等待一个一个文件内容的下载(分层)
    • UnionFS(联合文件系统)

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

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

  • Docker 镜像 commit 操作

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

    • 命令

      1
      docker commit -m="提交的描述信息"  -a="作者" 容器id 要创建的目标镜像名:[标签名]
    • 案例: ubuntu 安装vim

      • Hub 上下载ubuntu 镜像到本地并成功运行

        启动,更新容器内部
      • 原始的默认Ubuntu 镜像时不带着vim 命令的

      • 外网联通的情况下,安装vim

        1
        2
        3
        # 容器内部执行
        apt-get -y update
        apt-get -y install vim
      • 安装完成后,commit 我们自己的新镜像

        1
        2
        # e50146ce2426: docker ps 获取
        docker commit -m="add vim" -a="coder-itl" e50146ce2426 coderitl/ubuntu:1.1
      • 启动我们的新镜像并和原来的对比

        1
        2
        # ctrl + p + q 【退出,不关闭容器】
        docker run -it coderitl/ubuntu:1.1 bash
        启动自己制作的镜像

镜像发布

公服
  • 本地镜像发布到阿里云

    • 创建阿里云镜像仓库

      1. 选择控制台,进入容器镜像服务(搜索容器镜像服务)

        进入容器镜像服务
      2. 选择个人实例

        点击个人实例
      3. 命名空间

        创建命名空间
      4. 仓库名称

        选择命名空间,创建镜像仓库 填写基本信息 直接选择本地仓库
      5. 进入管理界面获得脚本

        获取脚本
      6. 推送到阿里云

        1
        2
        3
        4
        5
        6
        # username: 阿里云账号的用户名,之后输入阿里云账号的密码
        $ docker login --username=bin_爱豆 registry.cn-hangzhou.aliyuncs.com
        # 如下命令中的 [ImageId] 和 [镜像版本号] 修改为本次推送之远程仓库的信息
        $ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/coder-itl/ubuntu:[镜像版本号]
        # [镜像版本号]: 填写版本号
        $ docker push registry.cn-hangzhou.aliyuncs.com/coder-itl/ubuntu:[镜像版本号]
        使用脚本
        信息修改
        推送到远程
  • 拉取阿里云镜像到本地

    • 拉取镜像

      1
      docker pull registry.cn-hangzhou.aliyuncs.com/coder-itl/ubuntu:[镜像版本号]
      拉取自己创建的镜像到本地
私服
  • Docker Registry

    • 下载镜像Docker Registry

      1
      docker pull registry
    • 运行私有库Registry,相当于本地有个私有Docker hub

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # 在宿主机创建目录【权限充足时将会自动创建】
      mkdir -p /coderitl/myregistry/
      # 默认情况,仓库被创建再容器的 /var/lib/registry 目录下,建议自行用容器卷映射,方便与宿主机联调
      docker run -d -p 5000:5000 -v /coderitl/myregistry/:/tmp/myregistry --privileged=true registry

      # -v: 相当于将这两个目录联通共享
      /coderitl/myregistry/【宿主机目录】:/tmp/myregistry【容器内目录】

      # 默认情况下容器中的root用户只是host主机的一个普通用户,但如果docker run --privileged=true 就真正的给这个普通用户赋予了和host主机root用户的特权。
      基础操作
    • 案例演示创建一个新镜像,ubuntu 安装ifconfig 命令

      • 进入容器内部【ubuntu】

        1
        2
        3
        4
        5
        6
        7
        8
        # 获取正在运行的容器 id
        docker ps
        # 进入容器内部
        docker exec -it 容器id bash

        # 未运行时,可执行如下 registry.cn-hangzhou.aliyuncs.com/coder-itl/ubuntu:1.1【替换】
        docker run -it registry.cn-hangzhou.aliyuncs.com/coder-itl/ubuntu:1.1 bash

        启动容器并进入交互界面
      • 执行如下下载ifconfig

        1
        2
        3
        4
        5
        6
        7
        # 安装
        apt-get -y update
        apt-get -y install net-tools

        # 测试
        ifconfig

        测试命令,使用ctrl+p+q 退出
      • 提交本次镜像

        1
        2
        # e50146ce2426: docker ps 获取
        docker commit -m="add vim" -a="coder-itl" e50146ce2426 coderitl/ubuntu:1.2
        镜像提交
    • curl 验证私服库上有什么镜像

      1
      2
      # ip: 本机
      curl -XGET http://192.168.2.3:5000/v2/_catalog
      私服初始为空
    • 将新镜像coderitl/ubuntu 修改为符合私服规范的Tag

      1
      2
      # 语法: docker tag 镜像:tag Host(ip):Port/Repository:Tag
      docker tag coderitl/ubuntu:1.2 192.168.2.3:5000/coderitl/ubuntu:1.2
    • 修改配置文件使之支持http

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # 编辑 daemon.json
      vim /etc/docker/daemon.json
      # 添加如下
      {
      ... ,
      # 在之前内容后补充,使用 "逗号" 分割
      "insecure-registries":["192.168.2.3:5000"]
      }

      # 上述保存退出后,重新加载 daemon
      systemctl daemon-reload
      systemctl restart docker
      # 添加原因: docker 默认不允许 http 方式推送镜像,通过配置选项来取消这个限制 => 修改完如果不生效,对 docker 进行重启
      修改daemon.json 重启docker 后,需要重新启动registry
    • push 推送到私服库

      1
      docker push 192.168.2.3:5000/coderitl/ubuntu:1.2
      推送时registry 必须是启动的
    • curl 验证私服库上有什么镜像

      1
      2
      # ip: 本机
      curl -XGET http://192.168.2.3:5000/v2/_catalog
      上传成功
    • 拉取到本地

      1
      docker pull 192.168.2.3:5000/coderitl/ubuntu:1.2
      拉取镜像

容器数据卷

  • 是什么

    可以将docker 容器内的数据保存在宿主机的磁盘中

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

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

  • 权限问题

    Docker 挂载目录访问如果出现 cannout open directory.: Oermission denid

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

    原因: 如果是Centos7 安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认认为不是安全的行为,在SELinux 里面挂载目录被禁止掉了,如果要开启,只需要添加--privileged=true 参数即可,可以扩大容器的权限解决挂载目录没有权限的问题,使用了该参数, 容器 内的root 将会拥有真正的root 权限,否则,root 将会只是一个普通root 用户而已

  • 运行一个带有容器数据卷存储功能的容器实例

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

    将运行的环境打包成镜像,run 后形成容器实例运行,但是我们对数据的要求希望是持久化的

    Docker 容器产生的数据,如果我们不备份,那么当容器实例删除后,容器内的数据自然也就没有了,为了能保存数据在docker 中我们使用

    特点:

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

    1
    2
    # 权限问题: 默认允许读写(rw),只读只需要添加配置 /tmp/centos_data:/tmp/docker_dat:ro【read only】
    docker run -it --privileged=true -v /tmp/centos_data:/tmp/docker_data --name="cut" ubuntu
  • 查看数据卷是否挂载成功

    1
    docker inspect 容器id
    查看挂载目录 容器与宿主机之间实现数据共享
  • 卷的继承和共享

    1
    2
    3
    4
    #  父类: cut
    docker run -it --privileged=true -v /tmp/centos_data:/tmp/docker_data --name="cut" ubuntu
    # name2 获取继承
    docker run -it --privileged=true --volumes-from 父类(名称) --name="name2" ubuntu

Docker-常规安装

总体步骤
  1. 搜索镜像
  2. 拉取镜像
  3. 查看镜像
  4. 启动镜像
  5. 停止镜像
  6. 移除镜像
Tomcat
  • 搜索

    1
    docker search --limit 1 tomcat
  • 拉取

    1
    2
    # Tomcat 10
    docker pull tomcat
  • 启动

    1
    docker run -d -p 8080:8080 --privileged=true --name="test-tomcat" tomcat
  • 新版发生改变

    • 首页发生变化

      出现如下
    • 进入Tomcat 容器内部

      1
      docker exec -it 容器id bash
    • 主要原因

      无法显示首页的原因
    • 删除该文件夹

      1
      rm -r webapps 
    • webapps.dist 重命名

      1
      2
      3
      4
      # 1. 先进性备份
      cp webapps.dist/ -r webapps.dist.back/
      # 2. 修改为 webapps
      cp -r webapps.dist webapps
      备份 成功加载首页
  • 免修该版本下载

    1
    2
    # tomcat8
    docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
MYSQL
  • 安装

    1
    2
    3
    4
    5
    6
    7
    8
    # 本机已经安装了 mysql 需要注意端口
    docker run -d -p 3306:3306 --privileged=true \
    -v /coderitl/mysql/log:/var/log/mysql \
    -v /coderitl/mysql/data:/var/lib/mysql \
    -v /coderitl/mysql/conf:/etc/mysql/conf.d \
    -e MYSQL_ROOT_PASSWORD=root \
    --name mysql \
    mysql:5.7
    • 在目录 /coderitl/mysql/conf 下新建my.cnf

      新建配置文件在数据卷挂载的conf 目录下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # 通过容器卷同步给 mysql 容器实例
      vim my.cnf

      # 添加如下内容
      [client]
      default-character-set=utf8
      [mysqld]
      character-set-server=utf8
      collation-server=utf8_general_ci

      1
      2
      3
      4
      5
      6
      7
      # 添加上下其一即可
      [client]
      default-character-set=utf8
      [mysql]
      default-character-set=utf8
      [mysqld]
      character-set-server=utf8
      1
      2
      # 查看字符集
      show variables like "character_%";
      字符集(等待后查看)
    • 重新启动mysql 容器实例再重新进入并查看字符集编码

      1
      docker restart mysql
    • 在新建库新建表再插入中文测试

      成功显示中文数据
  • mysql 最新版

    1
    2
    3
    4
    5
    6
    7
    docker run -d -p 3306:3306 --privileged=true \
    -v /coderitl/mysql/log:/var/log/mysql \
    -v /coderitl/mysql/data:/var/lib/mysql \
    -v /coderitl/mysql/conf:/etc/mysql/conf.d \
    -e MYSQL_ROOT_PASSWORD=root \
    --name mysql \
    mysql
Redis
  • docker hub 上拉取

    1
    docker pull redis:6.0.8
  • Redis6.0 的配置文件地址

    https://raw.githubusercontent.com/redis/redis/6.0/redis.conf

    • 修改配置文件

      • protected-mode no
      • # bind 127.0.0.1
      • daemonize no
    • 个人已修改使用的配置

      获取配置
      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
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      protected-mode no

      port 6379

      tcp-backlog 511

      timeout 0

      tcp-keepalive 300

      daemonize no


      supervised no

      pidfile /var/run/redis_6379.pid

      loglevel notice


      logfile ""


      databases 16


      always-show-logo yes


      save 900 1
      save 300 10
      save 60 10000


      stop-writes-on-bgsave-error yes


      rdbcompression yes

      dbfilename dump.rdb


      rdb-del-sync-files no

      dir ./


      replica-serve-stale-data yes

      replica-read-only yes

      repl-diskless-sync no

      repl-diskless-sync-delay 5

      repl-diskless-load disabled

      repl-disable-tcp-nodelay no

      replica-priority 100

      acllog-max-len 128

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


      lazyfree-lazy-user-del no

      oom-score-adj no


      oom-score-adj-values 0 200 800

      appendonly no

      appendfilename "appendonly.aof"

      appendfsync everysec

      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-log-slower-than 10000

      slowlog-max-len 128

      latency-monitor-threshold 0

      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

      client-output-buffer-limit normal 0 0 0
      client-output-buffer-limit replica 256mb 64mb 60
      client-output-buffer-limit pubsub 32mb 8mb 60

      hz 10

      dynamic-hz yes

      aof-rewrite-incremental-fsync yes

      rdb-save-incremental-fsync yes

      jemalloc-bg-thread yes
  • 创建容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 创建目录
    mkdir -p /coderitl/redis/conf
    # 添加 redis 的配置文件
    cd /coderitl/redis/conf
    # 将提供的配置文件内容写入 redis.conf 文件中
    vim redis.conf

    # 注意宿主机是否已经安装 安装需要注意端口
    docker run -p 6379:6379 \
    --name redis \
    --restart=always \
    --privileged=true \
    -v /coderitl/redis/data/:/data \
    -v /coderitl/redis/conf/redis.conf:/etc/redis/redis.conf \
    -d redis:6.0.8 redis-server /etc/redis/redis.conf
    • 拉去镜像后更新添加选项

      1
      2
      # 未添加时执行,作用: 当启动 linux 时跟随启动,不常用 Redis 时慎用
      docker update redis --restart=always

NotePad++

  • 插件

    1
    NppFTP
  • 使用

    SFTP
  • 作用

    可以直接修改虚拟机内部文件,支持语法高亮

  • 文件打开

    双击打开的文件

MYSQL-主从复制-Docker

  • 步骤

    1. 新建主服务器容器实例3307

      1
      2
      3
      4
      5
      6
      docker run -p 3307:3306 --name mysql-master \
      -v /mydata/mysql-master/log:/var/log/mysql \
      -v /mydata/mysql-master/data:/var/lib/mysql \
      -v /mydata/mysql-master/conf:/etc/mysql \
      -e MYSQL_ROOT_PASSWORD=root \
      -d mysql:5.7
    2. 进入/mydata/mysql-master/conf 目录下新建my.cnf

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      [mysqld]
      ## 设置server_id,同一局域网中需要唯一
      server_id=101
      ## 指定不需要同步的数据库名称
      binlog-ignore-db=mysql
      ## 开启二进制日志功能
      log-bin=mall-mysql-bin
      ## 设置二进制日志使用内存大小(事务)
      binlog_cache_size=1M
      ## 设置使用的二进制日志格式(mixed,statement,row)
      binlog_format=mixed
      ## 二进制日志过期清理时间。默认值为0,表示不自动清理。
      expire_logs_days=7
      ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
      ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
      slave_skip_errors=1062
    3. 修改完配置后重启master 实例

      1
      docker restart mysql-master
    4. 进入mysql-master 容器

      1
      2
      # 进入容器 测试是否可以登录成功
      docker exec -it id bash
      测试是否可以登录成功
    5. master 容器实例内创建数据同步用户

      1
      2
      3
      4
      # 创建用户
      create user 'slave'@'%' identified by '123456';
      # 授权【虚拟机内的 MSQL 没有忽略大小写】
      GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
      windows 忽略大小写 Linux 大小写敏感
    6. 新建从服务器实例容器3308

      1
      2
      3
      4
      5
      6
      docker run -p 3308:3306 --name mysql-slave \
      -v /mydata/mysql-slave/log:/var/log/mysql \
      -v /mydata/mysql-slave/data:/var/lib/mysql \
      -v /mydata/mysql-slave/conf:/etc/mysql \
      -e MYSQL_ROOT_PASSWORD=root \
      -d mysql:5.7
    7. 进入/mydata/mysql-slave/conf 目录下新建my.cnf

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

      1
      docker restart mysql-slave
    9. 在主数据库中查看主从同步状态

      1
      show master status;
    10. 进入mysql-slave 容器

      1
      docker exec -it mysql-slave bash
    11. 从数据库中配置主从复制

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      # 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=617, master_connect_retry=30;

      # 需要启动的命令
      change master to master_host='192.168.2.3', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000002', master_log_pos=154, master_connect_retry=30;

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


    12. 从数据库中查看主从同步状态

      1
      show slave status\G;
      还未开始
    13. 从数据库中开启主从同步

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

      主从同步已开启
    15. 主从复制测试

      • 主机新建库-使用库-新建表-插入数据

      • 从机使用库-查看记录

        主从测试

安装Redis集群-分布式存储案例真题

  • cluster(集群模式)-docker:哈希槽分区进行亿级数据存储

  • 面试题

    • 1~2 亿条数据需要缓存,请问如何设计这个存储案例

      解决方案如下:

      • 哈希取余分区

        模型

        2 亿条记录就是2 亿个k,v,我们单机不行必须要用分布式多机,假设有3 台机器构成一个集群,用户每次读写操作都是根据公式:hash(key)%N 个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。

        • 优点

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

        • 缺点

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

      • 一致性哈希算法分区

        • 背景

          一致性算法在1997 年由麻省理工学院中剔除,设计目标是为了解决分布式缓存数据变动和映射问题某个机器宕机了,分母数量改变了,自然取余数就不OK

        • 作用

          提出一致性Hash 解决方案,目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系

        • 实现的三大步骤

          • 算法构建一致性哈希环

            一致性哈希算法必然有个hash 函数并按照算法产生hash 值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash 空间【0,2^32-1】,这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制它首尾相连(0=2^32),这样让他逻辑上形成了一个环形空间

            它也是按照使用取模的方法,前面提到的是对服务器数量进行取模。而一致性Hash 算法是对2^32 取模,简单来说: 一致性 Hash 算法将整个哈希值空间组织成一个虚拟的圆环 ,如果假设某哈希函数H 的值空间为0-2^32-1(即哈希值是一个 32 位无符号整型),整个哈希环如下: 整个空间按顺时针方向组织,圆环的正上方的点代表00 点右侧的第一个点代表1,依次类推,直到2^32-1,也就是说0 点左侧的第一个点代表2^32-10 2^32-1 在零点房中重合,我们把这个由2^32 个点组成的圆环称为Hash

            哈希环
          • 服务器IP 节点映射

            将集群中各个IP 节点映射到环上的某一个位置。

            将各个服务器使用Hash 进行一个哈希,具体可以选择服务器的IP 或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如:4 个节点A、B、C、D 经过IP 地址的哈希函数计算(hash(ip)),使用IP 地址后在环空间的位置如下:

            服务器IP 节点映射(Eg)
          • key 落到服务器的落键规则

            当我们需要存储一个kv 键值对时,首先计算key hash 值,hash(key),将这个key 使用相同的函数Hash 计算出哈希值并确定此数据在环上的位置, 从此位置沿环顺时针"行走" ,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。

            如果我们有Object A、B、C、D 四个数据对象,经过哈希计算后,在环空间的位置如下: 根据一致性Hash 算法,数据A 会被定位到Node A 上,…

            落键规则
        • 优点

          • 一致性哈希算法的容错性

            假设Node C 宕机,可以看到此时对象A、B、D 不会受到影响,只有C 对象被重定位到Node D。一般的,在一致性Hash 算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据,并且这些数据会转移到D进行存储。

          • 一致性哈希算法的扩展性

            数据量增加了,需要增加一台节点NodeX,X的位置在AB之间,那收到影响的也就是AX之间的数据,重新把AX的数据录入到X上即可,

            不会导致hash取余全部数据重新洗牌。

        • 缺点

          一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,

      • 哈希槽分区

        • 为什么会出现

          是由于一致性哈希算法中数据倾斜

          哈希槽实质上就是一个数组,数组[0,2^14-1] 形成一个hash slot 空间

        • 能干什么

          解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

          槽解决的是粒度问题,相当于把粒度变大了,这样方便于数据移动

          哈希解决的是映射问题,使用key 的哈希值来计算所在的槽,便于数据分配

        • 多少个hash

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

        • 哈希槽计算

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

        • 3 3

          • 分段

            分段
          • 创建实例

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            # --cluster-enabled yes【开启集群】 --appendonly yes【持久化】
            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 -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382

            docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383


            docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384

            docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385

            docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386


            启动查看
          • 进入容器redis-node-1 并为6 台机器构建集群关系

            1
            2
            3
            4
            5
            6
            7
            8
            # 进入 redis-node-1
            docker exec -it redis-node-1 bash

            # -cluster-replicas 1 表示为每个master创建一个slave节点
            redis-cli --cluster create 192.168.2.3:6381 192.168.2.3:6382 192.168.2.3:6383 192.168.2.3:6384 192.168.2.3:6385 192.168.2.3:6386 --cluster-replicas 1

            # 之后输入: yes

            关系构建(分段)
        • 链接进入6381 作为切入点,查看集群状态

          1
          2
          # 在 redis-node-1 容器内部
          redis-cli -p 6381
          整体情况 节点信息
        • 主机下挂载从机情况

          通过cluster nodes 查看
  • 主从容错切换迁移案例

    • 数据读写存储

      • 启动3 3 从,进入redis-node-1

        正常启动 连接6381
      • 连接6381,添加2key

        添加情况,原因是由于集群分槽导致的,如果在某一个槽超出,将无法插入数据
      • 防止路由失效加参数-c 并再次新增2 个 key

        1
        2
        3
        4
        # 单机连接方式
        redis-cli -p 6381
        # 由于现在是集群环境,所以退出单机登录,添加 -c 参数【集群启动】
        redis-cli -p 6381 -c
        添加情况
      • 查看集群信息

        1
        redis-cli --cluster check 192.168.2.3:6381
        集群检查
  • 容错切换迁移

    • 6381 从机切换,先停止主机 6381

      6381 停止 停止
    • 再次查看集群情况

      当前情况 从机上位,对数据未造成影响
    • 先还原之前的3 3

      1
      2
      # 启动 reids-node-1
      docker start reids-node-1
      恢复
    • 查看集群状态

      当前状态 挂载情况

      恢复的主机并不会再次成为主机,而是成为其中的一个从机

  • 主从扩容

    • 新建6387,6388 两个节点+新建后启动+查看是否是8 节点

      1
      2
      3
      docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387

      docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
      成功启动8 台容器
    • 进入6387 容器内部实例

      1
      docker exec -it redis-node-7 bash
    • 将新增的6387 节点(空槽好)作为master 节点加入原集群

      1
      2
      3
      4
      5
      6
      7
      # 将新增的6387作为master节点加入集群
      redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:6381

      redis-cli --cluster add-node 192.168.2.3:6387 192.168.2.3:6381

      6387 就是将要作为master新增节点
      6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
      添加节点
    • 检查集群情况第一次

      1
      2
      # redis-cli --cluster check 真实ip地址:6381
      redis-cli --cluster check 192.168.2.3:6381
      成功添加
    • 重新分配槽号

      1
      2
      # 重新分派槽号 命令: redis-cli --cluster reshard IP地址:端口号
      redis-cli --cluster reshard 192.168.2.3:6381
      添加节点后槽位信息为空 16384/master=4096 选择分配的容器id,后续输入yes
    • 检查集群情况第二次

      再次查看槽位信息(6387槽位来自于其他三个的分配组成了4096)

      为什么6387 3 个新的区间,以前的还是连续?

      重新分配成本太高,所以前3 家各自匀出来一部分,从6381/6382/6383 三个旧节点分别匀出1364 个坑位给新节点6387

    • 为主节点6387 分配从节点6388

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # 命令:redis-cli --cluster add-node ip:slave端口 ip:master端口 --cluster-slave --cluster-master-id 新主机节点ID

      # 查看 id
      redis-cli --cluster check 192.168.2.3:6381

      # 364259ffcb88b0f84cc14c1e3686bf94ed3708d4: -------这个是6387的编号,按照自己实际情况

      # 分配
      redis-cli --cluster add-node 192.168.2.3:6388 192.168.2.3:6387 --cluster-slave --cluster-master-id 364259ffcb88b0f84cc14c1e3686bf94ed3708d4

      主节点: 6387
    • 检查集群情况第三次

      44
  • 主从缩容

    • 目的: 63876388 下线

    • 检查集群情况获得6388(从机端口) 的节点ID

      1
      2
      redis-cli --cluster check 192.168.2.3:6381
      slave: 38829c4b96974ad6002a8c71c55722a6787a14c5
    • 6388 删除,从集群中将4号从节点 6388 删除

      1
      2
      # 命令:redis-cli --cluster del-node ip:从机端口 从机6388节点ID
      redis-cli --cluster del-node 192.168.2.3:6388 38829c4b96974ad6002a8c71c55722a6787a14c5
    • 6387 的槽号清空,重新分配,本例将清出来的槽号都给6381

      1
      redis-cli --cluster reshard 192.168.2.3:6381
      输入
    • 检查集群情况第二次

      4 主3
    • 6387(主) 删除

      1
      2
      # 命令:redis-cli --cluster del-node ip:端口 6387节点ID
      redis-cli --cluster del-node 192.168.2.3:6387 364259ffcb88b0f84cc14c1e3686bf94ed3708d4
    • 检查集群情况第三次

      恢复33

Dockerfile

  • 是什么

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

  • 构建三步骤

    • 编写Dockerfile 文件
    • docker build 命令构建镜像
    • docker run 以镜像运行容器实例
  • Dockerfile-构建过程解析

    • 基础内容

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

      • docker 从基础镜像运行一个容器
      • 执行一条指令并对容器做出修改
      • 执行类似docker commit 的操作提交一个新的镜像层
      • 执行dockerfile 中的下一条指令直到所有指令都执行完成
  • 保留字

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

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

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

      • shell 格式

        1
        RUN yum -y install vim
      • exec 格式

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

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

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

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

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

    • COPY

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

    • CMD

      • 指定容器启动后要干的事情,可以有多个,但只有最有一条生效
      • RUN 的区别
        • CMD 是在docker run 时运行
        • RUN 是在docker build 时运行
    • ENTRYPOINT

      • 是用来指定一个容器启动时要运行的命令
      • 类似于CMD 指令,但是ENTRYPOINT 不会被docker run 后面的命令覆盖,而且这些命令行参数会被当做参数送给 ENTRYPOINT 指令指定的程序
      • 优点: 在执行docker run 的时候可以指定ENTRYPOINT 运行时所需的参数
      • 注意: 如果Dockerfile 中如果存在多个ENTRYPOINT 指令,仅最后一个生效
  • 实战

    • 镜像地址

      https://mirrors.yangxingzhen.com/

    • 目标: 自定义镜像

      • 基础镜像centos
      • 添加vim
      • 添加net-tools
    • 步骤

      • 编写Dockerfile 文件名就是Dockerfile
      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
      FROM centos
      MAINTAINER coderitl<3327511395@qq.com>

      ENV MYPATH /usr/local
      WORKDIR $MYPATH

      # 更新yum
      RUN cd /etc/yum.repos.d/
      RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
      RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
      RUN yum -y update
      RUN yum makecache

      #安装 vim 编辑器
      RUN yum -y install vim
      #安装ifconfig命令查看网络IP
      RUN yum -y install net-tools
      #安装java8lib
      RUN yum -y install glibc.i686
      RUN mkdir /usr/local/java
      # ADD 是相对路径jar,jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
      ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
      #配置java环境变量
      ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
      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
        # 语法: 最后有一个 点
        docker build -t 镜像名称:TAG .
        # 构建
        docker build -t centos-java8:1.0 .
        构建
      • 运行

        1
        docker run -it 新镜像名称:TAG
        测试
  • 虚悬镜像

    虚悬镜像
    • 查看所有虚悬镜像

      1
      docker image ls -f dangling=true
    • 删除

      1
      2
      # 虚悬镜像已经失去存在价值,可以删除
      docker image prune

Docker-网络

  • 虚拟网桥

    docker0
  • 查看docker 网络模式命令

    1
    docker network ls
    网络模式
  • 能干什么

    • 容器间的互联和通信以及端口映射
    • 容器IP 变动时候可以通过服务名直接网络通信而不受到影响
  • docker0

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

    bridge 模型

Docker-Compose

  • 是什么

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

  • 作用

    简化参数,使用*.yml 文件易于维护,yml 文件严格要求空格和缩进,不要使用tab

  • 下载

    1
    2
    3
    4
    5
    6
    7
    # 下载: https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64(下载地址)
    curl -SL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
    # 如果是在 windows 上下载传输到linux,需要重命名
    # 添加可执行权限
    chmod 777 docker-compose
    # 软连接【不需要再进行后续的环境变量配置】
    sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
    下载
  • 测试docker-compose 环境变量

    测试docker-compose 环境变量
  • 核心概念

    • 一个文件:docker-compose.yml
    • 两个要素
      • 服务: 一个个应用容器实例:mysql、redis....
      • 工程: 由一组关联的应用容器组成的一个完整业务单元,docker-compose.yml 文件中定义
  • 常用命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 # 检查配置,有问题才有输出
    docker-compose restart # 重启服务
    docker-compose start # 启动服务
    docker-compose stop # 停止服务


  • docker-compose 管理容器

    • 语法

      yml 文件以key:value 方式来指定配置信息

      多个配置信息以换行 + 缩进的方式来区分

    • 管理Tomcat mysql

      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
      version: '3.1' # docker 版本
      services:
      mysql: # 服务名称
      restart: always # 代表只要 docker 启动,那么这个容器就跟着一起启动
      image: daocloud.io/library/mysql:5.7.31 # 指定镜像路径
      container_name: mysql # 指定容器名称
      ports:
      - 3306:3306 # 指定端口号映射 (- 可以映射多个)
      environment:
      MYSQL_ROOT_PASSWORD: root # 指定 MYSQL 的root用户登录密码
      TZ: Asia/Shanghai # 指定时区
      volumes:
      - /opt/docker_mysql_tomcat/mysql_data:/var/lib/mysql # 映射数据卷
      tomcat:
      restart: always # 代表只要 docker 启动,那么这个容器就跟着一起启动
      image: daocloud.io/library/tomcat:8.0.45 # 指定镜像路径
      container_name: tomcat # 指定容器名称
      ports:
      - 8080:8080 # 指定端口号映射 (- 可以映射多个)
      environment:
      TZ: Asia/Shanghai # 指定时区
      volumes:
      - /opt/docker_mysql_tomcat/tomcat_webapps:/usr/local/tomcat/webapps # war 映射数据卷
      - /opt/docker_mysql_tomcat/tomcat_logs:/usr/local/tomcat/logs # 日志映射数据卷

    • 使用docker-compose 命令管理*.yml 文件

      1
      2
      3
      4
      5
      6
      7
      8
      # 先删除之前的 mysql 和 tomcat 
      docker images
      # 1. 停止
      docker stop $(docker ps -qa)
      # 2. 删除
      docker rm $(docker ps -qa)
      # 3. 检测
      docker images
      删除之前所有镜像
    • docker-compose 命令启动

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # 后台启动
      docker-compose up -d
      # 关闭删除容器
      docker-compose down
      # 开启 | 关闭 | 重启 已经存在的由 docker-compose维护的容器
      docker-compose start | stop | restart

      # 查看由 docker-compose 管理的容器
      docker-compose ps

      # 查看日志
      docker-compose logs -f

      • 运行

        成功执行docker-compose.yml
  • docker-compose 管理自定义镜像

    • 文件目录层级

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      ➜ cprogram  tree /f
      Folder PATH listing
      Volume serial number is 214A-AF6E
      E:.
      │ Dockerfile
      │ index.html

      └───docker-compose
      docker-compose.yml # docker-compose up -d 在此目录执行

      ➜ cprogram

    • Dockerfile

      1
      2
      3
      # 容器内部路径需要准确无误
      from daocloud.io/library/nginx:1.9.1
      copy index.html /usr/share/nginx/html # 如果后面的路径不正确nginx是不能访问到指定的资源文件,会启动为 nginx默认页面
    • docker-compose.yml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      version: '3.1'
      services:
      nginx_show_index:
      restart: always
      build:
      # 构建自定义镜像
      context: ../ # 指定 dockerfile 文件的所在路径
      dockerfile: Dockerfile # 指定Dockerfile 文件名称
      image: myNginxShowIndex:1.0.0 # 自定义镜像名
      container_name: nginx_show_index # 容器名称
      ports:
      - 81:80
      environment:
      TZ: Asia/Shanghai
    • 提示

      1
      2
      3
      4
      5
      6
      7
      8
      # 可以直接启动基于 docker-compose.yml 以及 Dockerfiler 文件构建的自定义镜像
      docker-compose up -d
      # 如果自定义镜像不存在,会帮助我们构建出自定义镜像,如果自定义镜像已经存在,会直接运行这个自定义镜像
      # 重新构建
      # 重新构建自定义镜像
      docker-compose build
      # 运行前 重新构建
      docker-compose up -d --build
  • 微服务制作

    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
    version: "3"
    services:
    microService:
    image: coderitl_docker:1.6
    container_name: ms01
    ports:
    - "6001:6001"
    volumes:
    - /app/microService:/data
    networks:
    - coderitl
    depends_on:
    - redis
    - mysql

    redis:
    image: redis:6.0.8
    ports:
    - "6379:6379"
    volumes:
    - /app/redis/redis.conf:/etc/redis/redis.conf
    - /app/redis/data:/data
    networks:
    - coderitl
    command: redis-server /etc/redis/redis.conf

    mysql:
    image: mysql:5.7
    environment:
    MYSQL_ROOT_PASSWORD: '123456'
    MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
    MYSQL_DATABASE: 'db2021'
    MYSQL_USER: 'root'
    MYSQL_PASSWORD: 'root'
    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:
    - coderitl
    command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
    # 配置在同一网段【docker-网络部分学习】
    networks:
    coderitl:

Docker-轻量级可视化工具 Portainer

  • 安装

    1
    2
    3
    4
    5
    6
    docker run -d -p 8000:8000 -p 9000:9000 \
    --name protainer \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    portainer/portainer-ce:latest
  • 通过ip:9000 访问

  • 设置admin 用户和密码(coder-itl)后首次登录

    创建用户
  • 登录后选择local

    监控本地

Docker-CI、CD

CI
  • ci 介绍

    **CI(continuous intergration)**:持续集成

    持续集成: 编写代码时,完成了一个功能后,立即提交代码到Git 仓库中,将项目重新构建并且测试

    • 快速发现错误
    • 防止代码偏离主分支
  • 搭建gitlab

    1
    2
    3
    4
    5
    6
    # 修改 ssh 默认连接端口
    vim /etc/ssh/sshd_config
    # 修改 Port 22 => 其他端口 保存 => 退出 注意下次连接Linux时,修改端口

    # 重启 sshd
    systemctl restart sshd
    修改ssh端口,为了给gitlab 使用
    修改ssh端口
  • 创建docker-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    version: '3.1'
    services:
    gitlab:
    image: 'coderitl2218/gitlab-ce-zh:11.1.4'
    container_name: "gitlab"
    restart: always
    privileged: true
    hostname: 'gitlab'
    environment:
    TZ: 'Asia/Shanghai'
    GITLAB_OMNIBUS_CONFIG: |
    external_url 'http://47.104.232.247' # 注意修改
    gitlab_rails['time_zone'] = 'Asia/Shanghai'
    gitlab_rails['smtp_enable'] = true
    gitlab_rails['gitlab_shell_ssh_port'] = 22
    ports:
    - '80:80' # 注意修改
    - '443:443'
    - '22:22'
    volumes:
    - /opt/docker_gitlab/config:/etc/gitlab
    - /opt/docker_gitlab/data:/var/opt/gitlab
    - /opt/docker_gitlab/logs:/var/log/gitlab

  • 搭建成功

    成功执行

    修改密码

    用户名root,密码为上步设置的密码

    进入gitlab首页

  • 搭建gitlab-runner

    • 创建 docker

      1
      docker volume create gitlab-runner-config
    • 使用我们刚刚创建的卷启动 GitLab Runner 容器

      1
      2
      3
      4
      5
      6
      7
      docker run -d --name gitlab-runner  --restart always \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v gitlab-runner-config:/etc/gitlab-runner \
      gitlab/gitlab-runner:latest


      # -v gitlab-runner-config 本地配置文件查看路径
    • 检测是否安装

      检测gitlab-runner
      检测gitlab-runner
    • 添加容器权限,保证容器可以使用宿主机的docker, docker exec -it gitlab-runner usermod -aG root gitlab-runner

    • 注册

      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
      docker exec -it gitlab-runner gitlab-runner register

      # 输入 GitLab 地址
      Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
      http://192.168.199.109/

      # 输入 GitLab Token
      Please enter the gitlab-ci token for this runner:
      1Lxq_f1NRfCfeNbE5WRh

      # 输入 Runner 的说明
      Please enter the gitlab-ci description for this runner:
      可以为空

      # 设置 Tag,可以用于指定在构建规定的 tag 时触发 ci
      Please enter the gitlab-ci tags for this runner (comma separated):
      deploy

      # 这里选择 true ,可以用于代码上传后直接执行(根据版本,也会没有次选项)
      Whether to run untagged builds [true/false]:
      true

      # 这里选择 false,可以直接回车,默认为 false(根据版本,也会没有次选项)
      Whether to lock Runner to current project [true/false]:
      false

      # 选择 runner 执行器,这里我们选择的是 shell
      Please enter the executor: virtualbox, docker+machine, parallels, shell, ssh, docker-ssh+machine, kubernetes, docker, docker-ssh:
      shell
      • 按顺序输入

        输入指定信息 成功创建
        输入指定信息 成功创建
      • 进一步设置

        点击编辑 选择如下选项
        编辑
  • 测试gitlab 推送

    • 这里比较麻烦我的 http 始终是没有测试推送成功过

    • windows 下关于ssh_key 始终也没能验证成功,为了赶进度,暂时跳过

    • 解决方案

      • 使用Linux 下创建 ssh-keygen -t rsa -C "admin@example.com"

        1
        2
        3
        # gitlab 默认提供的 邮箱也用它,没能验证成功邮箱,gitlab 注册页面没有在弹出,也就再没理会该问题
        git config --global user.name "Administrator"
        git config --global user.email "admin@example.com"
      • 查看并添加SSH gitlab

        1
        2
        3
        4
        5
        cd ~/.ssh/
        ls
        cat xxx.pub
        # 复制该文件内容,注意空格

      • 修改linux 下的~/.ssh/ 的权限

        1
        2
        3
        # 都执行一下
        chmod 755 ~/.ssh/
        chmod 600 ~/.ssh/id_rsa ~/.ssh/id_rsa.pub #一般执行这条就行了。
      • 寻找SSH 添加位置

        添加ssh_key
        添加ssh
      • 验证是否成功

        1
        2
        # 验证 gitlab 服务器
        ssh -T git@47.104.232.247
        • 输出

          验证是否添加成功
          验证是否添加成功
      • 尝试克隆仓库

        拉取gitlab 公共仓库
        拉取远程仓库
      • 再次测试直接添加remote 初始化本地仓库

        • 创建远程仓库

          创建远程仓库
          创建远程仓库
        • 关联仓库测试推送(第一天是没能实现管理的,一直报错是关于 not found)

          关联仓库测试推送
          关联仓库测试推送
        • windows 再次测试拉取

          未能正确解决该问题

          • 解决方案

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            # 在 ~/.ssh/config 文件中添加如下信息
            # gitlab
            Host gitlab-服务器ip 不添加端口号
            HostName gitlab-服务器ip 不添加端口号
            User root
            IdentityFile ~/.ssh/cp_id_rsa # 我这里将 linux 的 文件复制下来了

            # 命令行执行
            ssh-keygen -R gitlab服务器IP

            # 输出一下信息
            # Host 47.104.232.247 found: line 8
            C:\Users\coderitl/.ssh/known_hosts updated.
            Original contents retained as C:\Users\coderitl/.ssh/known_hosts.old


          • 测试拉取远程仓库

            Windows拉取远程仓库
            Windows终于成功拉取gitlab仓库
            • 成功解决在windows 上的免密推送

              Windows 成功推送到gitlab 仓库
              Windows成功推送到gitlab仓库
持续集成
  • 创建maven 项目,并关联gitlab 远程仓库

  • 创建.gitlab-ci.yml

    选择 CI-CD 创建.gitlab-ci.yml
    CI-CD 创建gitlab-ci.yml
    • 失败(进入流水线之后,观察到是使用http,而我已经开启了ssh)

      日志报错信息 runner类型 服务器阻塞 本地centos成功运行
      日志报错信息 runner类型 阻塞 测试任务
    • 宿主机安装java 、maven 并配置环境变量

      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
      # 先安装 wget
      yum -y install wget
      # 创建文件夹管理(Linux其实和Windows安装一样,位置首先自己得清楚)
      mkdir environment
      # 进入该目录
      cd environment
      # 下载 maven 需要注意下载的文件里面是否含有 bin 目录 ,下载3.8.4 没有出现bin目录,这里使用3.6
      wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
      # alibaba => Java(github下载很慢,建议下载到windows传输)
      wget https://github.com/alibaba/dragonwell8/releases/download/dragonwell-8.8.9_jdk8u302-ga/Alibaba_Dragonwell_8.8.9_x64_linux.tar.gz
      # 解压
      tar -zxvf apache-maven-3.6.3-bin.tar.gz
      # 进入解压后的目录
      cd apache-maven-3.6.3
      # 获取所在目录
      pwd
      # 复制好上述输出的目录

      # 编辑环境变量
      vim /etc/profile
      # 进入文件末尾 添加如下,注意匹配
      JAVA_HOME=/root/maven_3.6.3/jdk1.8.0_231
      MAVEN_HOME=/root/maven_3.6.3/apache-maven-3.6.3
      export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH

      # 是环境变量生效
      source /etc/profile

      • 检测是否安装成功

        检测安装环境是否正常
        检测安装环境是否正常
http解决连接
  • 创建访问令牌

    头像 => 设置 => 左侧(访问令牌) =>

    创建访问令牌,最后添加的是此处的令牌
    访问令牌
    创建仓库令牌
    创建仓库令牌
  • 修改连接参数

    1
    2
    3
    http:oauth:拥有可读可写的令牌@gitlab-服务器地址:端口/用户名/仓库名.git
    # Eg
    http:oauth2:xxxxxx@192.168.0.128:22/root/coder-itl.git
  • 测试

    修改连接参数
    修改连接参数
CD(Jenkins)
  • 实现持续交付持续部署

    • 官网

      https:www.jenkins.io

    • docker-compose.yml

      1
      2
      3
      4
      5
      6
      # 当前工作目录: /root/data/jenkins
      mkdir data
      chmod 777 data
      # useruid1000
      mkdir -p /var/jenkins_home
      chown -R 1000:1000 /var/jenkins_home
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      version: "3.1"
      services:
      jenkins:
      image: jenkins/jenkins
      restart: always
      container_name: jenkins
      ports:
      - 8888:8080
      - 50000:50000
      volumes:
      - ./data:/var/jenkins_home
    • 密码在jenkins 容器日志中,访问时输入

      1
      docker logs -f jenkins
      Jenkins 密码
      Jenkins密码
    • 访问

      1
      http://ip:8888/
    • 选择插件安装

      • git 系列

        git 系列选择
        git系列选择
      • ssh,publish 因为安全问题被下架

  • 配置目标服务器与Gitlab 免密登录

    • 目标服务器

      入口 SSH配置 测试链接
      入口 SSH配置 测试链接
    • 免密登录

      • 进入jenkins 容器内创建密钥

        1
        2
        3
        4
        5
        6
        7
        8
        9
        # docker ps
        docker exec -it [jenkins | 容器id] bash
        # 三次回车
        ssh-keygen -t rsa -C "email"
        # 退出容器
        exit
        # 进入容器中显示存放的目录
        cd /root/data/jenkins/data/.ssh

      • gitlab 添加SSH 生成的xxx.pub 的内容

    • Jenkins 配置maven、java(添加容器内的路径)

      1
      2
      3
      4
       # 复制环境中已经存在的文件 到 jenkins 的映射目录中
      cp -R maven/ ~/data/jenkins/data/
      cp -R java/ ~/data/jenkins/data/
      # 宿主机的映射路径
      Maven配置位置,全局配置的下面` 容器内环境位置
      容器内环境位置
  • 手动拉取gitlab 项目

    • 生成密钥

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      ssh-keygen -t rsa -C "admin@example.com" 

      # 生成 config 文件
      # gitlab
      Host ip
      HostName ip
      User root
      IdentityFile ~/.ssh/id_rsa

      # 权限
      chmod 400 ~/.ssh/id_rsa

      IdentityFile ~/.ssh/id_rsa => 这个目录不变,在 jenkins容器内生成的密钥默认放在容器内的该路径下,

    • gitlab 添加密钥

    • 测试克隆项目

      clone 一次,输入yes,二次拉取就不需要验证了
      clone
  • Jenkins 创建maven 任务

    • 全局凭证

      添加私钥
      添加私钥
    • maven

      构建选择maven
      构建选择maven
    • 配置maven 本地仓库 和 阿里云镜像

    • 构建输出

      Jenkins 成功实现
      成功实现Jenkins
    • 文件位置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      [INFO] Copying webapp resources [/var/jenkins_home/workspace/Test-CD/src/main/webapp]
      [INFO] Building war: /var/jenkins_home/workspace/Test-CD/target/gitlab-ci-1.0-SNAPSHOT.war
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 01:20 min
      [INFO] Finished at: 2022-02-17T07:40:12Z
      [INFO] ------------------------------------------------------------------------
      Finished: SUCCESS
  • 实现持续交付持续部署

    • 安装Git Parameter | Persistent

      根据版本可选择,完成后选择重启 重启(过程漫长)
      根据版本可选择 重启
    • 重新指定构建项目的方式

      • 添加参数构建

        添加参数构建 配置
        添加参数构建 选择标签
      • 修改构建

        删除初始的maven 选择为脚本shell
        删除初始的maven shell
        • 编写shell

          1
          2
          3
          4
          5
          echo $Tag
          cd /var/jenkins_home/workspace/Test-CD
          git checkout $Tag
          git pull origin $Tag
          /var/jenkins_home/maven/apache-maven-3.6.3/bin/mvn clean package
          容器内maven
          容器内maven
      • 构建后配置

    • 构建项目成功后,需要将内容发布到目标服务器

    • 修改程序代码

    • 测试

GITLAB-删除不需要的远程仓库

  • 删除位置路径

    1
    进入项目 => 点击左侧导航栏设置 => 通用 => Advanced(展开) => 下拉 => 删除(输入红色标注内容)
    • 演示

      gitlab 仓库删除
      gitlab仓库删除

Docker-快速安装

  • vim docker-install.sh

    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
    echo -e "\e[1m\e[4m\e[34minto.........................................................\e[0m\n"

    echo -e "\e[1m\e[4m\e[34minto remove docker...........\e[0m"
    sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine

    echo -e "\e[1m\e[4m\e[34minto download utils...........\e[0m\n"
    yum install -y yum-utils device-mapper-persistent-data lvm2

    echo -e "\e[1m\e[4m\e[34minto add repo...........\e[0m\n"
    sudo yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo

    echo -e "\e[1m\e[4m\e[34minto yum makecache...........\e[0m\n"
    yum makecache fast

    echo -e "\e[1m\e[4m\e[34minto install docker-ce...........\e[0m\n"
    sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

    echo -e "\e[1m\e[4m\e[34minto config daemon.json...........\e[0m\n"
    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
    "registry-mirrors":[
    "https://eyy45bvx.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com",
    "https://registry.aliyuncs.com",
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn"
    ]
    }
    EOF

    echo -e "\e[1m\e[4m\e[34minto daemon-reload...........\e[0m\n"
    sudo systemctl daemon-reload

    echo -e "\e[1m\e[4m\e[34minto restart docker...........\e[0m\n"
    sudo systemctl restart docker
    echo -e "\e[1m\e[4m\e[34mend.........................................................\e[0m\n"