Bootstrap

Docker 高级篇

第一章 Docker复杂安装详说


1.1 安装mysql主从复制

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

    docker run -p 3307:3306 --privileged=true --name mysql-master \
     -v /cjz/docker/mysql-master/log:/var/log/mysql \
     -v /cjz/docker/mysql-master/data:/var/lib/mysql \
     -v /cjz/docker/mysql-master/conf:/etc/mysql/conf.d \
     -e MYSQL_ROOT_PASSWORD=root  \
     -d mysql:5.7
    
  2. 进入/cjz/docker/mysql-master/conf新建my.cnf

     [client]
     default_character_set=utf8
     [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
     collation_server = utf8_general_ci
     character_set_server = utf8
    
  3. 修改完配置后重启master实例

    docker restart mysql-master

  4. 进入mysql-master容器,链接mysql

    docker exec -it mysql-master /bin/bash

    mysql -uroot -proot

  5. master容器实例内创建数据同步用户

    CREATE USER 'slave'@'%' IDENTIFIED BY '123456';

    GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';

  6. 新建从服务器容器实例3308

     docker run -p 3308:3306 --privileged=true --name mysql-slave\
     -v /cjz/docker/mysql-slave/log:/var/log/mysql \
     -v /cjz/docker/mysql-slave/data:/var/lib/mysql \
     -v /cjz/docker/mysql-slave/conf:/etc/mysql/conf.d \
     -e MYSQL_ROOT_PASSWORD=root  \
     -d mysql:5.7
    
  7. 进入/cjz/docker/mysql-slave/conf目录下新建my.cnf

     [client]
     default_character_set=utf8
     [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
     collation_server = utf8_general_ci
     character_set_server = utf8
    
  8. 修改完配置后重启slave实例

    docker restart mysql-slave

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

    show master status;

  10. 进入mysql-slave容器

    docker exec -it mysql-slave /bin/bash

    mysql -uroot -proot

  11. 在从数据库中配置主从复制

    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;

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

    在这里插入图片描述

  12. 在从数据库中查看主从同步状态
    show slave status \G;
    在这里插入图片描述

  13. 在从数据库中开启主从同步
    start slave;
    在这里插入图片描述

  14. 查看从数据库状态发现已经同步
    在这里插入图片描述

  15. 主从测试

    主机新建库、使用库、新建表、插入数据OK
    从机查看记录ok

1.2 安装redis集群(哈希槽分区进行亿级数据存储)

1.2.1 相关面试题

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

  单机单台100%不可能,肯定是分布式存储,用redis如何落地?

  上述问题阿里P6~P7工程案例和场景设计类必考题目,一般业界有3种解决方案

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

      优点:简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。
      缺点:原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌。

  2. 一致性哈希算法分区

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

    1. 算法构建一致性哈希环
         一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。
         它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模。而一致性Hash算法是对232取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-232-1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到232-1,也就是说0点左侧的第一个点代表232-1, 0和232-1在零点中方向重合,我们把这个由232个点组成的圆环称为Hash环。
      在这里插入图片描述

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

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

         一致性哈希算法的容错性:
         假设Node C宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据,并且这些数据会转移到D进行存储。
      在这里插入图片描述    一致性哈希算法的扩展性
         数据量增加了,需要增加一台节点NodeX,X的位置在A和B之间,那收到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可,不会导致hash取余全部数据重新洗牌。
      在这里插入图片描述
      缺点一致性哈希算法的数据倾斜问题
         一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器:
      在这里插入图片描述

  3. 哈希槽分区
      解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。
    在这里插入图片描述
      槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。

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

      一个集群只能有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 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上。
    在这里插入图片描述

1.2.2 集群搭建步骤

https://editor.csdn.net/md/?articleId=125790214

第二章 Dockerfile解析


2.1 是什么

  Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
在这里插入图片描述
官网

2.2 DockerFile构建过程解析

2.2.1 Dockerfile内容基础知识

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

2.2.2 Docker执行Dockerfile的大致流程

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

2.2.3 Dockerfile 常用保留字指令

保留字说明
FROM拉取基础镜像,作为模板,然后再在其上进行指令操作,构建自己的镜像
MAINTAINER镜像维护者的姓名和邮箱地址
COPY镜拷贝目录或文件进镜像,不自动处理url与tar压缩包 COPY src dest
ADD将宿主机中某个目录下的文件拷贝进镜像,并且会自动处理url以及解压tar压缩包
RUN容器构建时执行的命令包括:shell命令与exec命令像
CMD容器构建完毕后运行的指令,同样包括shell命令与exec命令,一个Dockerfile中只有最后一个CMD指令会被运行,也会被docker run后面的参数替换
ENV配置环境变量
EXPOSE当前容器对外暴露的端口
VOLUME容器卷,用于数据保存和持久化工作。类似于linux的镜像挂载
ENTRYPOINT与CMD指令相似,但是不会被docker run后面的参数给替换掉,而是会被当做参数更新原有参数(与CMD指令同时使用,此时CMD指令起到的作用就是变换参数)
WORKDIR指定终端登录容器的默认工作目录
USER指定登录容器的用户,默认root,一般不怎么使用

需要注意的命令

  1. CMD
      Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
  2. CMDRUN的区别
      CMD是在docker run 时运行
      RUN是在 docker build时运行。
  3. ENTRYPOINT
      ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。
    当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成
      如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
    在这里插入图片描述

2.3 案例

2.3.1 自定义mycentosjava8

  1. 要求
    Centos7镜像具备vim+ifconfig+jdk8

    JDK下载镜像地址

    https://www.oracle.com/java/technologies/downloads/#java8

    在这里插入图片描述

  2. 编写

    在这里插入图片描述

    FROM centos:7
    MAINTAINER cjz<[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-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
    
  3. 构建

    docker build -t 新镜像名字:TAG .
    

    在这里插入图片描述

2.4 虚悬镜像

  仓库名、标签都是的镜像,俗称dangling image
在这里插入图片描述
  删除命令

  docker images prune
在这里插入图片描述

第三章 Docker 微服务实战


3.1 新建一个普通微服务模块

  1. pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.6</version>
            <relativePath/>
        </parent>
    
        <groupId>com.atguigu.docker</groupId>
        <artifactId>docker_boot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <junit.version>4.12</junit.version>
            <log4j.version>1.2.17</log4j.version>
            <lombok.version>1.16.18</lombok.version>
            <mysql.version>5.1.47</mysql.version>
            <druid.version>1.1.16</druid.version>
            <mapper.version>4.1.5</mapper.version>
            <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
        </properties>
    
        <dependencies>
            <!--SpringBoot通用依赖模块-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--test-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
            </plugins>
        </build>
    
    </project>
     
     
    
    
  2. yml 文件

    server:
      port: 6001
    
  3. 主启动类

    package com.atguigu.docker;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DockerBootApplication
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DockerBootApplication.class, args);
        }
    
    }
     
     
    
    
  4. 业务类

    package com.atguigu.docker.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.UUID;
    
    
    @RestController
    public class OrderController
    {
        @Value("${server.port}")
        private String port;
    
        @RequestMapping("/order/docker")
        public String helloDocker()
        {
            return "hello docker"+"\t"+port+"\t"+ UUID.randomUUID().toString();
        }
    
        @RequestMapping(value ="/order/index",method = RequestMethod.GET)
        public String index()
        {
            return "服务端口号: "+"\t"+port+"\t"+UUID.randomUUID().toString();
        }
    }
    
    

