Docker镜像,容器,数据卷和dockerfile篇
基础概念
- 容器(Container):
定义:镜像是一个只读的模板,包含了运行应用所需的所有内容:代码,运行时,库文件,环境变量和配置文件
特点:
分层存储:镜像由多个层组成,每一层代表一次修改
只读性:镜像本身是可读的,不能直接修改
可复用:同一个镜像可以创建多个容器
版本管理:通过标签(tag)进行版本管理
轻量化的运行实例,包含应用代码,运行时环境和依赖库.基于镜像创建,与其他容器隔离,共享主机操作系统内核(比虚拟机更高效) - 镜像(Image):
定义:容器是镜像的运行实例,是一个轻量级,可移植的执行环境
制度模板,定义了容器的运行环境(如操作系统,软件配置等).通过分层存储(Layer)优化空间和构建速度 - Dockerfile:文本文件,描述如何自动构建镜像(例如指定基础镜像,安装软件,复制文件等)
镜像和容器的关系:
1. 当我们利用docker安装应用时,docker会自动搜索并下载应用的镜像(image).镜像不仅包含应用本身,还包含应用运行所需要的环境,配置,系统函数库.Docker会在运行镜像时创建一个隔离环境,称为容器(container)
2. 镜像类似于一个模具,容器就是制作出来的糕点
- 镜像仓库:存储和管理镜像的平台,Docker官方维护了一个公共仓库:Docker Hub
客户端Client执行docker run命令,Docker Server的docker daemon守护进程监听到之后,就去镜像仓库拉取镜像images,运行的时候创建一个隔离的环境container
# 从镜像仓库拉取镜像到本地
docker pull
# 查看所有本地镜像
docker images
# 删除镜像(remove image)
docker rmi
# 自定义镜像(打包)
docker build
# 将demo包下的内容构建成一个镜像 demo包下包括:docker-demo.jar和Dockerfile
docker build -t docker-demo .
# 拉取别人的镜像方法1
# 将打包的镜像保存到本地,变成一个压缩文件
docker save
# -o是起名字 将最新版本的nginx镜像压缩成名为nginx的压缩包
docker save -o nginx.tar nginx:latest
# 将压缩文件加载到镜像中-->解压
docker load
docker load -i jdk.tar
#方法2 推到镜像仓库
docker push
# 创建并运行容器,一条龙服务,此时容器处于运行中状态
docker run
# 停止容器-->就是停止容器中某个进程
docker stop
# 重新启动容器-->将容器内部停掉的进程重新启动
docker start
# 查看当前容器的运行状态(process status)
docker ps
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
# 查看所有的容器(包括运行完被停掉的)
docker ps -a
# 删除容器
docker rm
# 查看容器日志
docker logs
#查看nginx的日志
docker logs nginx
# -f持续输入
docker -f logs nginx
# 进入到容器内部(execute)
docker exec
# attach也可以,但是进入再退出之后,容器也会停止运行
docker attach
# -it添加一个可输入的终端,在里面可以使用ls命令
docker exec -it nginx bash
# 查看某个镜像的历史
docker history 镜像名
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等等。
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootf基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs.
分层理解
比如拉取一个tomcat镜像的时候,有的显示Already exists;有的是pull complete
通过 docker image inspect tomcat查看分层情况
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层。

这种情况下,上层镜像层中的层堆栈,并保证多镜像层对外展示为统一的文件系统。Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。Docker 在 Windows 上仅支持 windowsfilter一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

Docker的镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部
这一层就是我们通常说的容器层,容器之下的都叫镜像层

如何提交自己的镜像
commit镜像
# docker commit 提交容器成为一个新的副本 提交到本地
# 命令和git原理类似
docker commit -m="提交的信息" -a="作者" 容器id 目标镜像名:[TAG]
实战测试
# 1.启动了一个默认的tomcat
#2.发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认 webapps下面是没有文件的!
#3.我自己拷贝进去了基本的文件
#4.将我们操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像
如果想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像
就好比之前学习VM的快照
数据卷
数据如果都存放在容器中,那么我们容器删除,数据就会丢失—>需求:数据可以持久化
Mysql,容器删了,删库跑路—>需求:Mysql数据可以存储在本地
Docker容器中产生的数据,同步到本地
多个容器用同一个目录,可以实现容器间的数据共享
数据卷(volume) 是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁;让数据在多个容器和宿主机之间共享,管理,备份

