当前位置: 首页 > news >正文

Docker-高级使用

前言

书接上文Docker-初级安装及使用_用docker安装doccano-CSDN博客,我们讲解了Docker的基本操作,下面我们讲解的是高级使用,请大家做好准备!

  • 大家如果是从初级安装使用过来的话,建议把之前镜像和搭载的容器数据卷里面文件数据都清掉,再进行下面操作,不操作也可

    • 如果删除的话,记得也把/etc/my.cnf的数据库文件一起删掉

      find / -name my.cnf   --查找rm $(find / -name my.cnf)  --删除
      
  • 基于docker(26.1.4)版本演示

MySql主从搭建

有了docker以后,我们的主从搭建也会变得相当简单,我们使用5.7版本演示,共有如下几步。

  1. 新建主服务器实例3307端口
  2. 进入/mydir/mysql/master/conf目录下新建my.cnf文件
  3. 修改完配置后重启master实例
  4. 进入mysql-master容器
  5. master容器实例内创建数据同步用户
  6. 新建从服务器实例3308
  7. 进入mydir/mysql/slave/conf目录下新建my.cnf
  8. 修改完配置后重启slave实例
  9. 在主数据库中查看主从同步状态
  10. 进入mysql-slave容器
  11. 在从数据库中配置主从复制
  12. 在从数据库中查看主从同步状态
  13. 在从数据库中开启主从同步
  14. 查看从数据库状态发现已经同步
  15. 主从复制测试

1.新建主服务器实例3307端口

  • docker镜像拉取我这里就不写了,演示版本为5.7

  • 虽然我在基础篇写过好几遍了,但是为了避免大家忘记,我这里从写以下,同时回顾回顾。参数讲解:

    • -d:后台启动

    • -p 3307:3306:宿主机3307端口映射到容器内的3306端口

    • --name mysql-master:定义容器名称为mysql-master

    • -v /mydir/mysql/master/log:/var/log/mysql:搭建容器数据卷映射,将log文件映射出来宿主机目录中,:前面为宿主机目录地址,后面为容器目录地址

    • -v /mydir/mysql/master/data:/var/lib/mysql:搭建容器数据卷映射,将数据文件映射出来宿主机目录中

    • -v /mydir/mysql/master/conf:/etc/mysql:搭建容器数据卷映射,将启动配置文件文件映射出来宿主机目录中

    • -e MYSQL_ROOT_PASSWORD=admin:设置环境变量,我这里是设置mysql的密码

    • mysql:5.7:镜像名:版本号

  • 如果大家启动以后执行ps命令报如下错了,就按照前言中的,把my.cnf文件全部清掉

    mysqld failed while attempting to check config 	command was: mysqld --verbose --help --log-bin-index=/tmp/tmp.Im9pj3bIY7 	mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 2 - No such file or directory) mysqld: [ERROR] Fatal error in defaults handling. Program aborted!
    
docker run -d -p 3307:3306 --name mysql-master -v /mydir/mysql/master/log:/var/log/mysql -v /mydir/mysql/master/data:/var/lib/mysql -v /mydir/mysql/master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=admin mysql:5.7

在这里插入图片描述

2.进入/mydir/mysql/master/conf目录下新建my.cnf文件

[mysqld]
## 设置 server_id,同一局域网中需要唯一
server_id=1
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能 mall-mysql-bin表示日志名称,例如,在一个服务器上运行多个 MySQL 实例,每个实例对应不同的业务系统(像商城系统、物流系统等)生成的二进制日志文件名称就会类似 mall-mysql-bin.000001、mall-mysql-bin.000002 等,其中 .000001、.000002 是递增的编号,用来区分不同的日志文件
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# 字符集设置
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
# 进入文件夹
cd /mydir/mysql/master/conf# 创建my.cnf文件,并写入如上内容
vim my.cnf# 保存并退出
:wq

3.修改完配置后重启master实例

docker restart mysql-master

4.进入mysql-master容器

# 进入容器
docker exec -it mysql-master /bin/bash# 打开mysql客户端
mysql -uroot -p
# 输入密码 admin(启动命令定义的)

在这里插入图片描述

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

创建用户命令

  • 创建用户slave,并指定密码为123456

赋予权限命令

  • GRANT 关键字
    • GRANT是 MySQL 中用于授予用户特定权限的关键字。使用这个关键字可以指定用户能够执行的操作以及操作的范围。
  • 权限列表
    • REPLICATION SLAVE:此权限允许用户连接到主服务器并接收二进制日志事件,是配置 MySQL 主从复制时从服务器必须具备的权限。从服务器借助该权限才能从主服务器获取二进制日志,从而实现数据同步。
    • REPLICATION CLIENT:该权限允许用户查看主服务器和从服务器的复制状态信息。拥有此权限的用户可以使用 SHOW MASTER STATUSSHOW SLAVE STATUS 等命令来查看复制相关的状态。
  • ON *.*
    • ON关键字用于指定权限作用的范围,*.* 表示权限适用于所有数据库的所有表。也就是说,被授予权限的用户在所有数据库和表上都具备 REPLICATION SLAVEREPLICATION CLIENT 权限。
  • TO 'slave'@'%'
    • 'slave':这是要授予权限的用户名,表明要为名为 slave 的用户授予指定的权限。
    • '%':代表用户可以从任意主机连接到 MySQL 服务器。如果将 % 替换为具体的 IP 地址或主机名,那么该用户就只能从指定的主机连接到 MySQL 服务器。
# 创建mysql从数据库用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 赋予用户权限
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';

6.新建从服务器实例3308

docker run -d -p 3308:3306 --name mysql-slave -v /mydir/mysql/slave/log:/var/log/mysql -v /mydir/mysql/slave/data:/var/lib/mysql -v /mydir/mysql/slave/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=admin mysql:5.7

在这里插入图片描述

7.进入mydir/mysql/slave/conf目录下新建my.cnf

[mysqld]
## 设置 server_id,同一局域网中需要唯一
server_id=2
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能 mall-mysql-slave1-bin表示日志名称,例如,在一个服务器上运行多个 MySQL 实例,每个实例对应不同的业务系统(像商城系统、物流系统等)生成的二进制日志文件名称就会类似 mall-mysql-slave1-bin.000001、mall-mysql-slave1-bin.000002 等,其中 .000001、.000002 是递增的编号,用来区分不同的日志文件
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# 字符集设置
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
# 进入文件夹
cd /mydir/mysql/slave/conf# 创建my.cnf文件,并写入如上内容
vim my.cnf# 保存并退出
:wq

8.修改完配置后重启slave实例

docker restart mysql-slave

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

# 进入容器
docker exec -it mysql-master /bin/bash# 打开mysql客户端
mysql -uroot -p
# 输入密码 admin(启动命令定义的)# 查看binlog文件
show master status

在这里插入图片描述

10.进入mysql-slave容器

docker exec -it mysql-slave bash# 进入mysql cli
mysql -uroot -p 
# 输入密码,我这里是admin(启动容器命令中有)

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

change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='第九步图片中File对应的值(我这里是 mall-mysql-bin.000001)', master_log_pos=第九步图中Positon对应的值(我这里是 962), master_connect_retry=30;## 如下是我的命令,每个人ip、文件名、Postion可能不一样,自行替换
change master to master_host='192.168.71.111', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=962, master_connect_retry=30;

