前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker 入门到实战教程(五)构建Docker镜像

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

作者头像
小东啊
发布2020-07-23 17:25:41
2.3K0
发布2020-07-23 17:25:41
举报
文章被收录于专栏:李浩东的博客李浩东的博客

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:

代码语言:javascript
复制
docker login

file

登录成功后,会收到Login Succeeded提示。登录后们就可以从 docker hub 上拉取自己账号下的全部镜像。认证信息上会被保存(保存于$HOME/.docker/config.json文件),以便之后使用。退出登录可以使用docker logout命令。

代码语言:javascript
复制
docker logout

file

docker commit可以通过修改容器创建新的镜像。这点类似于git commit的提交代码更新,我们可以首先创建一个容器,然后对容器进行修改,修改完成后像提交代码一样将修改提交为一个新镜像。

docker commit命令格式如下:

代码语言:javascript
复制
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镜像:

代码语言:javascript
复制
docker run -it --name centos_test my_centos:1.0 /bin/bash

file

2.1.1 安装软件

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

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

代码语言:javascript
复制
yum update
yum install nginx

file

file

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

代码语言:javascript
复制
exit
2.2 提交更改

提交时要通过容器名或容器ID指定所要提交的容器,并要指定一个目标仓库和镜像名。docker commit提交时比较轻量,只会提交创建容器的镜像与容器当前状态之间有差异的部分。

如,提要刚才配置的容器centos_test,并指定目标仓库和镜像名为centos/nginx:

代码语言:javascript
复制
docker commit centos_test centos/nginx

file

提交后,就可以通过docker images命令看到新创建的容器:

代码语言:javascript
复制
docker images centos/nginx

file

提交镜像时,还可以指定一些提交参数和标签等。如:

代码语言:javascript
复制
docker commit -m "一个自定义centos容器" -a "小东啊" centos_test centos/nginx:webserver

file

在这条命令中,我们通过-m参数添加了一些提交备注,通过-a参数添加了镜像作者,并为新镜像添加了webserver标签。

2.2.1 查看镜像:
代码语言:javascript
复制
docker images centos/nginx

file

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

代码语言:javascript
复制
 docker inspect centos/nginx:webserver

file

2.3 使用新镜像

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

代码语言:javascript
复制
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下载指定镜像。格式:

代码语言:javascript
复制
  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>

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

3.1.2 MAINTAINER

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

代码语言:javascript
复制
  MAINTAINER <name>

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

3.1.3 RUN

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

代码语言:javascript
复制
  RUN <command>
  RUN ["executable","param1","param2"]

(RUN ["可执行文本","参数1","参数2"]) 指令会被解析为Json数组,因此必须用双引号。实例:

代码语言:javascript
复制
  RUN echo hello
  RUN ["/bin/bash","-c","echo hello"]

RUN默认会在shell终端中运行命令,即/bin/sh -c RUN ["","",""] 使用exec执行,不会启动shell环境 每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。 当命令较长时,可以使用\来换行。

3.1.4 CMD

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

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

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

3.1.5 LABEL

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

代码语言:javascript
复制
  LABEL <key>=<value> <key>=<value> <key>=<value>...

实例:

代码语言:javascript
复制
  LABEL version="1.0"
  LABEL description="This is test_label"
3.1.6 EXPOSE

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

代码语言:javascript
复制
  EXPOSE <port> [<port> <port> ...]

实例:

代码语言:javascript
复制
  EXPORT 22 80 443

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

3.1.7 ENV

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

代码语言:javascript
复制
  ENV <key> <value>
  ENV <key>=<value>

实例:

代码语言:javascript
复制
  ENV PG_MAJOR 9.8.3

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

3.1.8 ADD

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

代码语言:javascript
复制
  ADD <src> <dest>

实例:

代码语言:javascript
复制
  ADD *.c /code/

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

3.1.9 COPY

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

代码语言:javascript
复制
  COPY <src> <dest>

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

3.1.10 ENTRYPOINT

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

代码语言:javascript
复制
  ENTRYPOINT ["executable","param1","param2"] exec调用执行
  ENTRYPOINT command param1 param2 shell中执行

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

3.1.11 VOLUME

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

代码语言:javascript
复制
VOLUME ["/data"]

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

3.1.12 USER

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

代码语言:javascript
复制
  USER daemon

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

3.1.13 WORKDIR

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

代码语言:javascript
复制
  WORKDIR /path/to/workdir

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

