文章目录
- DokcerFile:按照层来构建image
- 1、什么是 DockerFile
- 2、使用DockerFile挂载数据卷
- (1)创建dockerfile文件
- (2)使用docker build构建镜像
- (3)启动镜像并操作镜像
- (4)验证挂载
- (5)最后总结
- 3. DockerFile编写细节
- (1)查看ubuntu在docker hub中的官方dockerfile
- (2) DockerFile的构建过程
- (3) DockerFile常用指令
- (4) CMD和ENTRYPOINT的区别
DokcerFile:按照层来构建image
1、什么是 DockerFile
- Dockerfile就是用来构建Docker镜像的构建文件,是一个命令脚本。
- 通过这个脚本可以生成镜像,镜像是一层一层的,而脚本也是一个个的命令,每个命令都是一层。
2、使用DockerFile挂载数据卷
(1)创建dockerfile文件
找一个测试文件夹,新建一个文件,取名例如dockerfile
然后在dockerfile中写入我们的命令脚本
FROM centos # 添加基础镜像
VOLUME ["volume01", "volume02"] # 添加两个容器数据卷,属于匿名挂载
CMD echo "--finished----success--" # 容器构建完成输出的信息
CMD /bin/bash # 指定终端命令
注意:
- 创建一个Dockerfile文件,名字可以随机起,建议使用Dockerfile命名。
- 文件中的指令都大写。
- Dockerfile里面的每个命令,就是镜像的一层!
- docker file中使用VOLUME给镜像添加一个或多个数据卷,但是其需要主机有这个目录,移植性不好
提示:
出于可移植和分享的考虑,用
-v
主机目录:容器目录这种方法不能够直接在Dockerfile
中实现。是由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录
(2)使用docker build构建镜像
docker build 参数:
test@P340:/$ sudo docker build --help
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Options:
-c, --cpu-shares int CPU shares (relative weight)
-f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile')
-m, --memory bytes Memory limit
-q, --quiet Suppress the build output and print image ID on success
-t, --tag list Name and optionally a tag in the 'name:tag' format
# -f 指定dockerfile文件路径;-t 指定镜像的`命名空间/镜像:TAG`
test@P340:/$ sudo docker build -f dockerfile -t test/ubuntu .
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM ubuntu
---> 1318b700e415
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 1911ef59f958
Removing intermediate container 1911ef59f958
---> 656521e484a9
Step 3/4 : CMD echo "---end---"
---> Running in 2cb2a7e0d28a
Removing intermediate container 2cb2a7e0d28a
---> 1c060daa940e
Step 4/4 : CMD /bin/bash
---> Running in 4e8a5ccb6ccd
Removing intermediate container 4e8a5ccb6ccd
---> 4b88b2784076
Successfully built 4b88b2784076
Successfully tagged liufeng/ubuntu:latest
# 查看新构建好的镜像
test@P340:/$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu latest 4b88b2784076 56 seconds ago 72.8MB
ubuntu latest 1318b700e415 3 weeks ago 72.8MB
(3)启动镜像并操作镜像
test@P340:/$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu latest 4b88b2784076 8 minutes ago 72.8MB
ubuntu latest 1318b700e415 3 weeks ago 72.8MB
test@P340:/$ sudo docker run -it --name ubuntu01 4b88b2784076 /bin/bash
root@7b0c1a867911:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
注意,进入容器之中就可以直接看到我们在images中挂载的volume1 和volume2连个容器卷了。
其实这两个文件夹就是我们在Dockerfile文件中定义的数据卷挂载,是以匿名挂载的方式挂载数据卷的。
在容器启动的时候,会自动挂载这两个数据卷目录。
(4)验证挂载
在我们打开的容器中的volume01或volume02文件夹中新建一个文件,写入点东西测试一下。然后退出容器。
查看一下我们容器数据卷的信息,因为是匿名挂载所以数据卷的名字是一大段字符
# 查看我们的容器
test@P340:/$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b0c1a867911 4b88b2784076 "/bin/bash" 7 minutes ago Exited (0) 2 minutes ago ubuntu01
# 查看容器元信息
test@P340:/data/liufeng/project/docker/test_volumn$ sudo docker inspect 7b0c1a867911
"Mounts": [
{
"Type": "volume",
"Name": "89bb825b92fb7e9293dbeb1ed0c5f9647006e7f5fd571dec4f97b05f471adf64",
"Source": "/var/lib/docker/volumes/89bb825b92fb7e9293dbeb1ed0c5f9647006e7f5fd571dec4f97b05f471adf64/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "42655cb1ce4f2b071858fe67ac50e8d74fc7ff409c2bfa9fb6e467c07de97ba7",
"Source": "/var/lib/docker/volumes/42655cb1ce4f2b071858fe67ac50e8d74fc7ff409c2bfa9fb6e467c07de97ba7/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
根据查看到的容器名和地址进入看看
test@P340:/# cd /var/lib/docker/volumes/89bb825b92fb7e9293dbeb1ed0c5f9647006e7f5fd571dec4f97b05f471adf64/_data
test@P340:/var/lib/docker/volumes/89bb825b92fb7e9293dbeb1ed0c5f9647006e7f5fd571dec4f97b05f471adf64/_data# ls
hello_dockerfile
ok!!!可以看到我们在容器中创建的那一个用来测试挂载的dockerfile了
(5)最后总结
- dockerfile 名字可以任意,但是建议使用Dockerfile
- 使用dockerfile来创建挂载的时候注意如果使用绝对路径
本机地址::容器地址
,那么构建的镜像可能移植性受限,因为其要求主机上要有这个目录 - 如果使用匿名挂载的方式来构建dockerfile的挂载,那么可以使用
docker inspect 容器id
来查看容器的元数据,包括匿名挂载的位置
3. DockerFile编写细节
(1)查看ubuntu在docker hub中的官方dockerfile
ubuntu在dockerhub中的地址 :https://hub.docker.com/_/ubuntu 然后可以点击其中的一个版本,跳转到ubuntu的github地址中:
https://github.com/tianon/docker-brew-ubuntu-core/blob/a967c2b8734c77f7f89449d0b87c2e1eebf8b26e/bionic/Dockerfile 可以打开其dockerfile进行查看了:
FROM scratch
ADD ubuntu-bionic-oci-amd64-root.tar.gz /
CMD ["bash"]
(2) DockerFile的构建过程
Dockerfile构建步骤
- 编写一个
Dockerfile
文件 - 使用
docker build
将其构建成为一个镜像 - 使用
docker run
运行镜像 - 使用
docker push
发布镜像
(3) DockerFile常用指令
基础知识
- 每个保留关键字( 指令 )都必须是大写字母
- 每一个指令都会创建提交一个新的镜像层
- 指令的执行顺序从上到下
-
#
表示注释(注意需要单独一行)
在 Docker 中创建镜像最常用的方式就是使用 Dockerfile. 其是一个 Docker 镜像的描述文件,包含了一条条的指令 : 每一条指令构建一层,因此每一条指令的内容就是描述该层应当如何构建. Dockerfile 常用指令如下图所示
-
FROM
: 基础镜像,一切从这里开始构建 -
MAINTAINER
: 镜像的作者信息 : 姓名 + 邮箱 -
RUN
: 镜像构建的时需要运行的命令 -
ADD
: 将所需文件拷贝到镜像中,例如 nginx,redis等. -
WORKDIR
: 指定镜像的工作目录 -
VOLUME
: 设置挂载目录 -
EXPOSE
: 暴露端口配置 -
CMD
: 指定容器启动时要运行的命令,但只有最后一个生效且可被替代 -
ENTRYPOINT
: 与 CMD 功能相同,区别为其可追加命令 -
ONBUILD
: 当构建一个被继承 Dockerfile 时这个指令就会被触发执行 -
COPY
: 与 ADD 指令类似,即可将文件拷贝到镜像中
ENV : 设置构建时所需的环境变量 -
USER
: 指定运行用户
(4) CMD和ENTRYPOINT的区别
CMD:
CMD是一个容器的默认可执行体:也就是说,容器启动之后,默认执行的命令。
- 如果
docker run
没有指定任何的执行命令或者dockerfile里面也没有entrypoint
,那么,就会使用cmd指定的默认的执行命令执行。同时也从侧面说明了entrypoint的含义,它才是真正的容器启动以后要执行命令。- 只有最后一个CMD才会被执行
CMD的官方说明:有三种用法
The CMD instruction has three forms:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
ENTRYPOINT
官方说明An ENTRYPOINT allows you to configure a container that will run as an executable.
也就是说:ENTRYPOINT才是通常用于定义容器启动后执行命令的执行体
ENTRYPOINT有两种用法:
ENTRYPOINT has two forms:
ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
ENTRYPOINT command param1 param2 (shell form)
如果run后面有东西,那么后面的全部内容都会作为ENTRYPOINT的参数
比如如果dockerfile为:
FROM ubuntu
ENTRYPOINT ['ls','a']
那么使用run运行不加参数的时候,其显示的结果和CMD是一模一样的
docker run 容器ID
但是如果你在后面加上一个参数-l
, 如果在CMD ['ls','a']
之中会接收到错误,二在我们的ENTRYPOINT之中就是正确的。也就是ENTRYPOINT会将传入的内容都当作是参数,如果没有传入的参数,而CMD中有,他也会把CMD的参数当作是自己的参数执行。
CMD是覆盖,ENTRYPOINT是追加