在这里插入图片描述

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

我这里列举下图几个重要的讲解

  • Master_Host:主数据库的IP地址
  • Master_Port:主数据库的运行端口
  • Master_User:主数据库创建的用于同步数据的用户账号
  • Master_Log_File:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数
  • Master_Log_Pos:指定从数据库从那个位置开始复制数据,通过查看主数据的状态,获取Position参数
  • Master_Connect_Retry:连接失败重试的时间间隔,单位为秒

看见如下两个属性值都为No表示同步还未开始

在这里插入图片描述

# 以下命令在从数据库中执行查看
show slave status \G;

在这里插入图片描述

13.在从数据库中开启主从同步

start slave;

在这里插入图片描述

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

show slave status \G;

在这里插入图片描述

15.主从复制测试

## 主数据中 master
-- 创建库
create database mydb;
-- 使用库
use mydb;
-- 创建表
create table user(id int, name varchar(50));
-- 新建数据
insert into user values(1, 'zhang3');
-- 查询数据
select * from user;## 从数据中 slave
# 使用库
use mydb;
# 查询数据
select * from user;

在这里插入图片描述

Redis主从搭建

  • Redis主从搭建共有三套方案,下面我们会讲到
    1. 哈希取余分区
    2. 一致性哈希算法分区
    3. 哈希槽分区

1、主从方案分析与选择

1.1、哈希取余分区

  • 假设我们3台机器上构成一个集群,用户每次读写操作都是根据公式:hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上,存取数据都会使用这个算法
  • 好处:简单,粗暴,实现起来容易,适合小厂使用
  • 缺点:当进行扩容或缩容时,映射关系需要重新进行计算Hash(key)/3可能会变成Hash(key)/?此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变的不可控

在这里插入图片描述

1.2、一致性哈希算法分区

  • 圆环形成

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

      在这里插入图片描述

  • 集群映射

    • 然后将集群中的各个IP节点映射到环上的某一个位置,将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。

    • 假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后再环空间的位置如下

      在这里插入图片描述

  • 键值存储

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

      在这里插入图片描述

  • 优缺点

    • 优点:增加了容错性,当删除/停用一个节点时,不会影响其他节点的读取。并且新增时一个节点影响的数据很少

    • 缺点:当节点少时,很容易造成数据倾斜的问题

      在这里插入图片描述

1.3、哈希槽分区

  • 能干什么

    • 可以解决上面的均匀分配的问题,在数据和节点之间又加入了一层,把这层成为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的时槽,槽里放的时数据
    • 槽解决的时粒度问题,相当于把粒度变大了,这样便于数据移动
    • 哈希解决的时映射问题,使用key的哈希值来计算所在的槽,便于数据分配
  • 多少个hash槽

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

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

      在这里插入图片描述

2、开始搭建

以下演示基于Redis6.0.8版本

2.1、关闭防火墙+启动docker后台服务

# 关闭防火墙
systemctl disable firewalld.service# 启动docker
systemctl start docker
# 开机启动docker
systemctl enable docker

2.2、新建6个redis容器实例

命令详解如下

  • -d:后台启动
  • --name:容器名称
  • --net host:共用宿主机的IP和端口,后面讲解Docker Network会讲解到
  • --privileged=true:开启权限,方便容器数据卷搭建
  • -v:搭建容器数据卷,将数据目录同步出来
  • redis:6.0.0:镜像名:版本号
  • --cluster-enabled yes:开启redis集群
  • --appendonly yes:开启持久化
  • --port 6381:redis端口号
docker run -d --name redis-node-1 --net host --privileged=true -v /mydir/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381docker run -d --name redis-node-2 --net host --privileged=true -v /mydir/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382docker run -d --name redis-node-3 --net host --privileged=true -v /mydir/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383docker run -d --name redis-node-4 --net host --privileged=true -v /mydir/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384docker run -d --name redis-node-5 --net host --privileged=true -v /mydir/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385docker run -d --name redis-node-6 --net host --privileged=true -v /mydir/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

在这里插入图片描述

2.3、进入容器redis-node-1并为6台机器构建集群关系

# 进入容器
docker exec -it redis-node-1 /bin/bash# 构建集群关系 将宿主机ip改为自己ip,--cluster-replicas 1表示为每个master创建一个slave节点
redis-cli --cluster create 宿主机ip:6381 宿主机ip:6382 宿主机ip:6383 宿主机ip:6384 宿主机ip:6385 宿主机ip:6386 --cluster-replicas 1# 下面是我自己的命令,你们自己改下ip即可
redis-cli --cluster create 192.168.71.111:6381 192.168.71.111:6382 192.168.71.111:6383 192.168.71.111:6384 192.168.71.111:6385 192.168.71.111:6386 --cluster-replicas 1

在这里插入图片描述

看到如下结果,代表配置成功

在这里插入图片描述

2.4、链接进入6381作为切入点,查看集群状态

注意:需要先进入redis-cli才能执行命令(一、二):redis-cli -p 6381

命令一
cluster info

在这里插入图片描述

命令二
cluster nodes

在这里插入图片描述

命令三
# 需要先exit 退出redis-cli,处于容器内部执行如下命令
redis-cli --cluster check 自己ip:6381

在这里插入图片描述

2.5、整理生成的主从映射关系

根据上面的信息以及id对应关系,我们可以整理出来如下图关系

在这里插入图片描述

3、读写路由增强:-c

  • 我们使用命令redis-cli -p 6381进入服务,然后执行set k1 v1,查看结果

    在这里插入图片描述

  • 上面报错是说,根据算法算出来这个k1,占用的哈希槽应该在端口为6383上面,不属于当前节点,要手动切换到6383redis服务中去放值

  • 这样的话,我们每次大概率都需要手动去切换,非常麻烦,那么我们可以在执行redis-cli命令时,在后面添加-c,这样就会自动切换服务了redis-cli -p 6381 -c

    在这里插入图片描述

  • 看上图可以发现,我们原本在6381的服务中,然后放入k1,服务自动根据k1算出来应该放入12706的哈希槽中,这个哈希槽属于端口为6383的主节点上,那么就会自动给我们重定向到6383的节点上,并且数据存入成功

4、主从容错切换迁移

  • 接下来,我们停掉主节点6381,然后进入6382中查看当前集群状态,从节点是否会代替主节点
  • 最后再启动6381,查看它原来的身份是否会恢复

4.1、停掉6381主节点,查看集群状态

可以发现,原从节点6384成为了主节点,继承了主节点的哈希槽分区

# 先停掉6381
docker stop redis-node-1# 进入6382
docker exec -it redis-node-2 /bin/bash# 以当前容器的 redis客户端6382 为切入点,查看当前集群信息
redis-cli --cluster check 自己ip:6382

在这里插入图片描述

4.2、重启6381节点,查看集群状态

可以发现,6384还是主节点,原主节点6381重连之后,成为了从节点

# 先从上面容器内部退出去,或者重新打开一个terminal
exit# 重启 6381节点
docker restart redis-node-1# 再次 随便进入一个节点内,查看当前集群信息
docker exec -it redis-node-2 /bin/bash# 这里
redis-cli --cluster check 自己ip:6382

在这里插入图片描述

5、主从扩容需求分析与演示

