专栏首页李浩东的博客Docker 入门到实战教程(五)构建Docker镜像

Docker 入门到实战教程(五)构建Docker镜像

Docker 镜像(Image)是一种分层结构的文件系统,基于Docker Hub中已构建好的镜像后,我们可以快速构建自己的镜像。还可以将自己构建的镜像免费推送到Docker Hub的用户仓库进行管理,然后就可以基于这些镜像创建容器。

一. 构建准备

1.1 注册账号

构建镜像构建完成后,需要将镜像推送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)

2.1 创建容器

首先创建一个容器,创建容器的镜像依然使用之前使用的centos镜像:

docker run -it --name centos_test my_centos:1.0 /bin/bash

file

2.1.1 安装软件

我们会将这个容器做为一个Web服务器使用,所以需要安装nginxapache

运行容器后,在容器中安装nginx

yum update
yum install nginx

file

file

安装完成后,可以将当前状态保存下来,这样就不用每次都创建容器并重新安装软件了。docker commit提交前,先退出容器:

exit

2.2 提交更改

提交时要通过容器名或容器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标签。

2.2.1 查看镜像:

docker images centos/nginx

file

每次提交都会创建一个新镜像,在centos/nginx仓库下现在有两个不同ID的镜像。现在使用docker inspect命令查看新创建镜像的详细信息:

 docker inspect centos/nginx:webserver

file

2.3 使用新镜像

镜像提交会,就可以通过使用提交的镜像来创建容器。

docker run -it centos/nginx:webserver /bin/bash

file

三. 使用Dockerfile构建镜像

使用Dockerfiledocker build命令来构建镜像操作更灵活、过程可重复,因此也更推荐使用这种方式来构建镜像。

Dockerfile基于DSL(Domain Specific Language)语言构建Docker镜像,Dockerfile编写完成后,就可以使用docker build命令来构建一个新镜像。

Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。 Dockerfile由一行行命令语句组成,并支持以#开头的注释行。 一般而言,Dockerfile分为四部分:基础镜像信息维护者信息镜像操作指令容器启动时执行的命令

3.1 Dockerfile指令说明:

file

下面是指令详情:

3.1.1 FROM

说明:指定所创建镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。格式:

  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>

任何Dockerfile中的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创造多个镜像,可以使用多个FROM指令,每个镜像一个。

3.1.2 MAINTAINER

说明:指定维护者信息 格式:

  MAINTAINER <name>

该信息会写入生成镜像的Author属性域中。

3.1.3 RUN

说明:运行指定命令 格式:

  RUN <command>
  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指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。 当命令较长时,可以使用\来换行。

3.1.4 CMD

说明:指定启动容器时默认执行的命令。格式:

  CMD ["executable","param1","param2"]使用exec执行,推荐使用的方式
  CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用
  CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数

每个Dockerfile只能有一条CMD命令,如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时,手动指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。

3.1.5 LABEL

说明:用来指定生成镜像的元数据标签信息。格式:

  LABEL <key>=<value> <key>=<value> <key>=<value>...

实例:

  LABEL version="1.0"
  LABEL description="This is test_label"
3.1.6 EXPOSE

说明:声明镜像内服务所监听的端口 格式:

  EXPOSE <port> [<port> <port> ...]

实例:

  EXPORT 22 80 443

注意,该指令只是起到声明作用,并不会自动完成端口映射。如果你要完成映射还是要在创建的时候使用-p/-P参数。

3.1.7 ENV

说明:指定环境变量,在镜像的生成过程中会被后续RUN指令调用,在启动的容器中也会存在。格式:

  ENV <key> <value>
  ENV <key>=<value>

实例:

  ENV PG_MAJOR 9.8.3

指令指定的环境变量在运行时可以被覆盖。

3.1.8 ADD

说明:复制指定的路径下的内容到容器中的路径下。格式:

  ADD <src> <dest>

实例:

  ADD *.c /code/

其中可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL, 还可以是一个tar文件(如果是tar文件会自动解压到路径下)。可以是镜像内的绝对路径,或者相对于工作目录(WORKDIR)的相对路径。

3.1.9 COPY

说明:复制本地主机的(Dockerfile所在目录的相对路径、文件或目录)下的内容到镜像中的下,目标路径不存在时,会自动创建。格式:

  COPY <src> <dest>

