- docker镜像制作,学习记录
-
这种方法将已有容器存为新的镜像,但是不建议使用使用这种方式,原因:
(1) 手工创建镜像容器出错,效率低且可重复性弱
(2) 使用者不知道镜像创建过程、里面是否有恶意程序 -
构建过程
(1) 运行容器
(2) 修改容器
(3) 将容器保存为新的镜像 -
举例:
docker run -it --name=myContainer myImage /bin/bash // 新建容器并运行 docker exec -it myContainer /bin/bash // 进入容器 vim .bashrc报错vim: command not found apt-get update // 更新安装源 apt-get install vim // 安装vim 退出来保存新镜像:使用commit存为新镜像 docker commit -m "install vim" myContainer newImage:newTag docker images // 查看新镜像 重新创建容器测试vim已可用 docker history newImage:newTag // 查看镜像构建历史
- docker程序通过读取Dockerfile文件中的指令生成生成镜像
- Dockerfile的每一行命令都生成了一个镜像层
- Dockerfile的结构:基础镜像信息 + 维护者信息 + 镜像操作指令 + 容器启动时执行指令
2. Dockerfile镜像构建命令
(1) FROM
-
功能:指定基础镜像,必须为第一条指令;如果不以任何镜像为基础,FROM scratch
-
语法:
FROM
: # tag可不指定,默认为latest -
注1:tag尽量具体指定,不要用latest,基础镜像更新后不一定是我们想要的
-
注2:在一个Dockerfile中使用多个基础镜像
一种是多阶段multi-stage构建:写多个基础镜像入口?构建时指定基于哪个创建
另一种是整合多个基础镜像的Dockerfile:Dockerfile内没法FROM多个基础镜像
-
举例
FROM ubuntu:latest # 基于ubuntu:latest创建镜像 FROM scratch # 不基于任何镜像创建
(2) RUN
-
功能:为镜像构建指定要运行的命令行命令,这些命令在docker build时执行
-
语法:
# shell格式(常用) RUN
# command为终端操作的shell命令,可以是下载或安装软件等 # exec格式 RUN ["executable", "param1", "param2", ...] # 可理解为可执行文件+参数 -
注1:每个RUN命令会生成一个镜像层,为了避免镜像臃肿尽量多个命令合到一个指令;不同命令间通过 && 间隔开,换行符 连接换行
-
举例
RUN apt-get update && apt-get install -y vim # 安装vim
(3) CMD
-
功能:容器启动时执行的命令,这些命令在docker run时执行
-
语法:
# 1、shell格式 CMD
# 2、exec命令格式(常用) CMD ["<可执行文件或命令>"," "," ",...] # 3、该写法是为ENTRYPOINT指令指定的程序提供默认参数 CMD [" "," ",...] -
注1:每个Dockerfile只能有一条CMD命令,如果有多条CMD命令只会执行最后一条
-
注2:容器启动时如果加了命令行参数会覆盖CMD指定的命令
-
举例
CMD /bin/bash # 启动容器后执行/bin/bash启动shell终端
(4) LABEL
-
功能:为镜像添加标签,包括创作者、公司、版本等
-
语法:
LABEL
= = ... # e.g. LABEL maintainer="shuaixio@gmail.com" LABEL version="1.1" LABEL maintainer="shuaixio@gmail.com" version="1.1" -
注1:LABEL可以替换MAINTAINER的功能,MAINTAINER已被弃用
-
注2:LABEL可以继承基础镜像中的LABEL,key相同则会覆盖
(5) ADD
-
功能:复制命令,把文件复制到镜像中;功能类似COPY,相当于linux中的scp
-
语法:
ADD
... 或 ADD [" ",... " "] -
注1:src可以是本地的一个文件、文件夹、压缩包甚至url,如果是url,则ADD相当于wget
尽量不要把src写成文件夹,会复制整个目录的内容包括系统元数据
如果是压缩包,拷贝后会自动解压到目标路径 -
注2:dest路径的填写可以是容器内的绝对路径也可以是相对路径
-
注3:除非需要从url提取文件或者自动解压文件,否则一律用COPY
-
举例
ADD xxx.zip /myzipdir/ # 拷贝后自动加压 ADD test1.txt test2.txt /mydir/ # 拷贝多个文件
(6) COPY
-
功能:复制命令,把文件复制到镜像中
-
语法
COPY
... COPY [" ",... " "] -
注1:与ADD的区别,COPY只能复制本地文件,其他一样
(7) WORKDIR
-
功能:指定工作目录。该工作目录必须提前创建好,在镜像构建的每一层中都存在,对RUN,CMD,ENTRYPOINT,COPY,ADD生效
-
语法:
WORKDIR /path/to/workdir # e.g. WORKDIR /a WORKDIR b WORKDIR c RUN pwd # 结果是/a/b/c
(8) ENV
-
功能:设置环境变量,通过$访问
-
语法:
ENV
# 设置一个 ENV = = # 设置多个 -
举例
ENV CUDA_VERSION=11.1.1 # 设置cuda版本,设置完可通过 ${CUDA_VERSION}来访问
(9) VOLUME
-
功能:可实现挂在,将本地文件夹或其他容器中文件夹挂在到这个容器中
-
为什么要挂载
避免重要数据因容器重启而丢失
避免容器体积不断扩大 -
语法
VOLUME
或 VOLUME [" ", " ", ...] -
注1:启动容器时可通过docker run -v参数修改挂载点
(10) EXPOSE
-
功能:暴露容器运行时候的端口给外部
-
语法
EXPOSE
[ ...] -
注1:使用docker run -P时会自动随机映射宿主机与EXPOSE的端口,-p需指定具体端口
-
举例
EXPOSE 80 # 在docker启动时 docker run -P # 宿主机随机端口映射到docker 80端口 docker run -d -p 80:80 nginx:v4cmd # -p设置具体的端口映射
(11) ARG
-
功能:设置镜像构建参数,只在docker build构建镜像的过程中有用
-
语法
ARG
= -
注1:镜像构建时使用docker build --build-tag =来指定参数
-
注2:- -build-tag中的参数名需在Dockerfile中定义,或者Dockerfile中ARG定义参数没有被使用,会报告警
-
注3:ARG可定义默认值,- -build-tag中进行覆盖
(12) ENTRYPOINT
-
功能:容器启动时执行的命令,与CMD类似
-
语法
# 可执行文件+参数 ENTRYPOINT command param1 param2 # shell格式 ENTRYPOINT ["executable", "param1", "param2"]
-
注1:与CMD命令的差异同
只能写一条,如果有多条,最后一条生效
容器启动时运行,而不是镜像构建时运行;CMD:docker run时如果加了命令行参数会被覆盖
ENTRYPOINT:不会被覆盖 -
注2:如果Dockerfile中同时写了ENTRYPOINT和CMD,并且CMD不是一个完整指令,那么CMD内容将作为ENTRYPOINT的参数(组合使用的方式更常见);如果CMD是一个完整指令,那么会相互覆盖,谁在最后谁生效
(13) ONBUILD
-
功能:配置当前镜像作为基础镜像时,子镜像执行的命令
-
语法
ONBUILD [INSTRUCTION]
-
举例
ONBUILD RUN ls -al
ls -al命令不会在当前镜像中执行,当作为基础镜像时,会在子镜像构建的时候执行ls -al
(14) HEALTHCHECK
-
功能:容器启动后健康检查命令
-
语法
# 容器内运行一个命令来检查容器的健康状况 HEALTHCHECK [OPTIONS] CMD command # 基础镜像中取消健康检查 HEALTHCHECK NONE
-
注1:命令只能出现一次,如果出现多次只有最后一个生效
-
注2:HEALTHCHECK支持的选项
- -interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
- -timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
- -retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次 -
CMD后命令的返回值决定了本次健康检查是否成功,具体返回值如下
0: success - 表示容器是健康的
1: unhealthy - 表示容器已经不能工作了
2: reserved - 保留,不要使用该值 -
注2:HEALTHCHECK的状态可以通过 docker container ls查看,健康检查的结果可以通过docker inspect来查看
# This dockerfile uses the alpine image # VERSION 1.0 # Author: shuaixio # base image FROM nvidia/cuda:11.1.1-cudnn8-runtime-ubuntu18.04 # label info LABEL maintainer="shuaixio@email.com" version="1.0" # apt-get: install necessary softwares RUN apt-get update && apt-get install -y vim wget libxml2 gcc g++ libeigen3-dev pkg-config sqlite3 libsqlite3-dev git autoconf automake libtool unzip libboost-dev && cd ~/ # wget: install cmake3.20.0 RUN wget http://www.cmake.org/files/v3.20/cmake-3.20.0.tar.gz && tar xf cmake-3.20.0.tar.gz && cd cmake-3.20.0 && ./configure && make -j8 && make install && cd ~/ # git clone: install geographiclib RUN git clone https://github.com/sotex/geographiclib.git && cd geographiclib && mkdir build && cd build && cmake .. && make -j8 && make install && cd ~ # set expose port EXPOSE 22 80 # /bin/bash after run container CMD /bin/bash2.2 镜像构建命令
-
通过docker build基于Dockerfile构建镜像
docker build -t imageName:Tag .
-
注1:.表示当前目录,代表从本目录的Dockerfile执行;也可以写成绝对路径
由于构建镜像可能有复制该目录下数据的操作,所以不要直接在根目录下进行构建 -
注2:tag自己写,如果和之前镜像重复则会覆盖之前镜像
-
使用docker history命令能清楚的看到每一层进行的操作,方便使用者review
docker history imageId
-
另外 docker history image 可以看到每一层的大小
-
docker history命令还可以用来保存镜像的dockerfile操作过程
docker history --no-trunc=true imageId
参考文章:
Dockerfile镜像构建命令1
Dockerfile镜像构建命令2
docker dockerfile详解
Dockerfile实战
Docker镜像构建实例-推荐
docker-hub官网
created by shuaixio, 2022.05.14