3.2 通过dockerfile发布微服务部署到docker容器

  1. IDEA工具里面搞定jar包
    在这里插入图片描述

  2. 编写Dockerfile

    # 基础镜像使用java
    FROM java:8
    # 作者
    MAINTAINER zzyy
    # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
    VOLUME /tmp
    # 将jar包添加到容器中并更名为zzyy_docker.jar
    ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
    # 运行jar包
    RUN bash -c 'touch /zzyy_docker.jar'
    ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
    #暴露6001端口作为微服务
    EXPOSE 6001
    
  3. 将微服务jar包和Dockerfile文件上传到同一个目录下/mydocker
    在这里插入图片描述

  4. 构建镜像

    docker build -t zzyy_docker:1.6 .

    在这里插入图片描述

  5. 运行容器

    docker run -d -p 6001:6001 zzyy_docker:1.6

    在这里插入图片描述

第四章 Docker 网络


4.1 是什么

  1. docker不启动,默认网络情况
    在这里插入图片描述

  2. docker 启动后,网络情况
    在这里插入图片描述

  3. 查看docker网络模式命令
    docker network ls

    默认创建3大网络模式

    在这里插入图片描述

4.2 常用基本命令

命令说明
docker network --help全部命令说明
docker network ls查看网络
docker network inspect XXX网络名字查看网络源数据
docker network rm XXX网络名字删除网络
docker network create XXX网络名字创建网络