当使用本地目录为源目录时,推荐使用COPY

3.1.10 ENTRYPOINT

说明:指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所以传入值作为该命令的参数。格式:

  ENTRYPOINT ["executable","param1","param2"] exec调用执行
  ENTRYPOINT command param1 param2 shell中执行

此时,CMD指令指定值将作为根命令的参数。每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个有效。在运行时,可以被 --entrypoint参数覆盖掉。

3.1.11 VOLUME

说明:创建一个数据卷挂载点。格式:

VOLUME ["/data"]

可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等

3.1.12 USER

说明:指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。格式:

  USER daemon

当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户。RUN groupadd -r postgres && useradd -r -g postgress postgress 要零时获取管理员权限可以使用gosu或sudo

3.1.13 WORKDIR

说明:为后续的RUN、CMD和ENTRYPOINT指定配置的工作目录。格式:

  WORKDIR /path/to/workdir

可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

  WORKDIR /a
  WORKDIR b
  WORKDIR c

则最终路径为/a/b/c

3.1.14 ARG

说明:指定一些镜像内使用的参数(例如版本号信息),这些参数在执行docker build命令时才以--build-arg=格式传入。格式:

  ARG <name> [=<default value>]
3.1.15 ONBUILD

说明:配置当前所创建的镜像作为其它镜像的基础镜像时,所执行的创建操作指令。格式:

  ONBUILD [INSTRUCTION]

例如,Dockerfile使用如下类容创建的镜像image-A

    [...]    
ONBUILD ADD . /app/src
    [...]

如果基于镜像image-A创建新的镜像,那么新的镜像就会自动执行上面的ONBUILD指定的内容,类似于继承的关系。

3.1.16 STOPSIGNAL

说明:指定所创建镜像启动的容器接收退出的信号值。实例:

  STOPSIGNAL signal
3.1.17 HEALTHCHECK

说明:配置所启动容器如何进行健康检查(如何判断健康与否) 格式:

  HEALTHCHECK [OPTIONS] CMD command

根据所执行命令返回值是否为0来判断 OPTION支持的选项:  --interval=DURATION(默认为:30s) 过多久检查一次   --timeout=DURAION(默认为:30s) 每次检查等待结果的超时   --retries=N(默认为:3) 如果失败了,重试几次才最终确定失败

HEALTHCHECK NONE 禁止基础镜像中的健康检查

3.1.18 SHELL

说明:指定其它命令使用shell时的默认shell类型。实例:

  SHELL ["executable","parameters"]

默认值为 ["/bin/sh","-c"]

3.1 创建Dockerfile文件

首先创建一个目录用于初始化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 小东啊 "im.lihaodong@gmail.com"
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文件,如果创建后会对每行进行模式匹配并排除符合条件的文件。

3.2 关于Dockerfile文件

Dockerfile是由一系列命令和参数组成的一个文件。其中,每条件命令都要大写(如:FROM),且其后都要跟一个参数(如:centos)。构建镜像时,Dockerfile中的命令会按顺序从上到下执行,在编写Dockerfile文件时应注意各条命令的顺序安排。Dockerfile文件中的每条命令,都会创建一个新的镜像层并会提交镜像。

Docker使用Dockerfile构建镜像流程大致如下:

  • 从基础镜像运行一个容器
  • 执行一条命令,对容器进行修改
  • 执行类似docker commit操作,提交一个新的镜像层
  • 基于刚创建的镜像运行一个新容器
  • 继续执行下一条命令,直到所有命令执行完

3.3 docker build构建新镜像

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 小东啊 "im.lihaodong@gmail.com"
 ---> 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 小东啊 "im.lihaodong@gmail.com"
 ---> Running in 423e78f29e83
Removing intermediate container 423e78f29e83

Step 6/6 : EXPOSE 80
 ---> Running in 2bcd8298c48b
Removing intermediate container 2bcd8298c48b
 ---> 8bf8ce5253df

在命令的最后,通过.(同./)告诉Docker从本地当前工作目录查找Dockerfile文件

3.3.1 构建缓存

由于构建过程中的每一步都会将结果提交为镜像,Docker 会将这些镜像做为缓存使用。重新构建时,Docker会对比每一步生成的镜像,如果没有变化就不会重新生成镜像,以节约构建时间。如,前面构建出错的情况,重新构建时,Docker并不是从头开始执行,而是直接从上次出错的位置开始。

