【Docker】Docker进阶(一)

时间:2022-11-14 09:54:08

一、Docker复杂安装

1.1、安装mysql主从复制

1.1.1、配置主机

主机的my.cnf

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


启动docker

docker run -p 3307:3306 --name mysql-master 
-v /www/wwwroot/dockerData/mysql/master/log:/var/log/mysql 
-v /www/wwwroot/dockerData/mysql/master/data:/var/lib/mysql 
-v /www/wwwroot/dockerData/mysql/master/conf:/etc/mysql/conf.d  
-e MYSQL_ROOT_PASSWORD=root 
-d mysql:5.7

主机容器实例内创建数据同步用户

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

1.1.2、配置从机

my.cnf

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

启动docker

docker run -p 3308:3306 
--name mysql-slave 
-v /www/wwwroot/dockerData/mysql/slave/log:/var/log/mysql 
-v /www/wwwroot/dockerData/mysql/slave/data:/var/lib/mysql 
-v /www/wwwroot/dockerData/mysql/slave/conf:/etc/mysql/conf.d  
-e MYSQL_ROOT_PASSWORD=root 
-d mysql:5.7

1.1.3、配置主从复制

在主机 输入show master status;
【Docker】Docker进阶(一)
在从机输入

-- 格式:
--change master to master_host='宿主机ip'
--master_user='主数据库配置的主从复制用户名' 
--master_password='主数据库配置的主从复制用户密码' 
--master_port=宿主机主数据库端口
--master_log_file='主数据库主从同步状态的文件名File'
--master_log_pos=主数据库主从同步状态的Position
--master_connect_retry=连接失败重试时间间隔(秒);

change master to master_host='192.168.3.100',master_user='slave',master_password='123456',master_port=3307,master_log_file='mysql-bin.000003',master_log_pos=154,master_connect_retry=30;

在从机查看主从同步状态:

# \G 可以将横向的结果集表格转换成纵向展示。
# slave status的字段比较多,纵向展示比友好
show slave status \G;

除了展示刚刚配置的主数据库信息外,主要关注 Slave_IO_RunningSlave_SQL_Running。目前两个值应该都为No,表示还没有开始。

在从机:开启主从同步:

start slave;

再次查看主从同步状态, Slave_IO_RunningSlave_SQL_Running都变为Yes
主从复制测试:
在主机

create database db01;
use db01;
create table t1 (id int, name varchar(20));
insert into t1 values (1, 'abc');

在从机

show databases;
use db01;
select * from t1;

1.2、安装Redis 3主3从

1.2.1、安装

使用docker搭建3主3从的Redis集群,每台主机都对应一台从机。
启动6台redis容器

# 启动第1台节点
# --net host 使用宿主机的IP和端口,默认
# --cluster-enabled yes 开启redis集群
# --appendonly yes 开启redis持久化
# --port 6381 配置redis端口号
docker run -d --name redis-node-1 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381

# 启动第2台节点
docker run -d --name redis-node-2 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382

# 启动第3台节点
docker run -d --name redis-node-3 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383

# 启动第4台节点
docker run -d --name redis-node-4 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384

# 启动第5台节点
docker run -d --name redis-node-5 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385

# 启动第6台节点
docker run -d --name redis-node-6 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

1.2.2、构建主从关系:

# 宿主机IP:端口
redis-cli --cluster create 192.168.xxx.xxx:6381 192.168.xxx.xxx:6382 192.168.xxx.xxx:6383 192.168.xxx.xxx:6384 192.168.xxx.xxx:6385 192.168.xxx.xxx:6386 --cluster-replicas 1

redis尝试自动进行主从节点分配
因为我们的docker容器IP相同,所以会出现警告[WARNING] Some slaves are in the same host as their master,可以直接忽略该警告

redis自动分配结果完成后,需要输入 Yes 确认配置信息:
【Docker】Docker进阶(一)
Waiting for the cluster to join长时间没有反应的解决方法

【Docker】Docker进阶(一)
在6381结点上查看集群状态:

redis-cli -p 6381
cluster info
其中:
cluster_state:ok 
分配的哈希槽数量 cluster_slots_assigned为16384
集群节点数量cluster_known_nodes为6 

1.2.3、集群读写

当使用 redis-cli连接redis集群时,需要添加 -c参数,否则可能会出现读写出错。

docker exec -it redis-node-1 /bin/bash
set k1 v1

会有提示信息,哈希槽为12706,重定向到6383(即节点3,哈希槽[10923, 16383]):

1.2.4、集群信息检查

# 输入任意一台主节点地址都可以进行集群检查
redis-cli --cluster check 192.168.xxx.xxx:6381

1.2.5、主从扩容

假如因为业务量激增,需要向当前3主3从的集群中再加入1主1从两个节点。

启动2台新的容器节点 :

# 启动第7台节点
docker run -d --name redis-node-7 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
#启动第8台节点
docker run -d --name redis-node-8 --net host --privileged=true -v /www/wwwroot/dockerData/redis/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388

进入6387(节点7)容器内部

docker exec -it redis-node-7 /bin/bash

将6387作为master加入集群

# redis-cli --cluster add-node 本节点地址 要加入的集群中的其中一个节点地址
redis-cli --cluster add-node 192.168.xxx.xxx:6387 192.168.xxx.xxx:6381

检查当前集群状态 可以发现,6387节点已经作为master加入了集群,但是该节点没有被分配槽位。
重新分配集群的槽位

redis-cli --cluster reshard 192.168.xxx.xxx:6381

redis经过槽位检查后,会提示需要分配的槽位数量:

例如,我们现在是4台master,我们想要给node7分配4096个槽位,这样每个节点都是4096个槽位。
输入4096后,会让输入要接收这些哈希槽的节点ID,填入node7的节点ID即可。(就是节点信息中很长的一串十六进制串)。

然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node7。一般选择all,即将之前的3个主节点的槽位都均一些给Node7,这样可以使得每个节点的槽位数相等均衡。

输入all之后,redis会列出一个计划,内容是自动从前面的3台master中拨出一部分槽位分给Node7的槽位,需要确认一下分配的计划。

输入yes确认后,redis便会自动重新洗牌,给Node7分配槽位

重新分配完成后,可以进行集群信息检查,查看分配结果
【Docker】Docker进阶(一)
为主节点6387分配从节点6388:

redis-cli --cluster add-node 192.168.xxx.xxx:6388 192.168.xxx.xxx:6381 --cluster-slave --cluster-master-id 【node7节点的十六进制编号字符串】

检查集群当前状态 成功!

1.2.5、主从缩容

假如业务高峰期过去,需要将4主4从重新缩容到3主3从。即从集群中移除node8和node7.
首先删除从节点6388:

redis-cli --cluster del-node 192.168.xxx.xxx:6388 6388节点编号

对node7重新分配哈希槽:

redis-cli --cluster reshard 192.168.xxx.xxx:6381

如果我们想直接把node7的4096个哈希槽全部分给某个节点,可以直接输入4096。
输入4096后,会让输入要接收这些哈希槽的节点ID。假如我们想把这4096个槽都分给Node1,直接输入node1节点的编号即可。
然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node1。这里我们输入node7的节点编号,回车后输入done。

将node7从集群中移除

redis-cli --cluster del-node 192.168.xxx.xxx:6387 node7节点编号

二、Dockerfile

2.1、Dockerfile

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

构建步骤:

  1. 编写Dockerfile文件
  2. docker build命令构建镜像
  3. docker run依据镜像运行容器实例

2.2、构建过程

Dockerfile编写:

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

Docker引擎执行Docker的大致流程:

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

2.3、 Dockerfile保留字

以tomcat为例

2.3.1、FROM

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

# FROM 镜像名
FROM hub.c.163.com/library/tomcat

2.3.2、MAINTAINER

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

# 非必须
MAINTAINER NaCl @163.com

2.3.3、RUN

容器构建时需要运行的命令。 RUN是在docker build时运行
有两种格式:
shell格式