4.3 有什么用

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

4.4 网络模式

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

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

      docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址

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

    在这里插入图片描述

    代码案例

    docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8

    docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8

    在这里插入图片描述

  2. host模式

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

      容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口
    在这里插入图片描述
       docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
    在这里插入图片描述
      docker启动时指定–network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
    并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。

  3. none模式

      禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)

       docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8

  4. container模式

      新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
       docker run -it --name alpine1 alpine /bin/sh
       docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
    在这里插入图片描述

  5. 自定义网络

       自定义网络之前通过服务名容器之间是ping不通的
    在这里插入图片描述
    在这里插入图片描述
    新建自定义网络

    docker network create cjz_network

    在这里插入图片描述
    新建容器加入上一步新建的自定义网络

    docker run -d -p 8081:8080 --network cjz_network --name tomcat81 billygoo/tomcat8-jdk8

    docker run -d -p 8082:8080 --network cjz_network --name tomcat82 billygoo/tomcat8-jdk8

    互相ping测试

    在这里插入图片描述
    在这里插入图片描述

自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

第五章 Docker-compose容器编排


5.1 是什么

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

5.2 能干嘛

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

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

5.3 安装

  1. 官方资料

    官方文档

    官方下载

  2. 安装步骤

    curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose
    #测试
    docker-compose --version
    
  3. 卸载
    sudo rm /usr/local/bin/docker-compose

5.4 核心概念

  1. 一文件

    docker-compose.yml

  2. 两要素

    服务(service):一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
    工程:由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

5.5 Compose使用的三个步骤

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

5.6 Compose常用命令

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

5.7 Compose编排微服务

5.7.1 改造之前的docker_boot微服务