如果不希望使用缓存,可以为docker build命令指定--no-cache参数。如:

docker build --no-cache -t web_test :v1.0 .

3.4 使用新镜像

使用docker images命令查看刚构建的镜像。

docker images web_test

file

如果想查看镜像的构建过程,可以使用docker history命令查看:

docker history web_test

file

通过docker history命令可以查看镜像的每一层,及创建这些层的Dockerfile命令。

3.4.1 使用
docker run -d -P --name web_test web_test

file

四. 新镜像推送到Docker Hub

新镜像构建完成后,可以将其推送到Docker Hub,这样就可以在需要的时候轻松获取和使用镜像,其它人也可以使用你构建的镜像。如果不希望镜像被无关人员看到,可以将其推送到私有仓库。

4.1 登录

docker login

然后输入账号密码

file

4.2 推送镜像

用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub

如,将前面创建的web_test推送到Docker Hub

 docker push web_test

file

如上图所示,我上传镜像失败 发布自己镜像问题denied: requested access to the resource is denied

4.3 denied解决办法:

1.先列出所有镜像

docker images
  1. 将要发布的镜像改到自己账户名下。我的账户名:xiaodonga
docker tag web_test xiaodonga/web
  1. 查看镜像列表
docker images

file

发现自己的已经在自己账户下的

  1. 再次发布镜像
docker push xiaodonga/web

可以在Docker Hub看到上传的镜像,如下图:

file

注意:推送镜像时,一定要使用用户ID/仓库名的形式。如果仅使用仓库名,Docker会认为这是一个root仓库,会推送失败。

从上面的推送过程可以看出,镜像是一种分层结构的文件系统。镜像推送到镜像仓库时,这些层都会被推送到仓库中。使用docker rmi删除镜像时,这些层也都会被删除。

参考链接: http://suo.im/5Nl8gJ http://suo.im/6obOIe

本文分享自微信公众号 - 小东IT技术分享(xiaodong_tech),作者:小东啊

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Docker 入门到实战教程(三)镜像和容器

    Docker完美融合Linux,所以Docker命令行的风格和Linux还是比较接近的,相对来说比较容易上手,首先,我们先说镜像相关的命令:

    小东啊
  • Docker 入门到实战教程(一)介绍Docker

    在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打...

    小东啊
  • Docker 入门到实战教程(二)安装Docker

    较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。

    小东啊
  • Docker的镜像

    镜像是容器的运行基础,容器是镜像运行后台的形态 镜像的概念 镜像是一个包含程序运行必要依赖环境和代码的只读文件,它采用分层的文件系统,将每一次改变以读写层的形式...

    coders
  • Docker镜像详谈(2): 深入理解镜像大小

    是否还记得第一个接触 Docker 的时候,你从 Docker Hub 下拉的那个镜像呢?在那个处女镜像的基础上,你运行了容器生涯的处女容器。镜像的基石作用已经...

    Henry Zhang
  • docker相关概念

    镜像是什么呢?通俗地讲,它是一个只读的文件和文件夹组合。它包含了容器运行时所需要的所有基础文件和配置信息,是容器启动的基础。所以你想启动一个容器,那首先必须要有...

    宇宙之一粟
  • 跟我一起学docker(三)--镜像的常用操作

    IT故事会
  • Docker 学习笔记--通过父镜像生成镜像

    一般情况下我们会通过已有镜像(父镜像)生成新的镜像,这个时候我们就需要使用到 FROM 命令。父镜像直接影响了生成新景象的大小和功能。我们可以把基础镜像或者普通...

    喵叔
  • Docker学习笔记--镜像

    镜像是Docker三大核心概念中最重要的一个,Dokcer运行容器钱需要本地存在对应的镜像,如果不存在对应的镜像,Doker 会先从默认的镜像仓库下载(如果用户...

    喵叔
  • Docker 入门(一)

    程序明明在我本地跑得好好的,怎么部署上去就出问题了?如果要在同一台物理机上同时部署多个 node 版本并独立运行互不影响,这又该怎么做?如何更快速的将服务部署到...

    凌虚

扫码关注云+社区

领取腾讯云代金券