1 docker复杂安装详说
1.1 mysql主从复制
1.1.1 启动主节点3307
docker run -p 3307:3306 \
-v /bf/mysql-master/log:/var/log/mysql \
-v /bf/mysql-master/data:/var/lib/mysql \
-v /bf/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-master \
-d mysql:5.7
docker run -p 3308:3306 \
-v /bf/mysql-slave/log:/var/log/mysql \
-v /bf/mysql-slave/data:/var/lib/mysql \
-v /bf/mysql-slave/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-slave \
-d mysql:5.7
1.1.2 在主节点conf目录下编辑配置文件my.cnf
master节点编辑my.cnf配置文件
[mysqld]
server_id=101
binlog-ignore-db=mysql
log-bin=mall-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
1.1.3 修改配置文件后重启主节点
1.1.4 进入master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -p
1.1.5 主节点创建同步用户
create user 'slave'@'%' identified by '123456';
grant replication slave, replication client on *.* to 'slave'@'%';
1.1.6 启动从节点3308
1.1.7从节点新建配置文件
从节点server_id = 102,注意不要重复
1.1.8 修改完配置重启slave实例
docker restart 59931682b155
docker ps
1.1.9 在主数据库中查看主从同步状态
1.1.10 进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -p
1.1.11 从数据库配置主从同步
change master to master_host='192.168.17.128',master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=617,master_connect_retry=30;
1.1.12 在从数据库查看主从同步状态
show slave status \G;
slave_io_running 和 slave_sql_running 为 NO
1.1.13 在从数据库开启主从同步
1.1.14 查看从数据库同步状态
slave_io_running 和 slave_sql_running 为 NO变为 YES
1.1.15 测试主从同步
操作数据库工具连接主库,并写入记录,切换到从库发现对应数据已经同步。
1.1.16 关于字符编码
经过测试,如果不按照初级篇修改对应编码,在centos上会出现乱码
所以我这里配置文件根据初级篇做了修改,完全版本如下所示。
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
server_id=101
binlog-ignore-db=mysql
log-bin=mall-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
1.2 安装redis集群
1.2.1 亿级数据缓存
为什么使用集群这里不再赘述。
1.2.2 启动6个redis容器实例
docker run -d \
--name redis-node-1 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-1:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6381
docker run -d \
--name redis-node-2 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-2:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6382
docker run -d \
--name redis-node-3 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-3:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6383
docker run -d \
--name redis-node-4 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-4:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6384
docker run -d \
--name redis-node-5 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-5:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6385
docker run -d \
--name redis-node-6 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-6:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6386
效果图如下
1.2.3 配置主从
redis-cli --cluster create
192.168.17.128:6381
192.168.17.128:6382
192.168.17.128:6383
192.168.17.128:6384
192.168.17.128:6385
192.168.17.128:6386
--cluster-replicas 1
–cluster-replicas 1 的 意思是一主一从
redis-cli -p 6381
cluster nodes
挂载关系 1主5从,2主6从,3主4从
1.2.4 读写error说明
redis-cli -p 6381
1.2.5 集群读写路由增强
以集群的形式连接
redis-cli -p 6381 -c
1.2.6 查看集群状态
redis-cli --cluster check 192.168.17.128:6381
1.3 主从切换
关闭1号节点,观察集群主从状态。
可以发现可以顺利取出之前存的4个key
将node1启动回来,发现主从关系没有重新改变,从节点升为主节点,之前的主节点变为从节点
1.4 主从扩容
操作步骤
- 启动redis容器6387 6388
- 将6387节点加入集群
- 查看集群状态
- 重新分配槽号
- 第二次查看集群状态
- 为6387分配6388从节点
- 第三次查看集群状态
1.4.1 启动容器6387 6388
docker run -d \
--name redis-node-7 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-7:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6387
docker run -d \
--name redis-node-8 \
--net host \
--privileged=true \
-v /data/redis/share/redis-node-8:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port 6388
1.4.2 将6387master节点添加进集群
redis-cli --cluster add-node 192.168.17.128:6387 192.168.17.128:6381
1.4.3 第一次查看集群状态
redis-cli --cluster check 192.168.17.128:6381
1.4.4 重新分派槽号
redis-cli --cluster reshard 192.168.17.128:6381
1.4.5第二次查看集群状态
redis-cli --cluster check 192.168.17.128:6381
1.4.6 为主节点6387分配从节点6388
redis-cli --cluster add-node 192.168.17.128:6388 192.168.17.128:6387 --cluster-slave --cluster-master-id a03199891da62047b7bbc3f6889acb655f468356
1.4.7第三次检查集群状态
redis-cli --cluster check 192.168.17.128:6381
1.5主从缩容
操作步骤
- 查看集群情况获得6388节点id
- 删除6388节点
- 将6387槽号重新分配
- 检查集群情况
- 将6387删除
- 检查集群情况
1.5.1获取节点id
1.5.2集群删除节点6388
redis-cli --cluster del-node 192.168.17.128:6388 90eecc6d32f52c19e460979eeb6c32194bcfeb8f
1.5.3重新分配slot
本例将6387的slot全部分给6382节点
redis-cli --cluster reshard 192.168.17.128:6381
1.5.4查看集群状态
发现6387节点已经没有slot
1.5.5 删除6387节点
查看集群状态
redis-cli --cluster del-node 192.168.17.128:6387 a03199891da62047b7bbc3f6889acb655f468356
1.6 Spring Boot 连接集群
这里以 Another Redis Desktop Manager为例来演示连接集群,配置如下图所示,ip要改成自己的集群。
1.6.1 注意事项和搭建
注意这三个命令,如果工具连不上很有可能是这个原因。
经过测试,如果开启防火墙,工具会立马断开连接。
systemctl start firewalld
systemctl stop firewalld
systemctl status firewalld
yml 配置文件,配置相关集群节点。
spring:
redis:
password:
cluster:
nodes:
- 192.168.139.131:6381
- 192.168.139.131:6382
- 192.168.139.131:6383
- 192.168.139.131:6384
- 192.168.139.131:6385
- 192.168.139.131:6386
编写一个简单的Controller来测试存值。
@RestController
public class TestController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@GetMapping("test")
public void test() {
for (int i = 0; i < 100; i++) {
stringRedisTemplate.opsForValue().set("k" + i, String.valueOf(i), 30, TimeUnit.SECONDS);
}
}
}
1.6.2 查看工具中key的状态
过期前
过期后
1.6.3 查看集群状态
redis-cli --cluster check 192.168.139.131:6381
key 生效后查询状态
key 过期后再次查询状态
2 DockerFile
2.1 DockerFile常用关键字
2.2 案例 使用DockerFile生成镜像 Centos+vim+java8+ifconfig
2.2.1下载windows下载jdk1.8,拷贝进目录,注意大小是否拷贝完全。
2.2.2 编写Dockerfile文件
一定要注意 $ 不要是#,否则java -version可能会出不来
一定要注意 $ 不要是#,否则java -version可能会出不来
一定要注意 $ 不要是#,否则java -version可能会出不来
FROM centos
MAINTAINER lzy<1033649766@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
ADD jdk-8u171-linux-x64.tar.gz /usr/local/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
CMD echo $MYPATH
CMD echo "success ----- ok "
CMD /bin/bash
2.2.3 Dockerfile构建镜像
docker build -t centosjdk8:1.1 .
生成的新镜像
2.2.4 启动新镜像
docker run -it b6c2b0d80d28 /bin/bash
2.2.5 测试vim ifconfig java -version
2.2.6 坑
第一个坑 由于Dockerfile比照视频手打的,所以将 $ 打成了 # ,java -version配置失败
第二个坑 虚拟机复制的jdk文件大小只有 2.5M,而源文件有180M,因而报错,一定要查看复制过来的文件大小是否缺失。
failed to copy files: Error processing tar file(exit status 1): unexpected EOF
2.3 虚悬镜像
通过Dockerfile产生一个虚悬镜像,虚悬镜像是错误的,理应删除
运行后产生虚悬镜像
虚悬镜像的查看和删除
docker image ls -f dangling=true
docker image prune
3. 微服务实战
3.1测试微服务接口
编写一个微服务,并使用maven打包成jar包,测试一下能否启动
3.2 jar包导入虚拟机
将Dockerfile和jar包放在同一目录下
3.3编写Dockerfile文件
Dockerfile文件内容
FROM java:8
MAINTAINER lzy
VOLUME /tmp
ADD mic-io-0.0.1-SNAPSHOT.jar a.jar
ENTRYPOINT ["java","-jar","a.jar"]
EXPOSE 8080
3.4构建镜像文件
docker build -t aaa:1.1 .
3.5后台启动容器 映射 8080
docker run -d -p 8080:8080 b73f7d27485e
3.6测试docker微服务接口
3.7坑
原因Dockerfile编写的时候多加了 ’
Docker Error :Invalid or corrupt jarfile .jar
产生原因: 虚拟机导入jar包大小不正确,导致缺失文件,重新导入后即可。
4 docker网络
4.1 docker网络基本命令
查询 docker 网络模式
docker network ls
bridge 和 host 比较重要 ,none 一般不用
docker network create 创建网络
docker network rm 删除网络
docker network inspect bridge
4.2 docker网络作用
容器间的互联和通信以及端口映射。
容器ip变动的时候通过服务名直接通信而不是ip。
4.3 docker网络模式
4.3.1 四种网络模式
4.4 容器发生变化时ip的变化
u1的inspect
u2的inspect
4.4.1 关闭u2,查看u3的ip变化
得出结论,当容器状态变更的时候,网络的ip会发生变化。
4.5 docker network inspect bridge
docker network inspect bridge
docker network inspect host
docker network inspect none
docker network inspect container
4.5.1 docker network inspect bridge
4.6
4.6.2 bridge
直接使用docker0和宿主机通信
bridge 模式 下 不需要 -p 来进行 端口映射
5 Docker Compose 容器编排
5.1下载
请求git地址下载docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
授权
chmod +x /usr/local/bin/docker-compose
查看版本
docker-compose --version
5.2 重新制作微服务jar包
service部分代码如下
@Service
public class DockerUserServiceImpl extends ServiceImpl<DockerUserMapper, DockerUser> implements DockerUserService {
public static final String PREFIX = "user:";
private final DockerUserMapper dockerUserMapper;
private final RedisTemplate redisTemplate;
public DockerUserServiceImpl(DockerUserMapper dockerUserMapper, RedisTemplate redisTemplate) {
this.dockerUserMapper = dockerUserMapper;
this.redisTemplate = redisTemplate;
}
@Override
public void addUser() {
DockerUser dockerUser = new DockerUser();
dockerUser.setAge(10);
dockerUser.setAddress("sdsdadsad");
dockerUser.setName("zzx");
dockerUser.setSex(1);
int i = dockerUserMapper.insert(dockerUser);
if (i > 0) {
dockerUser = dockerUserMapper.selectById(dockerUser.getId());
String key = PREFIX + dockerUser.getId();
redisTemplate.opsForValue().set(key, dockerUser);
}
}
@Override
public DockerUser findUserById(Integer id) {
DockerUser user = null;
String key = PREFIX + id;
user = (DockerUser) redisTemplate.opsForValue().get(key);
if (user == null) {
user = dockerUserMapper.selectById(id);
if (user == null) {
return user;
}
redisTemplate.opsForValue().set("key", user);
}
return user;
}
}
配置文件注意要把mysql和redis的路径更换为虚拟机ip
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
server:
port: 8080
spring:
application:
name: micDocker
datasource:
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/demo01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
url: jdbc:mysql://192.168.17.128:3306/demo01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
redis:
database: 0
# host: 192.168.17.128
host: 192.168.17.128
lettuce:
pool:
max-active: 8
max-idle: 8
max-wait: -1
min-idle: 0
password:
port: 6379
timeout: 30000
5.3 不用compose编排服务
操作步骤:
- 编写微服务程序,本地测试并打包后移植虚拟机上
- 编写Dockerfile将jar包变为镜像
- 启动mysql redis jar包三个容器
- 测试插入用户
- 测试获取用户信息
5.3.1 移植虚拟机
注意jar包大小要和容器外保持一致。
5.3.2 编写Dockerfile将jar包变为镜像
5.3.3 启动三个容器
后台启动 redis、mysql、jar 三个容器,查看是否启动成功
测试容器8080能否访问
插入用户报错,查看容器日志 docker logs + 容器id。
将redis中protected_mode改为no后重启实例
mysql成功插入数据
测试 redis 成功获取
数据库记录
测试获取用户接口
根据日志,没有select记录,成功在redis中获取用户信息。
总结 当微服务变多,手动启动容器的难度就会加大,同时也会增加出错概率,这个时候使用compose进行一文件多容器的启动和停止就十分的有必要
5.4 compose编排服务
docker-compose.yml文件内容如图所示
version: "3"
services:
microService:
image: yyds:1.0
container_name: ms01
ports:
- "8080:8080"
volumes:
- /bf/usecmps/microService:/data
networks:
- lzy_net
depends_on:
- redis
- mysql
redis:
image: redis:6.2.6
ports:
- "6379:6379"
volumes:
- /bf/usecmps/redis/redis.conf:/etc/redis/redis.conf
- /bf/usecmps/redis/data:/data
networks:
- lzy_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: 'demo01'
MYSQL_USER: 'admin'
MYSQL_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- /bf/usecmps/mysql/db:/var/lib/mysql
- /bf/usecmps/mysql/conf/my.cnf:/etc/my.cnf
- /bf/usecmps/mysql/init:/docker-entrypoint-initdb.d
networks:
- lzy_net
command: --default-authentication-plugin=mysql_native_password
networks:
lzy_net:
compose文件检查
第一个原因: version拼写错误
第二个原因: redis挂载的容器数据卷重复
第三个: 无输出代表正常
启动redis和mysql之前,把redis.conf和my.cnf文件复制到相应位置,不然会启动会创建目录
redis.conf和my.cnf目录,虽然不会报错,但是读取不到配置文件。
docker-compose up -d
启动命令如下
docker-compose up -d
访问swagger测试insert
进入redis容器内容,尝试获取user:2的值
测试查询接口,可以看到成功获取到id=3的用户
通过这个命令可以查看日志
docker-compose logs microService
通过查看日志得出查询id=3走的redis,测试成功
docker-compose stop
docker-compose start
docker-compose restart
docker-compose 常用命令
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
6 Docker轻量级工具portainer
6.1 下载安装
–restart=always 参数补充说明,docker重启后容器仍然存活
-------https
docker run -d -p 8000:8000 -p 9443:9443 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:2.11.0
------ http
docker run -d -p 8000:8000 -p 9000:9000 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:2.11.0
运行后查看启动情况
6.2 9000端口
设置用户密码后,登录界面如图所示
显示磁盘使用情况
docker system df
对应portainer统计
6.3 界面上启动nginx
访问 80 端口,可以看到容器nginx已经成功创建
6.4 更新版本
步骤如下,首先停止容器,删除容器,删除镜像,以2.13.1版本为例,运行下面代码启动
docker run -d -p 8000:8000 -p 9000:9000 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:2.13.1
更新版本后需要更新密码至少12个字符,我这里是 123456789123456789
7 Docker容器监控重量级 CAdivsor+InfluxDB+Granfana
docker stats
docker stats
7.1 CIG介绍
由于 docker stats 过于简单,所以引入 cig来强化监控。
企业上云之容器监控利器-cAvisor
InfluxDB(时序数据库),常用的一种使用场景:监控数据统计 influxDB官网
可视化监控指标展示工具-Grafana https://grafana.com/
7.2 使用compose编排 CIG
编写文件 docker-compose.yml
version: "3.1"
volumes:
grafana_data: { }
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
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
执行检查命令
docker-compose config -q
执行启动命令
docker-compose up
使用portainer查看启动状态
8083 influxdb
8080 cadvisor
3000 grafana 默认账号密码 admin/admin
配置grafana数据源
保存并测试
添加面板
配置完成后面板如图所示
7.3 问题记录
可以看到在cadvisor中时间是比实际时间快8个小时的