Docker

提供了系统的平滑移植、容器虚拟化的技术,在部署项目时,把原始环境直接复制过来,以免出现换个环境不能正常运行的情况 可以将运行文档、配置环境、运行环境、依赖、操作系统发行版、内核打包为一个镜像 理念:一次镜像,处处运行 Docker使用Go实现,是内核级别的虚拟化,不需要非必要功能支持,是在已经运行的Linux上制造了一个隔离的文件环境,执行效率几乎等同于Linux主机,必须部署在Linux内核的系统上 DevOps开发/运维,新一代开发工程师 由镜像、容器、仓库组成 Docker是一个客户端服务器结构的系统,Docker的守护进程运行在主机上,通过Scoket连接从客户端进行访问 验证是否安装成功:

 docker run hello-world

如果看到:

 Unable to find image 'hello-world:latest' locally
 latest: Pulling from library/hello-world
 7050e35b49f5: Pull complete Digest: sha256:6e8b6f026e0b9c419ea0fd02d3905dd0952ad1feea67543f525c73a0a790fefb
 Status: Downloaded newer image for hello-world:latest
 
 Hello from Docker!
 This message shows that your installation appears to be working correctly.
 
 To generate this message, Docker took the following steps:
  1. The Docker client contacted the Docker daemon.
  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
     (arm64v8)
  3. The Docker daemon created a new container from that image which runs the
     executable that produces the output you are currently reading.
  4. The Docker daemon streamed that output to the Docker client, which sent it
     to your terminal.
 
 To try something more ambitious, you can run an Ubuntu container with:
  $ docker run -it ubuntu bash
 
 Share images, automate workflows, and more with a free Docker ID:
  <https://hub.docker.com/>
 
 For more examples and ideas, visit:

代表安装成功

如果显示没有权限,需要将当前用户添加到 docker 用户组中:

sudo groupadd docker
sudo gpasswd -a $USER docker
newgrp docker

Docker run命令做了什么:

  • 先在本机中查找镜像,如果有就直接以这个镜像作为模板进行生产容器实例运行
  • 如果没有将会在Docker Hub中查找镜像
    • 如果能找到则将该镜像下载到本地,然后再运行
    • 如果没有,则返回错误 为什么Docker比虚拟机快:
  • 传统虚拟机是虚拟出一套硬件之后在上边运行操作系统
  • 容器内的进程依赖于宿主,容器内没有自己的内核,也没有进行硬件虚拟,直接使用实际物理机上的硬件资源
  • 每个容器之间相互隔离,每个容器都有自己的文件系统

帮助类命令

查看概要信息:

 docker info

查看帮助信息:

 docker --help
 docker  --help

查看所有镜像:

 docker images

表头内容为:

  • REPOSITORY 仓库名称
  • TAG 版本号
  • IMAGE ID 镜像ID
  • CREATED 镜像创建时间
  • SIZE 大小 同一个仓库源可以有多个TAG,代表这个仓库源的不同版本,格式为仓库名:标签名如果不指定标签名,代表仓库名:latest
  • latest,读音为leɪtɪst中文为最新的

监控

docker stats

搜索

命令:

 docker search 名称
 docker search --limit 数量 名称

搜索结果结构为:

  • NAME
  • DESCRIPTION 中文为描述,读音为dɪˈskrɪpʃn
  • STARS
  • OFFICIAL代表官方的
  • AUTOMATED 中文为自动化,读音为ɔːtəmeɪtɪd

拉取

 docker pull 镜像名:版本

默认情况下不指定版本将会拉取latest最新版

查看空间占用

 docker system df

删除镜像

docker rmi 镜像名/id

# 如果这个镜像正在运行则无法删除,需要强制删除
docker rmi -f 镜像名/id

docker 虚悬镜像

仓库名、标签都是 none

容器命令

