一、安装
1.1本地环境
![](https://i-blog.csdnimg.cn/blog_migrate/605f961f8e6fb6610c928a4fe8e55188.png)
1.2三要素
1.2.1镜像
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
1.2.2容器
从面向对象角度
Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台
从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
1.2.3仓库
仓库(Repository)是集中存放镜像文件的场所。
类似于
Maven仓库,存放各种jar包的地方;
github仓库,存放各种git项目的地方;
Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等
1.3安装
1.3.1卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
1.3.2安装gcc
yum -y install gcc
yum -y install gcc-c++
1.3.3安装需要的软件包
sudo yum install -y yum-utils
1.3.4设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
1.3.5更新yum软件包索引
yum makecache fast
1.3.6安装DOCKER CE
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
1.3.7启动容器
sudo systemctl start docker
docker version
1.3.8运行一个hello world镜像
sudo docker run hello-world
![](https://i-blog.csdnimg.cn/blog_migrate/c70fad35fd311d301fecf8fb5233572e.png)
1.3.8卸载
systemctl stop docker
sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
1.4阿里云镜像加速
![](https://i-blog.csdnimg.cn/blog_migrate/a4c25cec72ba91c722f3da4eeaca1487.png)
直接把下面命令粘贴运行即可
1.5docker run hello-world干了啥
![](https://i-blog.csdnimg.cn/blog_migrate/aa08ec8e270c5f0d477b39231938a963.png)
1.6底层原理
docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
二、Docker的常用命令
2.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.2镜像命令
docker images
![](https://i-blog.csdnimg.cn/blog_migrate/5c9c3d432067649d61ff357c51259a0d.png)
各个选项说明:
REPOSITORY:表示镜像的仓库源 TAG:镜像的标签版本号 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小 |
同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
![](https://i-blog.csdnimg.cn/blog_migrate/ae476c62c95928ce23252a233b471b15.png)
-a:列出本地所有镜像(含历史映像层)
-q:只显示镜像ID
docker search 某个XXX镜像名字
查看远程库是否有镜像
![](https://i-blog.csdnimg.cn/blog_migrate/766cb78af6b8eb6d00143daf9e533bdf.png)
--limit : 只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull 某个XXX镜像名字
拉取镜像
docker pull 镜像名字[:TAG]
没有TAG就是最新版
![](https://i-blog.csdnimg.cn/blog_migrate/16a921fbc050c21cf0e0baf6599ddb30.png)
docker system df 查看镜像/容器/数据卷所占的空间
![](https://i-blog.csdnimg.cn/blog_migrate/5e69fcf2a6b549bfdfbd4ec3fbd1bc25.png)
docker rmi 某个XXX镜像名字ID
删除镜像
可以根据名字删除也可以是id
#删除单个
docker rmi -f 镜像ID
#删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部docker rmi -f $(docker images -qa)
docker的虚悬镜像
仓库名、标签都是<none>的镜像,俗称虚悬镜像dangling image
![](https://i-blog.csdnimg.cn/blog_migrate/1c1b917a01bb19b47d572f8aa22a40a6.png)
2.3容器命令
有镜像才能创建容器,先拉取一个ubuntu镜像
新建+启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
[OPTIONS]
--name="容器新名字" 为容器指定一个名称;
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
启动交互式容器(前台命令行)
docker run -it ubuntu /bin/bash
参数说明: -i: 交互式操作。 -t: 终端。 ubuntu : ubuntu 镜像。 /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。 要退出终端,直接输入 exit:容器停止,run进去容器,ctrl+p+q退出,容器不停止 |
![](https://i-blog.csdnimg.cn/blog_migrate/1beccec4bfa7fd32c5538b712812f9ad.png)
列出当前所有正在运行的容器
docker ps [OPTIONS]
OPTIONS说明(常用):
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
![](https://i-blog.csdnimg.cn/blog_migrate/aff26d1fb6d1a0571a1de66ade82a9f4.png)
启动已停止运行的容器
docker start 容器ID或者容器名
重启容器
docker restart 容器ID或者容器名
停止容器
docker stop 容器ID或者容器名
强制停止容器
docker kill 容器ID或容器名
删除已停止的容器
docker rm 容器ID
重要
在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的后台运行模式。
docker run -d 容器名
使用镜像centos:latest以后台模式启动一个容器
docker run -d centos
问题:然后docker ps -a 进行查看, 会发现容器已经退出
很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,
我们配置启动服务只需要启动响应的service即可。例如service nginx start
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,
这样的容器后台启动后,会立即自杀因为他觉得他没事可做了.
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有交互操作,别中断
查看容器日志
docker logs 容器ID
查看容器内运行的进程
docker top 容器ID
查看容器内部细节
docker inspect 容器ID
进入正在运行的容器并以命令行交互
docker exec -it 容器ID bashShell
docker exec -it f0ee24f4d027 /bin/bash
重新进入docker attach 容器ID
区别
attach 直接进入容器启动命令的终端,不会启动新的进程用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程用exit退出,不会导致容器的停止。
从容器内拷贝文件到主机上
docker cp 容器ID:容器内路径 目的主机路径
导入和导出容器
export 导出容器的内容留作为一个tar归档文件[对应import命令]
docker export f0ee24f4d027 > abcd.tar
import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
cat abcd.tar | docker import - msjava/ubuntu:3.7
![](https://i-blog.csdnimg.cn/blog_migrate/8adb503c65f10e393850668a3734565d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3d2a070252d8bf77c935223d5889a534.png)
三、Docker镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
3.1分层的镜像
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
![](https://i-blog.csdnimg.cn/blog_migrate/5cb5ec79dd47b66eb9206d78e80e9d77.png)
3.2UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
3.3 Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的
3.4Docker镜像commit操作案例
docker commit提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
例:案例演示ubuntu安装vim
原始的默认Ubuntu镜像是不带着vim命令的
3.4.1进入ubuntu容器安装vim
# 更新包管理工具
apt-get update
# 安装vim
apt-get -y install vim
3.4.2安装完成后,commit我们自己的新镜像
docker commit -m="add vim to ubuntu" -a="majava" 7f24413021d9 msjava/ubuntu:2.0
![](https://i-blog.csdnimg.cn/blog_migrate/12f8bf6093a7ffd95fa2371c185c9344.png)
镜像变大了
四、本地镜像发布到阿里云
4.1登录阿里云
![](https://i-blog.csdnimg.cn/blog_migrate/906de247932522d87c0117be22c50037.png)
选择个人实例
![](https://i-blog.csdnimg.cn/blog_migrate/41fa233f0b254841d0495f086a84561d.png)
新建命名空间
![](https://i-blog.csdnimg.cn/blog_migrate/1d1b7e824bd16025cf392bbd7bb5cbd8.png)
在创建的命名空间下新建镜像仓库,选择本地仓库
床架安完成,点击管理,获取操作脚本
4.2推送至仓库
从获得的操作脚本中可以看到
![](https://i-blog.csdnimg.cn/blog_migrate/81e47b8f62dd9918d239591114da9c40.png)
根据命令复制粘贴即可
![](https://i-blog.csdnimg.cn/blog_migrate/34a3c10db2baf7eb6ced032106542549.png)
代表推送成功
4.3拉取镜像
![](https://i-blog.csdnimg.cn/blog_migrate/1052848f38e3eea932e2c8dffc2220bf.png)
五、本地镜像发布到私有库
5.1下载镜像Docker Registry
docker pull registry
相当于本地也有一个docker hub
![](https://i-blog.csdnimg.cn/blog_migrate/a998e4cbe820269aafaeaa9badd8af49.png)
5.2根据镜像运行容器
docker run -d -p 5000:5000 -v /msjava/myregistry/:/tmp/registry --privileged=true registry
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
-d:后台运行
-p 5000:5000:容器端口5000映射到主机端口5000(前主机后容器)
![](https://i-blog.csdnimg.cn/blog_migrate/c007e6ecadad345c2daf25ea07e03134.png)
5.3案例演示创建一个新镜像,ubuntu安装ifconfig命令
5.3.1安装命令
apt-get update
apt-get install net-tools
5.3.2commit
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
命令:在容器外执行,记得
docker commit -m="ifconfig cmd add" -a="majava" e62cfb09b2fc myubuntu:2.0
![](https://i-blog.csdnimg.cn/blog_migrate/38564f42c1562271cf1c87850174b241.png)
5.3.3curl验证私服库上有什么镜像
curl -XGET http://192.168.232.130:5000/v2/_catalog
![](https://i-blog.csdnimg.cn/blog_migrate/099df0045d5ec0da2f3a9ff60da721d7.png)
5.3.4将新镜像修改符合私服规范的Tag
docker tag 镜像:Tag Host:Port/Repository:Tag
docker tag myubuntu:2.0 192.168.232.130:5000/myubuntu:2.0
![](https://i-blog.csdnimg.cn/blog_migrate/6efd717d955e454462259c774a4e80ed.png)
5.3.5修改配置文件使之支持http
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://zw7p1qdg.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.232.130:5000"]
}
上述理由:docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====> 修改完后如果不生效,建议重启docker
5.3.6push推送到私服库
docker push 192.168.232.130:5000/myubuntu:2.0
5.3.7curl验证私服库上有什么镜像
curl -XGET http://192.168.232.130:5000/v2/_catalog
![](https://i-blog.csdnimg.cn/blog_migrate/0316272721e4e6e1f8aca0fdc224c613.png)
5.3.8pull到本地并运行
docker pull 192.168.232.130:5000/myubuntu:2.0
![](https://i-blog.csdnimg.cn/blog_migrate/af807ac989827106483735645b8d72bf.png)
5.3.9验证
![](https://i-blog.csdnimg.cn/blog_migrate/b7805e02478535bc65d76779d41fa3ef.png)
六、Docker容器数据卷
5.2中,根据私有库镜像运行容器
docker run -d -p 5000:5000 -v /msjava/myregistry/:/tmp/registry --privileged=true registry
-v 添加自定义的容器卷
:左边是宿主机的路径
:右边是容器内路径
要记得在后面加--privileged=true
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
Docker挂载主机目录访问 如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,
在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用--privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即
使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
6.1是什么
![](https://i-blog.csdnimg.cn/blog_migrate/0aacebde755b5c0177a9540d5d6190ea.png)
运行一个带有容器卷存储功能的容器实例
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
6.2能干嘛
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。
为了能保存数据在docker中我们使用卷。
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效,爽
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
6.3案例
docker run -it --privileged=true -v /tmp/host_data:/tmp/docker_data --name="u1" bc99ed49b67c
在容器目录下新建文件,会同步到主机目录下
![](https://i-blog.csdnimg.cn/blog_migrate/011cd730537a225561a1be263137788b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8e47f1bd466acd29ff85ed2aa7bcbd58.png)
反过来也一样,同样修改文件内容也会同步
6.3.1查看数据卷是否挂载成功
docker inspect 容器ID
![](https://i-blog.csdnimg.cn/blog_migrate/901b1a336bd408c3acb53468f022e12f.png)
-v可以有多个
6.3.2读写规则映射添加说明
默认是可读可写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
容器内只读
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
6.3.3卷的继承和共享
容器1完成和宿主机的映射
docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
容器2继承容器1的卷规则
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
docker run -it --privileged=true --volumes-from u1 --name u2 bc99ed49b67c
如果u2继承的u1挂了,挂载不会丢失,单纯的继承规则
七、Docker常规软件安装
总体步骤:
搜索镜像、拉取镜像、查看镜像、启动镜像(服务端口映射)、服务端口映射、停止容器、移除容器
7.1安装tomcat
7.1.1docker hub上面查找tomcat镜像
![](https://i-blog.csdnimg.cn/blog_migrate/c68ffa1f3fc047c5832ac7789ce38ab6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0f257b66af8f0ea06d8e43bad089e44f.png)
7.1.2从docker hub上拉取tomcat镜像到本地
docker pull tomcat
7.1.3docker images查看是否有拉取到的tomcat
![](https://i-blog.csdnimg.cn/blog_migrate/1d1981cff2daf5943eafa15ab717f650.png)
7.1.4使用tomcat镜像创建容器实例(也叫运行镜像)
docker run -it -p 8080:8080 tomcat
7.1.5测试
出现404
可能1:没有映射端口,没有关闭防火墙
可能2:把webapps.dist目录换成webapps
![](https://i-blog.csdnimg.cn/blog_migrate/ec7cbf94ab16334526e4c8af1131e3b0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0b52747b3ca3fdcb4b6ab36c564af401.png)
说明
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
7.2安装mysql
7.2.1拉取镜像
docker pull mysql:5.7
![](https://i-blog.csdnimg.cn/blog_migrate/e35bc285ddcf0b2b4c6d8a1fb2358d44.png)
7.2.2创建容器
docker run -p 3388:3306 --name="some-mysql" -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
![](https://i-blog.csdnimg.cn/blog_migrate/610036a35f6ca91a9ad70862cb355b1d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ca97e3d42e756e6e595b50607a973460.png)
同时可以用navicat连接
存在问题:插入中文报错
容器停止或删除,数据丢失
![](https://i-blog.csdnimg.cn/blog_migrate/049d95118d207db1cdf90451894a8c84.png)
7.2.3实战版
7.2.3.1新建实例
docker run -d -p 3399:3306 --privileged=true -v /msdocker/mysql/log:/var/log/mysql -v /msdocker/mysql/data:/var/lib/mysql -v /msdocker/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
7.2.3.2新建my.cnf
通过容器卷同步给mysql容器实例
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
7.2.3.3重新启动mysql容器实例再重新进入并查看字符编码
![](https://i-blog.csdnimg.cn/blog_migrate/f5e79ae21332bffb82c0fe2844a881d9.png)
即使删除容器,由于数据卷挂载,数据不会丢失
7.3安装redis
7.3.1拉取镜像
docker pull redis:6.0.8
7.3.2创建容器
![](https://i-blog.csdnimg.cn/blog_migrate/ffc55efa7d816d7248aaf14eedd3d6ff.png)
7.3.3测试
![](https://i-blog.csdnimg.cn/blog_migrate/7fe3d83a5c4105e51888ef23f643b23d.png)
7.3.4实战
7.3.4.1宿主机中新建一个redis.conf
![](https://i-blog.csdnimg.cn/blog_migrate/089e28b246ad30948b9bb5b579fdc1bb.png)
从其他地方拷贝过来
拷贝过来的配置文件对应redis的版本最好和你拉取的一致,否则容器可能创建不起来
7.3.4.2创建容器
docker run -p 6399:6379 --name myredis --privileged=true -v /msdocker/redis/redis.conf:/etc/redis/redis.conf -v /msdocker/redis/data:/data -d redis:6.2.1 redis-server /etc/redis/redis.conf
八、安装mysql主从复制
8.1新建主服务器容器实例
docker run -d -p 3399:3306 --privileged=true -v /msdocker/mysql/mysql-master/log:/var/log/mysql -v /msdocker/mysql/mysql-master/data:/var/lib/mysql -v /msdocker/mysql/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-master mysql:5.7
![](https://i-blog.csdnimg.cn/blog_migrate/3c3b1eda4eb783ac7ea99fe87d7f5bc5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e59cb15f7123c672babad4b3d2a8c6c7.png)
8.2进入主机的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
8.3重启master实例并进入,创建同步用户
docker restart mysql-master
docker exec -it mysql-master /bin/bash
创建同步用户
mysql -uroot -p
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
8.4新建从服务器实例
docker run -d -p 3377:3306 --privileged=true -v /msdocker/mysql/mysql-slave/log:/var/log/mysql -v /msdocker/mysql/mysql-slave/data:/var/lib/mysql -v /msdocker/mysql/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-slave mysql:5.7
![](https://i-blog.csdnimg.cn/blog_migrate/a521f17ca9d0db3fe6a03d1b98a6af74.png)
![](https://i-blog.csdnimg.cn/blog_migrate/de0ea40918f34d8d1f95bed8a97be763.png)
8.5进入主机的conf目录下新建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
8.6重启slave实例
docker restart mysql-slave
8.7进入主机实例的MySQL,查看同步状态
show master status;
![](https://i-blog.csdnimg.cn/blog_migrate/afe8245d4a5a16b6fc4ef18e7caa7455.png)
8.8进入从实例配置主从复制
docker exec -it mysql-slave /bin/bash
mysql -uroot -p
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;
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
![](https://i-blog.csdnimg.cn/blog_migrate/4ebd87ceed49f3cb5dfb06260b58e791.png)
8.9从数据库中查看主从同步状态
show slave status \G
![](https://i-blog.csdnimg.cn/blog_migrate/89fa23416fd2bdff8354835ea60dcc9e.png)
8.10从数据库中开启主从同步
start slave;
![](https://i-blog.csdnimg.cn/blog_migrate/a187577814e424d02cd419a81106d320.png)
我这里第一个Slave_IO_Running:no
1、关闭防火墙
2、配置文件那个server-id不要和你主机上的重复
然后:stop slave; reset slave; start slave;
8.11测试
8.11.1主机创建库表,插入数据
![](https://i-blog.csdnimg.cn/blog_migrate/73790cf4c0d56e392e9bc5835d15de59.png)
8.11.2从机读取数据
![](https://i-blog.csdnimg.cn/blog_migrate/f71b299cb4d63a0932577c91ac10e22c.png)
九、分布式存储中的一些算法
9.1哈希取余算法
hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。
优点:
简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。
缺点:
原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。
某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌。
9.2一致性哈希算法
提出一致性Hash解决方案。目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系
9.2.1三大步骤
9.2.1.1算法构建一致性哈希环
一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。
它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模。而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。
![](https://i-blog.csdnimg.cn/blog_migrate/815fe3cffb5a9a609e088c78deffd273.png)
9.2.1.2服务器IP节点映射
将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
![](https://i-blog.csdnimg.cn/blog_migrate/949862136d0078a0fc314e90f563af30.png)
9.2.1.3key落到服务器的落键规则
当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。
![](https://i-blog.csdnimg.cn/blog_migrate/0375ff4a4a55c7cca49ffd5930895140.png)
9.2.3优缺点
容错性
假设Node C宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据,并且这些数据会转移到D进行存储。
扩展性
数据量增加了,需要增加一台节点NodeX,X的位置在A和B之间,那收到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可,不会导致hash取余全部数据重新洗牌。
![](https://i-blog.csdnimg.cn/blog_migrate/4dfe714b1cb854d5c0fee4c11f1fa730.png)
缺点
Hash环的数据倾斜问题
一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,
例如系统中只有两台服务器:
![](https://i-blog.csdnimg.cn/blog_migrate/68576d29efe96395b2bfbd71852d6ef0.png)
9.3哈希槽分区
1 为什么出现
有效解决一致性哈希算法的数据倾斜问题
哈希槽实质就是一个数组,数组[0,2^14 -1]形成hash slot空间。
2 能干什么
解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。
槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。
哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
3 多少个hash槽
一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上
![](https://i-blog.csdnimg.cn/blog_migrate/1cdd896d7be6f1e64f066454d2883c4e.png)
十、使用docker搭建Redis3主3从
关闭防火墙
10.1新建6个docker容器redis实例
docker run -d --name redis-node-1 --net host --privileged=true -v /msdocker/redis/share/redis-node-1:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /msdocker/redis/share/redis-node-2:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /msdocker/redis/share/redis-node-3:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /msdocker/redis/share/redis-node-4:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /msdocker/redis/share/redis-node-5:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /msdocker/redis/share/redis-node-6:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6386
![](https://i-blog.csdnimg.cn/blog_migrate/60c774413629945521f1cbf862bbecf1.png)
效果
![](https://i-blog.csdnimg.cn/blog_migrate/265ed5bdb4faeb5f9ca029a7b5b7061a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3acf059aa3346cc1e7264f2b37afb980.png)
10.2进入容器并为6台机器构建集群关系
# 随便就进入哪个
docker exec -it redis-node-1 /bin/bash
# 注意,进入docker容器后才能执行一下命令,且注意自己的真实IP地址
redis-cli --cluster create 192.168.232.130:6381 192.168.232.130:6382 192.168.232.130:6383 192.168.232.130:6384 192.168.232.130:6385 192.168.232.130:6386 --cluster-replicas 1
--cluster-replicas 1 表示为每个master创建一个slave节点
![](https://i-blog.csdnimg.cn/blog_migrate/ad459046673cca652f3d4dfd2c098205.png)
10.3链接进入6381作为切入点,查看集群状态
![](https://i-blog.csdnimg.cn/blog_migrate/bef000af5fba8a20ff3d6ed017033830.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d0dd76f540a6755b24b95f69010904af.png)
10.4主从容错切换迁移案例
10.4.1数据读写存储
进入redis-node-1容器[6381]
redis-cli -p 6381操作Redis存在的问题
![](https://i-blog.csdnimg.cn/blog_migrate/e8aa5aeb2e0b4964311ee0f646af42ec.png)
插入数据可能失败,可能成功,因为对于key计算出的slot可能查出6381所对应的slot范围
所以使用redis-cli -p 6381 -c
![](https://i-blog.csdnimg.cn/blog_migrate/2fbf6d1bc2854e816b1cf762b10d7862.png)
查看集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/328c8d95e66a0d3a4583f1ed1867fac2.png)
10.4.2容错切换迁移
停掉作为主机的6381,看其从机6386是否上位成为master
![](https://i-blog.csdnimg.cn/blog_migrate/4d3cf95ea9a1ae7ce3c352eed995d1d1.png)
进入一个活着的容器,查看redis集群状态
![](https://i-blog.csdnimg.cn/blog_migrate/418ce39913a6a54ab76cc9fd7f44870a.png)
如果6381从新启动,那么它将作为6386的从机
![](https://i-blog.csdnimg.cn/blog_migrate/38524729c2859900f9d72ad7889ffef2.png)
若要还原为以前的状态,启动6381之后,过会停掉6386,过会再启动6386
10.5主从扩容案例
10.5.1新建6387、6388两个节点
docker run -d --name redis-node-7 --net host --privileged=true -v /msdocker/redis/share/redis-node-7:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /msdocker/redis/share/redis-node-8:/data redis:6.2.1 --cluster-enabled yes --appendonly yes --port 6388
![](https://i-blog.csdnimg.cn/blog_migrate/78f35e1fbee378b05958f8c19a77732b.png)
10.5.2将新增的6387节点(空槽号)作为master节点加入原集群
redis-cli --cluster add-node 192.168.232.130:6387 192.168.232.130:6381
6387 就是将要作为master新增节点
6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
![](https://i-blog.csdnimg.cn/blog_migrate/3a14ad01424916cf0c514e7d3ad6f438.png)
第一次检查集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/7adb35f6bcf684df13d02372a9cbd98f.png)
10.5.3重新分派槽号
redis-cli --cluster reshard 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/3e4f0e43d92ad1bf4b9044387dbffbe9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/00fc7c97e3d05f5e3c4cb86124d07cd9.png)
第二次检查集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/5b55b79bd944b7bdccf7fe668f15d38e.png)
为什么6387是3个新的区间,以前的还是连续?
重新分配成本太高,所以前3家各自匀出来一部分,从6381/6382/6383三个旧节点分别匀出1364个坑位给新节点6387
10.5.4为主节点6387分配从节点6388
命令:redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
redis-cli --cluster add-node 192.168.232.130:6388 192.168.232.130:6387 --cluster-slave --cluster-master-id 0b7886b2866bf8320bd074e8a147554d40391c9a
-------这个是6387的编号,按照自己实际情况
redis-cli --cluster add-node 192.168.232.130:6388 192.168.232.130:6387 --cluster-slave --cluster-master-id 0b7886b2866bf8320bd074e8a147554d40391c9a
第三次检查集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/3df60e230e4320f94d9b520513a9fab2.png)
10.6主从缩容案例
10.6.1将6388删除从集群中将4号从节点6388删除
redis-cli --cluster del-node 192.168.232.130:6388 42fa651e7955f25f2b24485678e7685ed8897e2a
检查集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/f6e449b4643da3eb37085253de990ce5.png)
10.6.2将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
redis-cli --cluster reshard 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/8d7cdc82a95961735f9993f094ca71d9.png)
检查集群状态
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/5a395aa22b8e66dc408197e85115de6a.png)
10.6.3将6387删除
redis-cli --cluster del-node 192.168.232.130:6387 0b7886b2866bf8320bd074e8a147554d40391c9a
查看集群情况
redis-cli --cluster check 192.168.232.130:6381
![](https://i-blog.csdnimg.cn/blog_migrate/af6134f37c8df13ad82e1ae5034c6ac6.png)
十一、DockerFile解析
11.1简介
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
11.2构建三步骤
编写Dockerfile文件
docker build命令构建镜像
docker run依镜像运行容器实例
11.3DockerFile构建过程解析
11.3.1Dockerfile内容基础知识
每条保留字指令都必须为大写字母且后面要跟随至少一个参数
指令按照从上到下,顺序执行
#表示注释
每条指令都会创建一个新的镜像层并对镜像进行提交
11.3.2Docker执行Dockerfile的大致流程
(1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
11.4DockerFile保留字简介
11.4.1FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
11.4.2MAINTAINER
镜像维护者的姓名和邮箱地址
11.4.3RUN
容器构建时需要运行的命令
两种格式
(1)shell格式
![](https://i-blog.csdnimg.cn/blog_migrate/ee789b4a6873d29344b1e85a48f065c2.png)
RUN yum -y install vim
(2)exec格式
![](https://i-blog.csdnimg.cn/blog_migrate/7053a06ca7b1c1ff3c69a08fba9f8a95.png)
RUN是在 docker build时运行
11.4.4EXPOSE
当前容器对外暴露出的端口
11.4.5WORKDIR
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
11.4.6USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
11.4.7ENV
用来在构建镜像过程中设置环境变量
ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
也可以在其它指令中直接使用这些环境变量,
比如:WORKDIR $MY_PATH
11.4.8ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
11.4.9COPY
类似ADD,拷贝文件和目录到镜像中。
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
COPY src dest
COPY ["src", "dest"]
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
11.4.10VOLUME
容器数据卷,用于数据保存和持久化工作
11.4.11CMD
指定容器启动后的要干的事情
![](https://i-blog.csdnimg.cn/blog_migrate/cf43b3c19bb845d827201a6ce71070a0.png)
Dockerfile 中可以有多个 CMD 指令, 但只有最后一个生效,CMD 会被 docker run 之后的参数替换
和RUN的区别
CMD是在docker run 时运行。
RUN是在 docker build时运行。
11.4.12ENTRYPOINT
也是用来指定一个容器启动时要运行的命令
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
命令格式和案例说明
![](https://i-blog.csdnimg.cn/blog_migrate/08f61bdbb191b252fb294450aaf5ea43.png)
![](https://i-blog.csdnimg.cn/blog_migrate/97453ebbe775887076b735c72c6cd06e.png)
优点:在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
注意
如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
11.5案例
Centos7镜像具备vim+ifconfig+jdk8
准备一个linux下的java8官网
docker拉取一个centos7的镜像
11.5.1编写Dockerfile文件
vim Dockerfile
FROM centos:7
MAINTAINER majava<1822172305@qq.com>
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-8u361-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u361-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_361
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
![](https://i-blog.csdnimg.cn/blog_migrate/ac06782fa95ceec4d79db67e0e9024d3.png)
11.5.2构建
docker build -t 新镜像名字:TAG .
docker build -t centosjava8:1.5 .
11.5.3验证
![](https://i-blog.csdnimg.cn/blog_migrate/61e7a0b09fe293846a531a48190dbcd4.png)
11.6虚悬镜像
仓库名、标签都是<none>的镜像,俗称dangling image
# 查看
docker image ls -f dangling=true
# 删除
docker image prune
十二、Docker微服务实战
12.1将springboot项目打包
打包结束上传到linux
12.2编写Dockerfile
# 基础镜像使用java,这是一个dockerhub中的一个java8镜像
FROM openwhisk/java8action
# 作者
MAINTAINER msjava
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为msjava_docker.jar
ADD service-ucenter-0.0.1-SNAPSHOT.jar msjava_docker.jar
# 运行jar包
RUN bash -c 'touch /msjava_docker.jar'
ENTRYPOINT ["java","-jar","/msjava_docker.jar"]
#暴露8160端口作为微服务
EXPOSE 8160
12.3创建镜像
docker build -t msjava_docker:1.6 .
![](https://i-blog.csdnimg.cn/blog_migrate/5b7b58dfc54cd14fcf4b5dd6336ce80c.png)
12.4创建容器测试
docker run -d -p 8160:8160 0a5c9bfcc628
![](https://i-blog.csdnimg.cn/blog_migrate/85b24ef2cb44ff4e7e504191aa120c0b.png)
访问我的项目的swagger页面
![](https://i-blog.csdnimg.cn/blog_migrate/3758fc8063bb33672df5dc928de53c06.png)
十三、Docker网络
![](https://i-blog.csdnimg.cn/blog_migrate/2804f13d21f9dd098adbcf44b30d1fbd.png)
docker容器启动后,会产生一个docker0的虚拟网桥
默认会创建三个网络模式
![](https://i-blog.csdnimg.cn/blog_migrate/2caec6e20f97e7e7e4d77e9646a61c29.png)
13.1常用命令
![](https://i-blog.csdnimg.cn/blog_migrate/2eafaa5fdc046611b5c01ef9dcfd073f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3146ca9ff6a3fb8a38103704734582f2.png)
13.2能干嘛
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
13.3网络模式
bridge模式:使用--network bridge指定,默认使用docker0
host模式:使用--network host指定
none模式:使用--network none指定
container模式:使用--network container:NAME或者容器ID指定
![](https://i-blog.csdnimg.cn/blog_migrate/7b701a66c3c4bc4d0972143ec2db1321.png)
13.3.1容器实例内默认网络IP生产规则
以ubuntu新建两个容器
docker run -it --name u1 ubuntu bash
docker run -it --name u2 ubuntu bash
查看容器详情
![](https://i-blog.csdnimg.cn/blog_migrate/6db5847a9bdb37376df8c07407178e04.png)
关闭u2新建u3
![](https://i-blog.csdnimg.cn/blog_migrate/85f0b23c99d6e28661e65c8b842492f6.png)
docker容器内部的ip是有可能会发生改变的
13.3.2bridge模式
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
![](https://i-blog.csdnimg.cn/blog_migrate/3d315fffc6c4fb8cf43f84e655242f22.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c61d420dfc429169a1ff93c533fae594.png)
13.3.3host模式
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
![](https://i-blog.csdnimg.cn/blog_migrate/ca3b3116c98fb09edebcf1191e02e427.png)
![](https://i-blog.csdnimg.cn/blog_migrate/46c8169af190d9d689bf9b43ba694f27.png)
问题:
docke启动时总是遇见标题中的警告
原因:
docker启动时指定--network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
直接取消配置端口映射即可消除警告
![](https://i-blog.csdnimg.cn/blog_migrate/d45da63a9b3665d61cc29d710f899674.png)
host模式没有自己的ip
那没有ip,且没有端口映射,如何访问呢
http://宿主机IP:8080/
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的,
所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
13.3.4none模式
在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo
需要我们自己为Docker容器添加网卡、配置IP等。
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
![](https://i-blog.csdnimg.cn/blog_migrate/7662f56b5dd128d1e016e2113a483a9d.png)
13.3.5container模式
container⽹络模式
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
![](https://i-blog.csdnimg.cn/blog_migrate/1b9ce30c58c1fb8e76c437c7cb6eef72.png)
docker run -d -p 8085:8080 --name tomcat85 tomcat
docker run -d -p 8085:8080 --network container:tomcat85 --name tomcat86 tomcat
报错
![](https://i-blog.csdnimg.cn/blog_migrate/304e63b2132c388fece59ec9170d63ee.png)
相当于tomcat86和tomcat85公用同一个ip同一个端口,导致端口冲突
换一个镜像
13.3.6自定义网络模式
13.3.6.1没有自定义之前
新建两个带ifconfig命令的ubuntu容器
docker run -it --name ubuntu1 bc99ed49b67c bash
docker run -it --name ubuntu2 bc99ed49b67c bash
它们的ip分别是172.17.0.2、172.17.0.3
现在我用ping命令,从一个容器ping向另一个容器,通过ip是可以ping通的
但是要是根据容器的名字去ping的话就会报错
![](https://i-blog.csdnimg.cn/blog_migrate/ee5749cbbf0db4ce0367c91744a1eb94.png)
由于ip是会变化的,所有就要想办法让它通过容器名ping通
13.3.6.2自定义网络模式
![](https://i-blog.csdnimg.cn/blog_migrate/a4bdc87bd67184790fb895d97e0049fe.png)
新建容器加入上一步新建的自定义网络
docker run -it --name ubuntu1 --network my_network bc99ed49b67c bash
docker run -it --name ubuntu2 --network my_network bc99ed49b67c bash
这样就完事了
十四、Docker-compose容器编排
14.1是什么
Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
14.2安装下载
此处安转的单机版
![](https://i-blog.csdnimg.cn/blog_migrate/3045b27d221e02ca50bf1073c1c182ac.png)
curl -SL https://github.com/docker/compose/releases/download/v2.17.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
测试安装成功
docker compose version
![](https://i-blog.csdnimg.cn/blog_migrate/824c1c8cd01163fda624aa196c60626c.png)
14.3Compose核心概念
14.3.1一文件
docker-compose.yml
14.3.2两要素
服务(service):一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
工程(project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
14.4Compose使用的三个步骤
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
14.5常用命令
Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
14.6微服务实战
可参考前面十二章
如果不使用服务编排存在的问题
先后顺序要求固定,先mysql+redis才能微服务访问成功
多个run命令......
容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错, 要么生产IP写死(可以但是不推荐),要么通过服务调用
使用Compose
14.6.1编写docker-compose.yml文件
version: "3"
services:
microService:
image: msjava_docker:1.7
container_name: service_ucenter
ports:
- "8160:8160"
volumes:
- /msdocker/district/microService:/data
networks:
- my_net
depends_on:
- redis
- mysql
redis:
image: redis:6.2.1
ports:
- "6388:6379"
volumes:
- /msdocker/district/redis/redis.conf:/etc/redis/redis.conf
- /msdocker/district/redis/data:/data
networks:
- my_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_USER: 'msjava'
MYSQL_PASSWORD: '123456'
ports:
- "3388:3306"
volumes:
- /msdocker/district/mysql/db:/var/lib/mysql
- /msdocker/district/mysql/conf/my.cnf:/etc/my.cnf
- /msdocker/district/mysql/init:/docker-entrypoint-initdb.d
networks:
- my_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
my_net:
14.6.2修改springboot工程重新打包
![](https://i-blog.csdnimg.cn/blog_migrate/48e8f2bd42326c82a8cc6f0d85de378a.png)
14.6.3编写Dockerfile
FROM java8
# 作者
MAINTAINER msjava
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为msjava_docker.jar
ADD service-ucenter-0.0.1-SNAPSHOT.jar msjava_docker.jar
# 运行jar包
RUN bash -c 'touch /msjava_docker.jar'
ENTRYPOINT ["java","-jar","/msjava_docker.jar"]
#暴露8160端口作为微服务
EXPOSE 8160
14.6.4创建镜像
docker build -t msjava_docker:1.8 .
14.6.5执行 docker-compose up或者执行 docker-compose up -d
docker-compose up
docker-compose up -d
![](https://i-blog.csdnimg.cn/blog_migrate/e44d1f24a155ba98eea892762f618238.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a0320997db6356f1cb37041e4e662d47.png)
14.6.6关停
docker-compase stop
![](https://i-blog.csdnimg.cn/blog_migrate/ea8c86fc40ced8e68dcd4d73308a94df.png)
十五、Docker轻量级可视化工具Portainer
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
15.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
![](https://i-blog.csdnimg.cn/blog_migrate/2c810dec0af99baf1717540f2acc8e1a.png)
15.2使用
第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
![](https://i-blog.csdnimg.cn/blog_migrate/5152e12d5f036f1b109c83307a0d1be4.png)
选择local,进行连接
![](https://i-blog.csdnimg.cn/blog_migrate/6ca9e3b031e6f2c6ede072619f9bd5a0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/626e69ab6f364bb15c4208c79dbeb0f1.png)
stacks代表compose编排的个数
15.3用其安装nginx
![](https://i-blog.csdnimg.cn/blog_migrate/9c720e394ef9b8b7e6737bd7b0f8a78a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/85dc29a9df66b1101e6894ffb9c4cb8e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6214a8e71d985cab23877c21d339799d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc2626c4aefc927fdc8e5efd37eab339.png)
15.4docker启动则Portainer也启动
安装命令中关注--restart=always
十六、Docker容器监控之CAdvisor+InfluxDB+Granfana
16.1是什么
![](https://i-blog.csdnimg.cn/blog_migrate/3c483f0e4adc75019b508012f0319911.png)
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
![](https://i-blog.csdnimg.cn/blog_migrate/3ef69990bc76d975462403bf03a5d235.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fe61ce88d979bf81be93589836452250.png)
![](https://i-blog.csdnimg.cn/blog_migrate/107dc1be7e50e6ad37778fea152448c7.png)
16.2在compose容器编排中的应用
16.2.1新建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:
user: "104"
image: grafana/grafana
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
16.2.2启动
docker-compose up
docker-compose up -d
![](https://i-blog.csdnimg.cn/blog_migrate/a3be4b747663d59a648e183f7addb27a.png)
16.2.3测试
浏览cAdvisor收集服务,http://ip:8080/
![](https://i-blog.csdnimg.cn/blog_migrate/780eb4c29df8897f682992d29af73bf6.png)
浏览influxdb存储服务,http://ip:8083/
![](https://i-blog.csdnimg.cn/blog_migrate/a46b62d8a3d731244d06cfb8daa6cb40.png)
浏览grafana展现服务,http://ip:3000
admin,admin
![](https://i-blog.csdnimg.cn/blog_migrate/fc572a80884fa9e36c71454c84588e88.png)
16.2.4配置步骤
16.2.4.1配置数据源
![](https://i-blog.csdnimg.cn/blog_migrate/4585fef6de121d998f560b4f9c283a40.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e40e059b4ab62916fb2a9203a0390a0d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2c61b1d7c922ce92a6b6d956cbe41897.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c026a619ffe81fa30986d2b7070c34f3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6cc86299fe980b0918782165cf918d3f.png)
16.2.4.2配置面板panel
![](https://i-blog.csdnimg.cn/blog_migrate/22385340ce0013983c6caf4196615dfc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9654668956da2b12de533c6f826b3b59.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4c7f13497f5e180890688c9b3cc25240.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a27b9d6cad6800013173933b524ef32a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fcf7c42e0eb6dc30aaff027bbfa2cdb5.png)