Docker进阶
一、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;
在从机输入
-- 格式:
--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_Running
、Slave_SQL_Running
。目前两个值应该都为No
,表示还没有开始。
在从机:开启主从同步:
start slave;
再次查看主从同步状态, Slave_IO_Running
、Slave_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 确认配置信息:
Waiting for the cluster to join长时间没有反应的解决方法
在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分配槽位
重新分配完成后,可以进行集群信息检查,查看分配结果
为主节点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镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
构建步骤:
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run依据镜像运行容器实例
2.2、构建过程
Dockerfile编写:
- 每条保留字指令都必须为大写字母,且后面要跟随至少一个参数
- 指令按照从上到下顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
Docker引擎执行Docker的大致流程:
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行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