docker:解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术
Docker本身是一个容器运行载体或称之为管理引擎。我们把引用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来的一个对象).
image文件可以看作是容器的模板,Docker根据image文件生成容器的实例,同一个image文件,可以生成多个同时运行的容器实例。
比较Docker和传统虚拟化方式的不同之处:
1.传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需要应用进程;
2.容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便;
3.每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源
Docker三要素:镜像,容器,仓库
镜像文件:image文件生成的容器实例,本身也是一个文件,称为镜像文件
容器实例:一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器。
仓库:就是防一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了
一、
Docker安装
Install Docker Engine on CentOS | Docker Documentation
yum install -y yum-utils
2.设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
3.更新yum软件包索引
yum makecache fast
4.安装docker引擎
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
5.启动docker
systemctl start docker
6.helloworld
docker run hello-world
安装成功:
(1)卸载docker
yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin
rm -rf /var/lib/docker
rm -rf/var/lib/containerd
(2)停止docker服务
systemctl stop docker
二、阿里云镜像加速器
注册阿里云开放云原生应用-云原生(Cloud Native)-云原生介绍 - 阿里云
控制台->弹性 计算
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://n3twaq8i.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
三.Docker常用命令
1.帮助启动类命令:
- 启动docker: systemctl start docker
- 停止docker: systemctl stop docker
- 重启docker: systemctl restart docker
- 查看docker状态:systemctl status docker
- 开机启动:systemctl enable docker
- 查看docker概要信息:docker info
- 查看docker总体帮助文档:docker --help
- 查看docker命令帮助文档:docker 具体命令 --help
2.镜像命令
列出本地主机上的镜像:docker images (-a:列出本地所有镜像;-q:只显示镜像ID)
(1)REPOSITORY:表示镜像的仓库源 (2)TAG:镜像的标签版本号 (3)IMAGE ID :镜像ID (4):CREATED:镜像创建时间 (5)SIZE:镜像大小
查询远程仓库镜像:docker search 镜像名字 (-limit :只列出N个镜像。默认25个)
3.下载镜像:docker pull 镜像名字 [:tag] (版本号,默认最新版本)
4.查看镜像/容器/数据卷所占的空间:docker system df
5.删除镜像:docker rmi 镜像名字
删除单个:docekr rmi -f 镜像ID
删除多个:docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部:docker rmi -f $(docker images -qa)
谈谈docker虚悬镜像是什么?
仓库名,标签都是<none>的镜像,俗称虚悬镜dangling image
3.容器命令
OPTIONS:
(1) --name="容器新名字" :为容器指定一个名称
(2) -d :后台运行容器并返回容器ID,也即启动守护容器;
(3) -i : 以交互模式运行容器。通常与 -t 同时使用;
(4)-t : 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即是启动交互式容器(前端有伪终端,等待交互);
(5)-P : 随机端口映射,大写P;
(6) -p : 指定端口映射,小写p;
启动交互式容器(前台命令行):
解决:
[root@localhost root123]# docker run -it ubuntu /bin/bash
WARNING: IPv4 forwarding is disabled. Networking will not work.
2.列出当前正在运行的容器:docker ps [OPTIONS]
OPTIONS:
(1) -a : 列出当前所有正在运行的容器 + 历史上运行过的
(2) -l : 显示最近创建的容器
(3) -n : 显示最近n个创建的容器
(4) -q : 静默模式,只显示容器编号
3.退出容器:
(1)exit : run进去容器,exit退出,容器停止;
(2)ctrl+p+q :run进去容器,ctrl+p+q退出,容器不停止;
** 4.启动已经停止运行的容器:docker start 容器ID或容器名**
** 5.重启容器:docker restart 容器ID或容器名**
** 6.停止容器:docker stop 容器Id或容器名**
** 7.强制停止容器:docker kill 容器ID或容器名**
** 8.删除已经停止的容器:docker rm 容器ID ;docker rmi 镜像 **
** -f: 强制删除 **
** 一次性删除多个容器实例:慎用!!!**
** (1):docker rm -f $(docker ps -a -q)**
** (2):docker ps -a -q | xargs docker rm**
-d的讲解:
** #使用镜像centos:latest 以后台模式启动一个容器 docker run -d centos**
问题:然后docker ps -a 进行查看,会发现容器已经退出
** **很重要的要说明一点:docker容器后台运行,就必须有一个前台进程
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出。
这是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可,例如service nginx start ,但是,这样做nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,就会自杀因为他觉得他没有事可做,所以,最佳的解决方案式是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有工作,别中端
运行redis 6.0.8
- 前台运行redis :docker run -it redis:6.0.8
- 后台运行redis:docker run -d reids:6.0.8
- 查看日志:docker logs 容器ID
- 查看容器内运行的进程:docker top 容器ID
- 查看容器内部细节:docker inspect 容器ID
- 进入正在运行的容器: 1. docker exec -it 容器ID bashShell2. 重新进入: docker attach 容器ID3. 上述两个区别: 1. attach 直接进入容器启动命令的终端,不会启动新的进程。用exit退出,会导致容器的停止;2. exec是在容器中打开新的终端,并且可以启动新的进程。用exit退出,不会导致容器的停止。3. 推荐使用docker exec 命令,因为退出容器终端,不会导致容器的停止。
7.从容器内拷贝文件到主机:docker cp 容器ID:容器内路径 目的主机路径
8.导入和导出容器:
(1)export 导出容器的内容留作为一个tar归档文件(对应import命令)
(2)import 从tar 包中的内容创建一个新的文件系统在导入为镜像
案例:
(1)docker export 容器ID > 文件名.tar
(2)cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号
四、Docker镜像
1.什么是镜像:
是一种轻量级,可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个 可交付的运行环境(包括代码,运行时需要的库,环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
2.UnionFS(联合文件系统):
Union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交 一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于继承镜像,可以制作各种具体的应用镜像
3.Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件bootfs。这一层与我们典型的Linux和Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核。此时系统也会卸载bootfs。
rootfs,在bootfs之上,包含的就是典型的Linux系统中的/dev,/proc/bin/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等待。
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的keernel,自己只需要提供rootfs就行了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版本可以公用bootfs。
4.为什么Docker镜像采用这种分层结构呢
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需要在磁盘上保存一份base镜像;同时内存也只需要加载一份base镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。
Docker镜像层都只是只读的,容器层是可写的;当容器启动时,一个新的可写容器被加载到镜像的顶部,这层通常被称作 ”容器层“,容器层之下的都叫”镜像层“;所有对容器的改动-无论添加删除,还是修改文件都只发生在容器层,只有容器层是可写的,容器层下面的所有镜像层都是只读的。
** 5.docker 的commit 案例 提交生成一个新的镜像**
docker commit 提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a=”作者“容器ID要创建的目标镜像名:[标签号]
案例演示ubuntu安装vim
1)apt-get update
2)apt-get -y install vim
五.本地镜像发布到阿里云
1.进入阿里云>控制台>弹性镜像容器服务>个人
2.创建镜像仓库>本地仓库>进入管理界面获得脚本
3.将镜像推送到阿里云registry
$ docker login --username=aliyun4214424794 registry.cn-hangzhou.aliyuncs.com$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/sutdy_docker/myubuntu1.3:[镜像版本号]$ docker push registry.cn-hangzhou.aliyuncs.com/sutdy_docker/myubuntu1.3:[镜像版本号]
4.将阿里云的镜像拉取到本地
六.本地镜像发布到私有库
1.下载镜像Docker Registry : docker pull registry
2.运行私有库有Registry ,相当于本地有个私有Docker hub :
docker run -d -p 5000:5000 -v/zcl/myregistry/:/tmp/registry --privileged=true registry
3.ubuntu安装ifconfig功能
(1) apt-get update
(2)apt-get install net-tools
(3)安装完成后,commit我们的新镜像:
docker commit -m="ifconfig cmd add" -a="zcl" 6ae9dccbc190 zclubuntu:1.2
4.curl验证私服库上有什么镜像: curl -XGET http://192.168.238.80:5000/v2/_catalog
5.将新镜像zclubuntu1.2修改符合规范的Tag: docker tag 镜像:TAG Host:Port/Repository:Tag
6.修改配置文件使之支持http
(1) vim /etc/docker/daemon.json
(2)配置文件中新增:别忘记” , “![](https://img-blog.csdnimg.cn/dcb631a8e4034433a7f80dedc32844f5.png)
(3)重启docker : systemctl restart docker
(4)开启本地私服库:
docker run -d -p 5000:5000 -v/zcl/myregistry/:/tmp/registry --privileged=true registry
7.push推送到私服库:docker push 192.168.238.80:5000/zclubuntu:1.2
8.curl验证私服库上有什么镜像: curl -XGET http://192.168.238.80:5000/v2/_catalog
9.pull到本地并运行: docker pull 192.168.238.80:5000/zclubuntu:1.2
七.Docker容器卷
Docker挂载主机目录访问如果出现cannot open dircctory.:Permission denied
解决方法:挂载目录后多加一个-privileged=true 参数即可
7.1.docker容器卷是什么:有点类似我们redis里面的rdb和aof文件 ;将docker容器内的数据保存进宿主机的磁盘中。
卷就是目录或文件。存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持久化存储或共享数据的特性;
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷;
** 运行一个带有容器卷存储功能的容器实例**:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
7.2.能干什么:将运用与运行的环境打包镜像,run后形成实例运行,但是我们对数据的要求时持久化的。
docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内地数据自然就没有了。为了能保存数据在docker中我们使用卷。
特点:
- 数据卷可在容器之间共享重用数据
- 卷中的更改可以直接实例时生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续待没有容器使用它为止
7.3.读写规则映射添加:
(1)读写(默认):
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
(2)只读:容器实例内部被限制,只能读取不能写:
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
**7.4.卷的继承和共享 **
** **容器2继承容器1的卷规则:
docker run -it --privileged=true--volumes-from父类 --name u2 ubuntu
八.Docker常规安装
1.安装Tomcat:
(1)Docker Hub 上面查找tomcat镜像
docker search tomcat
(2)从docker hub 上拉取tomcat镜像到本地
docker pull tomcat
(3)查看是否有拉取到tomcat
docker images
(4)使用tomcat镜像创建容器实例(也叫运行镜像):
-p小写:主机端口号:docker容器端口 ; -P大写:随机分配端口
-i:交互 ; t:终端 ; -d:后台
docker run -it -p 8080:8080 tomcat
(5)访问猫主页
问题报404!!!
解决:1.可能没有映射端口或者关闭防火墙
2. (1)进入tomcat容器中,删除webapps: rm -r webapps
(2)将webapps.dist 改名替换成webapps : mv webapps.dist webapps
(6)免修改版:docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat billygoo/tomcat8-jdk8
安装成功
** 2.安装mysql**
** 简易版的运行:(存在中文乱码问题,以及数据备份问题)**
** **(1)Docker Hub 上面查找mysql镜像:docker search mysql
(2)从docker hub上(阿里云加速器)拉取MySQL镜像到本地 标签为5.7 :
docker pull mysql:6.7
(3)使用mysql5.7镜像创建容器(也叫运行镜像):
docker run -p 3306:3306 --name some-mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:tag
(4)进入mysql :docker exec -it > 进入mysql 密码:123456 ![](https://img-blog.csdnimg.cn/b8267428559c4e25af7cc136e97c8055.png) (5)使用mysql
(6)使用navicat连接mysql
1)插入中文会报错
2)修正字符集编码:SHOW VARIABLES LIKE 'character%'
** 实战版:解决简易版存在的问题**
一.乱码
** 1.**
docker run -d -p 3306:3306 --privileged=true -v /zclroot/mysql/log:/var/log/mysql -v /zclroot/mysql/data:/var/lib/mysql -v /zclroot/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
2.新建my.conf ,通过容器卷同步给mysql容器实例,解决中文乱码问题
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
3.重新启动mysql容器实例再重新进入并查看字符编码 : docker restart mysql
乱码解决成功!!!
二.数据库被删除数据恢复
在这已经配置了容器数据卷,当容器重新启动时,数据会从容器卷中重新读取达到数据备份的作用![](https://img-blog.csdnimg.cn/99c9f319651445e383d5cd213e260ce7.png)
数据依旧可以读取
3.安装Redis
(1)在centos宿主机下新建目录/app/redis: mkdir -p /app/redis
(2)将一个redis.conf文件模板拷贝到/app/redis目录下
(3)修改redis.conf配置
将bind注解掉,允许redis外地连接
![](https://img-blog.csdnimg.cn/94320927f6394dfea285c86a45c94847.png)
daemonize 改为no 或注释起来,因为该配置和docker run 中 -d 参数冲突,会导致容器一直启动失败
![](https://img-blog.csdnimg.cn/5a9ed297481f418abeb92e93a860c938.png)
(3)启动redis镜像
docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v/app/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
九.高级学习
1.docker复杂安装
** 1.mysql主从复制原理:**
(1)新建主服务器容器实例3307
docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
(2)进入/mydata/mysql-master/conf目录下新建my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=1
## 指定不需要同步的数据库名称
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
(3)修改完配置后重启master实例
docker restart mysql-master
(4)进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -proot
(5)master容器实例内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';
(6)创建从服务器容器实例3308
docker run -p 3308:3306 --name mysql-slave -v /mydata/mysql-slave /log:/var/log/mysql -v /mydata/mysql-slave /data:/var/lib/mysql -v /mydata/mysql-slave /conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
(7)进入/mydata/mysql-slave/conf目录下新建my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=2
## 指定不需要同步的数据库名称
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
(8)修改完配置后重启slave实例
docker restart mysql-slave
(9)在主数据库中查看主从同步状态
show master status;
(10)进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -p
(11)在从数据库中配置主从复制
·主从复制命令参数说明
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
change master to master_host='宿主机ip',
master_user='slave',
master_password='123456',
master_port=3307,
master_log_file='mall-mysql-bin.000001',
master_log_pos=617,
master_connect_retry=30;
(12)在从数据库中查看主从同步状态
show slave status \G;
(13)在从数据库中开启主从同步
start slave;
(14)查看从数据库状态发现已经同步
show slave status \G;
(15)主从复制测试:主机新建库-使用库-新建表-插入数据,
从机使用库-查看记录
master:
![](https://img-blog.csdnimg.cn/06cfa26ec1b7432c93f0756d80338ba0.png)
slave:
![](https://img-blog.csdnimg.cn/c5e5cd39d47f4268bc57e5d9cf3c6702.png)
** 2.安装redis集群**
面试题:1~2亿条数据需要缓存,请问如何设计这个存储案例
** 回答:单机单台100%不可能,肯定是分布式存储。有三种方式**
** 1.哈希取余分区**
** 2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机,假设有三台机器构成一个集群,用户每次读写操作都是根据公式hash(key)%N个机器个数,计算出哈希值,用来决定数据映射到哪一个节点上。**
** 优点:简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台,8台,10台,就能保证一段时间的数据支撑,使用hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求,起到负载均衡——分而治之的作用。**
** 缺点:原来规划好的节点,进行扩容或缩容就比较麻烦,不管是扩容,每次数据变动导致节点有变化,映射关系需要重新进行计算,在服务器个数不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取余公式就会发生变化,Hash(key)%3会变成Hash(key)%?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。**
** 某个redis机器宕机,由于台数数量发生变化,会导致hash取余全部数据重新洗牌。**
** 2.一致性哈希算法分区**
** 当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到临界的存储点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。三个步骤: 算法构建一致性哈希环;服务器IP节点映射;key落到服务器的落键规则 .**
** 优点:加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。**
** 缺点:数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。**
** 3.哈希槽分区(常用)**
** 哈希槽实质就是一个数组,数组【0~2^14-1】形成的hash slot 空间。解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽,用于管理数据和节点之间的关系。现在就相当于节点上方的就是槽,槽里面放的是数据。**
**三主三从redis集群扩缩容配置案例 **
** **1.关闭防火墙+启动docker后台服务
2.新建6个docker容器实例 --net hsot :使用宿主机的IP和端口,默认;--privileged=true :获取宿主机root用户权限 ;--cluster-enable yes : 开启redis集群 --appendonly yes :开启持久化
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
3.进入容器redis-node-1并为6台机器构建集群关系
(1)进入容器
docker exec -it redis-node-1 /bin/bash
(2)构建主从关系 --cluster-replicas 1 :表示为每个master构建一个slave节点
redis-cli --cluster create 192.168.238.80:6381 192.168.238.80:6382 192.168.238.80:6383 192.168.238.80:6384 192.168.238.80:6385 192.168.238.80:6386 --cluster-replicas 1
![](https://img-blog.csdnimg.cn/204263cbf3f644198f37363b1d08e54c.png)
** **链接进入6381作为切入点,查看集群状态 ** **
主从容错切换迁移案例
** 数据读取存储**
** · **启动6机构成的集群并通过exec进入
**·** 对6381新增两个key :以单机的方式启动redis
**` **防止路由失效加参数-c并新增key : 加 -c :表示以集群的方式启动redis
![](https://img-blog.csdnimg.cn/f2d005cc73334772a0ff9e5f7db139ad.png)
**`**检查集群信息: redis-cli --cluster check 192.168.238.80:6381
![](https://img-blog.csdnimg.cn/b88c1eb4e4de4f1999674c9318b4a624.png)
** 容错切换迁移**
** ·**主6381和从机切换,先停止主机6381
** ·**再次查看集群信息 (哨兵模式:反客为主的自动版)
** ·**先还原之前的3主3从
1.先启动6381 docker start redis-node-1 (6381恢复后成为了6385的slaver )![](https://img-blog.csdnimg.cn/fe912d6f2412493c90d4a9e8df6d6b38.png)
2.再停6385 docker stop redis-node-5
3.再重新启动6385 : docker start redis-node-5
** ·**查看集群状态
** 主从扩容案例**
- 新建6387,6388两个节点+新建后启动+查看是否有8节点
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 6387docker 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
- 进入6387容器实例内部 :docker exec -it redis-node-7 /bin/bash
- 将新增的6387节点(空槽号)作为master节点加入原集群
redis-cli --cluster add-node 192.168.238.80:6387 192.168.238.80:6381
- 检查集群情况第1次 ;redis-cli --cluster check 192.168.238.80:6381
- 重新分配槽号:redis-cli --cluster reshard 192.168.238.80:6387
- 检查集群情况第2次:原来的三个master每个将自己从左边开始给了一点给6387,是的6387有4096个槽位,并不是重新分配
- 为主节点6387分配从节点6388:redis-cli --cluster add-node ip:新slaver端口 ip:新master端口 --cluster-slaver --cluster-master-id 新主机节点ID
redis-cli --cluster add-node 192.168.238.80:6388 192.168.238.80:6387 --cluster-slave --cluster-master-id 6899abd525f6a3088cbc345a2efcbd333de4f02e
- 检查集群情况第3次
** 主从缩容案例**
- 检查集群情况1获得6388的节点ID : redis-cli --cluster check 192.168.238.80:6382
- 将6388删除,从集群中将4号从节点6388删除 : redis-cli --cluster del-node ip:从机端口号 从机6388节点ID
redis-cli --cluster del-node 192.168.238.80:6388 aadd958f00fec4424a340844854a9cf95781d922
- 将6387的槽号清空,重新分配,本例将清出来的槽号都给6381 :
redis-cli --cluster reshard 192.168.238.80:6381
- 检查集群情况第2次1. 将6387删除 :redis-cli --cluster del-node ip:端口号 6387节点ID
redis-cli --cluster del-node 192.168.238.80:6387 6899abd525f6a3088cbc345a2efcbd333de4f02e
- 检查集群情况第三次
2.DockerFile解析
Docker是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
dockerfile保留字指令:tomcat/Dockerfile at master · docker-library/tomcat · GitHub
- FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
- MAINTAINER:镜像维护者的姓名和邮箱地址
- RUN:容器构建时需要运行的命令;RUN是再docker build时运行;两种格式: - shell格式- exec格式
- EXPOSE:当前容器对外暴露出的端口
- WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV:用来在构建镜像过程中设置环境变量
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
- COPY:类似ADD,拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内<目标路径>位置: - COPY src dest- COPY ["src","dest"]- <src源路径>:源文件或者源目录- <dest目录路径>:容器内的指定路径,该路径不用事先建好
- VOLUME:容器数据卷,用于数据保存和持久化工作
- CMD: 指定容器启动后要干的事情 - 注意:Dockerfile中可以有多个CMD指定,但只有最后一个生效,CMD会被docker run之后的参数替代- 它和RUN命令的区别: - CMD是在docker run 时运行- RUN是在 docker build时运行
- ENTRYPOINT: 也是用来指定一个容器启动时要运行的命令。类似于CMD指令。但是ENTRYPOINT不会被docker run 后面的命令覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT指令指定的程序
案例
自定义镜像mycentosjava8:
要求:centos7镜像具备vim + ifconfig + jdk8
JDK下载:Java Downloads | Oracle
- 准备编写Dockerfile文件 ,在压缩包同一目录下创建Dockerfile文件:
FROM centos7.6.1810
MAINTAINER zcl
ENV MYPATH /usr/local
WORKDIR $MYPATH
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux.x64.tar.gz添加到容器中,安装包必须要和Dckerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置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.构建:docker build -t 新镜像名字:TAG . 注意TAG后面有个空格,有个点
docker build -t centosjava8:1.5 .
3.运行:docker run -it 心镜像名:TAG
docker run -it 87ea3c3e1155 /bin/bash
虚悬镜像
** **虚悬镜像:仓库名,标签名都是<none>的镜像,俗称dangling image
删除:docker image prune
3.Docker微服务
一.通过IDEA新建一个普通微服务模块
package com.example.docker.controller;/**
* @Author: ZCL
* @DATE: 2022/11/8 21:07
*/
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
/**
* @program: docker-boot
* @author: ZCL
* @create: 2022-11-08 21:07
*/
@RestController
public class OrderController {
@Value("${server.port}")
private String port;
@RequestMapping("/order/docker")
public String helloDocker(){
return "hello docker"+"/t"+port+"/t"+ UUID.randomUUID().toString();
}
@RequestMapping(value = "/order/index",method = RequestMethod.GET)
public String index(){
return " 服务端口号"+"/t"+port+"/t"+ UUID.randomUUID().toString();
}
}
二.通过dockerfile发布微服务部署到docker容器
1.编写dockerfile
#基础使用镜像java
FROM java:8
#作者
MAINTAINER zcl
#VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建一个临时文件并链接到容器的/tmp
VOLUME /tmp
#将jar包添加到容器中并更名为zcl_docker.jar
ADD docker-0.0.1-SNAPSHOT.jar zcl_docker.jar
#运行jar包
RUN bash -c 'touch /zcl_docker.jar'
ENTRYPOINT ["java","-jar","/zcl_docker.jar"]
#暴露6001端口号作为微服务
EXPOSE 6001
2.构建
docker build -t zcl_docker:1.6 .
3.运行容器
docker run -d -p 6001:6001 ab6314e8f16a
4.访问微服务
4.Docker网络
能干什么:容器间的互联和通信以及端口映射
:容器IP变动时候可以通过服务名直接网络通信而不受影响
docker启动后其网络情况:
查看docker网络模式:docker network ls
** 常用命令**
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
查看网络:docker network ls
查看网络源数据:docker network inspect 网络名字
删除网络:docker network rm 网络名字
网络模式:
网络模式简介bridge
为每一个容器分配,设置IP等,并将容器链接到一个docker0
虚拟网桥,默认为该模式
host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配wrth pair 和网桥连接,IP等container新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等
bridge:Docker服务器默认会创建一个docker0网桥(其上有一个docker0内部接口),这桥接网络的名称为docker0,它在内部层连接了其他的物理或虚拟网卡,这就是将所有容器和本地主机都放到同一个物理网络,Docker默认指定docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
案例:
1.启动两个tomcat容器
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
原理:
1.整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair) 2.每个容器实例内部也有一块网卡,每个接口叫eth0; 3.docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
host:直接使用宿主机的IP地址与外界直接进行通信,不在需要额外进行NAT转换
原理:容器将不会获得一个独立的Nwtwork Namespace ,而是和宿主机公用一个Network Namespace,容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口
案例:
docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
- 查看tomcat83网络数据源:docker inspect tomcat83
3.进入tomcat83:docker exec -it tomcat83 bash :发现与宿主机的网络配置一样
** none:禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)**
在none模式下,并不为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡,IP,路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡,配置IP等。
案例:
docker run 8084:8080 --network none --name tomcat84 billygoo/tomcat -jdk8
3.进入内部查看:只有一个lo
** container:新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享,新建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定容器共享IP,端口范围等,同样,两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的。**
案例:
错误案例
docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --name container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
tomcat86与tomcat85公用一个ip同一个端口,导致端口冲突
正确案例 :Alpine操作系统是一个面向安全的轻型Linux发行版
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
分别进入两个容器中,发现alpine2使用的是alpine1的网络配置,当alpine1共享源关闭后,alpine2就没有自己的配置了
自定义网络
案例:
** 1.自定义桥接网络,自定义网络默认使用的是桥接网络bridge**
** 2.新建自定义网络 : docker network create a_network**
** 3.新建容器加入上一步新建的自定义网络**
docker run -d -p 8081:8080 --network a_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network a_network --name tomcat82 billygoo/tomcat8-jdk8
** 4.互相ping测试**
5.Docker-compose容器编排
Docker_compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排,可以管理多个Docker容器组成一个应用,你需要定义一个YAML格式的配置文件docker-compose.yml,写好多个容器之间的调用关系,然后只需要一个命令,就能同时启动/关闭这些容器
Overview | Docker Documentation
安装
1curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s
-
uname -m` > /usr/local/bin/docker-compose2.chmod +x /usr/local/bin/docker-compose
3.docker-compose --version
Maven打包命令
** >mvn clean install -Dmaven.test.skip=true**
将jar放到mydocker目录下
编写Dockerfile
#基础使用镜像java
FROM java:8
#作者
MAINTAINER zcl
#VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建一个临时文件并链接到容器的/tmp
VOLUME /tmp
#将jar包添加到容器中并更名为zcl_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zcl_docker.jar
#运行jar包
RUN bash -c 'touch /zcl_docker.jar'
ENTRYPOINT ["java","-jar","/zcl_docker.jar"]
#暴露6001端口号作为微服务
EXPOSE 6001
build
docker build -t zcl_docker:1.7 .
Docker-compose.yml 在mydocker目录下
version: "3"
services:
microService:
image: zcl_docker:1.7
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- zcl_net
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- zcl_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: 'dbdocker'
MYSQL_USER: 'root'
MYSQL_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- zcl_net
command: --default-authentication-plugin=mysql_native_password
networks:
zcl_net:
修改原来项目的配置。重新打包成jar
检查docker-compose 中是否存在语法错误:docker-compose config -q
执行docker-compose up 或者 docker-compose up -d
Pointainer的安装
Powerful container management software for Platform Teams, DevOps, Dev
命令安装:
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
1.第一次登录需创建admin,访问地址:本机IP:9000
2.设置admin用户和密码后首次登录密码八位
3.选择local选项卡后本机docker详细信息展示
容器监控3剑客:CAdivsor监控收集+InfluxDB存储数据+Granfana 数据分析
docker-compose容器编排:
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:
user: "104"
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 启动
测试
acdvisor: http://192.168.238.80:8080
influxdb : http://192.168.238.80:8083/
Grafana : http://192.168.238.80:3000/
为grafana配置数据源:
![](https://img-blog.csdnimg.cn/e2ac5b91d4ca4f218c240fc356fd0d4d.png)
选择influxdb为数据源:
面板panel的添加:
选择图形化展示方式:
版权归原作者 Maserati477 所有, 如有侵权,请联系我们删除。