常见的镜像在Docker Hub就能找到,但是要部署自己的服务可能需要自己构建镜像。构建镜像可以使用Dockerfile。Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

镜像结构

镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。

以MySQL镜像的组成结构为例:

MySQL镜像的组成结构

镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件。构建镜像,其实就是实现上述打包的过程。

语法

构建自定义的镜像时,并不需要一个个文件去拷贝,打包。我们只需要告诉Docker,镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么。Dockerfile就是描述上述信息的文件。Docker会通过Dockerfile构建镜像。

Dockerfile是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。

指令 说明 示例
FROM 指定基础镜像。必须在Dockerfile的第一行指定。 FORM centos:6
ENV 设置环境变量。在使用docker run时可以通过-e重设环境变量值。 ENV key=value
COPY 拷贝本地文件到镜像的指定目录。 复制当前目录下的mysql-5.7.rpm到镜像的/tmp目录:
COPY ./mysql-5.7.rpm /tmp
RUN 执行Linux的Shell命令,一般是安装过程的命令。RUNdocker build时执行。 RUN yum install gcc
EXPOSE 指定容器运行时监听的端口。 EXPOSE 8080
CMD (可以被覆盖)指定容器创建时的默认命令。CMDdocker run时执行。
ENTRYPOINT (不可被覆盖)镜像中应用的启动命令,容器运行时调用。 ENTRYPOINT java -jar xxx.jar
VOLUME 为容器创建挂载点或声明卷。
WORKDIR 设置后续指令的工作目录。
USER 指定后续指令的用户上下文。
SHELL 覆盖Docker中默认的Shell,用于RUN、CMD和ENTRYPOINT指令。

更新详细语法说明,请参考官网文档:Dockerfile reference

在使用Ubuntu、Debian这样的容器的时候,我们可能没办法使用它们的systemctl命令。这是因为它们在启动时默认没有初始化系统(init进程没有运行)。新的Debian和Ubuntu镜像中移除了init软件包,我们可以通过Dockerfile在创建一个包含init软件包的Debian镜像:

FROM debian:latest
# 设置环境变量
ENV APT_ETC_DIR=/etc/apt SOURCES_LIST_PATH=./sources.list
# 将在本地配置好的镜像源文件拷贝到镜像
COPY $SOURCES_LIST_PATH $APT_DIR
# 更换镜像源
RUN apt update && apt-get update
# 安装init软件包
RUN apt-get install init -y
# 安装ssh
RUN apt-get install -y openssh-server
RUN apt-get clean all
# 暴露端口
EXPOSE 22

接着通过docker build命令构建镜像:

docker build -f ./Dockerfile . -t linner/debian

然后使用以下命令运行容器:

docker run -ti \
    --name my-debian \
    --privileged=true \
    -e SOURCES_LIST_PATH=/etc/apt/sources.list \    # 把本地上使用的镜像源配置拷贝到容器中
    linner/debian \
    /sbin/init      # 启动时运行init