# 等同于在终端操作的shell命令
# 格式:RUN <命令行命令>
RUN yum -y install vim

exec格式

# 格式:RUN ["可执行文件" , "参数1", "参数2"]
RUN ["./test.php", "dev", "offline"]  # 等价于 RUN ./test.php dev offline

2.3.4、EXPOSE

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

# EXPOSE 要暴露的端口
# EXPOSE <port>[/<protocol] ....
EXPOSE 3306 33060

2.3.5、WORKDIR

指定在创建容器后, 终端默认登录进来的工作目录。

ENV CATALINA_HOME /usr/local/tomcat
WORKDIR $CATALINA_HOME

2.3.6、USER

指定该镜像以什么样的用户去执行,如果不指定,默认是root。(一般不修改该配置)

# USER <user>[:<group>]
USER patrick

2.3.7、ENV

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

这个环境变量可以在后续的任何RUN指令或其他指令中使用

# 格式 ENV 环境变量名 环境变量值
# 或者 ENV 环境变量名=值
ENV MY_PATH /usr/mytest

# 使用环境变量
WORKDIR $MY_PATH

2.3.8、VOLUME

容器数据卷,用于数据保存和持久化工作。类似于 docker run 的-v参数。

# VOLUME 挂载点
# 挂载点可以是一个路径,也可以是数组(数组中的每一项必须用双引号)
VOLUME /var/lib/mysql

2.3.9、ADD

将宿主机目录下(或远程文件)的文件拷贝进镜像,且会自动处理URL和解压tar压缩包。

2.3.10、COPY

类似ADD,拷贝文件和目录到镜像中。

将从构建上下文目录中<源路径>的文件目录复制到新的一层镜像内的<目标路径>位置。

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

2.3.11、CMD

指定容器启动后要干的事情。
有两种格式:
shell格式:

# CMD <命令>
CMD echo "hello world"

exec格式

# CMD ["可执行文件", "参数1", "参数2" ...]
CMD ["catalina.sh", "run"]
# CMD ["参数1", "参数2" ....],与ENTRYPOINT指令配合使用

Dockerfile中如果出现多个CMD指令,只有最后一个生效。CMD会被docker run之后的参数替换。
CMD是在docker run时运行,而 RUN是在docker build时运行。

2.3.12、ENTRYPOINT

用来指定一个容器启动时要运行的命令。

类似于CMD命令,但是ENTRYPOINT不会被docker run后面的命令覆盖,这些命令参数会被当做参数送给ENTRYPOINT指令指定的程序。

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

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

FROM nginx

ENTRYPOINT ["nginx", "-c"]  # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

对于此Dockerfile,构建成镜像 nginx:test后,如果执行;

  • docker run nginx test,则容器启动后,会执行 nginx -c /etc/nginx/nginx.conf
  • docker run nginx:test /app/nginx/new.conf,则容器启动后,会执行 nginx -c /app/nginx/new.conf

2.4、构建镜像

2.4.1、eg:CentOS+JDK8

编写DockerFile文件

FROM centos:7 #安装CentOS7
MAINTAINER NaCl<> #作者+邮箱
 
ENV MYPATH /usr/local #启动docker后命令行在/usr/local
WORKDIR $MYPATH
 
RUN yum -y install vim          #安装vim编辑器

RUN yum -y install net-tools    #安装ifconfig命令查看网络IP

RUN yum -y install glibc.i686   #安装lib库

RUN mkdir /usr/local/java       #在docker里创建安装java的文件路径

#ADD 是相对路径jar,把jdk-8u341-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u341-linux-x64.tar.gz /usr/local/java/

#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_341
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
 
EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash

进入到DockerFile文件路径下进行构建镜像(带一个.)
docker build -t mycentos:1.0.0 .

2.5、虚悬镜像

虚悬镜像:仓库名、标签名都是 的镜像,称为 dangling images(虚悬镜像)。

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

列出docker中的虚悬镜像:

docker image ls -f dangling=true

虚悬镜像一般是因为一些错误而出现的,没有存在价值,可以删除:\

# 删除所有的虚悬镜像
docker image prune