5.1、分析

  • 主从扩容,我们就要先添加主节点,然后再添加从节点
  • 既然要扩容,那么新增加进来的服务必然要分配哈希槽,但是我们前面已经分完了,那么怎么分配呢
  • 注意:会从分配过的每个节点上,提取一部分出来,分配给新节点,如下图所示

在这里插入图片描述

5.2、主节点添加演示

5.2.1、启动新容器
docker run -d --name redis-node-7 --net host --privileged=true -v /mydir/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387docker run -d --name redis-node-8 --net host --privileged=true -v /mydir/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388

在这里插入图片描述

5.2.2、将新的主节点加入集群
  • 以下命令相当于,将6387加入6381所在的集群中
# 进入节点node-7中
docker exec -it redis-node-7 /bin/bashredis-cli --cluster add-node 自己ip:6387 自己ip:6381

在这里插入图片描述

5.2.3、查看集群状态

可以发现,端口6387已经加入成功,但是没有从节点,并且没有分配哈希槽

redis-cli --cluster check 自己ip:6382

在这里插入图片描述

5.2.4、分配哈希槽
redis-cli --cluster reshard 自己ip:6381
5.2.5、选择要移动多少哈希槽

在这里插入图片描述

5.2.6、输入待分配的节点ID

在这里插入图片描述

5.2.7、输入从哪个节点拆分出来

下面要输入从哪个节点拆分出来4096个槽给它,那么我们这里输入all,就是平均每个节点取出来一点给它

在这里插入图片描述

5.2.8、确定按照这样分配

在这里插入图片描述

5.2.9、查看集群情况
  • 从下图可以看到,我们的63874096个槽位了,并且是分了三段加在一起的[0-1364],[5461-6826],[10923-12287]
  • 并且,原来节点的槽位分区也都发生了改变,下面的槽号,对应了5.1小节分析的图
redis-cli --cluster check 自己ip:6382

在这里插入图片描述

5.3、从节点添加演示

5.3.1、命令
redis-cli --cluster add-node 你的ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主节点ID# 我这里是如下 命令,新主节点id上面是可以看到的
redis-cli --cluster add-node 192.168.71.111:6388 192.168.71.111:6387 --cluster-slave --cluster-master-id ab733301ab56ee869b1d46672b67c6b37ae6339b

在这里插入图片描述

5.3.2、查看集群状态
redis-cli --cluster check 自己ip:6382

在这里插入图片描述

6、主从缩容需求与演示

6.1、分析

  • 既然扩容的时候,我们是先新增主节点,然后再新增从节点,那么缩容我们就要先删从节点,再删主节点了
  • 那么缩容以后,我们可以选择还回去,或者都分配给某一个节点,下面我演示的为分配给某一个节点
  • 其他情况可以自行一点一点分配(分配三次还回去),或者查看是否有批量分配命令

6.2、移除从节点

6.2.1、命令
redis-cli --cluster del-node 你的ip:从机端口 从机6388节点ID# 下面是我的命令,大家自行替换
redis-cli --cluster del-node 192.168.71.111:6388 55c5e1defef92e749ce6e65088f16edfaf78b7fd

在这里插入图片描述

6.2.2、再次查看集群状态
# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382

在这里插入图片描述

6.3、移除主节点

6.3.1、分配哈希槽命令
redis-cli --cluster reshard 你的ip:6381
6.3.2、输入要移动的哈希槽数

在这里插入图片描述

6.3.3、指定要移动到哪个节点的Id
  • 这里我们输入6384节点的ID,将4096个哈希槽全部给6384服务
  • 因为我们上面演示过主从容错切换迁移6381服务是从节点了,6384才是主节点

在这里插入图片描述

6.3.4、指定要从哪个节点移动
  • 我们这里只指定6387端口的ID即可,全部移走

在这里插入图片描述

6.3.5、确定当前分配

在这里插入图片描述

6.3.6、然后查看集群状态

可以发现,6387节点没有再占用哈希槽了,并且6384的槽位也增加了

# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382

在这里插入图片描述

6.3.7、将6387从集群删除即可
redis-cli --cluster del-node 你的ip:主节点端口 主节点6387节点ID# 下面是我的命令,大家自行替换
redis-cli --cluster del-node 192.168.71.111:6387 ab733301ab56ee869b1d46672b67c6b37ae6339b

在这里插入图片描述

6.3.8、最后再查看当前集群状态
# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382

在这里插入图片描述

Dockerfile

  • Dockerfile官网配置详解:Dockerfile 参考 |Docker 文档

  • 我们生成镜像共有两种方式,正式开发中,我们一般都会使用第二种

    1. 一种是通过我们的docker commit命令,基于优化过的镜像,重新打包为一个新镜像
    2. 那么第二种就是通过Dockerfile文件,执行docker build命令,基于文件配置,生成一个新的镜像
    3. 注意:必须要以Dockerfile命名,大小写写错也不行!,还有文件内命令必须全大写!!!
  • 当我们第一次在微服务中写了Dockerfile后,那么后面所有的镜像,我们只需要升级代码,然后mvn package打成jar/war包后,其余Dockerfile几乎不用任何修改(除非你jar包名修改了),就可以打成一个新的镜像,供服务器使用

  • Docker整体流程图如下

    在这里插入图片描述

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

  • Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Docker镜像时会真正开始提供服务

  • Docker容器,容器时直接提供服务的

  • Dockerfile常用命令如下

    Dockerfile命令说明
    FROM指定基础镜像,用于后续的指令构建,如果本地没有安装,那么会尝试pull远程仓库的。
    MAINTAINER指定Dockerfile的作者/维护者。
    LABEL添加镜像的元数据,使用键值对的形式。
    RUN在构建过程中在镜像中执行命令。
    CMD指定容器创建时的默认命令。(可以被覆盖)
    ENTRYPOINT设置容器创建时的主要命令。(不可被覆盖)
    EXPOSE声明容器运行时监听的特定网络端口。
    ENV在容器内部设置环境变量。
    ADD将文件、目录或远程URL复制到镜像中。
    COPY将文件或目录复制到镜像中。
    VOLUME为容器创建挂载点或声明卷。
    WORKDIR设置后续指令的工作目录。
    USER指定后续指令的用户上下文。
    ARG定义在构建过程中传递给构建器的变量,可使用 “docker build” 命令设置。
    ONBUILD当该镜像被用作另一个构建过程的基础时,添加触发器。
    STOPSIGNAL设置发送给容器以退出的系统调用信号。
    HEALTHCHECK定义周期性检查容器健康状态的命令。
    SHELL覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