在这里插入图片描述

  1. pow文件

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.2.RELEASE</version>
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <junit.version>4.12</junit.version>
            <log4j.version>1.2.17</log4j.version>
            <lombok.version>1.16.18</lombok.version>
            <mysql.version>5.1.47</mysql.version>
            <druid.version>1.1.16</druid.version>
            <mapper.version>4.1.5</mapper.version>
            <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!--guava Google 开源的 Guava 中自带的布隆过滤器-->
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>23.0</version>
            </dependency>
            <!-- redisson -->
            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.13.4</version>
            </dependency>
            <!--SpringBoot通用依赖模块-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--swagger2-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.9.2</version>
            </dependency>
            <!--SpringBoot与Redis整合依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <!--springCache-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-cache</artifactId>
            </dependency>
            <!--springCache连接池依赖包-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
            <!-- jedis -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>3.1.0</version>
            </dependency>
            <!--Mysql数据库驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!--SpringBoot集成druid连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--mybatis和springboot整合-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
    
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.10</version>
            </dependency>
            <!--通用基础配置junit/devtools/test/log4j/lombok/hutool-->
            <!--hutool-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
            <!--persistence-->
            <dependency>
                <groupId>javax.persistence</groupId>
                <artifactId>persistence-api</artifactId>
                <version>1.0.2</version>
            </dependency>
            <!--通用Mapper-->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper</artifactId>
                <version>${mapper.version}</version>
            </dependency>
    
        </dependencies>
    
        <build>
    
            <plugins>
    
                <plugin>
    
                    <groupId>org.springframework.boot</groupId>
    
                    <artifactId>spring-boot-maven-plugin</artifactId>
    
                    <version>2.0.0.RELEASE</version>
    
                    <executions>
    
                        <execution>
    
                            <goals>
    
                                <goal>repackage</goal>
    
                            </goals>
    
                        </execution>
    
                    </executions>
    
                </plugin>
    
            </plugins>
    
        </build>
    
  2. yml文件

    server:
      port: 6001
    
    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.80.131:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: 123456
        druid:
          test-while-idle: false
      redis:
        database: 0
        host: 192.168.80.131
        port: 6379
        password: 123456
        lettuce:
          pool:
            max-active: 8
            max-wait: -1ms
            max-idle: 8
            min-idle: 0
      swagger2:
        enabled: true
    
    
    mybatis:
      mapper-locations: classpath:mapper/*.xml
      type-aliases-package: com.atguigu.docker.entities
    
    
  3. 主启动类

    package com.docker.test;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import tk.mybatis.spring.annotation.MapperScan;
    
    
    @SpringBootApplication
    @MapperScan("com.docker.test.mapper") //import
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    }
    
  4. config

    package com.docker.test.config;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.io.Serializable;
    
    @Configuration
    @Slf4j
    public class RedisConfig {
        /**
         * @param lettuceConnectionFactory
         * @return
         *
         * redis序列化的工具配置类,下面这个请一定开启配置
         * 127.0.0.1:6379> keys *
         * 1) "ord:102"  序列化过
         * 2) "\xac\xed\x00\x05t\x00\aord:102"   野生,没有序列化过
         */
        @Bean
        public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
        {
            RedisTemplate<String,Serializable> redisTemplate = new RedisTemplate<>();
    
            redisTemplate.setConnectionFactory(lettuceConnectionFactory);
            //设置key序列化方式string
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            //设置value的序列化方式json
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    
            redisTemplate.afterPropertiesSet();
    
            return redisTemplate;
        }
    
    }
    
    
    package com.docker.test.config;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        @Value("${spring.swagger2.enabled}")
        private Boolean enabled;
    
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .enable(enabled)
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("com.docker.test")) //你自己的package
                    .paths(PathSelectors.any())
                    .build();
        }
    
        public ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("尚硅谷Java大厂技术"+"\t"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
                    .description("docker-compose")
                    .version("1.0")
                    .termsOfServiceUrl("https://www.atguigu.com/")
                    .build();
        }
    }
    
    
  5. entity

    package com.docker.test.entity;
    
    import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.util.Date;
    
    @Table(name = "t_user")
    public class User
    {
        @Id
        @GeneratedValue(generator = "JDBC")
        private Integer id;
    
        /**
         * 用户名
         */
        private String username;
    
        /**
         * 密码
         */
        private String password;
    
        /**
         * 性别 0=女 1=男
         */
        private Byte sex;
    
        /**
         * 删除标志,默认0不删除,1删除
         */
        private Byte deleted;
    
        /**
         * 更新时间
         */
        @Column(name = "update_time")
        private Date updateTime;
    
        /**
         * 创建时间
         */
        @Column(name = "create_time")
        private Date createTime;
    
        /**
         * @return id
         */
        public Integer getId() {
            return id;
        }
    
        /**
         * @param id
         */
        public void setId(Integer id) {
            this.id = id;
        }
    
        /**
         * 获取用户名
         *
         * @return username - 用户名
         */
        public String getUsername() {
            return username;
        }
    
        /**
         * 设置用户名
         *
         * @param username 用户名
         */
        public void setUsername(String username) {
            this.username = username;
        }
    
        /**
         * 获取密码
         *
         * @return password - 密码
         */
        public String getPassword() {
            return password;
        }
    
        /**
         * 设置密码
         *
         * @param password 密码
         */
        public void setPassword(String password) {
            this.password = password;
        }
    
        /**
         * 获取性别 0=女 1=男
         *
         * @return sex - 性别 0=女 1=男
         */
        public Byte getSex() {
            return sex;
        }
    
        /**
         * 设置性别 0=女 1=男
         *
         * @param sex 性别 0=女 1=男
         */
        public void setSex(Byte sex) {
            this.sex = sex;
        }
    
        /**
         * 获取删除标志,默认0不删除,1删除
         *
         * @return deleted - 删除标志,默认0不删除,1删除
         */
        public Byte getDeleted() {
            return deleted;
        }
    
        /**
         * 设置删除标志,默认0不删除,1删除
         *
         * @param deleted 删除标志,默认0不删除,1删除
         */
        public void setDeleted(Byte deleted) {
            this.deleted = deleted;
        }
    
        /**
         * 获取更新时间
         *
         * @return update_time - 更新时间
         */
        public Date getUpdateTime() {
            return updateTime;
        }
    
        /**
         * 设置更新时间
         *
         * @param updateTime 更新时间
         */
        public void setUpdateTime(Date updateTime) {
            this.updateTime = updateTime;
        }
    
        /**
         * 获取创建时间
         *
         * @return create_time - 创建时间
         */
        public Date getCreateTime() {
            return createTime;
        }
    
        /**
         * 设置创建时间
         *
         * @param createTime 创建时间
         */
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    }
    
    
    
    package com.docker.test.entity;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.Date;
    
    /**
     * @Author cjz
     * @Date 2022/7/18 21:08
     */
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @ApiModel(value = "用户信息")
    public class UserDTO {
    
        @ApiModelProperty(value = "用户ID")
        private Integer id;
    
        @ApiModelProperty(value = "用户名")
        private String username;
    
        @ApiModelProperty(value = "密码")
        private String password;
    
        @ApiModelProperty(value = "性别 0=女 1=男 ")
        private Byte sex;
    
        @ApiModelProperty(value = "删除标志,默认0不删除,1删除")
        private Byte deleted;
    
        @ApiModelProperty(value = "更新时间")
        private Date updateTime;
    
        @ApiModelProperty(value = "创建时间")
        private Date createTime;
    
        /**
         * @return id
         */
        public Integer getId() {
            return id;
        }
    
        /**
         * @param id
         */
        public void setId(Integer id) {
            this.id = id;
        }
    
        /**
         * 获取用户名
         *
         * @return username - 用户名
         */
        public String getUsername() {
            return username;
        }
    
        /**
         * 设置用户名
         *
         * @param username 用户名
         */
        public void setUsername(String username) {
            this.username = username;
        }
    
        /**
         * 获取密码
         *
         * @return password - 密码
         */
        public String getPassword() {
            return password;
        }
    
        /**
         * 设置密码
         *
         * @param password 密码
         */
        public void setPassword(String password) {
            this.password = password;
        }
    
        /**
         * 获取性别 0=女 1=男
         *
         * @return sex - 性别 0=女 1=男
         */
        public Byte getSex() {
            return sex;
        }
    
        /**
         * 设置性别 0=女 1=男
         *
         * @param sex 性别 0=女 1=男
         */
        public void setSex(Byte sex) {
            this.sex = sex;
        }
    
        /**
         * 获取删除标志,默认0不删除,1删除
         *
         * @return deleted - 删除标志,默认0不删除,1删除
         */
        public Byte getDeleted() {
            return deleted;
        }
    
        /**
         * 设置删除标志,默认0不删除,1删除
         *
         * @param deleted 删除标志,默认0不删除,1删除
         */
        public void setDeleted(Byte deleted) {
            this.deleted = deleted;
        }
    
        /**
         * 获取更新时间
         *
         * @return update_time - 更新时间
         */
        public Date getUpdateTime() {
            return updateTime;
        }
    
        /**
         * 设置更新时间
         *
         * @param updateTime 更新时间
         */
        public void setUpdateTime(Date updateTime) {
            this.updateTime = updateTime;
        }
    
        /**
         * 获取创建时间
         *
         * @return create_time - 创建时间
         */
        public Date getCreateTime() {
            return createTime;
        }
    
        /**
         * 设置创建时间
         *
         * @param createTime 创建时间
         */
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", sex=" + sex +
                    '}';
        }
    
    }
    
    
  6. mapper

    package com.docker.test.mapper;
    
    import com.docker.test.entity.User;
    import tk.mybatis.mapper.common.Mapper;
    
    
    
    public interface UserMapper extends Mapper<User> {
    }
    
    
  7. service

    package com.docker.test.service;
    
    import com.docker.test.entity.User;
    import com.docker.test.mapper.UserMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    
    @Service
    @Slf4j
    public class UserService {
        public static final String CACHE_KEY_USER = "user:";
    
        @Resource
        private UserMapper userMapper;
        @Resource
        private RedisTemplate redisTemplate;
    
        /**
         * addUser
         * @param user
         */
        public void addUser(User user)
        {
            //1 先插入mysql并成功
            int i = userMapper.insertSelective(user);
    
            if(i > 0)
            {
                //2 需要再次查询一下mysql将数据捞回来并ok
                user = userMapper.selectByPrimaryKey(user.getId());
                //3 将捞出来的user存进redis,完成新增功能的数据一致性。
                String key = CACHE_KEY_USER+user.getId();
                redisTemplate.opsForValue().set(key,user);
            }
        }
    
        /**
         * findUserById
         * @param id
         * @return
         */
        public User findUserById(Integer id)
        {
            User user = null;
            String key = CACHE_KEY_USER+id;
    
            //1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql
            user = (User) redisTemplate.opsForValue().get(key);
    
            if(user == null)
            {
                //2 redis里面无,继续查询mysql
                user = userMapper.selectByPrimaryKey(id);
                if(user == null)
                {
                    //3.1 redis+mysql 都无数据
                    //你具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redis
                    return user;
                }else{
                    //3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率
                    redisTemplate.opsForValue().set(key,user);
                }
            }
            return user;
        }
    
    }
    
    
  8. controller

    package com.docker.test.TesControlelr;
    
    import cn.hutool.core.util.IdUtil;
    import com.docker.test.entity.User;
    import com.docker.test.service.UserService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.util.Random;
    
    
    @Api("用户User接口")
    @RestController
    @Slf4j
    public class TestController {
    
        @Resource
        private UserService userService;
    
        @ApiOperation("数据库新增3条记录")
        @RequestMapping(value = "/user/add",method = RequestMethod.POST)
        public void addUser()
        {
            for (int i = 1; i <=3; i++) {
                User user = new User();
    
                user.setUsername("zzyy"+i);
                user.setPassword(IdUtil.simpleUUID().substring(0,6));
                user.setSex((byte) new Random().nextInt(2));
    
                userService.addUser(user);
            }
        }
    
    
    }
    
    
  9. mapper

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.docker.test.mapper.UserMapper">
    
        <resultMap id="BaseResultMap" type="com.docker.test.entity.User">
            <!--
              WARNING - @mbg.generated
            -->
            <id column="id" jdbcType="INTEGER" property="id" />
            <result column="username" jdbcType="VARCHAR" property="username" />
            <result column="password" jdbcType="VARCHAR" property="password" />
            <result column="sex" jdbcType="TINYINT" property="sex" />
            <result column="deleted" jdbcType="TINYINT" property="deleted" />
            <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
            <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
        </resultMap>
    </mapper>
    

