标签:成功 不能 unionfs base volume 备份 命令 vim 根目录
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
Union 文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 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 等等。
Q1:平时我们安装进虚拟机的 CentOS 都是好几个 G,为什么 Docker 这里才 215M?
对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用 Host 的 Kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的 Linux 发行版,bootfs 基本是一致的,只是 rootfs 会有差别,因此不同的发行版可以共用 bootfs。
Q2:为什么 tomcat 这么大?→ “分层”的镜像
在下载的过程中我们可以看到 Docker 的镜像好像是在一层一层的下载 ...
Q3:为什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是共享资源。比如:有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份 base 镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享!
Docker 镜像都是只读的。当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
Docker 方式启动 tomcat,访问首页出现 404 错误。
docker run -it -p 8888:8080 tomcat # 分别代表 <docker容器>:<tomcat端口>
docker run -it -P tomcat # 随机分配docker容器端口,但是tomcat依旧会是默认的8080
通过 netstat -anp | more
查看端口占用情况,docker 的确在监听 8888 端口。
进入正在运行的容器,一探究竟:
这时候再访问,成了!
但这么做,只在当前有效。容器停止后,下一次再使用镜像生成新的容器时,这个错误还是存在,即实际上问题的根源是在生成容器的镜像上,只有将镜像修改了,再生成的容器才不会再出现这个问题。
由镜像可以生成容器实例,也可以根据当前正在运行的容器实例的实际状况又生成新的镜像(有点像反射)。通过 docker commit
提交容器副本使之成为一个新的镜像,命令格式如下:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
上一小节修改过 webapps 的 tomcat 运行实例算是一个标准的 tomcat 容器了,故以它为模板 commit 一个新的 tomcat 镜像 nuist/mytomcat。这样一来,以后再创建 tomcat 容器时,使用我们自己生成的镜像即可(它跟阿里云拉下来的没什么差别,只是保存了我们之前对容器做的修改)。
docker commit -a="ljq" -m="tomcat update the folder-webapps" c9e9af3087aa nuist/mytomcat:1.1
测试:
顺便 review 下“守护方式”启动容器:
Q1:是什么?
先来看看 Docker 的理念:
Docker 容器产生的数据,如果不通过 docker commit
生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。
为了能保存数据,在 Docker 中我们使用“容器数据卷”// 有点类似我们 Redis 里面的 rdb 和 aof 文件!
Q2:作用
① 容器的持久化;② 容器间继承+共享数据;③ 容器和宿主机共享数据
“卷”就是目录或文件,存在于一个或多个容器中,由 Docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System 提供一些用于持续存储或共享数据的特性:
“卷”的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷。
命令格式(-v 即 volume):
docker run -it -v </宿主机绝对路径目录:/容器内目录>[:ro] <镜像名>
# ro即readonly,一旦添加这个选项,容器只能读宿主机往目录里添的内容,自己不能做增删改操作。
Dockers 自动创建对应的文件夹:
查看数据卷是否挂载成功:
容器和宿主机之间共享数据:
容器停止退出后,主机修改后数据是否同步?同步!
[Java] Hello.java → Hello.class
[Docker] Images → DockFile
VOLUME
指令来给镜像添加一个或多个数据卷(出于可移植和分享的考虑,用 -v 主机目录:容器目录
这种方法不能够直接在 dockerFile 中实现。由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录)。# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished, success!"
CMD /bin/bash
docker build -f /mydocker/dockerFile -t mycentos .
docker run -it mycentos
通过上述步骤,容器内的卷目录地址已经知道,那么对应的主机目录地址在哪呢?→ 通过 docker inspect <容器ID>
查看:
Docker 挂载主机目录,访问时出现 cannot open directory .: Permission denied
。
解决办法:在挂载目录后多加一个 --privileged=true
参数即可~
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,则这个挂载数据卷的容器,就称之为“数据卷容器”。
测试容器间传递共享(--volumes-from):
Dockerfile 是用来构建 Docker 镜像的构建文件,是由一系列命令和参数构成的脚本。
构建三步骤:dockerfile(编写) → docker build(构建) → docker run(运行)
Dockerfile 内容基础知识:
#
表示注释Docker 执行 Dockerfile 的大致流程:
docker commit
的操作提交一个新的镜像层Docker Hub 中 99% 的镜像都是通过在 base 镜像(scratch) 中安装和配置需要的软件构建出来的。
小结:
从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的 3 个不同阶段:
Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
docker build
时会产生一个 Docker 镜像,当运行 Docker 镜像时,会真正开始提供服务。自定义 mycentos 使我们自己的镜像具备如下:
1. 编写 Dockfile 文件:dockFile2
2. 构建命令:docker build -f /mydocker/dockFile2 -t mycentos:1.2 .
3. 运行:docker run -it mycentos:1.2
4. 列出镜像的变更历史:docker history mycentos:1.2
CMD、ENTRYPOINT 都是指定一个容器启动时要运行的命令。不同点是,一个会被 run 后的参数覆盖,另一个被追加组合。
1. Dockerfile 中可以有多个 CMD
指令,但只有最后一个生效,CMD
会被 docker run
之后的参数替换。
2. docker run
之后的参数会被当做参数传递给 ENTRYPOINT
,之后形成新的命令组合。
【crul 命令解释】curl
命令可以用来执行下载、发送各种 HTTP 请求,指定 HTTP 头部等操作。如果系统没有 curl
可以使用 yum install curl
安装,也可以下载安装。curl
是将下载文件输出到 stdout
。使用命令:curl http://www.baidu.com
,执行后,www.baidu.com 的 html 就会显示在屏幕上了。如果我们希望显示 HTTP 头信息,就需要加上 -i
参数。
我们可以看到 myip 报可执行文件找不到的报错(executable file not found)。之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i
替换了原来的 CMD 后面的命令,而不是添加在原来的 curl -s http://ip.cn
后面。而 -i
根本不是命令,所以自然找不到。
那么如果我们希望加入 -i
这参数,我们就必须重新完整的输入这个命令:docker run myip curl -s http://ip.cn -i
。但这也太麻烦了,故当遇到这种组合命令,就该用 ENTRYPOINT
来指定一个容器启动时要运行的命令。
当构建一个被继承的 Dockerfile 时运行命令,父镜像在被子继承后父镜像的 onbuild 被触发。
1. mkdir -p /zzyyuse/mydockerfile/tomcat9
2. 在上述目录下touch c.txt
3. 将 jdk 和 tomcat 安装的压缩包拷贝进上一步目录
4. 在 /zzyyuse/mydockerfile/tomcat9 目录下新建 Dockerfile 文件
FROM centos
MAINTAINER zzyy<zzyybs@126.com>
# 把宿主机当前上下文的 c.txt 拷贝到容器 /usr/local/ 路径下
COPY c.txt /usr/local/cincontainer.txt
# 把 jdk 与 tomcat 添加到容器中(ADD是带解压功能的COPY)
ADD jdk-8u171-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.8.tar.gz /usr/local/
# 安装 vim 编辑器
RUN yum -y install vim
# 设置工作访问时候的 WORKDIR 路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 配置 jdk 与 tomcat 环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.8
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.8
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 容器运行时监听的端口
EXPOSE 8080
# 启动时运行 tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.8/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.8/bin/startup.sh (不要换行,我这里是为了赏心悦目)
&& tail -F /usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out
5. 构建 docker build -t zzyytomcat9 .
6. run
docker run -d -p 9080:8080 --name myt9 (没有换行,我这里纯粹是为了赏心悦目)
-v /zzyyuse/mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.8/webapps/test
-v /zzyyuse/mydockerfile/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.8/logs
--privileged=true zzyytomcat9
7. 验证
![](_v_images/20201113212250547_14690.png =600x)
8. 结合前述的容器卷将测试的web服务test发布
从 Docker Hub上(阿里云加速器) 拉取 MySQL 镜像(标签为 5.7) 到本地:
docker run -p 12345:3306 --name mysql
-v /mydocker/mysql/conf:/etc/mysql/conf.d
-v /mydocker/mysql/logs:/logs
-v /mydocker/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456
-d mysql:5.7
外部 Win10 也来连接运行在 Dokcer 上的 MySQL 服务:
数据备份小测试:
docker exec mysql容器ID sh -c ‘ exec mysqldump --all-databases -uroot -p"123456" ‘ > /dbs.sql
从 Docker Hub上(阿里云加速器)拉取 Redis 镜像(标签为 3.2) 到本地:
docker run -p 6379:6379
-v /mydocker/myredis/data:/data
-v /mydocker/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf
-d redis:3.2 redis-server /usr/local/etc/redis/redis.conf
--appendonly yes
本地镜像发布到阿里云流程:
1. 创建仓库镜像:命名空间、仓库名称
2. 将镜像推送到 Registry,其中 [ImageId]、[镜像版本号] 根据自己的镜像信息进行填写 ↓
3. 将阿里云上的镜像下载到本地
标签:成功 不能 unionfs base volume 备份 命令 vim 根目录
原文地址:https://www.cnblogs.com/liujiaqi1101/p/13976368.html