1、案例讲解

  • 下面,我们以MySQLDockerfile文件为例来讲解该文件都用到了哪些命令,有什么含义:mysql Dockerfile

  • FROM <镜像名:版本号>必须卸载文件最顶端,表示基于哪个镜像修改构建新镜像

    在这里插入图片描述

  • RUN <命令行命令>,等同于在终端操作的shell命令,比如要下载vim功能,就写RUN yum -y install vim

    在这里插入图片描述

  • ENV <变量名> <值>:定义容器内的环境变量,在容器内,或者下文中都可以使用$变量名

    在这里插入图片描述

  • VOLUME <容器内目录>:定义挂载点,明确表示该目录需要进行数据持久化,能让使用该镜像的人清楚知道哪些目录的数据需要持久保存。

    在这里插入图片描述

  • COPY <src> <dest>:将文件/目录,拷贝到镜像中文件系统的另一个目录中

    在这里插入图片描述

  • ENTRYPOINT <入口文件>:配置镜像的入口文件,供exec -it进入容器

    在这里插入图片描述

  • EXPOSE <端口>:指定容器内监听的端口

    在这里插入图片描述

  • CMD <默认命令>:容器启动时的默认命令,如果在启动的run 后面指定了启动命令,那么就会被启动命令替换,不执行DockerfileCMD的命令

    • centosCMDCMD ["/bin/bash"]

    • 比如在运行镜像的时候命令为docker run -exec -it centos bash,这时候就会执行bash命令,不是/bin/bash

      在这里插入图片描述

  • 除了上面这些还有一些常用的命令

    • WORKDIR <容器内目录名>:指定当使用exec -it进入容器中,默认进入的文件位置,像我们进入Redis中,默认会在/data目录中

      在这里插入图片描述

1.1、ADD和COPY

  • 两个都是将文件copy到指定目录中
  • 不同的是,ADD命令具有自动解压的特性。如果 <源路径> 是一个压缩文件(如 .tar.tar.gz.xz 等),ADD 会自动将其解压到 <目标路径>

在这里插入图片描述

在这里插入图片描述

1.2、RUN

RUN命令有两种写法

  • RUN [OPTIONS] <command>
  • RUN [OPTIONS] ['<command>', ...]
  • 比如下载vim命令,
    • 写法一:RUN yum -y install vim
    • 写法二:RUN ['yum', '-y', 'install', 'vim']

1.3、CMD和RUN区别

  • RUN命令是在**构建镜像时执行的**
  • CMD命令是在**运行镜像时执行的**

1.4、ENTRYPOINT

  • 命令格式ENTRYPOINT ["executable", "param1", "param2"]

  • 它也是用来指定一个容器启动时要运行的命令,可以和CMD一起使用,一般是变参才会使用CMD。

  • 单独使用CMD的话,当运行镜像未在docker run xxxxxx 镜像名:版本号后面添加命令的话,后面就会自动加上CMD命令

  • 一起用的话,CMD命令会放到ENTRYPOINT 后面,当作参数。

  • 我们以Redis为案例redis-dockerfile:

    • Dockerfile为:

      在这里插入图片描述

  • 当我们执行docker run -exec -it redis:6.0.8的时候,实际会执行的是我们的命令 ENTRYPOINT配置的命令 CMD配置的命令docker run -exec -it redis:6.0.8 docker-entrypoint.sh redis-server

  • 当执行docker run -exec -it redis:6.0.8 redis-server /etc/redis/redis.conf的时候,实际会执行的是我们的命令 ENTRYPOINT配置的命令

2、案例一:实现Ubuntuifconfig命令

  • 当我们从docker仓库中下载的ubuntu中,是没有ifconfig命令的
  • 我们在Docker 初级的时候,演示过在ubuntu中安装vim命令,并使用commit重新创建了一个属于我们的新镜像。
  • 我们下面演示下,使用Dockerfile文件,构建新镜像,实现在ubuntu上,安装ifconfig命令

2.1、Dockerfile

  • 我们首先进入/mydir/myUbuntu目录中(没有则创建),vim命令新建文件,并编写如下内容
# 新镜像基于ubuntu镜像 最新版
FROM ubuntu:latest# 更新软件包列表
RUN apt update# 安装 net-tools 包
RUN apt install net-tools# 测试定义变量
ENV MY_PATH /user/local# 测试使用变量,并在控制台打印
CMD echo MY_PATH# 暴露主文件
CMD /bin/bash

2.2、执行命令

执行完命令后,可以发现,回根据文件内的内容,一步一步执行,并显示执行进度。等所有命令执行完,那么就代表镜像也创建成功了

# 注意:最后的.代表以当前目录中的Dockerfile 来构建新镜像,前提我们要在/mydir/myUbuntu中写了文件,并且处于这个文件中
docker build -t 新镜像名:版本号 .# 我这里命令是
docker build -t my-ubuntu:1.0.0 .

在这里插入图片描述

2.3、运行新镜像并查看命令是否安装成功

1.查看是否生成新镜像
docker images

在这里插入图片描述

2.进入新镜像中,然后查看ifconfig命令
docker run -it my-ubuntu

在这里插入图片描述

3、案例二:实现my-ubuntu带Java8

  • 上面,我们演示的是最简单的步骤,下面,我们再来个稍微难点的
  • my-ubuntu的基础上,再安装java8

3.1、本地下载JDK8版本

  • 下载地址:Java Archive Downloads - Java SE 8u211 and later | Oracle 中国

  • 选择这个即可

    在这里插入图片描述

3.2、将jdk8放入/mydir/my-ubuntu-java8目录中

  1. 使用IDEA 或 Xftp工具连接服务器,将下载好的JDK文件放入

    1. 不知道怎么使用IDEA自带工具连接的,可以查看:IDEA-不使用插件连接SSH、SFTP_idea ssh插件-CSDN博客
    2. 在这里插入图片描述
  1. 连接好后,注意,使用这个工具,只能将左侧项目中有的文件,ctrl+c、ctrl+v进连接的服务器目录中,拷贝文件夹中的文件不能直接粘贴进去

    在这里插入图片描述

3.1、Dockerfile

下面,我们进入/mydir/my-ubuntu-java8目录中,编写Dockerfile文件

# 基于上面创建的ubuntu
FROM my-ubuntu:1.0.0# 定义作者信息
MAINTAINER tcc<897113177@qq.com># 创建放置jdk的目录
RUN mkdir -p /usr/local/java# 将宿主机内刚刚粘贴进去的jdk拷贝到容器目录内,并解压,前提是当前Dockerfile 和 jdk 是在同一目录中,才能直接使用jdkxxx.tar.gz
ADD jdk-8u431-linux-x64.tar.gz /usr/local/java/#配置jdk的全局环境变量 注意,这里/java/后面要写jdk解压后的文件名,可以先在宿主机内解压看看文件名
ENV JAVA_HOME /usr/local/java/jdk1.8.0_431
ENV JRE_HOME $JAVA_HOME/jre
ENV PATH $JAVA_HOME/bin:$PATHCMD /bin/bash

在这里插入图片描述

3.2、构建镜像

docker build -t my-ubuntu:2.0.0 .

在这里插入图片描述

3.3、进入新构建的镜像,验证是否有java

# 查看新生成镜像
docker images# 运行镜像
docker run -it my-ubuntu:2.0.0 /bin/bash# 验证java
java -version

在这里插入图片描述

4、案例三:实现部署我们的项目

  • 上面,我们已经将jdk装进去了,下面我们来一个接近真实项目的案例
    1. 我们自己写一个SpringBoot项目,并且暴露一个接口
    2. 然后使用maven clearn package构建jar
    3. 然后在这个项目根目录内新建Dockerfile文件,在IDEA编写Dockerfile文件
    4. /target/下面的jar包和/Dockerfile文件一起移入服务器的/mydir/my-project/
    5. 最后进入目录,使用build命令构建我们的镜像

