文章目录
笔记来源:kuangstudy视频学习
学习链接
Docker进阶
1. 容器数据卷
什么是数据卷
docker的理念回顾:
将我们的应用和运行环境打包成镜像发布,之后启动以容器运行。
数据怎么保存呢?如果数据存储在容器中,容器删除的时候,数据就会丢失。这肯定是不合理的。
需求:数据持久化
容器之间应该有一个数据共享的技术。docker容器中产生的数据,可以同步到本地!
这就是卷技术!
——目录的挂载:将我们容器内的目录,挂载到Linux上面!
总结一句话:
- 容器的持久化和同步操作!
- 容器间也是可以数据共享的
使用数据卷
方式一:使用命令挂载
docker run -it -v 主机目录:容器内目录 # 可以类比 -p 端口的映射
# 测试
docker run -it -v /home/ceshi:/home centos /bin/bash
挂载之后,容器内的/home目录和Linux的/home/ceshi目录就共享了!
容器内/home目录资源的变化,Linux目录可以共享;
容器外Linux目录资源的变化,容器内目录可以共享!
好处:我们以后修改只需要在本地修改就好,容器内会自动同步!
实战测试
思考:MySQL的数据持久化问题!
# 下载mysql
docker pull mysql:5.7
# 启动容器+数据挂载! # 安装启动mysql,需要密码
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql --name mysql01 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
# 解释
-d # 后台运行
-p # 端口映射
-v # 卷挂载
-e # 环境配置
--name # 容器命名
# 启动成功,本地通过workbench测试连接
# workbench---> 连接到服务器的 3306 映射到容器的3306
# 在本地创建一个数据库 test,查看是否同步成功
# 将mysql容器删除,发现挂载到本地的数据为丢失,这就实现了容器数据的持久化
具名和匿名挂载
# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有的 volume
local 1ee598ebd27a034a9724b33fdf94f912b77983055aeca17902440db67a5edbe9
local e87a415937e57a9c0ee21c08e3407d705487d8b0ffd1c3d4a347b2112012f16d
local ee5e212634a4da79f10b3f607c4e9455cf231e7d2ae72e6a6abbffcb4381c1ce
# 这里发现,这种就是匿名挂载,我们在 -v 只写了容器内路径,没有写容器外路径
# 具名挂载
-v 卷名:容器内路径
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 查看一下所有的 volume
DRIVER VOLUME NAME
local 1ee598ebd27a034a9724b33fdf94f912b77983055aeca17902440db67a5edbe9
local e87a415937e57a9c0ee21c08e3407d705487d8b0ffd1c3d4a347b2112012f16d
local ee5e212634a4da79f10b3f607c4e9455cf231e7d2ae72e6a6abbffcb4381c1ce
local juming-nginx
发现多了一个juming-nginx
所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_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就说明这个路径只能通过宿主机来操作,容器内部是无法操作的
初识DockerFile
DockerFile 就是用来构建docker镜像的构建文件!命令脚本!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层。
# dockerfile 指令(大写) 参数 每一步就是一层
FROM centos
VOLUME ["volume01", "volume02"]
CMD echo "----end----"
CMD /bin/bash
# 启动一下自己生成的容器
volume01,volume02是我们生成镜像的时候自动挂载的,数据卷目录。
这个卷和外部一定有一个同步的目录!
发现主机确实有被同步挂载的目录,匿名挂载方式。
在volume01新建了一个container.txt文件,看是否被同步。
这种方式我们使用很多,因为通常情况下我们会构建自己的镜像。
假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径(具名挂载,常用)
数据卷容器
容器间同步数据。
test
通过 --volumes-from docker01 将docker02挂载docker01
在docker02的volume01内创建一个文件docker01,发现在docker02容器内可见
说明数据同步成功
注意
一旦各容器之间互相挂载,只要有一个容器被使用,那么他们之间的数据共享关系就还在,哪怕父容器被删除,其他容器的共享关系也依然存在。
好处:mysql,redis数据共享。
比如两个数据库的数据共享
# 启动父容器 mysql01,匿名挂载目录
docker run -d -p 3301:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT-PASSWORD=root --name mysql01 mysql:5.7
# 启动子容器 mysql02,同步挂载mysql01
docker run -d -p 3302:3306 -e MYSQL_ROOT_PASSWORD=root --name mysql02 --volumes-from mysql01 mysql:5.7
结论
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。(除非所有容器都停止)
2. DockerFile
dockerfile是用来构建docker镜像的文件!命令参数脚本!
构建步骤:
- 编写一个dockerfile文件
- docker build构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(DockerHub,阿里云镜像仓库)
DockerFile构建过程
基础知识
- 每个保留关键字(指令)都必须是大写字母
- 执行从上到下顺序执行
- #号表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交
dockerfile是面向开发的,发布项目,做镜像,就需要编写dockerfile文件!
DockerFile:构建文件,定义了一切的步骤,好比源代码。
DockerImages:通过DockerFile构建生成的镜像,这就是最终要发布运行的产品。
Docker容器:容器就是镜像运行起来提供服务的。
DockerFile的指令
From # 基础镜像,镜像从这里开始构建,最底层 centos
MAINTAINER # 镜像是谁写的,姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤:tomcat镜像,tomcat压缩包,添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录位置
EXPOSE # 保留端口暴露的配置
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承的DockerFile 这个时候会运行ONBUILD的指令。触发指令。
COPY # 类似ADD,将我们的文件拷贝到镜像中
ENV # 构建的时候设置环境变量
实战测试:构建自己的centos
Docker Hub中 大多数的镜像都是从这个基础镜像构建的:FROM scratch,然后配置需要的软件和配置来进行的构建。
创建一个自己的centos:包含centos,增加vim,ifconfig命令
# 1. 编写自己的dockerfile文件
# 基于centos镜像编写
FROM centos
# 作者
MAINTAINER zhangtong<[email protected]>
# 环境变量:工作路径
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 下载基础命令vim,net-tools
RUN yum -y install vim
RUN yum -y install net-tools
# 暴露80端口
EXPOSE 80
# 执行一些打印的命令
CMD echo $MYPATH
CMD echo -----end-----
# 使用/bin/bash解析
CMD /bin/bash
# 2.通过这个文件构建镜像
# docker build -f dockerfile文件路径 -t 镜像名[:tag] .
# 注意末尾有小数点
Successfully built 4a911b3865b1
Successfully tagged mycentos:1.0
# 3.测试运行
docker run -it mycentos:1.0
# 会发现几点:
# 1. 跳转到了工作目录 /usr/local
# 2. 新下载的命令vim,ifconfig可以使用了
我们可以列出本地镜像变更的历史:
docker history 镜像名[:tag]/镜像id
我们可以通过这个命令去查看镜像的变更记录,可以查到具体镜像层的变更和命令的执行。
CMD和ENTRYPOINT的区别
测试cmd:
# 编写dockerfile-cmd-test
FROM centos
CMD ["ls", "-a"]
# 构建镜像
docker build -f dockerfile-cmd-test -t cmdtest .
# 运行镜像容器
docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 发现 ls -a执行成功的
# 想追加一个命令 -l 想执行 ls -al
docker tun cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
# cmd的前提下,-l替换了CMD ["ls","-a"]命令,执行-l 不是命令,所以报错
# 必须使用完整的命令
docker run cmdtest ls -al
# 因为他把docker的cmd给覆盖掉了
测试entrypoint:
# 编写dockerfile-entrypoint-test
FROM centos
ENTRYPOINT ["ls","-a"]
# 构建之后执行测试
docker run entrypoint-test -l
total 56
drwxr-xr-x 1 root root 4096 Mar 8 16:19 .
drwxr-xr-x 1 root root 4096 Mar 8 16:19 ..
-rwxr-xr-x 1 root root 0 Mar 8 16:19 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Mar 8 16:19 dev
drwxr-xr-x 1 root root 4096 Mar 8 16:19 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 17:37 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 15:22 media
drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt
dr-xr-xr-x 105 root root 0 Mar 8 16:19 proc
dr-xr-x--- 2 root root 4096 Dec 4 17:37 root
drwxr-xr-x 11 root root 4096 Dec 4 17:37 run
lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv
dr-xr-xr-x 13 root root 0 Mar 8 16:19 sys
drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp
drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr
drwxr-xr-x 20 root root 4096 Dec 4 17:37 var
# 发现 -l追加成功了
总结
cmd永远你只执行最后一条命令,新来的cmd会覆盖掉之前的cmd
entrypoint其实如果在同一个dockerfile中出现的话,他也是只执行最后一条命令的。但是entrypoint在运行容器的时候,可以增加参数。使用cmd,参数会把命> 令给覆盖掉
且entrypoint优先级高于cmd,如果同时存在的话,cmd无法覆盖entrypoint,但是entrypoint会覆盖cmd。
实战测试:tomcat镜像
-
准备镜像文件 tomcat压缩包,jdk的压缩包
-
编写dockerfile文件:Dockerfile
FROM centos
MAINTAINER zhangtong<[email protected]>
COPY README.md /usr/local/README.md
ADD jdk-8u281-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.43.tar.gc /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_281
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.43
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.43
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.43/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.43/bin/logs/catalina.out
- 构建镜像
# 由于文件名是官方推荐 Dockerfile,因此不再需要指定文件,会默认找寻目录下该文件
docker build -t mytomcat .
- 启动镜像
# 后台启动mytomcat镜像容器
# 服务器端口开放8080,映射容器端口8080
# 容器命名mytomcat
# 挂载两个目录,test和logs
# 可以在容器外部test目录编写项目即可同步到容器内了
docker run -d -p 8080:8080 --name mytomcat -v /home/zhangtong/build/tomcat/test:/url/local/apache-tomcat-9.0.43/webapps/test -v /home/zhangtong/build/tomcat/tomcatlogs:/url/local/apache-tomcat-9.0.43/logs mytomcat
- 访问测试
curl localhost:8080
# 得到html回显
浏览器访问 ip:8080,得到tomcat页面回显。
- 发布项目(由于做了卷挂载,可以直接在linux本地编写项目)