Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。
先来看一下我们最常用的centos的Dockerfile
在hub.docker.com中所有centos
FROM scratch MAINTAINER The CentOS Project <cloud-ops@centos.org> ADD c68-docker.tar.xz / LABEL name="CentOS Base Image" vendor="CentOS" license="GPLv2" build-date="2016-06-02" # Default command CMD ["/bin/bash"]
含义:
FROM scratch 这里引用了一个父镜像. 我们通常在使用tomcat或者jdk的时候, 他的父类镜像是centos. 而centos的父类镜像是scratch, scratch是所有镜像的基础镜像 MAINTAINER The CentOS Project <cloud-ops@centos.org> MAINTAINER是备注的意思, 这是哪个团队,哪个人写的 ADD c68-docker.tar.xz / 这个参数后面讲解 LABEL name="CentOS Base Image" vendor="CentOS" license="GPLv2" build-date="2016-06-02" LABEL顾名思义,就是描述的含义 # Default command CMD ["/bin/bash"] 表示运行/bin/bash. 我们通常在运行docker run -it lxl/centos的时候, 有时候加/bin/bash,有时候不加. 那么什么时候加, 什么时候不加呢? 其实加和不加都是可以的....因为这里已经给我们自动加了/bin/bash, 如果不加就是用默认的, 如果加了, 就相当于有两个/bin/bash, 他只会执行一个
1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2. 指令按照顺序, 从上到下, 一条指令就是一层
3. #表示注释
4. 每条指令都会创建一个新的镜像层, 并对镜像进行提交
1. docker从基础镜像运行一个容器
2. 执行一条指令并对容器修改
3. 执行类似docker commit的操作提交一个新的镜像层
4. docker在基于刚提交的镜像运行一个新容器
5. 执行dockerfile中的下一条指令直到所指令都执行完成
基础镜像, 当前镜像是基于哪一个镜像
镜像维护者的姓名, 邮箱地址
容器构建时需要运行的命令
当前容器对外暴露的端口号
指定在创建容器后, 终端默认登录进来的工作目录, 一个落脚点
没有指定, 进入到容器的根目录
用来在构建镜像的过程中设置环境变量
这个环境你变量可以在后续的任务Run指令中使用, 这就如同在命令前面指定了环境变量前缀一样, 也可以在其他指令中直接使用这些环境变量.
举个例子:
ENV MY_PATH /usr/home
WORKDIR $MY_PATH
这就是说, 进入到容器以后, 直接进入的工作目录不是根目录, 而是/usr/home
ADD 和 COPY一起说
他俩都有将宿主机指定目录下的文件拷贝到到镜像中的含义.
ADD比COPY更强大.
ADD有拷贝并解压的含义
例如:
ADD c68-docker.tar.xz /
这个含义就是, 拷贝到根目录, 并进行解压
容器数据卷, 用于数据保存和持久化
指定一个容器启动时需要运行的命令,
Dockerfile中可以有多个CMD命令, 但只有最后一个生效, CMD会被docker run之后的参数替代
和CMD有相同之处
指定一个容器启动时要运行的命令
ENTRYPOINT的目的和CMD一样, 都是在绑定容器启动程序及参数.
不同之处是, ENTRYPOINT 不会被docker run后面的参数代替, 而是追加
子镜像继承自父类镜像以后, 父镜像的onbuild就会被触发,
这就相当于一个触发器, 满足一定条件的时候触发
文件名叫Dockerfile. 固定叫法
文件内容如下
From ubuntu MAINTAINER lxl CMD echo ‘hello docker‘
docker build -t demo-docker .
domo-docker: 是生成的新的docker镜像的名字.
. 表示的是文件生成在当前目录
构建的时候, 首先会判断基础镜像是否存在, 如果不存在, 则下载
docker image demo-docker
我们看到生产了一个64.2M的镜像. 版本定义了一个最新版本
docker run demo-docker
运行镜像, 打印输出hello docker
以上我们就自己定义了一个dockerfile,并运行起来了.
FROM ubuntu MAINTAINER lxl RUN apt-get update RUN apt-get install -y nginx COPY index.html /var/www/html ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"] EXPOSE 80
这是一个比较复杂的dockerfile, 那么每句话的含义是什么呢?
docker build -t demo-docker2 .
运行结果
docker run -d -p 80:80 demo-docker2
容器就启动起来了
curl http://localhost:80/
命令 | 用途 |
FROM | 依赖的基础镜像 |
RUN | 执行命令, 比如运行应用 |
ADD/COPY | 都是添加文件, COPY可以添加文件或目录,ADD还可以添加远程文件 |
CMD/ENTRYPOINT | 执行命令, 容器的启动入口 |
EXPOSE | 暴露端口, 如果是一个web服务器,可以是用EXPOSE来暴露端口 |
WORKDIR | 指定路径 |
MAINTAINER | 维护者, 当前dockerfile由谁来维护 |
EVN | 设定环境变量 |
USER | 指定用户 |
VOLUME | mount point挂载点 |
每一层都会有一个对应的编号.
我们之前有过操作, 修改nginx的文件index.html. 这个修改是不会被容器保存的, 需要docker commit生成一个新的镜像. 修改才能生效.
volume提供了一个方便的可持久化存储的方式. 比如我们的数据库数据. 应该是被持久化的. Volume可以做这件事, 并且Volume可以提供给容器和容器之间共享数据
docker run -d --name nginx -v /usr/share/nginx/html nginx -v /usr/share/nginx/html: 表示挂载的目录地址
-d: 表示在后台执行
--name nginx: 容器的名字叫nginx
什么意思呢? 就是说nginx对应文件会有一个经常变动的文件夹, 我们将这个文件夹挂载到本地.
那么挂载到了本地的什么位置呢?
通过docker inspect nginx 可以查看. inspect是检查的意思
这里有很多容器启动的信息.
其中有一个是和挂载目录有关的信息. 我们来看一下
就是这个.
"Source": "/var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data", "Destination": "/usr/share/nginx/html",
Source: 表示的是本地目录
Destination: 表示容器中需要挂载的目录
我们进入目录修改文件的内容,试一试
执行命令:
cd /var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data
看到目录找不到. 为什么找不到呢? 因为我们是在mac上, mac上还有一层虚拟机, 在虚拟机里面运行的docker. 所以我们要进入到那个主机里面去.
screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
18.06.0-ce-mac70 (26399)
采用上面的指令,如果不是这个version请使用screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
enter
,此时你就在docker虚拟机中了。cd /var/lib/docker/volumes/1ef20c41a9fe15914ad240e968da9f3cf3998822a96ba6cdb8361fdd14b17052/_data
就是nginx这个volume的
接下来, 修改index.html文件的内容
结果: 看一看nginx有没有变化
进入到docker容器里面查看,文件内容是否有改变
使用命令docker exec进入容器
docker exec -it nginx /bin/bash
docker exec : 表示进入到docker容器
nginx:表示的是容器的名字
查看挂载目录/usr/share/nginx/html下的index.html是否改成我们本地的内容
修改成功!
docker run -p 88:80 -d -v $PWD/html:/usr/share/nginx/html nginx
此时你修改当前目录下的html/index.html文件, 对应的容器中的index.html目录也会修改
这里有两步操作:
docker create -v $PWD/data:/var/mydata --name data_container ubuntu 创建一个容器 $PWD/data:/var/mydata 将容器的/var/mydata目录挂载到$PWD/data目录下 --name data_container 给创建的容器起个名字 ubuntu 创建容器的镜像是ubuntu
这就创建好了一个容器
docker run -it --volumes-from data_container ununtu /bin/bash 运行容器, --volumes-from data_container 表示从一个容器指定挂载的目录 -it /bin/bash : 指打开容器运行
我们进入容器, 然后创建一个文件
我们创建了一个aaa.txt, 然后我们退出容器, 进入data目录, 看到也有一个aaa.txt
文件
原文:https://www.cnblogs.com/ITPower/p/12677533.html