3.1、编写项目及jar包生成

  1. 我们使用SpringBoot项目构建器创建一个基本的项目,然后编写一个简单的接口,项目端口设置为9999即可

    在这里插入图片描述

  1. 然后在/src/main/resources/目录中新建logback-spring.xml文件,这样在我们请求接口的时候,就会在jar包所在目录中创建/logs/app.xxxx-xx-xx.log日志文件,后面我们把它用Docker挂载出来

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 文件输出 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志文件输出的文件名 --><fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern><!-- 日志文件保留天数 --><maxHistory>30</maxHistory></rollingPolicy><encoder><charset>UTF-8</charset><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 根日志 --><root level="info"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root>
    </configuration>
    
  2. 启动项目,打开浏览器,访问localhost:9999/getUser,返回信息正常即可

    在这里插入图片描述

  1. 并且在项目所在目录新建了/logs/app.log文件

    在这里插入图片描述

  1. 使用maven,分别执行clean、package命令,将项目打包为jar

    在这里插入图片描述

  1. 命令执行完后,可以在/target目录查看

    在这里插入图片描述

2.2、创建Dockerfile文件并编写内容

在这里插入图片描述

# 基于my-ubuntu2.0.0
FROM my-ubuntu:2.0.0# 作者
MAINTAINER tcc <897113177@qq.com># 定义日志目录为挂载盘
VOLUME /log# 将当前目录jar包,拷贝进容器的 /app/ 目录下 并命名为 user-project.jar
ADD UserProject-0.0.1-SNAPSHOT.jar /app/user-project.jar# 启动容器时运行
ENTRYPOINT ["java","-jar","/app/user-project.jar"]# 暴露端口作为微服务
EXPOSE 9999

2.3、将jar包和Dockerfile移入服务器内

  • 连接服务器步骤就不说了
  • 左边ctrl+c,右边创建目录后ctrl+v

在这里插入图片描述

2.4、服务器进入目录,构建镜像

docker build -t user-project:1.0.0 .

在这里插入图片描述

2.5、运行镜像

  • 注意:由于我们配置的logback-spring.xml使用的是相对路径,输出日志文件的时候,就会在执行java -jar的工作窗口所处位置创建日志文件,我们上面创建的Dockerfile文件由于默认就是在根目录中,所以日志也会在根目录的/logs目录中
  • 解决办法:
    1. Dockerfile中添加RUN cd /app
    2. logback-spring.xml配置文件名的时候使用绝对路径
# 后台运行容器,并挂载日志文件目录 
docker run -d --name user-project -p 9999:9999 -v /mydir/my-project/logs:/logs user-project:1.0.0

在这里插入图片描述

2.6、在自己电脑上访问接口

  • 由于我的容器IP192.168.71.111,所以我的请求地址为http://192.168.71.111:9999/getUser,你们自行替换ip

在这里插入图片描述

2.7、查看挂载的日志

  • 上面我们接口请求成功了,那么日志文件内肯定会记录,我们启动容器的时候也挂载了
  • 我们按照启动时配的挂载盘目录/mydir/my-project/logs查看

在这里插入图片描述

5、虚悬镜像

5.1、复现

  • Docker-初级的时候,我们提到过虚悬镜像,但是怎么来的我们没说,这里就可以演示
  • 其实就是在首次构建使用docker build,没有使用-t xxx:xxx指定镜像名

在这里插入图片描述

5.2、查询所有虚悬镜像

docker image ls -f dangling=true

在这里插入图片描述

5.3、删除所有虚悬镜像

docker image prune

在这里插入图片描述

Docker Network容器网络

  • 上面我们有几次提到过使用--net命令配置容器启动时使用的网络,下面我们开始讲解如何使用
  • 使用网络可以实现访问其他容器可以直接使用 容器名,可以自动匹配到对应的容器IP
  • docker默认有4中网络模式
    1. bridge为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,默认为该模式
    2. host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
    3. none:容器有独立的Network namespace,但并没有对其进行任务网络设置,比如分配veth pair和网桥链接,IP等
    4. container:新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口

1、命令

  • docker网络命令全部都是由docker network开头,可以使用docker network --help查看所有命令,主要用的就是如下几个

    在这里插入图片描述

# 列出所有网络
docker network ls# 新增网络模式
docker network create test_network# 查看网络源数据
docker network inspect test_network# 删除网络
docker network rm test_network

2、docker0网络介绍

  • 当我们启动docker以后,使用ifconfig命令,可以看到一个docker0的网络
  • docker0 网络是 Docker 默认创建的虚拟网桥,以下是关于它的详细介绍:
    • 基本概念
      • 网桥功能:docker0 作为一个网桥,连接了容器网络与主机网络,工作在数据链路层,使连接到它的容器之间以及容器与主机之间能够进行通信,就像现实中的交换机将不同设备连接在一个局域网内一样2。
      • 默认网络:当安装并启动 Docker 时,会自动创建 docker0 网桥及默认的桥接网络。在没有为容器指定网络的情况下,新创建的容器会自动连接到 docker0 网络23。
    • 工作原理
      • IP 地址分配:默认情况下,docker0 有一个与之关联的子网,如 172.17.0.0/16,它可以分配此范围内的 IP 地址给容器。Docker 主机的 IP 地址在 docker0 网桥上通常是 172.17.0.1,作为容器的默认网关2。
      • 数据转发:容器要与外部网络通信时,流量会首先经过 docker0 的 IP 地址,由主机进一步处理和转发。对于容器之间的通信,如果目标容器也连接在同一个 docker0 网桥上,数据可以直接在容器之间传输;如果目标容器在其他网络或外部网络,则数据会通过 docker0 网桥转发到相应的网络2。
      • 网络隔离:docker0 网桥提供了一定程度的网络隔离,通过在主机上安装规则,使得连接到不同网桥网络的容器不能直接相互通信,保障了容器网络的安全性和独立性3。

在这里插入图片描述

3、网络模式-bridge网桥

  • Docker启动一个容器时,会根据Docker网桥的网段分配给容器一个IP地址,成为Container-IP,同时Docker网桥时每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信
  • docker run的时候,如果没有指定network的话,默认使用的网桥模式就是bridge,使用的就是docker0
  • 网桥docker0创建一对对等虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配
    • 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
    • 每个容器实力内部也有一块网卡,每个接口叫eth0
    • docker0上面的每个veth匹配某个容器实力内部的eth0,两两配对

在这里插入图片描述

3.1、验证

  • 下面,我们启动三台billygoo/tomcat8-jdk8容器,然后分别进入容器中,执行ifconfig命令验证
  • billygoo/tomcat8-jdk8:这个是可以不用修改webapps文件夹的
# 启动容器如果不指定网络的话,默认就是bridge,可以手动添加 --network bridge 指定
docker run -d --name tomcat81 -p 8081:8080 billygoo/tomcat8-jdk8docker run -d --name tomcat82 -p 8082:8080 billygoo/tomcat8-jdk8

在这里插入图片描述

然后分别进入tomcat81、tomcat82容器

docker exec -it tomcat81 /bin/bashdocker exec -it tomcat82 /bin/bash

然后分别使用ip addr命令,查看网络情况

在这里插入图片描述

在这里插入图片描述

最后,我们使用如下命令,查看容器内的网络情况,可以发现容器有自己ip和网关

# 查询 容器详细信息,并且只展示最后20行
docker inspect tomcat81|tail -n 20