docker run [options] 镜像名 [命令] [参数]
  • options :

    • --name :容器 新名称
    • -d:后台运行容器并返回id,又被称为启动守护容器
    • -i :以交互方式启动容器,全称是 interactive 读音为 ˌin(t)ərˈaktiv z中文为交互的
    • -t:为容器分配一个终端,全称为 tty
    • -P:随机端口分配
    • -p:指定端口分配
    • -e 环境变量
    • --restart=always 可以设置 docker 重启后,容器也跟着重启

    通常 it:都是结合起来用的,例如

    docker run -it ubuntu /bin/bash
    # 指定名称并运行
    docker run -it --name=uuu ubuntu /bin/bash
    

查看正在运行的容器

docker ps
# 查看所有曾经运行过的
docker ps -a

退出容器

在容器内:

# 自动退出容器
exit
# 退出但不停止
ctrl + p + q

启动容器

docker start id/name

停止容器

docker stop id/name

重启容器

docker restart id/name

强行停止容器

docker kill id/name

删除已停止的容器

docker rm id/name

强制删除正在运行的容器

docker rm -f id/name

后台运行

如果想要让容器在后台运行,需要保证必须有一个前台进程,否则将会自动退出

docker run -d 镜像名

查看容器日志

docker logs id/name

查看容器内进程的情况

每个容器可以看作是一个简易版的linux环境

docker top id/name

查看容器内部信息

inspect` 中文为检查,读音为 `inˈspekt
docker inspect id/name

进入正在运行的容器并打开终端

docker exec -it id/name /bin/bash
attach` 中文为连接、附属,读音为 `əˈtaCH

attach 会直接进入容器的启动命令的终端,不会启动新的进程,用 exit 退出时会导致容器的停止

exec 是在容器中打开新的终端,可以启动新的进程,不会导致容器的停止

从容器中拷贝文件

docker cp id/name:文件名和路径 本机目的路径

导出整个容器

docker export 容器 > 路径文件名.tar

导入整个容器

cat 文件 | docker import - 名称:版本号

镜像

镜像是分层的,拉取镜像的过程中可以看出

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

一次加载多个文件系统,从外面看只有一个文件系统,联合加载会将各个文件系统叠加起来,最终组成一个文件系统。

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

另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。

commit

提交容器副本,使之成为新的镜像

命令:

docker commit -m="消息" -a="作者" 容器id 名称:tag版本号

这时候可以在 docker images 看到自己提交的镜像

提交到远程仓库

本地自建库

docker pull registry
docker run -d -p 5000:5000 -v ~/program/registry/:/tmp/registry --privileged=true registry