代码语言:javascript
复制
  WORKDIR /a
  WORKDIR b
  WORKDIR c

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

3.1.14 ARG

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

代码语言:javascript
复制
  ARG <name> [=<default value>]
3.1.15 ONBUILD

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

代码语言:javascript
复制
  ONBUILD [INSTRUCTION]

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

代码语言:javascript
复制
    [...]    
ONBUILD ADD . /app/src
    [...]

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

3.1.16 STOPSIGNAL

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

代码语言:javascript
复制
  STOPSIGNAL signal
3.1.17 HEALTHCHECK

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

代码语言:javascript
复制
  HEALTHCHECK [OPTIONS] CMD command

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

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

3.1.18 SHELL

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

代码语言:javascript
复制
  SHELL ["executable","parameters"]

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

3.1 创建Dockerfile文件

首先创建一个目录用于初始化Dockerfile文件

代码语言:javascript
复制
mkdir test_web_server
cd test_web_server
touch Dockerfile

file

如上所示,我们使用命令创建test_web_server目录,并在其中创见了Dockerfile文件。这个目录就是我们的构建环境,在Docker中,将这个环境称为上下文(content)或者构建上下文(build content)。构建镜像时,Docker会将构建环境中的文件和目录传递给守护进程,这样守护进程就访问到用户想在镜像中存储的任何代码、文件或其它数据。

接下来,编辑刚创建Dockerfile文件,比如编写Web服务器的构建代码:

代码语言:javascript
复制
# 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命令,这时需要使用数组来传递指令和参数。如:

代码语言:javascript
复制
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中的命令都会被执行和提交,且每次提交都会创建一个新镜像。

开始构建上面的例子,构建过程如下

代码语言:javascript
复制
[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做为镜像名

构建镜像时,还可以为镜像设置标签,设置格式为镜像名:标签。如:

代码语言:javascript
复制
docker build -t web_test:v1.0 .

还可以为镜像设置仓库,设置格式为仓库名/镜像名

代码语言:javascript
复制
docker build -t web/web_test:v1.0 .

在构建时我们可以看到,构建上下文被传给了Docker的守护进程。在构建过程中,每执行一条命令都会有一次镜像创建提交,和使用上一步生成的镜像运行新容器的过程。如:

代码语言:javascript
复制
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参数。如:

代码语言:javascript
复制
docker build --no-cache -t web_test :v1.0 .
3.4 使用新镜像

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

代码语言:javascript
复制
docker images web_test

file

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

代码语言:javascript
复制
docker history web_test

file

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

3.4.1 使用
代码语言:javascript
复制
docker run -d -P --name web_test web_test

file

四. 新镜像推送到Docker Hub

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

4.1 登录
代码语言:javascript
复制
docker login

然后输入账号密码

file

4.2 推送镜像

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

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

代码语言:javascript
复制
 docker push web_test

file

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

4.3 denied解决办法:

1.先列出所有镜像

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

file

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

  1. 再次发布镜像
代码语言:javascript
复制
docker push xiaodonga/web

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

file

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小东IT技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 构建准备
    • 1.1 注册账号
      • 2.1 创建容器
        • 2.1.1 安装软件
      • 2.2 提交更改
        • 2.2.1 查看镜像:
          • 2.3 使用新镜像
          • 三. 使用Dockerfile构建镜像
            • 3.1 Dockerfile指令说明:
              • 3.1.1 FROM
              • 3.1.2 MAINTAINER
              • 3.1.3 RUN
              • 3.1.4 CMD
              • 3.1.5 LABEL
              • 3.1.6 EXPOSE
              • 3.1.7 ENV
              • 3.1.8 ADD
              • 3.1.9 COPY
              • 3.1.10 ENTRYPOINT
              • 3.1.11 VOLUME
              • 3.1.12 USER
              • 3.1.13 WORKDIR
              • 3.1.14 ARG
              • 3.1.15 ONBUILD
              • 3.1.16 STOPSIGNAL
              • 3.1.17 HEALTHCHECK
              • 3.1.18 SHELL
            • 3.1 创建Dockerfile文件
              • 3.2 关于Dockerfile文件
                • 3.3 docker build构建新镜像
                  • 3.3.1 构建缓存
                • 3.4 使用新镜像
                  • 3.4.1 使用
              • 四. 新镜像推送到Docker Hub
                • 4.1 登录
                  • 4.2 推送镜像
                    • 4.3 denied解决办法:
                    相关产品与服务
                    容器镜像服务
                    容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档