在这里插入图片描述

4、网络模式-host

  • 容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace容器将不会虚拟出自己的网卡,而是使用宿主机的IP和端口
  • 注意:在启动命令的时候,使用-p映射端口是无效的。端口号会以主机端口号为主,重复时则递增

在这里插入图片描述

4.1、验证

  • 下面我们启动一台billygoo/tomcat8-jdk8
  • 然后进入容器内查看其网络信息
# 我这里故意写-p,执行会有警告,说 -p指令不生效的,但是不影响容器启动,只是警告
docker run -d --network host -p 8083:8080 --name tomcat83 billygoo/tomcat8-jdk8

在这里插入图片描述

这时候我们执行ip addr命令,主机上是看不到容器对应的veth网络的,因为没有使用网桥,和宿主机共用的

在这里插入图片描述

并且,我们在虚拟机内访问localhost:8083是没东西的,只有访问localhost:8080才会打开页面。在虚拟机外则使用ip+:8080。因为我们的-p命令是无效的

在这里插入图片描述

然后我们进入容器,并且使用ip addr查看容器内网络情况

可以发现,网络情况和宿主机是一模一样的,代表了容器和宿主机共用的同一个网络

docker exec -it tomcat83 /bin/bash

在这里插入图片描述

  • 最后,我们使用如下命令,可以发现,容器内没有自己的ip和网关,因为和宿主机共享的,并且网络模式为host
# 查询 容器详细信息,并且只展示最后20行
docker inspect tomcat83|tail -n 20

在这里插入图片描述

5、网络模式-none

  • 禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
  • none模式下,并不为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为自己Docker容器添加网卡、配置IP等
  • 以这种方式启动的容器,只能内部自己访问自己,外部无法访问

5.1、验证

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

进入容器使用ip addr命令可以看到只有一个回环网络

在这里插入图片描述

对容器使用如下命令也可以看到,该容器是没有网络的

docker inspect tomcat84|tail -n 20

在这里插入图片描述

5、网络模式-container

  • 新建的容器和已经存在的一个容器共享一个网络ip配置,而不是和宿主机共享。
  • 新床就的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等
  • 同样,两个容器除了网络方面,其他的如:文件系统、进程列表等还是隔离的
  • 当被依赖的容器宕机了,那么依赖的容器则会失去网络,只剩下自己的回环地址
  • 这个案例我们就不再使用tomcat演示了,因为会共用同一个ip、端口,导致端口冲突。下面我们使用一个面相安全的轻型Linux发版:Alpine,各位先拉取最新的镜像
# 注意:是使用 /bin/sh
docker run -it --name alpine1 alpine /bin/sh# 再打开一个窗口执行如下命令# 基于容器1的网络创建
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh

然后在两个命令窗口中,分别执行ip addr,查看网络,可以发现两个网络一模一样

在这里插入图片描述

最后,我们停掉左边的容器(被依赖的),再次查看右边的网络情况

在这里插入图片描述

5、自定义网络(重要)

  • 自定义网络就是执行docker netword create 网络名,自己创建的网络
  • 创建的网络默认也是==bridge网桥模式==
  • 但是,自己创建的网络和默认自带的网桥区别是自带的网桥不能通过容器名,访问容器内接口。而自己创建的网络可以
  • 自己创建的网络内,会维护好一组一组的容器名:容器IP,而自带的则不具备这种功能

在这里插入图片描述

5.1、验证

我们先创建网络test_bridge,可以发现新创建的网络驱动也是bridge

# 创建网络
docker network create test_bridge# 列出所有网络
docker network ls

在这里插入图片描述

然后我们使用刚刚创建的网络,启动两个tomcat 85|86容器来验证

docker run -d --network test_bridge --name tomcat85 billygoo/tomcat8-jdk8docker run -d --network test_bridge --name tomcat86 billygoo/tomcat8-jdk8

在这里插入图片描述

我们各自进入容器内,然后互相ping 容器名,查看是否可以ping通,符合我们的说法。至于使用默认的bridge启动的容器,互相ping不通的案例,大家可以自行去尝试。

docker exec -it tomcat85 /bin/bashdocker exec -it tomcat86 /bin/bash

在这里插入图片描述

Docker Compose容器编排

  • docker建议我们每一个容器只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来。
  • 正常我们的服务会有很多组件还有数据库一起组成的,比如mysqlrediskafka、微服务模块等,我们一个一个执行的话,很容易出错,并且我们的服务和其他容器有可能有先后顺序,比如先启动依赖容器(比如:mysqlredis等),才能启动我们的微服务
  • Docker就提供了一种工具Docker Compost容器编排的技术,让我们通过写一个文件,实现所有配置的容器一起启动
  • 我们只需要在目录中编写compose.yml 或 compose.yaml文件即可,文件名称不能改变
  • 官网地址:插件 |Docker 文档

1、安装

  • 我这里是用的CentOS 7演示的,所以用下面这个命令
# 对于 Ubuntu 和 Debian,请运行:
apt-get update
apt-get install docker-compose-plugin# 对于基于 RPM 的发行版,请运行:
yum update
yum install docker-compose-plugin

在这里插入图片描述

2、验证

docker compose version

在这里插入图片描述

3、卸载

# 要删除 Docker Compose CLI 插件,请运行:
apt-get remove docker-compose-plugin# 基于 RPM 的发行版:
yum remove docker-compose-plugin

4、Compose常用命令

下面的命令,会在后面第5章节演示

4.1、查看帮助

docker compose -h

在这里插入图片描述

4.2、启动yml内服务

# 也可以查看服务启动时,每个服务的启动日志报错等
docker compose up

在这里插入图片描述

4.3、启动所有yml服务并后台运行

docker compose up -d

在这里插入图片描述

4.4、停止并删除yml内容器、网络、卷、镜像

# 相当于 docker rm -f 容器名
docker compose down

在这里插入图片描述

4.5、进入容器实例内部

# 相当于 docker exec -it mydir-my-mysql-1 /bin/bash
docker compose exec yml里面的服务id <command命令>

在这里插入图片描述

4.6、展示当前yml编排过的运行的所有容器

# 展示的不是所有容器,而是当前yml中配置的yml
docker compose ps

在这里插入图片描述

4.7、展示当前yml编排过的容器进程

# 相当于 docker top 容器名
docker compose top

在这里插入图片描述

4.8、查看容器输出日志

# 相当于 docker logs 容器名
docker compose logs yml里面的服务id

在这里插入图片描述

4.9、检查配置

docker compose config

在这里插入图片描述

4.10、检查配置,有问题才有输出

docker compose config -q

在这里插入图片描述

4.11、重启yml内服务

# 相当于一键重启yml配置中所有启动的容器
docker compose restart

在这里插入图片描述

4.12、启动yml内服务

# 相当于一键启动yml配置中所有停止的容器
docker compose start

在这里插入图片描述

4.13、停止yml内服务

# 相当于一键停止yml配置中所有启动的容器
docker compose stop

在这里插入图片描述

5、使用

两要素:

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

使用的三个步骤

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

如下演示,我们使用mysql、redis以及我们之前演示Dockerfile创建的user-project微服务来掩饰

  • 这里正常微服务都是依赖于mysql、redis的,但是我这里微服务图省事,就不改了,假装依赖一下吧。
  • 各位如果要自己修改微服务的话,可以使用之前讲的Docker Network,在配置文件里把依赖mysql、reids等第三方组件依赖,IP改为容器名尝试

