尚硅谷Docker学习笔记
尚硅谷周阳老师的docker学习笔记
尚硅谷docker学习笔记
参考资料: 尚硅谷docker2022版教程
学习五部曲:
1、是什么?
2、能干嘛?
3、去哪下?
4、怎么玩?
5、helloworld
1.docker简介(基础篇)
(a)为什么会有docker出现?
在传统的开发中,当代码结束开发和测试,要交给运维部署时,开发团队也得准备完整的部署文件,让维运团队得以部署应用程式,开发需要清楚的告诉运维部署团队,用的全部配置文件+所有软件环境。不过,即便如此,仍然常常发生部署失败的状况。 所以就出现了docker,从根本上解决环境配置的问题,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
一句话:从原来的搬家,变成整栋楼一起搬,一次镜像,处处运行。
(b)容器与虚拟机比较
在我们之前的学习中,我们有用到过vmware和centos来搭建linux虚拟机,但是,这种方式有一个缺点,就是我们在开启一个虚拟机,就需要一个完整的镜像文件,资源占用多,冗余步骤多,启动慢。
Docker 和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
(c)docker能干嘛?
(d)docker官网介绍
docker官网:http://www.docker.com
Docker Hub官网(安装docker镜像的仓库):https://hub.docker.com/
(e)docker三要素
1、镜像
Docker 镜像(Image)就是一个只读的模板(我们把应用程序和配置依赖打包好形成一个可交付的运行环境)。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
2、容器
Docker 利用容器独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
3、仓库
仓库是集中存放镜像文件的场所。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等
(f)docker工作架构
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。
2.docker的安装
(a)前提说明
- docker必须部署在linux内核的系统上,如果其他系统想部署docker就必须安装一个虚拟linux环境
- 技术选型:centos7
(b)centos7安装docker
https://docs.docker.com/engine/install/centos/
(1)在官网的docs中,点击下载的选项,然后依次点击下面的,就可以找到教程
(2)根据官网提示,卸载旧版本
(3)yum安装gcc相关环境
yum -y install gcc
yum -y install gcc-c++
(4)安装需要的软件包,并设置稳定的镜像仓库
官网说明,我们采用第一种,设置存储库的方式
这些命令也来自于官网,第二条命令为可选项,但是问题在于他是国外的网址,很可能会连接超时,所以不推荐执行
yum install -y yum-utils
# 不推荐
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#国内推荐使用阿里云
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
(5)更新yum软件包索引(可选,推荐执行)
yum makecache fast
(6)安装DOCKER CE(docker引擎)
下面的所有命令都来自于docker官网
yum -y install docker-ce docker-ce-cli containerd.io
(7)启动docker并测试
systemctl start docker
#查看情况
ps -ef | grep docker
#查看版本
docker version
#helloworld
下面简单的了解一下run的原理~
(8)卸载docker(别真去卸载了)
systemctl stop docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
(c)注册一个属于自己的阿里云账户(可复用淘宝账号)
(1)去下面的网址注册一个账号
https://promotion.aliyun.com/ntms/act/kubernetes.html
(2)进入容器镜像服务
(3)获取你自己的镜像加速地址
(4)点击centos,复制里面的代码到你的centos中执行即可
3.docker的常用命令
3.1帮助启动类命令
#启动docker
systemctl start docker
#停止docker
systemctl stop docker
#重启docker
systemctl restart docker
#查看docker状态
systemctl status docker
#开机启动
systemctl enable docker
#查看概要信息
docker info
#查看docker总体帮助文档
docker --help
#查看docker命令帮助文档
docker 具体命令 --help
3.2镜像命令
(a)docker images
列出本地主机上的所有镜像
同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
通过3.1中的命令,我们也可以发现这个命令是有参数的
(b)docker search [OPTIONS] 镜像名字
在远程库中查询某个镜像
(c)docker pull XX镜像名字
从远程库中下载镜像
#不写tag,默认就是latest
docker pull 镜像名字:TAG
(d)docker system df
查看镜像/容器/数据卷所占的空间
(e)docker rmi XX镜像名字ID
看到rm,就应该想到删除了
删除使用镜像ID或者镜像名:TAG都可以
#删除单个,-f是强制的意思
docker rmi -f 镜像ID
#删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
#删除全部,其实就是先查询再删除(慎用!)
docker rmi -f $(docker images -qa)
(f)面试题:什么是docker虚悬镜像
单独查看所有的虚悬镜像的命令
docker image ls -f dangling=true
3.3容器命令
有镜像才能创建容器,这是根本前提,所以我们先准备一个Ubuntu镜像,以这个镜像为例子
docker pull ubuntu
(a)新建+启动容器docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
OPTIONS说明:
更加具体的options请使用–help学习,这里只列出最常用的
–name=“容器新名字” 为容器指定一个名称(没有指定系统会随机分配);
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
-i:以交互模式运行容器,通常与 -t 同时使用;(i就是交互的意思)
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);
(下面这两个后面再说,先混个眼熟)
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p(通过主机的端口映射冬奥docker容器的端口)
接下来我们启动一个交互式的容器
docker run -it ubuntu /bin/bash
(b)列出当前所有正在运行的容器docker ps [OPTIONS]
OPTIONS:
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
(c)删除停止容器相关命令
#run进去容器,exit退出,容器停止
exit
#run进去容器,ctrl+p+q退出,容器不停止
ctrl+p+q
#启动已停止运行的容器
docker restart 容器ID或者容器名
#重启容器
docker restart 容器ID或者容器名
#停止容器
docker stop 容器ID或者容器名
# 强制停止容器
docker kill 容器ID或容器名
#删除已经停止的容器,容器未停止,需要在rm后加上-f
docker rm 容器ID
#删除多个容器(慎用!),类似于先查询出所有容器的id,然后一起删除
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm
(d)其他重要的命令
有镜像才能创建容器,这里以redis6.0.8的镜像为例来玩一玩~
(1)启动守护式容器(后台服务器)
我们可以通过-d,来指定容器的后台运行模式
docker run -d 容器名
问题:有些时候,使用后台守护进程启动然后docker ps -a 进行查看, 会发现容器已经退出
原因:Docker容器后台运行,就必须有一个前台进程.容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
(2)查看容器日志
docker logs 容器ID
(3)查看容器内运行的进程
docker top 容器ID
(4)查看容器内部细节
docker inspect 容器ID
(5)进入正在运行的容器并以命令行交互
当我们使用Ctrl+q+p后台运行容器后,怎么再进入呢?
docker exec -it 容器ID bashShell
还有另一种方式
docker attach 容器ID
两者区别,推荐使用exec
一般用-d后台启动的程序,再用exec进入对应容器实例
(5)从容器内拷贝文件到主机上
有时候,我们需要把容器内的重要数据拷贝到主机上,那么应该怎么操作呢?
docker cp 容器ID:容器内路径 目的主机路径
(6)导入和导出容器
这个和5类似,也是备份的一种,这点就是我们直接把容器做备份
#export 导出容器的内容留作为一个tar归档文件,保存位置就是你输入这行命令时主机的位置
docker export 容器ID > 文件名.tar
#import 从tar包中的内容创建一个新的文件系统再导入为镜像,之后可以用这个镜像再生成对应的容器
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
4.对docker镜像的深入理解
回顾一下镜像,到目前为止,我们都是直接pull的别人的镜像,从而创建容器,但对于镜像本身,也需要深入了解。
4.1镜像的一些重要概念
(a)镜像的分层
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
(b)联合文件系统
使用联合文件系统,目的就是为了复用!
Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
一句话:以tomcat为例,我们对外只能看见一个tomcat文件镜像,但是我们在下载时,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
(c)docker镜像加载原理
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等等。
思考:为什么我们的镜像可以做到比之前单独学习时小好几倍呢?
rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了
就比如说linux系统Ubuntu和centos,bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
当我们需要使用rootfs包含之外的指令时,直接在容器层添加即可。
(d)采用分层结构的好处
共享资源,方便复用
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
4.2docker镜像commit操作案例
一句话:提交容器副本使之成为一个新的镜像
案例:我们在docker中pull下来的Ubuntu,是不带vim指令的,但是正好我们需要呢?那么接下来,我们就用之前镜像创建的容器,在里面添加vim指令,然后再commit,使其成为一个全新的镜像
在Ubuntu中添加vim:
#更新包管理工具
apt-get update
#安装vim
apt-get -y install vim
安装完成后,commit我们自己的新镜像
代码公式:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
接下来我们就可以通过这个镜像,来创建有vim功能的容器啦~ 其实就类似于java中的继承
4.3本地镜像发布到阿里云/私有库
这里就是使用我们上面的带有vim的Ubuntu
(a)流程简介
(b)发布到阿里云
和我们之前一样,到这个网址阿里云,找到镜像容器服务。
选择个人版,没有建一个
创建一个命名空间
创建一个仓库镜像
进入仓库的管理页面,即可获得脚本,复制黏贴里面的代码即可上传镜像或者把镜像拉倒本地
(b)发布到私有库Docker Registry
Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。
(1)下载镜像Docker Registry
docker pull registry
(2)运行私有库Registry,相当于本地有个私有Docker hub
下面的命令使用了容器卷参数,后面会讲,先混个眼熟
#默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调,
docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry
(3)创建一个新的Ubuntu容器,此次我们在里面安装ifconfig
docker run -it ubuntu bash
#更新包,加快安装速度
apt-get update
#安装ifconfig
apt-get install net-tools
(4)commit我们的新镜像
提交后就可以使用docker images查看我们提交的镜像,已提交至本地
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
(5)curl验证私服库上有什么镜像
镜像仓库的地址部署在虚拟机上,所以这里写你虚拟机的ip地址,结果发现啥也没有
这里的:5000,因为我们启动时,传了一个-p参数,映射我们主机的5000端口
curl -XGET http://你的虚拟机ip:5000/v2/_catalog
(6)将新镜像zzyyubuntu:1.2(第4步提交的)修改符合私服规范的Tag
docker tag 镜像:Tag Host:Port/Repository:Tag
(7)修改配置文件使之支持http
vim /etc/docker/daemon.json
#下面是添加内容
"insecure-registries": ["你的ip:5000"]
(8)重启docker,重新运行registry
(9)push推送到私服库
docker push 你的ip:5000/zzyyubuntu:1.2
(10)第二次用相同的curl验证,发现多了个镜像
(11)从私有库把镜像拉下来
docker pull 你的ip:5000/zzyyubuntu:1.2
5.docker容器数据卷(实现持久化)
首先先来看一个小坑:
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
使用该参数container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限
(a)是什么?
我们在上一个知识点中,已经使用过一个参数v
一句话概括一下:将docker容器内的数据保存进宿主机的磁盘中,类似于我们redis中的aof和rdb文件
(b)能干嘛?
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。
为了能保存数据在docker中我们使用卷。
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效,爽(容器里写的东西可以实时同步到卷中)
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
(c)宿主vs容器之间映射添加容器卷
如果宿主机绝对目录不存在,会自己新建一个(前提是开放了写的权限)
注:-v可以有多个
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
经过测试,容器和宿主机是双向同步的,在双方任意一边修改,都会同步给另一方 ,并且假如容器停了后在主机中修改,容器重启后,会重新同步~
(d)查看数据卷是否挂载成功
docker inspect 容器ID
(e)读写规则映射添加说明
在上面,我们并没有写读写规则,所以我们发现默认是可以读写的
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
但是有时候,我们想让容器中的内容是只读的,怎么办,就要设置为ro
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
但此时如果宿主机写入内容,可以同步给容器内,容器可以读取到。
(f)卷的继承和共享
假设我们现在有一个容器1完成和宿主机的映射,并且容器2要继承容器1的卷规则
docker run -it --privileged=true --volumes-from 父类(容器名) --name u2 ubuntu
集成测试,继承成功~并且如果u2继承的u1挂了,u2的继承关系依然在
6.docker常规安装简介(基础篇结束,恭喜入门~)
总体步骤:搜索镜像->拉取镜像->查看镜像->启动镜像->停止容器->移除容器
6.1tomcat
#搜
docker search tomcat
#拉
docker pull tomcat
#查
docker images
#启(小写p的意思:通过访问宿主机的8080端口,可以映射到docker的8080)
docker run -it -p 8080:8080 --name t1 tomcat
注:新版的tomcat,webapps中是没有页面的,页面在webapps.dist中,如果需要访问主页,需要删掉webapps并且将webapps.dist改名为webapps
然后再虚拟机的浏览器中输入网址就能访问主页啦~
#停
docker stop t1
#删
docker rm -f t1
如果说,我们希望拉下来tomcat就能不修改直接访问首页,可以拉取别的版本
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
6.2mysql
#搜
docker search mysql
#拉
docker pull mysql:5.7
#查
docker images
#启,命令可以参考官网
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
#查
docker ps
#进
docker exec -it 容器ID /bin/bash
#登
mysql -uroot -p
剩下的基本操作就和我们之前学的mysql完全一致,并且在本机使用mysql工具输入虚拟机的ip地址后也可以连接并使用数据库
坑:插入中文数据报错
上文只是最基础的mysql的安装,那么现在还存在问题:中文乱码以及备份问题,那么接下来,就来看一下实战版
#新建容器,使用容器数据卷持久化,备份很关键!
docker run -d -p 3306:3306 --privileged=true -v /opt/mysql/log:/var/log/mysql -v /opt/mysql/data:/var/lib/mysql -v /opt/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
接下来解决中文乱码,在我们备份conf的位置,写一个.cnf文件(注意不是.conf!),把下面的东西复制进去
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
重启mysql,进入后查看字符编码, SHOW VARIABLES LIKE ‘character%’,成功解决中文乱码
并且我们已经使用容器卷进行了同步数据至本机,所有即使我们不小心删除了mysql容器,再新建容器时,数据依然存在。
6.3redis
#拉
docker pull redis:6.0.8
#启
docker run -d -p 6379:6379 redis:6.0.8
docker exec -it 7aca9383d458 bash
然后通过redis-cli即可连接,不过这只是最基础的,同样的和mysql一样的问题,我们怎么持久化?redis的配置文件怎么办?
首先是持久化
我们想要把redis持久化进/opt/redis,首先现在该文件夹中准备一份原始的redis.conf,然后先修改
docker run -p 6379:6379 --name myr3 --privileged=true -v /opt/redis/redis.conf:/etc/redis/redis.conf -v /opt/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
docker exec -it myr3 bash
上面的代码,我们启动类redis,并且使用数据卷完成了持久化,并且使用redis-server,使用我们修改过的配置文件来运行redis,因为我们设置了/opt/redis/redis.conf同步给/etc/redis/redis.conf
7.mysql主从复制docker版(高级篇开始)
(a)新建主服务器实例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
进入/mydata/mysql-master/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
修改完配置后重启master实例
docker restart mysql-master
进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -proot
创建数据的同步用户
#建立用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
#给用户授权
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
(b)新建从服务器实例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
进入/mydata/mysql-slave/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
重启slave实例
docker restart mysql-slave
在主数据库中查看主从同步状态
show master status;
进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot
在从数据库中配置主从复制
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:连接失败重试的时间间隔,单位为秒。
在从数据库中查看主从同步状态
show slave status \G;
在从数据库中开启主从同步
start slave;
重新查看主从同步状态,发现已经yes,至此,主从配置完成~
8.redis集群docker版(三主三从)
8.1基础配置
整体架构如下,首先做好准备工作,关掉虚拟机的防火墙(因为是学习所以就直接关了)+启动docker服务
(a)新建6个docker容器redis实例
按照这个为例,修改最后的端口即可,新建六个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
(b)进入容器redis-node-1并为6台机器构建集群关系
#一定要先进入容器
docker exec -it redis-node-1 /bin/bash
#换成你的ip地址即可,这个在redis中已经学习过,--cluster-replicas 1 表示为每个master创建一个slave节点
redis-cli --cluster create 192.168.111.147:6381 192.168.111.147:6382 192.168.111.147:6383 192.168.111.147:6384 192.168.111.147:6385 192.168.111.147:6386 --cluster-replicas 1
可以看到系统为我们分配的插槽,redis一个有16384个插槽,这些都是redis的知识,这里就不再赘述,且系统已经为我们分配好了主从关系
三主三从搞定~
(c)链接进入6381作为切入点,查看集群状态
#以集群的方式连接
redis-cli -p 6381 -c
#查看集群信息
cluster info
#查看集群有哪些节点
cluster nodes
注意,这里需要以集群的方式连接,加一个-c,具体是为什么,redis中已经学过,因为redis将槽平均分配给了主机,不以集群启动,就只能存对应主机槽的数据了,以集群启动,就可以在6381,6382,6383中持续切换了
查看集群信息
redis-cli --cluster check 192.168.111.147:6381
(d)容错切换迁移
由于每次开启集群,主从都会有所变化,在本次的案例中
主:1 2 3
从:6 4 5
接下来我们使6381宕机,发现6386上位,成为了主机
接下来重启6381,发现6381变成了从机
8.2主从扩容/缩容
(a)主从扩容案例
如果说我们刚刚的三主单从不够了呢?就需要增加,假设我们需要变成四主四从,加入主机6387和从机6388
重点:哈希槽的重新分配
新建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
进入6387容器实例内部,将新增的6387节点(空槽号)作为master节点加入原集群
docker exec -it redis-node-7 /bin/bash
redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:6381
6387 就是将要作为master新增节点
6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群
使用redis-cli --cluster check 192.168.111.147:6381,发现主机已加入,但是没有槽位
重新分配槽号
redis-cli --cluster reshard IP地址:端口号
redis-cli --cluster check 真实ip地址:6381,第二次查看集群
为主节点6387分配从节点6388
redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点的容器ID
redis-cli --cluster check 真实ip地址:6381,第三次查看集群,发现四主四从成功~
(b)主从缩容案例
目的:6387和6388下线,注意最好从从机开始删
redis-cli --cluster check 你的ip:6382,检查集群情况1获得6388的节点ID
从集群中删除四号从节点6388
redis-cli --cluster del-node ip:从机端口 从机6388节点ID
将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
#以81为落脚点操作整个集群
redis-cli --cluster reshard 你的ip:6381
执行后
将6387删除
redis-cli --cluster del-node ip:端口 6387节点ID
再次输入redis-cli --cluster check 你的ip:6382检查集群情况,发现又恢复到了三主三从~
9.DockerFile
官网:https://docs.docker.com/engine/reference/builder/
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
在之前的学习中,我们已经学习了使用commit来提交docker镜像,这种方式没有问题,但是如果镜像一直在变化呢?反复的进行commit会很麻烦,那么就需要我们接下来要学的dockerfile知识了,他就像是一个清单,列举了所有我们需要安装的环境。
构建三部曲:编写Dockerfile文件->docker build命令构建镜像->docker run依镜像运行容器实例
9.1一些重要的概念
(a)基础知识
1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层并对镜像进行提交(镜像上面叠镜像)
(b)Docker执行Dockerfile的大致流程
9.2dockerfile常用保留字
1、from
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
2、MAINTAINER
镜像维护者的姓名和邮箱地址
3、RUN
容器构建时需要运行的命令(也就是从dockerfile build成镜像时),有shell和exec两种格式,这里以shell为例
例:RUN yum -y install vim
4、EXPOSE
当前容器对外暴露出的端口
5、WORKDIR
指定在创建容器后,终端默认登陆(docker run的-it参数)的进来工作目录,一个落脚点
6、USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
7、ENV
用来在构建镜像过程中设置环境变量
8、VOLUME
容器数据卷,用于数据保存和持久化工作,相当于原来的-v
9、COPY
拷贝文件和目录到镜像中。
10、ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
相当于COPY+解压
11、CMD
指定容器启动后的要干的事情,Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
以官网tomcat的dockerfile为例
12、ENTRYPOINT
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
注:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
13、小总结
9.3案例
需求Centos7镜像具备vim+ifconfig+jdk8(自己安装)
在开始之前,先准备一个java8的tar包https://mirrors.yangxingzhen.com/jdk/
1、然后创建一个文件夹,myfile,把tar放进去,在这个文件夹下,准备编写Dockerfile文件
vim Dockerfile
#Dockerfile里的内容
FROM centos:7.6.1810 #不要用latest,8版本停止维护了,会报错!
MAINTAINER zzyy<zzyybs@126.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-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
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、准备构建
#注意,TAG后面有个空格,有个点
docker build -t 新镜像名字:TAG .
然后再输入docker images,发现我们的镜像已经添加到本地
3、运行
docker run -it 新镜像名字:TAG
经过测试,发现我们添加的三个功能都存在,测试成功~
10.docker微服务实战
(a)通过IDEA新建一个普通微服务模块
1、建module:docker_boot
2、改pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/>
</parent>
<groupId>com.atguigu.docker</groupId>
<artifactId>docker_boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mapper.version>4.1.5</mapper.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
</project>
3、写yml
server:
port: 6001
4、主启动,普通的主启动类即可
5、业务类
import org.springframework.beans.factory.annotation.Value;
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;
/**
* @auther zzyy
* @create 2021-10-25 17:43
*/
@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();
}
}
(b)通过dockerfile发布微服务部署到docker容器
1、首先在idea工具中,将其打包成jar包
2、然后把这个jar包导进linux虚拟机中
3、在jar包的目录下编写Dockerfile
vim Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
4、构建镜像
docker build -t zzyy_docker:1.6 .
5、运行容器
docker run -d -p 6001:6001 a969763df521
6、访问测试
经过测试,访问成功,在docker中部署微服务成功~
11.docker网络
11.1基础简介
(a)是什么
启动docker后,他会默认创建三大网络模式
(b)常用命令
(c)能干嘛
1、容器间的互联和通信以及端口映射
2、容器IP变动时候可以通过服务名直接网络通信而不受到影响
(d)几种网络模式介绍
(e)容器实例内默认网络IP生产规则
我们先启动两个Ubuntu容器实例u11和u12,发现他们人手一个ip
接下来删除u12,新建一个u13,发现原来u12的IP地址给u13了,这说明容器的ip是会变化的,所以ip不能写死!
11.2五种网络模式的案例(bridge,host,none,container,自定义)
(a)bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
接下来代码验证一下,先启动两个tomcat容器
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
两两匹配验证成功~
(b)host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换,容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
案例,注意,因为是host,所以-p参数就没有意义了,会抛出警告,可以直接无视,或者不写
docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
进入容器,使用ip addr,发现没有网桥和网关了
如果想访问,直接用主机ip:8080即可
(c)none
在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo(本地链路回环地址)
需要我们自己为Docker容器添加网卡、配置IP等。
docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
(d)container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
案例,注,这里不能用tomcat,因为tomcat公用8080,会冲突,所以换了一个镜像
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
此时,如果我们关掉alpine2共用网卡的alpine1呢?此时发现又只剩一个lo了
(e)自定义
在前面的案例中,我们的容器ping其他容器的ip是可以ping通的,但是并不能按照服务名ping,上文也说过,容器的ip地址是会变的,我们不能把ip地址写死,那么这个时候,就需要自定义网络了。
1、自定义桥接网络,自定义网络默认使用的是桥接网络bridge
docker network create zzyy_network
2、新建的容器加入上面的自定义网段
docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
3、互相ping试试
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
12.Docker-compose容器编排
官网https://docs.docker.com/compose/compose-file/compose-file-v3/
12.1核心概念与安装
(e)是什么?
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
(b)能干嘛?
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
下面我们类比spring,spring是对bean的管理,而我们现在学的compose,是对容器的管理(一键启动,一键stop)
(c)下载安装
官网下载:https://docs.docker.com/compose/install/linux/
注:新版本官网可能有所不同,但大体都是一致的
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
查看在docker官网中查看安装与卸载步骤,不同的版本会有差别,因为是学习,所以使用和周阳老师一致的版本~
(d)核心概念
一文件:docker-compose.yml
两要素:
(e)三个步骤
其中,docker-compose up相当于一次执行了多个docker run
(e)常用操作
docker compose --help
12.2Compose编排微服务实例
还记得第十章中我们微服务实战做过一个镜像吗~
现在假设,我们运行这个镜像生成容器时,必须先有redis和mysql
(a)不使用compose
先来看看如果头铁,不用docker compose
那就是依次docker run啦~
docker run -p 3306:3306 --name mysql57 --privileged=true -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -v /zzyyuse/mysql/logs:/logs -v /zzyyuse/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
docker run -d -p 6001:6001 zzyy_docker:1.6
上述操作存在的问题
(b)使用compose
1、编写docker-compose.yml文件
version: "3"
services:
#下面相当于 docker run -d -p 6001:6001 -V /app/microService:/data --network atguigu_net --name ms01 zzyy_docker:1.6
microService:
image: zzyy_docker:1.6
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- atguigu_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:
- atguigu_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: 'db2021'
MYSQL_USER: 'zzyy'
MYSQL_PASSWORD: 'zzyy123'
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:
- atguigu_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
#创建三个容器的网段,指定了这个网络以后,我们的微服务就不用写死ip了,可以通过redis和mysql这两个服务名来访问两个微服务
networks:
atguigu_net:
2、执行 docker-compose up或者执行 docker-compose up -d
注:使用docker-compose config -q可以检查从docker-compose的语法是否有误
13.Docker轻量级可视化工具Portainer
官网:https://www.portainer.io/
安装指导:https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
(a)安装步骤
首先使用docker命令安装
–restart=always:这个容器会随着docker重启,也就是不会因为docker关了而消失
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
第一次登录需要创建admin,访问地址:linux虚拟机ip地址:9000
设置完后选择local,监控本地,然后进入
其中的stack是有多少组compose编排的容器
(b)常规操作
在container中,点击下面四个按钮,依次是查看日志,容器情况,容器占用的资源,以及进入容器
并且,可以在图形化界面,直接创建容器,并且没有的话也会自动去拉取镜像
其他的操作也大同小异,有了前面的基础,这个只是把我们的代码变成了可视化界面而已~
14.Docker容器监控之CAdvisor+InfluxDB+Granfana
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。。。。 但是,
docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
(a)是什么?
CAdvisor负责收集和分析数据
InfluxDB负责数据的存储
Granfana负责可视化界面
(b)compose容器编排一键搭建监控平台
1、新建一个文件夹,在这个文件夹中新建新建3件套组合的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
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
2、docker-compose up启动docker-compose文件(没有-d参数就是直接前台启动)
3、docker ps查看三个服务是否启动
(c)测试
1、浏览cAdvisor收集服务,http://ip:8080/
注:第一次启动会比较慢,在这里可以浏览数据的收集~
2、浏览influxdb存储服务,http://ip:8083/
3、浏览grafana展现服务,http://ip:3000
账号密码初始都是admin
为他配置一个数据源,选择influxdb
然后添加一个控制面板
选择一个图形
填充数据
这里我们选择监控cpu
点击save,到这里cAdvisor+InfluxDB+Grafana容器监控系统就部署完成了~
更多推荐
所有评论(0)