Docker 镜像(Image)是一种分层结构的文件系统,基于Docker Hub中已构建好的镜像后,我们可以快速构建自己的镜像。还可以将自己构建的镜像免费推送到Docker Hub的用户仓库进行管理,然后就可以基于这些镜像创建容器。
构建镜像构建完成后,需要将镜像推送Docker Hub
或自已私有Regitry
中。本文使用Docker Hub,因此开始前需要首先注册一个Docker Hub帐号。可以在Docker Hub官网https://hub.docker.com
完成帐号的注册。
注册时需要输入用户名、邮箱、帐号密码,注册后会收到一封激活邮件,需要登录邮箱完成帐号的激活。
注册后,可以通过docker login
命令登录Docker Hub:
docker login
file
登录成功后,会收到Login Succeeded
提示。登录后们就可以从 docker hub
上拉取自己账号下的全部镜像。认证信息上会被保存(保存于$HOME/.docker/config.json
文件),以便之后使用。退出登录可以使用docker logout
命令。
docker logout
file
docker commit可以通过修改容器创建新的镜像。这点类似于git commit的提交代码更新,我们可以首先创建一个容器,然后对容器进行修改,修改完成后像提交代码一样将修改提交为一个新镜像。
docker commit命令格式如下:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
主要选项(OPTIONS)如下:
-a, --author - {string}, 作者(如:"John Hannibal Smith ")
-c, --change - {list}, 使用Dockerfile指令来创建镜像(默认 [])
-m, --message - {string}, 提交备注信息
-p, --pause - {string}, 提交时暂停容器(默认 true)
首先创建一个容器,创建容器的镜像依然使用之前使用的centos镜像:
docker run -it --name centos_test my_centos:1.0 /bin/bash
file
我们会将这个容器做为一个Web服务器使用,所以需要安装nginx
或apache
。
运行容器后,在容器中安装nginx
:
yum update
yum install nginx
file
file
安装完成后,可以将当前状态保存下来,这样就不用每次都创建容器并重新安装软件了。docker commit
提交前,先退出容器:
exit
提交时要通过容器名或容器ID指定所要提交的容器,并要指定一个目标仓库和镜像名。docker commit
提交时比较轻量,只会提交创建容器的镜像与容器当前状态之间有差异的部分。
如,提要刚才配置的容器centos_test,并指定目标仓库和镜像名为centos/nginx:
docker commit centos_test centos/nginx
file
提交后,就可以通过docker images
命令看到新创建的容器:
docker images centos/nginx
file
提交镜像时,还可以指定一些提交参数和标签等。如:
docker commit -m "一个自定义centos容器" -a "小东啊" centos_test centos/nginx:webserver
file
在这条命令中,我们通过-m参数添加了一些提交备注,通过-a参数添加了镜像作者,并为新镜像添加了webserver标签。
docker images centos/nginx
file
每次提交都会创建一个新镜像,在centos/nginx仓库下现在有两个不同ID的镜像。现在使用docker inspect命令查看新创建镜像的详细信息:
docker inspect centos/nginx:webserver
file
镜像提交会,就可以通过使用提交的镜像来创建容器。
docker run -it centos/nginx:webserver /bin/bash
file
使用Dockerfile
和docker build
命令来构建镜像操作更灵活、过程可重复,因此也更推荐使用这种方式来构建镜像。
Dockerfile
基于DSL(Domain Specific Language)语言构建Docker镜像,Dockerfile
编写完成后,就可以使用docker build命令来构建一个新镜像。
Dockerfile
是一个文本格式的配置文件,用户可以使用Dockerfile
来快速创建自定义的镜像。Dockerfile
由一行行命令语句组成,并支持以#开头的注释行。
一般而言,Dockerfile
分为四部分:基础镜像信息
、维护者信息
、镜像操作指令
和容器启动时执行的命令
。
下面是指令详情:
说明:指定所创建镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。格式:
FROM
FROM :
FROM @
任何Dockerfile中的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创造多个镜像,可以使用多个FROM指令,每个镜像一个。
说明:指定维护者信息 格式:
MAINTAINER
该信息会写入生成镜像的Author属性域中。
说明:运行指定命令 格式:
RUN
RUN ["executable","param1","param2"]
(RUN ["可执行文本","参数1","参数2"]) 指令会被解析为Json数组,因此必须用双引号。实例:
RUN echo hello
RUN ["/bin/bash","-c","echo hello"]
RUN默认会在shell终端中运行命令,即/bin/sh -c
RUN ["","",""] 使用exec执行,不会启动shell环境 每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。
当命令较长时,可以使用\来换行。
说明:指定启动容器时默认执行的命令。格式:
CMD ["executable","param1","param2"]使用exec执行,推荐使用的方式
CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用
CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数
每个Dockerfile只能有一条CMD命令,如果指定了多条命令,只有最后一条会被执行
。如果用户启动容器时,手动指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。
说明:用来指定生成镜像的元数据标签信息。格式:
LABEL = = =...
实例:
LABEL version="1.0"
LABEL description="This is test_label"
说明:声明镜像内服务所监听的端口 格式:
EXPOSE [ ...]
实例:
EXPORT 22 80 443
注意,该指令只是起到声明作用,并不会自动完成端口映射。如果你要完成映射还是要在创建的时候使用-p/-P参数。
说明:指定环境变量,在镜像的生成过程中会被后续RUN指令调用,在启动的容器中也会存在。格式:
ENV
ENV =
实例:
ENV PG_MAJOR 9.8.3
指令指定的环境变量在运行时可以被覆盖。
说明:复制指定的路径下的内容到容器中的路径下。格式:
ADD
实例:
ADD *.c /code/
其中可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL, 还可以是一个tar文件(如果是tar文件会自动解压到路径下)。可以是镜像内的绝对路径,或者相对于工作目录(WORKDIR)的相对路径。
说明:复制本地主机的(Dockerfile所在目录的相对路径、文件或目录)下的内容到镜像中的下,目标路径不存在时,会自动创建。格式:
COPY
当使用本地目录为源目录时,推荐使用COPY
说明:指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所以传入值作为该命令的参数。格式:
ENTRYPOINT ["executable","param1","param2"] exec调用执行
ENTRYPOINT command param1 param2 shell中执行
此时,CMD指令指定值将作为根命令的参数。每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个有效。在运行时,可以被 --entrypoint参数覆盖掉。
说明:创建一个数据卷挂载点。格式:
VOLUME ["/data"]
可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等
说明:指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。格式:
USER daemon
当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户。RUN groupadd -r postgres && useradd -r -g postgress postgress 要零时获取管理员权限可以使用gosu或sudo
说明:为后续的RUN、CMD和ENTRYPOINT指定配置的工作目录。格式:
WORKDIR /path/to/workdir
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
WORKDIR /a
WORKDIR b
WORKDIR c
则最终路径为/a/b/c
说明:指定一些镜像内使用的参数(例如版本号信息),这些参数在执行docker build命令时才以--build-arg=格式传入。格式:
ARG [=]
说明:配置当前所创建的镜像作为其它镜像的基础镜像时,所执行的创建操作指令。格式:
ONBUILD [INSTRUCTION]
例如,Dockerfile使用如下类容创建的镜像image-A
[...]
ONBUILD ADD . /app/src
[...]
如果基于镜像image-A创建新的镜像,那么新的镜像就会自动执行上面的ONBUILD指定的内容,类似于继承的关系。
说明:指定所创建镜像启动的容器接收退出的信号值。实例:
STOPSIGNAL signal
说明:配置所启动容器如何进行健康检查(如何判断健康与否) 格式:
HEALTHCHECK [OPTIONS] CMD command
根据所执行命令返回值是否为0来判断 OPTION支持的选项: --interval=DURATION(默认为:30s) 过多久检查一次
--timeout=DURAION(默认为:30s) 每次检查等待结果的超时
--retries=N(默认为:3) 如果失败了,重试几次才最终确定失败
HEALTHCHECK NONE 禁止基础镜像中的健康检查
说明:指定其它命令使用shell时的默认shell类型。实例:
SHELL ["executable","parameters"]
默认值为 ["/bin/sh","-c"]
首先创建一个目录用于初始化Dockerfile
文件
mkdir test_web_server
cd test_web_server
touch Dockerfile
file
如上所示,我们使用命令创建test_web_server
目录,并在其中创见了Dockerfile
文件。这个目录就是我们的构建环境,在Docker中,将这个环境称为上下文(content)或者构建上下文(build content)。构建镜像时,Docker会将构建环境中的文件和目录传递给守护进程,这样守护进程就访问到用户想在镜像中存储的任何代码、文件或其它数据。
接下来,编辑刚创建Dockerfile
文件,比如编写Web服务器的构建代码:
# Version: 1.0
FROM centos
MAINTAINER 小东啊 "[email protected]"
RUN yum update -y
RUN yum install -y nginx
RUN echo "Hello World, 我是个web容器" \
> /usr/share/nginx/html/index.html
EXPOSE 80
file
在以上示例中,我们首先通过FROM指定了一个基础镜像centos
。在Dockerfile
中,FROM
命令只能有一个,该命令用于指定基础镜像,后续的命令都会基于该镜像进行。接着通过MAINTAINER
命令告诉Docker镜像的作者、联系邮箱。
接下来,通过三条RUN
语句安装软件环境。在这个示例中,首先通过RUN
更新了yum
源,然后安装了nginx
,最后创建一个文件/usr/share/nginx/html/index.html并在其中添加了一些简单的示例文本。
RUN
语句表示要在镜像中运行的命令。默认情况下,RUN指令会在/bin/sh -c
。如果不想使用shell
执行,可以exec
来运行RUN
命令,这时需要使用数组来传递指令和参数。如:
RUN ["yum", "install", "-y", "nginx"]
在Dockerfile
文件的最后,通过EXPOSE
命令对外开放了80
端口。出于安全考虑,Docker
默认不会打开任何端口。EXPOSE
会告诉Docker容器内应用将要使用的端口(可以指定多个),但这并不意味着会自动打开该端口,还需要在docker run
运行容器时,通过--expose
参数来指定要打开的端口。
注意:Dockerfile
支持使用注释,注释以#
开头,如上例中的第一行。
构建镜像时,构建目录下的文件默认都会被传入守护进程,如果有不需要传递守护进程的文件。可以通过.dockerignore
文件指定,该文件类似.gitignore
文件,如果创建后会对每行进行模式匹配并排除符合条件的文件。
Dockerfile
是由一系列命令和参数组成的一个文件。其中,每条件命令都要大写(如:FROM),且其后都要跟一个参数(如:centos)。构建镜像时,Dockerfile
中的命令会按顺序从上到下执行,在编写Dockerfile
文件时应注意各条命令的顺序安排。Dockerfile
文件中的每条命令,都会创建一个新的镜像层并会提交镜像。
Docker
使用Dockerfile
构建镜像流程大致如下:
从基础镜像运行一个容器
执行一条命令,对容器进行修改
执行类似docker commit操作,提交一个新的镜像层
基于刚创建的镜像运行一个新容器
继续执行下一条命令,直到所有命令执行完
Dockerfile
文件创建完成后,就可以通过docker build
命令来构建新镜像。执行docker build
命令时,Dockerfile
中的命令都会被执行和提交,且每次提交都会创建一个新镜像。
开始构建上面的例子,构建过程如下
[root@izuf6f2iqt161crtd1qaapz test_web_server]# docker build -t web_test .
Sending build context to Docker daemon 2.048kB
Step 1/6 : FROM centos
---> 470671670cac
Step 2/6 : MAINTAINER 小东啊 "[email protected]"
---> Running in 423e78f29e83
Removing intermediate container 423e78f29e83
---> 7151b8cda488
Step 3/6 : RUN yum update -y
---> Running in f22ddcccc345
CentOS-8 - AppStream 1.7 MB/s | 6.5 MB 00:03
CentOS-8 - Base 5.4 MB/s | 5.0 MB 00:00
CentOS-8 - Extras 2.4 kB/s | 2.1 kB 00:00
Step 4/6 : RUN yum install -y nginx
---> Running in 8d288e80e915
Complete!
Removing intermediate container 8d288e80e915
---> a0743512819d
Step 5/6 : RUN echo "Hello World, 我是个web容器" > /usr/share/nginx/html/index.html
---> Running in 85e09cec1ad5
Removing intermediate container 85e09cec1ad5
---> 753663cf801b
Step 6/6 : EXPOSE 80
---> Running in 2bcd8298c48b
Removing intermediate container 2bcd8298c48b
---> 8bf8ce5253df
Successfully built 8bf8ce5253df
Successfully tagged web_test:latest
在使用docker build构建镜像时,我们通过-t参数指定web_test
做为镜像名
构建镜像时,还可以为镜像设置标签,设置格式为镜像名:标签。如:
docker build -t web_test:v1.0 .
还可以为镜像设置仓库,设置格式为仓库名/镜像名
docker build -t web/web_test:v1.0 .
在构建时我们可以看到,构建上下文被传给了Docker
的守护进程。在构建过程中,每执行一条命令都会有一次镜像创建提交,和使用上一步生成的镜像运行新容器的过程。如:
Sending build context to Docker daemon 2.048kB
Step 1/6 : FROM centos
Step 2/6 : MAINTAINER 小东啊 "[email protected]"
---> Running in 423e78f29e83
Removing intermediate container 423e78f29e83
Step 6/6 : EXPOSE 80
---> Running in 2bcd8298c48b
Removing intermediate container 2bcd8298c48b
---> 8bf8ce5253df
在命令的最后,通过.(同./)告诉Docker从本地当前工作目录查找Dockerfile文件
由于构建过程中的每一步都会将结果提交为镜像,Docker 会将这些镜像做为缓存使用。重新构建时,Docker会对比每一步生成的镜像,如果没有变化就不会重新生成镜像,以节约构建时间。如,前面构建出错的情况,重新构建时,Docker并不是从头开始执行,而是直接从上次出错的位置开始。
如果不希望使用缓存,可以为docker build命令指定--no-cache参数。如:
docker build --no-cache -t web_test :v1.0 .
使用docker images命令查看刚构建的镜像。
docker images web_test
file
如果想查看镜像的构建过程,可以使用docker history命令查看:
docker history web_test
file
通过docker history
命令可以查看镜像的每一层,及创建这些层的Dockerfile
命令。
docker run -d -P --name web_test web_test
file
新镜像构建完成后,可以将其推送到Docker Hub,这样就可以在需要的时候轻松获取和使用镜像,其它人也可以使用你构建的镜像。如果不希望镜像被无关人员看到,可以将其推送到私有仓库。
docker login
然后输入账号密码
file用户登录后,可以通过 docker push
命令将自己的镜像推送到 Docker Hub
。
如,将前面创建的web_test
推送到Docker Hub
:
docker push web_test
file
如上图所示,我上传镜像失败
发布自己镜像问题denied: requested access to the resource is denied
1.先列出所有镜像
docker images
将要发布的镜像改到自己账户名下。我的账户名:xiaodonga
docker tag web_test xiaodonga/web
查看镜像列表
docker images
file
发现自己的已经在自己账户下的
再次发布镜像
docker push xiaodonga/web
可以在Docker Hub看到上传的镜像,如下图:
file注意:推送镜像时,一定要使用用户ID/仓库名
的形式。如果仅使用仓库名,Docker会认为这是一个root仓库,会推送失败。
从上面的推送过程可以看出,镜像是一种分层结构的文件系统。镜像推送到镜像仓库时,这些层都会被推送到仓库中。使用docker rmi
删除镜像时,这些层也都会被删除。
参考链接:
http://suo.im/5Nl8gJ
http://suo.im/6obOIe
往期推荐
????
Docker 入门到实战教程(一)介绍Docker
Docker 入门到实战教程(二)安装Docker
Docker入门到实战教程(三)镜像和容器
Docker 入门到实战教程(四)容器链接