5.1、编写compose.yml文件

  • 我们使用的镜像以及版本为:mysql:5.7、redis:6.0.8、user-project:1.0.0,各位缺少哪个镜像拉取一下,最后一个user-project是你自己的微服务,使用Dockerfile构建出来的镜像
  • 下面我们编排的文件内的容器是有启动的先后顺序的mysql、redis、user-project在容器内,我们只需要使用depends_on标明我们的服务需要哪几个其他服务的ID即可
  • 如下文件我们放到/mydir/compose.yml中即可
  • 如果直接粘贴进去会把所有命令前面都加一个#的话,把如下内容的注释全部删掉,再粘贴即可
# 容器列表,所有容器都配置再其中
services:# 相当于id,一个Compose中唯一user-project:# 镜像名称:版本号image: user-project:1.0.0# 容器名称container_name: user-project# 端口号,使用 - xxx 表示数组形式,可以指定多个端口,我这里服务端口为9999ports:- "9999:9999"# 指定容器挂载卷,也是数组形式,可以配置多个volumes:- /mydir/my-project/logs:/logs# 指定容器使用的网络配置,tcc_network会在文件最后面定义networks:- tcc_network# 指定该容器依赖的其服务的id,并不用于启动命令中depends_on:- my-redis- my-mysql# 如下容器不指定容器名,那么生成的容器名为`目录名-容器名-compose编排序号`,mydir-my-mysql-1my-mysql:image: mysql:5.7# 指定容器内的环境变量environment:# 用来设置 MySQL 数据库的 root 用户密码MYSQL_ROOT_PASSWORD: 'admin'# 用于控制是否允许 MySQL 使用空密码。把它设置为 no 表示不允许使用空密码,以此增强数据库的安全性。MYSQL_ALLOW_ENPTY_PASSWORD: 'no'# 指定在 MySQL 容器启动时自动创建的数据库名称MYSQL_DATABASE: 'testdb'# 用于指定在 MySQL 容器启动时自动创建的新用户名称MYSQL_USER: 'tcc'# 用于为 MYSQL_USER 指定的用户设置密码MYSQL_PASSWORD: 'tcc123'ports:- "3306:3306"volumes:- /mydir/mysql/log:/var/log/mysql- /mydir/mysql/data:/var/lib/mysql- /mydir/mysql/conf:/etc/mysql/conf.dnetworks:- tcc_network# 将默认认证插件设置为 mysql_native_password 解决外部无法访问command: --default-authentication-plugin=mysql_native_password# my-redis:image: redis:6.0.8ports:- "6379:6379"volumes:- /mydir/redis/redis.conf:/etc/redis/redis.conf- /mydir/redis/data:/datanetworks:- tcc_networkcommand: redis-server /etc/redis/redis.conf# 相当于 docker network create tcc_network
networks:tcc_network:

5.2、运行yml文件

# 注意,编写完文件以后,最好先执行如下命令,校验一下
docker compose config -q# 后台运行
docker compose up -d

在这里插入图片描述

5.3、验证

docker compose ps

在这里插入图片描述

进入mysql容器中查看是否默认创建了testdb

# 进入my-mysql容器中 或者使用 docker exec -it 容器名 /bin/bash
docker compose exec my-mysql /bin/bash# 连接Mysql服务,打开客户端
mysql -uroot -p# 输入compose.yml定义的密码# 显示所有数据库
show databases;

在这里插入图片描述

Portainer安装与使用(简单版页面管理)

  • 官网:Kubernetes and Docker Container Management Software
  • Portainer是一款轻量级的应用,它提供了图形化界面,用于方便的管理Docker环境,包括单机环境和集群环境
  • 在这个平台上,我们能很方便的对Docker进行一切操作,包括监控容器使用情况。而不需要我们连接进入服务器去进行操作。重要的是,我们可以给登入网站的用户权限限制,实现对操作可控制,减少误操作

1、安装命令

  • 安装地址:Install Portainer CE with Docker on Linux | Portainer Documentation
  • Portainer也是放置在Docker上的一个镜像,我们通过拉取镜像,运行即可
  • 特别命令解析,前面简单的我就不说了
    • -p:官网是监听了8000、9443两个端口
      • 8000 端口用于 Portainer 服务器与 Edge 代理之间的通信,支持对远程节点的管理。
      • 9443 端口用于用户通过 Web 界面安全地访问 Portainer 管理控制台,方便用户进行日常的管理操作
    • --restart=always:指定容器跟随Docker启动而自启,意思就是,Docker内部的开机自启
    • -v /var/run/docker.sock:/var/run/docker.sock:宿主机的 /var/run/docker.sock 文件挂载到容器内的 /var/run/docker.sock 路径。/var/run/docker.sock 是 Docker 守护进程的 Unix 套接字文件,通过挂载这个文件,容器就能和宿主机的 Docker 守护进程进行通信,进而管理宿主机上的 Docker 资源
    • -v /mydir/portainer:/data:将portainer内部生成的数据同步到宿主机目录中做备份
    • portainer/portainer-ce:lts:容器名portainer/portainer-ce,版本号:lts
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /mydir/portainer:/data portainer/portainer-ce:lts

在这里插入图片描述

2、使用

2.1、登录页面

  • 注意:访问页面时,必须使用https,不能使用http,否则页面会出不来

  • 访问页面可以使用如下两种方式

    1. 服务器内访问:我们在虚拟机内部使用https://localhost:9443 或 https://127.0.0.1:9443
    2. 内网其他电脑访问:https:// + 服务器IP + :9443即可
  • 我们首次访问可能会出现如下界面,点击高级->继续访问即可

    在这里插入图片描述

2.2、创建账号

  • 注意,Portainer初次启动以后,要在5分钟内完成账号注册,否则就要重启容器,然后再重新注册

  • 文档地址:安装 Portainer 后,我收到消息“出于安全目的,您的 Portainer 实例已超时”,我该如何解决这个问题?

    在这里插入图片描述

在这里插入图片描述

2.3、使用页面

  • 页面使用文档:Home | Portainer Documentation

  • 注册成功后,我们会进入如下页面

    在这里插入图片描述

2.4、查看Docker内部所有信息

  • 我们要先点击右侧那个localDocker,选择我们的当前绑定的镜像实例

  • 然后在左侧,我们就会看到我们Docker内部的详细信息了

  • 仪表盘内容,相当于我们的命令docker system df

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.5、操作

  • 我们不仅能观察Docker内部的信息,还能进行我们之前大部分的操作,只需要点点按钮即可
  • 我这里只演示对于Containers容器的操作,其他的按钮跟我们之前代码命令都大差不差,大家自行研究使用

在这里插入图片描述