查看自建库中的所有的仓库:GET [<http://localhost:5000/v2/_catalog>](<http://localhost:5000/v2/_catalog>)

打包:

docker commit -m="消息" -a="作者" 容器id 名称:tag版本号

标记镜像:

相当于把本地的某个镜像取个别名,将需要推送到的远程仓库地址添加上

格式通常为:

docker tag 本地的镜像名 仓库地址/名称:tag
# 例如
docker tag admin/ifconfig:1.0 localhost:5000/admin/ifconfig:1.0

推送:

docker push 名称
# 例如
docker push localhost:5000/admin/ifconfig:1.0

此时查看自建库中的所有的仓库GET [<http://localhost:5000/v2/_catalog>](<http://localhost:5000/v2/_catalog>)

{
	"repositories": [
	"songxiaoxu/ifconfig"
	]
}

Docker容器卷

可以完成容器中的目录和主机的目录进行映射,在docker容器删除时不会删除挂载到的位置的数据

以下是自建仓库时候的命令:

docker run -d -p 5000:5000 -v ~/program/registry/:/tmp/registry --privileged=true registry
  • :之前的内容代表宿主机的路径

  • 之后的内容代表容器内的路径

  • -privileged=true 可以用来防止权限不够

  • -v
    

    中的

    v
    

    volumes
    
    • /ˈvɑljumz/
    • 中文为卷

例如:

docker run --name=ubuntu -it -v ~/program/docker/ubuntu-data/:~/ ubuntu /bin/bash

容器卷映射规则

可以设置容器和宿主机映射目录之间的规则,之前的命令中没有加任何限制,相当于 rw 可读可写,也就是说相当于:

docker run --name=ubuntu -it -v ~/program/docker/ubuntu-data/:~/:rw ubuntu /bin/bash

可以设置为容器内只读 roreadonly

docker run --name=ubuntu -it -v ~/program/docker/ubuntu-data/:~/:ro ubuntu /bin/bash

如果在容器内被设置为只读的目录下创建/修改/删除文件将会报错:

root@3c1e68b3c0ce:~# touch abc.txt
touch: cannot touch 'abc.txt': Read-only file system
root@3c1e68b3c0ce:~# rm -rf abc.txt
root@3c1e68b3c0ce:~# ls
1.txt
root@3c1e68b3c0ce:~# rm -rf 1.txt  
rm: cannot remove '1.txt': Read-only file syste

容器卷的继承

继承的是规则,即使被继承的容器删除掉了,规则仍然生效

docker run --name=名称 -it --volumes-from 要继承的容器名/id 镜像 /bin/bash
docker run -d -p 3306:3306 \\
-v ~/.mysql/log:/var/log/mysql \\
-v ~/.mysql/data:/var/lib/mysql \\
-v ~/.mysql/conf:/etc/mysql/conf.d \\
-e MYSQL_ROOT_PASSWORD=xxxxx \\
--name mysql mysql
docker run --name redis -p 6379:6379  \\
-v ~/.redis/redis.conf:/etc/redis/redis.conf \\
-v ~/.redis/data:/data \\
-d redis redis-server /etc/redis/redis.conf

集群

MySQL集群

主机:

docker run -d -p 3307:3306 \\
-v ~/cluster/mysql/master/log:/var/log/mysql \\
-v ~/cluster/mysql/master/data:/var/lib/mysql \\
-v ~/cluster/mysql/master/conf:/etc/mysql/conf.d \\
-e MYSQL_ROOT_PASSWORD=xxxxx \\
--name mysql-master mysql

修改配置文件,在conf下新建一个 my.cnf

[mysqld]

## 设置server_id,同一局域网中需要唯一

server_id=101 

## 指定不需要同步的数据库名称

binlog-ignore-db=mysql  

## 开启二进制日志功能

log-bin=mall-mysql-bin  

## 设置二进制日志使用内存大小(事务)

binlog_cache_size=1M  

## 设置使用的二进制日志格式(mixed,statement,row)

binlog_format=mixed  

## 二进制日志过期清理时间。默认值为0,表示不自动清理。

expire_logs_days=7  

## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。

## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致

slave_skip_errors=1062

创建一个用户并授权:

CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';

创建从机:

docker run -d -p 3308:3306 \\
-v ~/cluster/mysql/slave/log:/var/log/mysql \\
-v ~/cluster/mysql/slave/data:/var/lib/mysql \\
-v ~/cluster/mysql/slave/conf:/etc/mysql/conf.d \\
-e MYSQL_ROOT_PASSWORD=xxxxx \\
--name mysql-slave mysql

从机配置文件:

[mysqld]

## 设置server_id,同一局域网中需要唯一

server_id=102 

## 指定不需要同步的数据库名称

binlog-ignore-db=mysql  

## 开启二进制日志功能

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=mall-mysql-relay-bin
## 表示将复制时间写到二进制日志
log_slave_updates=1
## slave设置为只读状态
read_only=1

进入主机查看日志:

show master status;
内容大致如下:
mysql> show master status;
+-----------------------+----------+--------------+------------------+-------------------+
| File                  | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------------+----------+--------------+------------------+-------------------+
| mall-mysql-bin.000001 |      157 |              | mysql            |                   |
+-----------------------+----------+--------------+------------------+-------------------+

进入从机:

change master to master_host='change master to master_host='172.17.0.1', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=157, master_connect_retry=30;', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=157, master_connect_retry=30;

从机查看连接状态:

show slave status \\G;
# 开始作为从机
start slave;

Redis

哈希槽:哈希槽是Redis集群中用于实现数据分片的一种机制。一个Redis集群包含16384个哈希槽,每个键都会被映射到一个哈希槽中,不同的节点可以负责不同数量的哈希槽。集群通过计算键的CRC16校验和对16384取余数来确定键属于哪个哈希槽。哈希槽的优点是可以方便地添加或删除节点,只需要将部分哈希槽转移即可。

需要6个,配置成3主3从的集群,每个主都带有一个从

  • 主1:6381,从1:6385
  • 主2:6382,从2:6386
  • 主3:6383,从3:6384

创建集群:

docker run -d --name redis-node-1 --net host --privileged=true -v ~/program/docker/redis/redis-node-1:/data redis --cluster-enabled yes --appendonly yes --port 6381

 

docker run -d --name redis-node-2 --net host --privileged=true -v ~/program/docker/redis/redis-node-2:/data redis --cluster-enabled yes --appendonly yes --port 6382

 

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

 

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

 

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

 

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

构建集群:

redis-cli --cluster create 198.18.0.1:6381 198.18.0.1:6382 198.18.0.1:6383 198.18.0.1:6384 198.18.0.1:6385 198.18.0.1:6386 --cluster-replicas 1

--cluster-replicas 1 代表两两配对

输出:

root@device:/data# redis-cli --cluster create 198.18.0.1:6381 198.18.0.1:6382 198.18.0.1:6383 198.18.0.1:6384 198.18.0.1:6385 198.18.0.1:6386 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 198.18.0.1:6385 to 198.18.0.1:6381
Adding replica 198.18.0.1:6386 to 198.18.0.1:6382
Adding replica 198.18.0.1:6384 to 198.18.0.1:6383
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots:[0-5460] (5461 slots) master
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[5461-10922] (5462 slots) master
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[10923-16383] (5461 slots) master
S: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   replicates 2c2a0666c9a379328073bd02afb5964120c6bef3
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
Can I set the above configuration? (type 'yes' to accept):

输入yes后就相当于进行了hash槽的分配了

看到以下信息代表成功:

>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 198.18.0.1:6381)
M: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   slots: (0 slots) slave
   replicates 2c2a0666c9a379328073bd02afb5964120c6bef3
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   slots: (0 slots) slave
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   slots: (0 slots) slave
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

进入redis中,查看集群的状态:

root@device:/data# redis-cli -p 6381
127.0.0.1:6381> keys *
(empty array)
127.0.0.1:6381> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:118
cluster_stats_messages_pong_sent:111
cluster_stats_messages_sent:229
cluster_stats_messages_ping_received:106
cluster_stats_messages_pong_received:118
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:229
total_cluster_links_buffer_limit_exceeded:

查看集群的详细信息:

127.0.0.1:6381> cluster nodes
2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381@16381 myself,master - 0 1681806481000 1 connected 0-5460
d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384@16384 slave 2c2a0666c9a379328073bd02afb5964120c6bef3 0 1681806482531 1 connected
ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385@16385 slave 70b9c8ee90c6238962cde70663504ebd197a8c1e 0 1681806479000 2 connected
fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383@16383 master - 0 1681806481000 3 connected 10923-16383
7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386@16386 slave fbfac12eaec0ec158a9b9573c9d6f559265554d1 0 1681806481000 3 connected
70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382@16382 master - 0 1681806481526 2 connected 5461-10922

在插入数据时,如果只连接到某一个 redis服务器,并且计算出键的哈希值不在当前主机所表示的槽中时,将无法直接插入进去

127.0.0.1:6381>  set k1 v1
(error) MOVED 12706 198.18.0.1:6383

所以在连接数据库时,需要使用:

redis-cli -p 端口号 -c

此时再尝试插入数据:

127.0.0.1:6381> set k1 v1
-> Redirected to slot [12706] located at 198.18.0.1:6383
OK

查看集群配置:

redis-cli --cluster check 198.18.0.1:6381

当某个主机宕机之后,从机将会马上补位,当某个主机恢复运行后,主从关系并没有恢复,此时的主机变为从机了,补位的从机依旧是主机

主从扩容

添加两台主机:

docker run -d --name redis-node-7 --net host --privileged=true -v ~/program/docker/redis/redis-node-7:/data redis --cluster-enabled yes --appendonly yes --port 6387

 

docker run -d --name redis-node-8 --net host --privileged=true -v ~/program/docker/redis/redis-node-8:/data redis --cluster-enabled yes --appendonly yes --port 6388

加入集群:

root@device:/data# redis-cli --cluster add-node 198.18.0.1:6387 198.18.0.1:6381
>>> Adding node 198.18.0.1:6387 to cluster 198.18.0.1:6381
>>> Performing Cluster Check (using node 198.18.0.1:6381)
S: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots: (0 slots) slave
   replicates d41df0822c86df4b18cdecbaad1fc6d22a25c824
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   slots: (0 slots) slave
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   slots: (0 slots) slave
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Getting functions from cluster
>>> Send FUNCTION LIST to 198.18.0.1:6387 to verify there is no functions in it
>>> Send FUNCTION RESTORE to 198.18.0.1:6387
>>> Send CLUSTER MEET to node 198.18.0.1:6387 to make it join the cluster.
[OK] New node added correctly.

通过执行:

root@device:/data# redis-cli --cluster check 198.18.0.1:6381
198.18.0.1:6383 (fbfac12e...) -> 1 keys | 5461 slots | 1 slaves.
198.18.0.1:6384 (d41df082...) -> 2 keys | 5461 slots | 1 slaves.
198.18.0.1:6382 (70b9c8ee...) -> 0 keys | 5462 slots | 1 slaves.
198.18.0.1:6387 (4af425ea...) -> 0 keys | 0 slots | 0 slaves.

可以发现,新加入的还没有被分配槽位,可以重新分配槽位:

root@device:/data# redis-cli --cluster reshard 198.18.0.1:6381
>>> Performing Cluster Check (using node 198.18.0.1:6381)
S: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots: (0 slots) slave
   replicates d41df0822c86df4b18cdecbaad1fc6d22a25c824
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 4af425ea9c2351fa21e248db44c9cc5237603b15 198.18.0.1:6387
   slots: (0 slots) master
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   slots: (0 slots) slave
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   slots: (0 slots) slave
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 4af425ea9c2351fa21e248db44c9cc5237603b15
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: done

重新分配槽位时相当于之前每个主机匀出了一部分给新的主机

最后将8号机器作为7号的从机,最后的id填写的是主机的id:

root@device:/data# redis-cli --cluster add-node 198.18.0.1:6388 198.18.0.1:6387 --cluster-slave --cluster-master-id 4af425ea9c2351fa21e248db44c9cc5237603b15
>>> Adding node 198.18.0.1:6388 to cluster 198.18.0.1:6387
>>> Performing Cluster Check (using node 198.18.0.1:6387)
M: 4af425ea9c2351fa21e248db44c9cc5237603b15 198.18.0.1:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   slots: (0 slots) slave
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
S: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots: (0 slots) slave
   replicates d41df0822c86df4b18cdecbaad1fc6d22a25c824
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   slots: (0 slots) slave
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 198.18.0.1:6388 to make it join the cluster.
Waiting for the cluster to join

>>> Configure node as replica of 198.18.0.1:6387.
[OK] New node added correctly.

主从缩容

先移除从机,再移除主机,最后一个参数为从机的id

root@device:/data# redis-cli --cluster del-node 198.18.0.1:6388 0cc7d9f92494fa84175eb554aa110d073e483c7f
>>> Removing node 0cc7d9f92494fa84175eb554aa110d073e483c7f from cluster 198.18.0.1:6388
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.

重新分配

root@device:/data# redis-cli --cluster reshard 198.18.0.1:6381
>>> Performing Cluster Check (using node 198.18.0.1:6381)
S: 2c2a0666c9a379328073bd02afb5964120c6bef3 198.18.0.1:6381
   slots: (0 slots) slave
   replicates d41df0822c86df4b18cdecbaad1fc6d22a25c824
M: fbfac12eaec0ec158a9b9573c9d6f559265554d1 198.18.0.1:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
M: d41df0822c86df4b18cdecbaad1fc6d22a25c824 198.18.0.1:6384
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
M: 70b9c8ee90c6238962cde70663504ebd197a8c1e 198.18.0.1:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: 4af425ea9c2351fa21e248db44c9cc5237603b15 198.18.0.1:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
S: 7b172a51bd097d0b0089853001b13e59f3ac8d99 198.18.0.1:6386
   slots: (0 slots) slave
   replicates fbfac12eaec0ec158a9b9573c9d6f559265554d1
S: ed72da0a50a94aaa49aea670ee100072b87e1cf7 198.18.0.1:6385
   slots: (0 slots) slave
   replicates 70b9c8ee90c6238962cde70663504ebd197a8c1e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
# 需要移动的大小
How many slots do you want to move (from 1 to 16384)? 4096
# 用来接收的节点id
What is the receiving node ID? fbfac12eaec0ec158a9b9573c9d6f559265554d1
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
# 从哪儿移出
Source node #1: 4af425ea9c2351fa21e248db44c9cc5237603b15
Source node #2: done

移除主机:

root@device:/data# redis-cli --cluster del-node 198.18.0.1:6387 4af425ea9c2351fa21e248db44c9cc5237603b15
>>> Removing node 4af425ea9c2351fa21e248db44c9cc5237603b15 from cluster 198.18.0.1:6387
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.

Dockerfile

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

  • 指令关键字要用大写字母,并且要跟着一个参数
  • # 表示注释
  • 每条指令将会创建一个新的镜像层并对镜像进行提交

执行流程:

  • 运行一个容器
  • 执行指令,并对容器进行修改
  • 执行类似于commit指令,生成新镜像
  • 基于新镜像运行一个新的容器
  • 重复第二步,直到所有指令执行完成

FROM

基础的镜像,也就是当前的镜像是基于哪个镜像的,在文件的第一行

MAINTAINER

maintainer中文为维护者

RUN

容器构建时执行的命令,两种格式,分别是 shellexec 两种格式

EXPOSE

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

WORKDIR

指定创建容器后终端默认登陆的工作目录

USER

指定镜像由哪个用户执行,如果不指定,默认为root

ENV

运行时环境变量,可以在后续的任何RUN指令使用

VOLUME

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

ADD

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

COPY

拷贝文件和目录到镜像中

CMD

指定容器启动后干的事,也有两种格式, shell 和exec格式

  • shell 格式: CMD <命令>
  • exec 格式: CMD ["可执行文件", "参数1", "参数2".....]

可以有多个指令,但只有最后一个生效,会被执行 run 中的参数覆盖:

例如:运行tomcat通常使用 docker run -d -p 端口:内部端口 tomcat 运行tomcat

但如果使用 docker run -it -p 端口:内部端口 tomcat /bin/bash 后,命令会被替换成了 /bin/bash

ENTRYPOINT

也是指定一个容器运行时的命令,类似于CMD,但不会被docker run后的命令覆盖,通常和CMD配合使用,当配合起来时,相当于CMD给ENTRYPONIT传递参数

例如:

ENTRYPONIT ["nginx", "-c"]
CMD ["/etc/nginx/nginx.conf"]

此时运行容器时相当于执行了: nginx -c /etc/nginx/nginx.conf

如果run命令运行容器时传递了一个命令:

docker run nginx -c /etc/aa.conf

此时运行容器时相当于执行了: nginx -c /etc/aa.conf

FROM ubuntu

ENV MY_DIR=/usr/local
WORKDIR $MY_DIR

RUN apt-get update
RUN apt-get install -y net-tools
RUN apt-get install -y vim
ADD jdk-17_linux-aarch64_bin.tar.gz /usr/local/java
ENV JAVA_HOME /usr/local/java/jdk-17.0.7
ENV JRE_HOME $JAVA_HOME
EXPOSE 2222
CMD echo "------------success-----------"
CMD /bin/bash

构建Dockerfile:

docker build -t 名称:tag ./

如果不使用 -t 指定名称和 tag 将会出现虚悬镜像,可以使用:

# 查找虚悬镜像
docker images ls -f dangling=true
# 删除虚悬镜像
docker image prune

查找、删除虚悬镜像, prune 中文为修剪,读音为: pro͞on

构建springboot:

FROM eclipse-temurin:17-jre

ENV MY_DIR=/root/application
WORKDIR $MY_DIR
COPY ./target/boot-docker-0.0.1-SNAPSHOT.jar $MY_DIR

EXPOSE 12300
ENTRYPOINT ["java", "-jar", "./boot-docker-0.0.1-SNAPSHOT.jar"]

network

# 查看所有网路
docker network ls
# 创建网络
docker network create 名称

创建网络后,可以在ifconfig中看到

也可以查看网络详情:

docker network inspect 网络名称

网络模式

  • bridge :为每个容器分配、设置一个ip,这是默认的模式

    • 可以通过 ip addr 命令看出,每次运行一个容器将会有一个新的信息出来
  • host :容器不会虚拟出自己的网卡,直接使用宿主机的IP和端口

    • 通过此模式启动的容器如果含有端口映射信息,那么会出现警告,这个时候再通过 docker ps查看运行的容器,此时将不会显示具体的端口信息,端口映射也不会生效,此时直接打开 localhost:原本的端口 就可以打开
    ➜  ~ docker run -d --name tomcat3 -p 18083:8080 --network host tomcat
    WARNING: Published ports are discarded when using host network mode
    22fa8a63c29cbaa682528d986b6fcc2b1cbf59dd15d360d5d1decbd31c3c8b92
    
  • none :几乎不用

  • container :新创建的容器不会创建自己的网卡和配置IP,而是和一个指定的容器共享IP和端口

新创建的网络默认是bridge模式

Docker Compose

compose中文为组成,为容器编排,可以一键启动多个容器实例,决定容器的启动顺序,可以通过 docker-compose.yml 配置文件定义,是 docker 官方的开源项目

命令

docker compose -h 帮助
docker compose up 启动
docker compose up -d 启动并后台运行
docker compose down 停止并删除容器、网络、卷、镜像
docker compose exec 服务id 进入容器内部
docker compose ps 查看编排过的容器
docker compose top 显示当前的进程

docker compose logs 服务id 查看所有的容器输出日志
docker compose config 检查配置
docker compose config -q 检查配置,有问题输出
docker compose restart 重启
docker compose start 开始
docker compose stop 停止
version: '3'

services:
  boot:
    image: my-boot:1.6
    container_name: my-boot-001
    restart: always
    ports:
      - "22300:12300"
    networks:
      - boot-net
    depends_on:
      - redis
      - mysql
    command:
      - --spring.data.redis.host=redis-boot
      - --spring.datasource.url=jdbc:mysql://mysql-boot:3306/good
  redis:
    restart: always
    image: redis:latest
    container_name: redis-boot
    ports:
      - "6379:6379"
    volumes:
      - ~/.redis/redis.conf:/etc/redis/redis.conf
      - ~/.redis/data:/data
    networks:
      - boot-net
  
  mysql:
    image: mysql:latest
    container_name: mysql-boot
    restart: always
    ports:
      - "3306:3306"
    volumes:
      - ~/.mysql/log:/var/log/mysql
      - ~/.mysql/data:/var/lib/mysql
      - ~/.mysql/conf:/etc/mysql/conf.d
    environment:
      - MYSQL_ROOT_PASSWORD=20020327
    networks:
      - boot-net
networks:
  boot-net:

Q.E.D.


念念不忘,必有回响。