0x01. 容器数据卷
1. 什么是容器数据卷
docker的理念回顾
将应用和环境打包成一个镜像, 启动运行就变成了一个容器, 我们都知道程序的运行是会产生数据的, 因为我们的容器是可以删除的, 如果把数据保存在容器中, 明显是一个不可取的方法。那如何将数据持久化呢?比如mysql中的数据, 如果你把mysql容器删除了,那不就相当于删除跑路了吗?
所以我们有一个需求就是把mysql容器中的数据保存到本地, 那么如何做呢?
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地! 这就是卷技术! 说白了就是一个目录的挂载, 将我们容器内的目录, 挂载到linux上面
我是不是可以粗疏的理解为这不就是一个同步数据的机制吗?
总结一句话 : 容器的持久化和同步操作 ! 容器间也是可以数据共享的 !
2. 使用数据卷
方式一: 直接使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录
# 命令
docker run -it -v /home/docke_home:/home centos /bin/bash
# 通过查看容器的元数据查看目录挂载信息
docker inspect 容器id
测试数据同步, 在容器添加数据, 宿主机也是同步增加
再来测试
- 停止容器
- 宿主机上修改文件
- 启动容器
- 容器内的数据依旧是同步的
好处: 我们以后修改只需要在本地修改即可, 容器内会自动同步
3. 实战mysql同步数据
思考 : mysql的数据持久化问题
# 获取镜像(指定了版本)
docker pull mysql:5.7
# 运行容器,需要做数据挂载! # 安装启动mysq1 ,需要配置密码的,这是要注意点 !
# 官方测试 : docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysq1:tag
# 启动我们的
# -d 后台运行
# -p 端口映射
# -v 数据卷挂载
# -e 环境配置
# --name 容器名称
[root@kuangshen home]# docker run -d -p 3344:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 mysql:5.7
打开我们的mysql客户端(sqlyog)连接一下试试能不能连接
发现连接成功
# sqlyog--连接到服务器的3344 -- 3344和容器内的3306映射, 这个时候
当我们在sqlyog创建一个新的数据库时, 会在宿主机的/home/mysql/data下新建一个文件
假设我们将容器删除, 发现我们挂载到本地的数据卷依旧没有丢失, 这就实现了容器数据化持久功能 !
4. 具名和匿名挂载
# 匿名挂载
-v 容器路径 容器路径
docker run -d -p 8881:80 --name nginx01 -v /etc/nginx nginx
# 查看所有的 volume (卷) 的情况
[root@centos7 data]# docker volume ls
DRIVER VOLUME NAME
local 4f834a0f6208c921bfbc459b0ad9a0c085e70c8f6180f523f0d525d5841ccbdd
local 56ccd3b8b5e855270a7ff5274b8b662c5c50d502ce6e32c73e347119510b9a36
local b35d6d3b8359b9bcbe1255b6eca4e7cb8044197b7e40919325c5d7e0befa3308
local cbec0103b17d37611a71acb661e5a0935f284b19363a71bd20d3c945578e1e91
local d793375a6414778fe113a659e6e44159937d25c37191d38fefdbce8e3be7f987
# 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!
# 查看nginx01的元数据
[root@centos7 data]# docker inspect nginx01
# 具名挂载
-v 卷名:容器路径 ( 注意不是路径,不加/ )
[root@centos7 data]# docker run -d -p 3344:80 -v juming:/etc/nginx --name nginx02 nginx
# 查看卷情况
[root@centos7 data]# docker volume ls
DRIVER VOLUME NAME
local 4f834a0f6208c921bfbc459b0ad9a0c085e70c8f6180f523f0d525d5841ccbdd
local 56ccd3b8b5e855270a7ff5274b8b662c5c50d502ce6e32c73e347119510b9a36
local b35d6d3b8359b9bcbe1255b6eca4e7cb8044197b7e40919325c5d7e0befa3308
local cbec0103b17d37611a71acb661e5a0935f284b19363a71bd20d3c945578e1e91
local d793375a6414778fe113a659e6e44159937d25c37191d38fefdbce8e3be7f987
local juming
# 发现最后一个是有名字的,这就是具名挂载
# 查看具体的挂载地址
[root@centos7 data]# docker volume inspect juming
所有的dcoker容器内的卷, 没有指定目录的情况下都是在/var/lib/docker/volumes/卷名/_data
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载
# 如何确定是具名挂载还是匿名挂载, 还是指定路径挂载 !
-v 容器路径 # 匿名挂载
-v 卷名:容器路径 # 具名挂载
-v /宿主机路径:容器路径 # 指定路径挂载
拓展 :
# 通过 -v 容器内路径: ro rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写 ( 默认 )
#一旦这个了设置了容器权限,容器对我们挂载出来的内容就有限定了!!
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作 !
5. 初始Dockerfile
Dockerfile 就是用来构建 docker 镜像的构建文件, 之前的docker commit类似二次开发, 这个是纯手工打造镜像
本质就是一串命令脚本 , 通过这个脚本可以生成一个镜像 , 我们来初体验一下
# 创建一个dockerfile文件, 名称随意 建议 dockerfile
# 文件内容 指令( 大写 ) 参数
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash
# 这里每条命令就是镜像的一层
# 启动一下自己写的容器[root@centos7 docker-test-volume]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEymn/centos 1.0 8f2fd6c82fd4 2 minutes ago 209MBtomcat02 1.0 b94af91084cb 5 hours ago 672MBtomcat latest bcd554d24cc5 5 days ago 667MBredis latest 7f33e76fcb56 5 days ago 105MBnginx latest 7ce4f91ef623 6 days ago 133MBmysql 5.7 cd0f0b1e283d 6 days ago 449MBportainer/portainer latest 580c0e4e98b0 2 weeks ago 79.1MBcentos latest 300e315adb2f 3 months ago 209MBelasticsearch 7.6.2 f29a1ee41030 12 months ago 791MB[root@centos7 docker-test-volume]# docker run -it 8f2fd6c82fd4 /bin/bash
这个卷和外部一定有一个同步的目录
查看一下卷挂载的路径
测试一下刚才的文件是否数据同步出去了
这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像 !
假设构建镜像时候没有挂载卷,要手动镜像挂载 -v卷名:容器内路径 !
6. 数据卷容器
两个容器同步数据, 或者多个容器同步数据
# 启动三个容器 , 就用我们刚才创建的镜像测试
# 测试,可以删除dockero1,查看一下docker02和docker03是否还可以访问这个文件# 测试依旧可以访问
实战测试, 两个mysql同步数据
[root@centos7 docker-test-volume]# docker run -d -p 3344:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7[root@centos7 docker-test-volume]# docker run -d -p 8881:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7# 这个时候可以实现两个容器数据同步
结论 :
容器之间配置信息的传递, 数据卷容器的生命周期一直持续到没有容器使用为止
但是一旦你持久化到了本地, 这个时候, 本地的数据是不会删除的
0x02. dockerfile
1. dockerfile介绍
核心 : 用来构建docker镜像的文件 ! 命令参数脚本 !
构建步骤 :
- 编写一个 dockerfile 文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像 ( dockerhub, 阿里云镜像仓库 )
查看一下官方是怎么做的
很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!
官方既然可以制作镜像,那我们也可以!
2. dockerfile构建过程
基础知识
- 每个保留关键字 (指令) 都必须是大写字母
- 执行从上到下顺序执行
#
表示注释- 每一个指令都会创建提交一个新的镜像层, 并提交
dockerfile是面向开发的, 我们以后要发布项目, 做镜像, 就需要编写dockerfile文件, 这个文件十分简单 !
你以前做java开发是写好一个jar包就好了, 但是现在公司都是问你要一个docker镜像
docker镜像逐渐成为了企业交付的标准, 必须掌握
dockerfile : 构建文件, 定义了一切的步骤
步骤 : 开发,部署,运维 缺一不可........
DockerFile : 构建文件,定义了一切的步骤,源代码
Dockerlmages : 通过 DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器 : 容器就是镜像运行起来提供服务器
3. dockerfile指令
FROM # 基础镜镜像,一切从这里开始构建MAINTAINER # 镜像是谁写的,姓名+邮箱RUN # 镜像构建的时候需要运行的命令ADD # 步骤:tomcat镜像,这个tomcat压缩包!添加内容WORKDIR # 镜像的工作目录VOLUME # 挂载的目录EXPOSE # 保留端口配置CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令ONBUILD # 当构建一个被继承DockerFile这个时候就会运行ONBUILD 的指令。触发指令。COPY # 类似ADD ,将我们文件拷贝到镜像中ENV # 构建的时候设置环境变量!
4. 实战测试
docker hub 中99%镜像都是从这个基础镜像过来的 FROM scratch, 然后配置需要的软件和配置来进行构建
创建一个自己的centos镜像
# 1.编写dockerfile文件[root@centos7 dockerfile]# cat dockerfile-mycentos FROM centosMAINTAINER ymn<2733673357@qq.com>ENV MYPATH /usr/localWORKDIR $MYPATHRUN yum -y install vimRUN yum -y install net-toolsEXPOSE 80CMD echo $MYPATHCMD echo "----end----"CMD /bin/bash# 2.通过文件构建镜像[root@centos7 dockerfile]# docker build -f dockerfile-mycentos -t mycentos:1.0 .# 3.测试运行
对比 : 之前原生的centos
我们增加之后的镜像
我们可以列出本地镜像的变更历史, 从中看出镜像是怎么一步一步做出来的
我们平时拿到一个镜像, 可以研究一下它是怎么做的
CMD 和 ENTRYPOINT 区别
CMD # 指定这个容器启动的时候要运行的命令, 只有最后一个会生效, 可被替代ENTRYPOINT # 指定这个容器启动的时候要运行的命令, 可以追加命令
个人理解 : 命令内容是在一个列表中, CMD会先把源列表的内容清空, 然后把新命令添加进去执行, 但是ENTRYPOINT不是, 他是在原来的基础上直接追加进去