CAdvisor+InfluxDB+Granfana(GIA)监控系统

  • 上面Portainer只是简单的监控操作,下面这三个组件加起来可以实现对容器以及宿主机详细的监控操作,适合生产系统的监控
  • docker status命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,小公司基本够用了。但是:docker status统计结果只是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
  • 三个组件功能如下:
    • CAdvisor:监控收集
      • 是一个容器资源监控工具,包括容器的内存,CPU,网络IO,磁盘IO等监控,同时提供了一个WEB页面用于查看容器的试试运行状态。CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过,CAdvisor提供了很多数据集成接口,支持InfluxDB,Redis,Kafka,Elasticsearch等集成,可以加上对应配置将监控数据发往这些数据库存储起来。
      • 功能点主要有两个
        1. 展示Host和容器两个层次的监控数据
        2. 展示历史变化数据
    • InfluxDB:存储数据
      • InfluxDB使用GO语言编写的一个开源分布式时序、事件和指标数据库,无需外部依赖。
      • Cadvisor默认只在本机保存最近2分钟的数据,为了持久化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合存储CAdvisor的数据。而且,CAdivisor本身已经提供了InfluxDB的继承方法,在容器启动时指定配置即可
      • 主要功能如下
        • 基于时间序列,支持于时间有关的相关函数(如最大、最小、求和等)
        • 可度量性:你可以实时对大量数据进行计算
        • 基于事件:它支持任意的事件数据
    • Granfana:展示图表
      • Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括InfluxDB,MySQL,Elasticsearch,OpenTSDB,Graphite等和丰富的插件及模板功能,支持图表权限控制和报警)
      • 主要功能如下
        • 灵活丰富的图形化选项
        • 可以混合多种风格
        • 支持白天和夜间模式
        • 多个数据源
  • 对于如下三个组件的演示,我这里只演示简单的启动以及登录使用。更复杂使用自行查询官网进行配置即可

1、Compose文件

  • 下面,我们使用Compose来对这三个服务进行配置,然后一起启动
  • 各位粘贴的话,记得先把里面注释删掉,不然可能粘贴进去错乱
services:influxdb:container_name: influxdbimage: tutum/influxdb:latest# 跟随docker启动restart: alwaysnetworks:- cig_network# 预先创建一个名为cadvisor的数据库environment:- PRE_CREATE_DB=cadvisorports:- "8083:8083"- "8086:8086"volumes:- /mydir/influxdb:/datacadvisor:container_name: cadvisorimage: google/cadvisornetworks:- cig_network# 配置启动后连接上influx数据库command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxdb:8086restart: alwaysports:- "8080:8080"volumes:- /:/rootfs:ro- /var/run:/var/run:ro- /sys:/sys:ro- /var/lib/docker/:/var/lib/docker:rodepends_on:- influxdbgrafana:container_name: grafanaimage: grafana/grafana# 使用root权限user: "root"restart: alwaysnetworks:- cig_networkports:- "3000:3000"volumes:- /mydir/grafana_data:/var/lib/grafana# 配置环境变量environment:- HTTP_USER=admin- HTTP_PASS=admin- INFLUXDB_HOST=influxdb- INFLUXDB_PORT=8086- INFLUXDB_NAME=cadvisor- INFLUXDB_USER=root- INFLUXDB_PASS=rootdepends_on:- influxdb# 创建网络
networks:cig_network:

2、访问并使用页面

  • 启动上面的文件时间可能比较久,因为大概率要拉取镜像,你本地没有。如果一直拉不下来,建议单独拉取compose中的某个镜像,单独拉下来即可
  • 当我们按照上面文件启动后,可以访问如下三个地址,首次访问可能会比较慢
    1. 浏览cAdvisor收集服务:http://宿主机ip:8080
    2. 浏览influxdb存储服务:http://宿主机ip:8083
    3. 浏览grafana展现服务:http://宿主机ip:3000

2.1、cAdvisor

在这个页面往下翻,可以看到简单的统计图,会显示当前宿主机系统的情况,CPU、内存等信息

在这里插入图片描述

在这里插入图片描述

2.2、influxdb

  1. 进入页面后,我们点击右上角的设置(齿轮图标),可以填写账号密码
  2. 然后点击右侧Query Templates选择需要的语句sql
  3. 输入框回车,执行sql

在这里插入图片描述

2.3、grafana

2.3.1、连接数据库
  1. 页面我们使用账号:admin 密码:admin登录进去

  2. 左侧Connections->Data sources,然后选择InfluxDB

    在这里插入图片描述

  1. 然后填写数据库信息,保存并测试即可

    在这里插入图片描述

2.3.2、配置图形化界面
  • 选择左侧的Dashboards菜单,点击右侧的create dashboard

  • 然后选择我们刚刚配置的数据库就来到了配置图形页面

  • 我这里配个简单的图形演示

    在这里插入图片描述

  • 配置查询的sql

    在这里插入图片描述

  • 然后点击右上角Save dashboard

  • 然后填写图形名称

    在这里插入图片描述

  • 保存成功后,我们即可刷新页面,再次查看我们的图形了

    在这里插入图片描述

开发软件中的Docker插件

  • 我这里以Idea开发工具中的Docker插件为例

  • 现在IDEA插件中一般都会自带一个Docker插件,没有的话自行安装

    在这里插入图片描述

  • 然后我们点击左上角的File->Build,Execution,Deployment

    在这里插入图片描述

  • 然后在右侧点击+号,选择SSH连接我们的服务器

    在这里插入图片描述

  • 然后在弹框中,填写我们的服务器ip,账号,密码,测试连接

    在这里插入图片描述

  • 最后我们点击ok即可

  • 然后在下面的Services中可以看到Docker的状态了,以及对Docker的一切操作

    在这里插入图片描述

相关文章:

  • 【python】Python 中,单下划线(_)和双下划线(__)开头以及结尾的命名方式具有特殊的含义和用途
  • 安恒web安全春招实战
  • 如何使用 Apache 配置用户主页 ?
  • 【前端】【面试】在前端开发中,如何优化 CSS 以提升页面渲染性能?
  • 轻松完成视频创作,在线视频编辑器,无需下载软件,功能多样实用!
  • 游戏引擎学习第243天:异步纹理下载
  • C++区别于C语言的提升用法(万字总结)
  • 推荐几个可以免费下载视频的软件(Neat Download Manager、蜗牛下载助手、bilidown)
  • 【安全扫描器原理】网络扫描算法
  • 【题解-Acwing】851. spfa求最短路
  • 动态自适应分区算法(DAPS)设计流程详解
  • 【Qt6 QML Book 基础】07:布局项 —— 锚定布局与动态交互(附完整可运行代码)
  • MySQL 报错解析:SQLSyntaxErrorException caused by extra comma before FROM
  • 网络原理 - 7(TCP - 4)
  • 技术视界 | 数据的金字塔:从仿真到现实,机器人学习的破局之道
  • EFISH-SBC-RK3588无人机地面基准站项目
  • 【Hive入门】Hive查询语言(DQL)完全指南:从基础查询到高级分析
  • 基于 EFISH-SBC-RK3588 的无人机通信云端数据处理模块方案‌
  • Redis-缓存应用 本地缓存与分布式缓存的深度解析
  • 解决 Dart Sass 的旧 JS API 弃用警告 的详细步骤和解决方案
  • 《我的后半生》:人生下半场,也有活力重启的可能
  • 韩国对华中厚板征收临时反倾销税
  • 为什么猛起身会头晕?你的身体在发出这个警报
  • 外交部:中方在黄海暂定海域建造渔业养殖设施,同中韩海域划界无关
  • 湖南永州公安全面推行“项目警官制”,为重点项目建设护航
  • 解放军报社论:谱写新时代双拥工作崭新篇章