# 创建数据卷
docker volume create
# 查看所有数据卷
docker volume ls
# 查看某个数据卷的详情-->可用于查看数据卷在宿主机的位置
docker volume inspect
# 删除指定数据卷
docker volume rm
# 清除数据卷
docker volume prune
# 查看某个容器的数据卷详情
docker inspect
注意区分
# 某个数据卷的详情
docker volume inspect
# 某个容器的详情
docker inspect
创建容器并挂在数据卷(数据卷挂载只能在创建容器的时候进行)
当创建容器时,如果数据卷不存在,会自动创建数据卷(没有指定名字,称为匿名卷);
也可以自己手动创建数据卷(docker volume create),然后在创建容器的时候使用这个已经存在的数据卷
# 创建容器并挂在数据卷
docker run -v 数据卷名字:容器内目录
本地目录挂载
docker run -v 本地目录:容器内目录
# 本地目录必须以"/"或者"./"开头,如果直接以名称开头,可能会被识别为数据卷而非本地目录
# -v mysql:/var/lib/mysql 会被识别为一个数据卷叫mysql
# -v ./mysql:/var/lib/mysql 会被识别为当前目录下的mysql目录
使用数据卷
方式一:直接使用命令来挂载
docker run -it -v 主机目录,容器内目录
# 启动后通过Docker inspect 容器名 来查看挂载情况

具名挂载和匿名挂载
# 匿名挂载
# -v 只有容器内路径!
docker run -d -p --name nginx01 -v /etc/nginx nginx
# 查看所有的volume 的情况
docker volume ls
[user@bogon data]$ docker volume ls
DRIVERVOLUME NAME
local 8844a5014041e7d3d780e314c8581df937ab9bcc4812764cd3510adb244c9a8a ---->匿名挂载
local html --------->具名挂载
# 具名挂载
通过inspect查看卷的位置
所有的docker容器内的卷,没有制定目录的情况下都是在/var/lib/dokcer/volumes/xxx/data
# 如何区分是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径::容器内路径 #指定路径挂载
拓展:
#通过 -v 容器内路径:rorw改变读写权限
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文件
#指令(大写) 参数
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "___end___"
CMD /bin/bash
# 这里的每一个参数,都是镜像的一层
数据卷容器
多个容器同步数据
docker run -it --name docker02 --volumes-from docker01 镜像名

数据卷容器和容器数据卷
- 容器数据卷:一个容器挂在了一个卷
docker run -v mydata:/app/data nginx- 使用 -v 挂载
- 或者在dockerfile 中写
VOLUME ["volume01","volume02"]挂载
- 数据卷容器:多个容器共享一个卷
docker create -v /app/data --name data-coontainer nginx,其他的容器通过--volumes-from来共享它的数据docker run --volume-from data-container ubuntu
Dockerfile语法
dockerfile就是用来构建docker镜像的文件
通过这个脚本可以生成一个镜像,镜像是一层一层的,脚本是一个一个的命令,每个命令都是一层
自定义镜像
镜像就是包含了应用程序,程序运行的系统函数库,运行配置等文件的文件包.构建镜像的过程其实就是把上述文件打包的过程
层(Layer)
添加安装包,依赖,配置等,每次操作都形成新的一层
基础镜像(BaseImage)
应用依赖的系统函数库,环境,配置,文件等
入口(Entrypoint)
镜像运行入口,一般是程序启动的脚本和参数
Dockerfile就是一个文本文件,其中包含一个个的指令,用指令来说说明要执行什么操作来构建镜像.将来dockerfile可以根据Dockerfile帮我们构建镜像,常见指令如
FROM 镜像名:tag #基础镜像
MAINTAINER ff <ff@example.com> #镜像是谁写的,姓名+邮箱,该写法已经弃用
LABEL maintainer="ff <ff@example.com>" #镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD <源路径> <目标路径> #步骤,添加其他东西
WORKDIR app #镜像的工作目录,用户进入容器之后的位置
VOLUME ["/app/data","/app/logs"] #挂载的目录;将app下的data和logs匿名挂载
EXPOSE 80 #暴露端口;告诉docker,这个容器会在80端口提供服务,只是声明,不会真的开放端口
CMD ["python3","app-py"] #指定容器启动的时候要运行的命令,只有最后一个会生效,可以被替代;
ENTRYPOINT #指定容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承Dockfile这个时候会运行ONBUILD 的指令
COPY <源路径> <目标路径> #类似ADD,将我们的文件拷贝到镜像中
ENV PATH=/usr/local/bin:$PATH #构建的时候设置环境变量
注意:
- CMD和ENTRYPOINT
- 比如在
docker run ls -l,CMD写ls -a,最后会按照ls -l执行------如果写多个CMD会执行最后一个 - 但是ENTRYPOINT会按照
ls -al执行
- 比如在
- ADD和COPY:
- COPY纯复制文件
- ADD:复制+解压+网络下载
- 每个保留关键字(指令)都必须是大写字母
- 执行从上到下顺序执行
#表示注释- 每一个指令都会创建一个新的镜像层
- dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件
基于ubuntu基础镜像,利用dockerfile描述镜像结构
#指定基础镜像
FROM ubuntu:16.04
#配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
#拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
#安装JDK
RUN cd $JAVA_DIR I && tar -xf ./jdk8.tar.gz
&& mv ./jdk1.8.0_144 ./java8
#配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENVPATH=$PATH:$JAVA_HOME/bin
#入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

更多推荐


所有评论(0)