5.7.2 将微服务构建成镜像

  1. 编写Dockerfile

    # 基础镜像使用java
    FROM java:8
    # 作者
    MAINTAINER cjz
    # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
    VOLUME /tmp
    # 将jar包添加到容器中并更名为zzyy_docker.jar
    ADD Docker_boot-1.0-SNAPSHOT.jar cjz_docker.jar
    # 运行jar包
    RUN bash -c 'touch /cjz_docker.jar'
    ENTRYPOINT ["java","-jar","/cjz_docker.jar"]
    #暴露6001端口作为微服务
    EXPOSE 6001
     
    
  2. 构建镜像

    docker build -t cjz_docker:1.6 .

5.7.3 使用Compose

  1. 编写docker-compose文件

    version: "3"
     
    services:
      microService:
        image: cjz_docker:1.6
        container_name: ms01
        ports:
          - "6001:6001"
        volumes:
          - /cjz/dockerCompose/microService:/data
        networks: 
          - atguigu_net 
        depends_on: 
          - redis
          - mysql
     
      redis:
        image: redis:6.0.8
        ports:
          - "6379:6379"
        volumes:
          - /cjz/docker/redis/redis.conf:/etc/redis/redis.conf
          - /cjz/docker/redis/data:/data
        networks: 
          - atguigu_net
        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: 'zzyy'
          MYSQL_PASSWORD: 'zzyy123'
        ports:
           - "3306:3306"
        volumes:
           - /cjz/dockerCompose/mysql/db:/var/lib/mysql
           - /cjz/dockerCompose/mysql/my.cnf:/etc/my.cnf
           - /cjz/dockerCompose/mysql/init:/docker-entrypoint-initdb.d
        networks:
          - atguigu_net
        command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
     
    networks: 
       atguigu_net: 
     
    
    
  2. 在dokcer-compose.yml文件当前目录执行docker-compose

    docker-compose up -d

  3. 进入mysql容器实例并新建库db2021+新建表t_user

    docker exec -it 容器实例id /bin/bash
    mysql -uroot -p
    create database db2021;
    use db2021;
    CREATE TABLE `t_user` (
      `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
      `username` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
      `password` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '密码',
      `sex` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
      `deleted` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
      `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
      `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      PRIMARY KEY (`id`)
    ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
    

    访问 http://localhost:你的微服务端口/swagger-ui.html#/ 测试通过

第六章 Docker 轻量级可视化工具Portainer


6.1 是什么

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

6.2 安装

  1. 官网

    https://www.portainer.io/

  2. 安装步骤

    安装命令

    docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /cjz/docker/portainer_data:/data portainer/portainer
    

    第一次登录需创建admin 访问路径 IP:9000

    在这里插入图片描述
    在这里插入图片描述

第七章 Docker容器监控之 CAdvisor+lnfluxDB+Granfana


7.1 是什么

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

  1. CAdvisor
      CAdvisor是Google开源的容器资源监控和性能分析工具,它是专门为容器而生。同时提供了WEB页面用于查看容器的实时运行状态。CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过,CAvisor提供了很多数据集成接口,支持influxdb、redis\kafka、ES等,可以对应配置将监控数据存储起来

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

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

      InfluxDB主要功能:
      基于时间序列,支持与时间有关的相关函数(如最大、最小、求和等);
      可度量性:你可以实时对大量数据进行计算;·
      基于事件:它支持任意的事件数据;

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

7.2 compose容器编排,一套带走

  1. 新建目录
    在这里插入图片描述

  2. 新建3件套组合docker-compose.ym文件

    version: '3.1'
     
    volumes:
      grafana_data: {}
     
    services:
     influxdb:
      container_name: influxdb
      image: tutum/influxdb:0.9
      restart: always
      environment:
        - PRE_CREATE_DB=cadvisor
      ports:
        - "8083:8083"
        - "8086:8086"
      volumes:
        - ./data/influxdb:/data
      networks:
        - cignet
     
     cadvisor:
      image: google/cadvisor
      container_name: cadvisor
      links:
        - influxdb:influxsrv
      command: 
        - -storage_driver=influxdb 
        - -storage_driver_db=cadvisor 
        - -storage_driver_host=influxsrv:8086
      restart: always
      privileged: true
      ports:
        - "8080:8080"
      volumes:
        - /:/rootfs:ro
        - /var/run:/var/run:rw
        - /sys:/sys:ro
        - /var/lib/docker/:/var/lib/docker:ro
      networks:
        - cignet
     
     grafana:
      container_name: 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
      networks:
        - cignet
    
    
    networks: 
      cignet: 
        driver: bridge    
    
    
    
  3. 启动docker-compose文件

    docker-compose up

    在这里插入图片描述

  4. 测试

      浏览cAdvisor收集服务 http:ip:8080/

      第一次访问慢,请稍等,cadvisor也有基础的图形展现功能,这里主要用它来作数据采集

    在这里插入图片描述

      浏览influxdb存储服务,http://ip:8083/
    在这里插入图片描述
      浏览grafana展现服务,http://ip:3000

      默认帐户密码(admin/admin)
    在这里插入图片描述

    配置步骤

    1. 配置数据源
      在这里插入图片描述
    2. 选择influxdb数据源
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      3.配置面板panel
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
;