前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >004.Docker镜像管理

004.Docker镜像管理

作者头像
木二
发布2019-07-26 10:08:10
1.2K0
发布2019-07-26 10:08:10
举报
文章被收录于专栏:木二天空木二天空

一 镜像基本操作

镜像是一个包含程序运行必要依赖环境和代码的只读文件,其本质是磁盘上一系列文件的集合。它采用分层的文件系统,将每一次改变以读写层的形式增加到原来的只读文件上。镜像是容器运行的基石。

1.1 搜索镜像

代码语言:javascript
复制
  1 root@docker:~# docker search centos				#查询centos共享镜像
01
01

docker命令必须具备root权限,普通用户可是用那个sudo。

提示:docker默认的Docker Hub 网址为: https://hub.docker.com/,速度很慢,建议添加国内的阿里云加速器,参考004-4.1。

选项说明:

NAME:镜像仓库源的名称

DESCRIPTION:镜像的描述

OFFICIAL:是否docker官方发布

AUTOMATED:是否使用了自动构建

1.2 下载(拉取)镜像

代码语言:javascript
复制
  1 root@docker:~# docker pull centos:7				#使用pull下载镜像
02
02

提示:

Registry:仓库,Registry包含一个或多个Repository

Repository:系列,Repository包含一个或多个Image

Tag and Image:Image用GUID表示,有一个或多个Tag与之关联,版本号。

1.3 列出(查看)本地镜像

代码语言:javascript
复制
  1 root@docker:~# docker images 	<特定标签>			#查看本地下载的镜像
03
03

选项说明:

  • REPOSTITORY:表示镜像的仓库源,有以下类型:
    • [namespace/centos]:由命名空间和实际的仓库名称组成。
    • [centos]:只有仓库名。属于顶级命名空间,只用于官方镜像。
    • [dl.dockerpool.com:5000\centos:7]:指定URL路径的方式。
  • TAG:镜像的标签
    • 未指定镜像tag时,默认为latest,但latest没有任何特殊含义,人为的将latest作为最新稳定版本的别名;
    • 一个repository可以有多个tag,而多个tag也可能对应同一个镜像。
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

1.4 推送镜像

代码语言:javascript
复制
  1 root@docker:~# docker push registry.cn-hangzhou.aliyuncs.com/xhy-study-01/xhy-images-01:centos-7-xhy
04
04

提示:推送镜像之前必须配置好仓库信息。建议推送至个人私有仓库,同时采用国内阿里云私有仓库,配置方法见《附001-docker阿里云Registry配置》。

1.5 导出镜像

代码语言:javascript
复制
  1 root@docker:~# docker save -o centos-7.tar centos:7

1.6 导入镜像

代码语言:javascript
复制
  1 root@docker:~# docker load -i centos-7.tar

1.7 删除镜像

代码语言:javascript
复制
  1 root@docker:/study# docker rmi httpd

1.8 设置镜像标签

代码语言:javascript
复制
  1 root@docker:~# docker tag 6de222aa7640 xhy/centos7:v3
  2 root@docker:~# docker images
05
05

二 docker文件系统

2.1 Linux文件系统简介

linux文件系统由bootfs和rootfs组成,bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,当kernel被加载到内存之后bootfs就被卸载掉了。rootfs包含的就是典型linux系统中/dev,/proc,/bin,/etc等标准目录。

2.2 docker文件系统

Docker容器是建立在Aufs基础上的,Aufs支持将不同的目录挂载到同一个虚拟文件系统下,并实现一种layer的概念。Aufs将挂载到同一虚拟文件系统下的多个目录分别设置成read-only,read-write以及whiteout-able权限。

read-only目录只能读,而写操作只能在read-write目录中实现。

写操作是在read-only之上的一种增量操作,不影响read-only目录。

docker 镜像中每一层文件系统都是read-only。

提示:当挂载目录的时候要严格按照各目录之间的这种增量关系,将被增量操作的目录优先于在它基础上增量操作的目录挂载,待所有目录挂载结束了,继续挂载一个read-write目录,如此便形成了一种层次结构。

2.3 docker镜像原理

在构建镜像时,从一个最基本的操作系统开始,每个构建的操作都相当于做一层修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性。当使用时,只会看到一个完全的整体,总共有多少层以及每层所做的修改都是透明的。

06
06

docker image 中最基础的两层结构:

07
07

不同的 linux 发行版(如 ubuntu 和 CentOS ) 在 rootfs 这一层会有所区别,体现发行版本的差异性:

08
08

传统的 Linux 加载 bootfs 时会将 rootfs 设为 read-only,然后在系统自检后将 rootfs 从 read-only改为 read-write,然后可在 rootfs 上进行读写操作。

Docker相比在 bootfs 自检完毕之后不会将 rootfs 的 read-only 改为 read-write,而是利用 union mount(UnionFS 的一种挂载机制)将 image 中其他的 layer 加载到之前的 read-only 的 rootfs 层之上,每一层 layer 都是 rootfs 的结构,并且是read-only 的。因此,无法修改一个已有镜像里面的 layer层数据,只有当创建一个容器,即将 Docker 镜像进行实例化后,系统会分配一层空的 read-write 的 rootfs ,用于提供数据修改。

三 镜像结构

3.1 image结构

09
09

docker image的layer组织方式通常由 json、layer.tar、VERSION组成。

代码语言:javascript
复制
  1 root@docker:/study# tar -xf centos-7.tar
10
10
代码语言:javascript
复制
  1 root@docker:/study# tree
11
11
代码语言:javascript
复制
  1 root@docker:/study# cat repositories
  2 {"centos":{"7":"d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064"}}

解释:repositories 文件,里面是一个 JSON 定义,保存了三个信息:镜像名字、tag、tag 对应的 layer。

代码语言:javascript
复制
  1 root@docker:/study# cat d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064/json | jq .
12
12

解释:主要关于镜像的配置信息,简要部分信息如上。

代码语言:javascript
复制
  1 root@docker:/study# tar -tf d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064/layer.tar
13
13

解释:包括一个类 Linux 文件目录的结构,保存着这个 layer 所做的修改。

四 Dockerfile、Docker镜像和Docker容器

4.1 关系

Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维。

14
14

Dockerfile构建出Docker镜像,通过Docker镜像运行Docker容器。

15
15

参考链接:http://dockone.io/article/783

https://blog.csdn.net/xuguokun1986/article/details/79295947

五 docker存储驱动

Docker最开始采用AUFS作为文件系统,也得益于AUFS分层的概念,实现了多个Container可以共享同一个image。但由于AUFS未并入Linux内核,且只支持Ubuntu,考虑到兼容性问题,在Docker 0.7版本中引入了存储驱动, 目前,Docker支持AUFS、Btrfs、Device mapper、OverlayFS、ZFS五种存储驱动。

5.1 底层技术

  • 写时复制(CoW)

所有驱动都需要用到写时复制(CoW),CoW就是copy-on-write,表示只在需要写时才去复制,这个是针对已有文件的修改场景。比如基于一个image启动多个Container,如果为每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。

所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。

  • 用时分配(allocate-on-demand)

用时分配是用在原本没有这个文件的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会为这个容器预分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。

5.2 AUFS

AUFS(AnotherUnionFS)是一种Union FS,是文件级的存储驱动。AUFS能透明覆盖一个或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示。即支持将不同目录挂载到同一个虚拟文件系统下的文件系统。

这种文件系统可以一层一层地叠加修改文件。无论底下有多少层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS创建该文件的一个副本,使用CoW将文件从只读层复制到可写层进行修改,结果也保存在可写层。

在Docker中,底下的只读层就是image,可写层就是Container。结构如下图所示:

16
16

5.3 OverlayFS

Overlay是Linux内核3.18后支持的,也是一种Union FS,和AUFS的多层不同的是Overlay只有两层:一个upper文件系统和一个lower文件系统,分别代表Docker的镜像层和容器层。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在Docker中,底下的只读层就是image,可写层就是Container。

17
17

5.4 Device mapper

Device mapper是Linux内核2.6.9后支持的,提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可根据需要制定实现存储资源的管理策略。

不同于AUFS和OverlayFS的文件级存储,Device mapper是块级存储,所有的操作都是直接对块进行操作,而不是文件。

Device mapper驱动会先在块设备上创建一个资源池,然后在资源池上创建一个带有文件系统的基本设备,所有镜像都是这个基本设备的快照,而容器则是镜像的快照。

所以在容器里看到文件系统是资源池上基本设备的文件系统的快照,并不有为容器分配空间。当要写入一个新文件时,在容器的镜像内为其分配新的块并写入数据,即用时分配。当要修改已有文件时,再使用CoW为容器快照分配块空间,将要修改的数据复制到在容器快照中新的块里再进行修改。

Device mapper 驱动默认会创建一个100G的文件包含镜像和容器。每一个容器被限制在10G大小的卷内,大小可配置调整。

18
18

5.5 Btrfs

Btrfs被称为下一代写时复制文件系统,并入Linux内核,也是文件级级存储,但可以像Device mapper直接操作底层设备。

Btrfs把文件系统的一部分配置为一个完整的子文件系统,称之为subvolume 。那么采用 subvolume,一个大的文件系统可以被划分为多个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中分配。

为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个chunk 。每个chunk可以使用不同的磁盘空间分配策略。比如某些chunk只存放metadata,某些chunk只存放数据。这种模型有很多优点,比如Btrfs支持动态添加设备。

用户在系统中增加新的磁盘之后,可以使用Btrfs的命令将该设备添加到文件系统中。

Btrfs把一个大的文件系统当成一个资源池,配置成多个完整的子文件系统,还可以往资源池里加新的子文件系统,而基础镜像则是子文件系统的快照,每个子镜像和容器都有自己的快照,这些快照则都是subvolume的快照。

当写入一个新文件时,为在容器的快照里为其分配一个新的数据块,文件写在这个空间里,这个叫用时分配。而当要修改已有文件时,使用CoW复制分配一个新的原始数据和快照,在这个新分配的空间变更数据,变结束再更新相关的数据结构指向新子文件系统和快照,原来的原始数据和快照没有指针指向,被覆盖。

19
19

5.6 ZFS

ZFS 文件系统是一个革命性的全新的文件系统,它从根本上改变了文件系统的管理方式,ZFS 完全抛弃了“卷管理”,不再创建虚拟的卷,而是把所有设备集中到一个存储池中来进行管理,用“存储池”的概念来管理物理存储空间。过去,文件系统都是构建在物理设备之上的。为了管理这些物理设备,并为数据提供冗余,“卷管理”的概念提供了一个单设备的映像。而ZFS创建在虚拟的,被称为“zpools”的存储池之上。每个存储池由若干虚拟设备(virtual devices,vdevs)组成。这些虚拟设备可以是原始磁盘,也可能是一个RAID1镜像设备,或是非标准RAID等级的多磁盘组。于是zpool上的文件系统可以使用这些虚拟设备的总存储容量。

20
20

Docker里ZFS的使用。首先从zpool里分配一个ZFS文件系统给镜像的基础层,而其他镜像层则是这个ZFS文件系统快照的克隆,快照是只读的,而克隆是可写的,当容器启动时则在镜像的最顶层生成一个可写层。如下图所示:

21
21

当要写一个新文件时,使用按需分配,一个新的数据快从zpool里生成,新的数据写入这个块,而这个新空间存于容器(ZFS的克隆)里。

当要修改一个已存在的文件时,使用写时复制,分配一个新空间并把原始数据复制到新空间完成修改。

5.7 存储驱动的对比及适应场景

特点

优点

缺点

使用场景

AUFS

联合文件系统 未并入内核主线 文件级存储

作为docker的第一个存储驱动,相对稳定,且在大量的生产中实践,有较强的社区支持。

有多层,在做写时复制操作时,如果文件较大且存在比较低的层,可能会慢一些。

大并发但少IO的场景。

OverlayFS

联合文件系统 并入内核主线 文件级存储

只有两层

不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件消耗更多的时间。

大并发但少IO的场景。

Device mapper

并入内核主线 块级存储

块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件。

不支持共享存储,即有多个容器读同一个文件时,需要生产多个副本,在多容器启停的情况下可能会导致磁盘溢出。

适合IO密集的场景。

Btrfs

并入内核主线 文件级存储

可如Device mapper直接操作底层设备,支持动态添加设备。

不支持共享存储,即有多个容器读同一个文件时,需要生产多个副本,在多容器启停的情况下可能会导致磁盘溢出。

不适合在高密度容器的PaaS平台上使用。

ZFS

把所有设备密集到一个存储池进行管理。

支持多个容器共享一个缓存块,适合内存大的环境。

COW使碎片化问题更加严重,文件在硬盘上的物理地址会变得不再连续,顺序读会变得性能比较差。

适合PaaS和高密度的场景。

参考链接:http://dockone.io/article/1513

5.8 修改docker存储驱动类型

代码语言:javascript
复制
  1 root@docker:~# vi /etc/docker/daemon.json
  2 {
  3 "storage-driver": "overlay2"
  4 }

六 创建镜像

从镜像仓库中下载的镜像若不能满足需求,可通过以下两种方式对镜像进行更改。

  • 从已经创建的容器中更新镜像,并且提交这个镜像
  • 使用 Dockerfile 指令来创建一个新的镜像

6.1 更新镜像并提交

  1. 运行容器
  2. 修改容器
  3. 将容器保存为新的镜像
代码语言:javascript
复制
  1 root@docker:~# docker run --name centos-7-01 -it centos:7 /bin/bash	#创建容器
  2 [root@01b2b251e216 /]# yum -y install net-tools vim openssh-clients wget ntp bash-completion    #安装软件
  3 [root@01b2b251e216 /]# exit
  4 root@docker:~# docker commit -m="has modify" -a="xhy" 01b2b251e216 centos-7-01
  5 root@docker:~# docker images
22
22

参数说明:

  • -m:提交的描述信息
  • -a:指定镜像作者
  • 01b2b251e216 :容器ID
  • centos-7-01:指定要创建的目标镜像名
代码语言:javascript
复制
  1 root@docker:~# docker images						#查看镜像

更新现有镜像缺陷

  • 手动创建,容易出错,效率低及可重复性弱
  • 使用者并不知道镜像是如何创建出来的,里面是否有恶意程序,可能存在案例隐患

6.2 Dockerfile构建镜像举例

代码语言:javascript
复制
  1 root@docker:~# mkdir /dockerfiles
  2 root@docker:~# cd /dockerfiles/
  3 root@docker:/dockerfiles# vi Dockerfile
  4 FROM            centos:7
  5 MAINTAINER  Fisher "xhy@imxhy.cn"
  6 
  7 RUN         /bin/echo 'root:x123456' |chpasswd
  8 RUN         useradd xhy
  9 RUN         /bin/echo 'xhy:x123456' |chpasswd
 10 RUN         /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
 11 EXPOSE      22
 12 EXPOSE      80
 13 CMD         /usr/sbin/sshd -D

语句说明:

第一条FROM,指定所采用的镜像源,每一个指令的前缀都必须是大写的;

RUN 指令表示docker在镜像内执行的命令,更多详见七Dockerfile详解。

代码语言:javascript
复制
  1 root@docker:/dockerfiles# docker build -t xhy/centos7 /dockerfiles/

参数说明:

  • -t :指定要创建的目标镜像名
  • /dockerfiles/:Dockerfile 文件所在目录
代码语言:javascript
复制
  1 root@docker:~# docker images						#查看镜像
23
23
代码语言:javascript
复制
  1 root@docker:/dockerfiles# docker run -t -i xhy/centos7  /bin/bash	#创建容器
24
24

七 Dockerfile详解

7.1 Dockerfile典型结构

代码语言:javascript
复制
  1 From ubutu						#第一行必须指令基于的基础镜像
  2 MAINTAINER docker_user  docker_user@mail.com        #维护者信息
  3 apt/sourcelist.list					#镜像的操作指令
  4 RUN apt-get update && apt-get install -y ngnix 	#镜像的操作指令
  5 RUN echo "\ndaemon off;">>/etc/ngnix/nignix.conf	#镜像的操作指令
  6 CMD /usr/sbin/ngnix					#容器启动时执行指令

7.2 Dockerfile相关指令

  • 指令:From

语法:

代码语言:javascript
复制
  1 FROM <image>
  2 FROM <image>:<tag>
  3 FROM <image>:<digest>

含义:FROM命令定义构建镜像的基础镜像,该条必须是dockerfile的首个命令。若同一个DockerFile创建多个镜像时,可使用多个From指令(每个镜像一次),FROM 是必备且必须是第一条指令。在FROM指定构建镜像的基础源镜像时,若本地没有指定的该镜像,则会自动从 Docker 的公共库 pull 镜像下来。

提示:

  • FROM必须是 Dockerfile 中非注释行的第一个指令,即一个 Dockerfile 从FROM语句开始。
  • 如果有需求在一个 Dockerfile 中创建多个镜像,则FROM可以在一个 Dockerfile 中出现多次。
  • 如果FROM语句没有指定镜像标签,则默认使用latest标签。

举例:FROM ubuntu

  • 指令:MAINTAINER

语法:

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

含义:声明作者信息,可以放在文件任何位置,建议放在FROM后面。

举例:

代码语言:javascript
复制
  1 MAINTAINER  xhy
  • 指令:RUN

语法:

代码语言:javascript
复制
  1 RUN <commands>
  2 RUN "executable", "param1", "param2"

含义:RUN 指令是用来执行命令行命令的,每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,后续RUN都在之前RUN提交后的镜像为基础.

exec 方式会被解析为一个 JSON 数组,所以必须使用双引号而不是单引号。exec 方式不会调用一个命令 shell,所以也就不会继承相应的变量,RUN产生的缓存在下一次构建的时依旧有效,且会被重用,可以使用--no-cache选项,即docker build --no-cache,如此便不会缓存。

举例:

代码语言:javascript
复制
  1 RUN echo 'Hello, Docker!'
  2 RUN ["/bin/bash", "-c","echo hello"]

提示:对于处理同一事件的多个命令,建议采用&&连接为一个命令,即构建一层即可。命令过长可使用\的换行方式。

  • 指令:CMD

语法:

代码语言:javascript
复制
  1 CMD "executable","param1","param2"
  2 CMD "param1","param2"
  3 CMD command param1 param2 (shell form)

含义:CMD配置在启动容器时提供一个默认的命令执行选项,如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

举例:

提示:在容器运行时可指定新的命令来替代镜像设置的默认命令,如ubuntu镜像默认的CMD是/bin/bash,直接docker run -it ubuntu则会进入bash。若在运行时指定其他的命令,如docker run -it ubuntu cat /etc/os-release 。则使用cat /etc/os-release命令替换默认/bin/bash命令。

注意:CMD会在启动容器的时候执行,build 时不执行,而RUN只是在构建镜像的时候执行。

  • 指令:ENTRYPOINT

语法:

代码语言:javascript
复制
  1 ENTRYPOINT "executable", "param1", "param2"
  2 ENTRYPOINT command param1 param2 (shell form)

含义:ENTRYPOINT配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,区别于CMD是可以被覆盖的。若需要ENTRYPOINT被覆盖,则可以使用docker run --entrypoint选项。

举例:

代码语言:javascript
复制
  1 ENTRYPOINT ["nginx"]
  2 CMD ["-g","daemon off;"]

注意:每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效;

当指定了 ENTRYPOINT 后, CMD 不再是直接的运行其命令,而是将CMD 的内容作为参数传给 ENTRYPOINT 指令,即:<ENTRYPOINT> "<CMD>"

  • 指令:ADD

语法:

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

含义:复制本地主机、url或启动配置上下文中的文件到容器指定路径中 。

举例:

代码语言:javascript
复制
  1 ADD http://mirrors.163.com/.help/CentOS7-Base-163.repo /etc/yum.repos.d/CentOS-Base.repo

提示:若 <src> 是一个 URL ,构建镜像时会下载这个链接的文件放至 <dest> ,下载后权限为 600;

若传入dest的是个tar压缩包,压缩格式为 gzip、bzip2 以及 xz 的情况下, ADD 指令将会自动解压缩这个压缩文件至 <dest> 。因此若只是复制个压缩文件进去,而不解压缩,建议使用copy;

ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

  • 指令:COPY

语法:

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

含义:复制新文件或者目录从 并且添加到容器指定路径中 ,用法参考ADD,但COPY不能指定远程文件 URLS。

举例:

代码语言:javascript
复制
  1 COPY package.json /usr/src/app/

建议:在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD 。

  • 指令:EXPOSE

语法:

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

含义:声明Docker服务端容器对外监听的端口,需要同时在docker run 的时候使用-p或者-P选项生效,默认为TCP。

举例:

代码语言:javascript
复制
  1 EXPOSE 22 80 8443
  • 指令:ENV

语法:

代码语言:javascript
复制
  1 ENV <key> <value>       # 只能设置一个变量
  2 ENV <key>=<value> ...   # 允许一次设置多个变量

含义:指定一个环节变量,会被后续RUN指令使用,并在容器运行时保留。

举例:

代码语言:javascript
复制
  1 ENV myName="John Doe" myDog=Rex myCat=fluffy
  2 ENV PG_MAJOR 9.3
  3 ENV PG_VERSION 9.3.4
  • 指令:VOLUME

语法:

代码语言:javascript
复制
  1 VOLUME ["<路径1>", "<路径2>"...]
  2 VOLUME <路径>

含义:卷分为宿主目录、数据卷、容器卷。VOLUME命令会设置挂载点,在启动容器的时候Docker会在/var/lib/docker/的下一级目录下创建一个卷,一般用来存放动态数据和需要保持的数据等。

举例:

代码语言:javascript
复制
  1 VOLUME ["/data","/opt"]
  • 指令:WORKDIR

语法:

代码语言:javascript
复制
  1 WORKDIR <path>

含义:使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),之后各层的当前目录就被改为指定的目录,如该目录不存在, WORKDIR 会帮你建立目录,在使用 docker run 命令启动容器时,默认会进入的目录是 WORKDIR 指定的目录。

举例:

代码语言:javascript
复制
  1 WORKDIR /app
  • 指令:USER

语法:

代码语言:javascript
复制
  1 USER <user>[:<group>]
  2 USER <UID>[:<GID>]

含义:指定运行容器时的用户名或UID,后续的 RUN 也会使用指定用户。当服务不需要管理员权限时,可以通过该命令指定运行用户。

举例:

代码语言:javascript
复制
  1 RUN groupadd -r redis && useradd -r -g redis redis
  2 USER redis
  3 RUN [ "redis-server" ]

提示:WORKDIR 是改变工作目录, USER 则是改变之后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。

  • 指令:ONBUILD

语法:

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

含义:ONBUILD 是一个特殊的指令,ONBUILD 后是其它指令,比如 RUN , COPY 等,而此类指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一个镜像的时候才会被执行。即配置当该镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。

举例:Dockerfile-01使用如下的内容创建了镜像image-A:

代码语言:javascript
复制
  1 [...]
  2 ONBUILD ADD . /app/src
  3 ONBUILD RUN /usr/local/bin/python-build --dir /app/src
  4 [...]

Dockerfile-02使用基于image-A的基础镜像创建image-B:

代码语言:javascript
复制
  1 FROM image-A

Dockerfile-02的内容等同于:

代码语言:javascript
复制
  1 ADD . /app/src
  2 RUN /usr/local/bin/python-build --dir /app/src
  • 指令:HEALTHCHECK

语法:

代码语言:javascript
复制
  1 HEALTHCHECK [选项] CMD <命令> :设置检查容器健康状况的命令
  2 HEALTHCHECK NONE :如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

含义:HEALTHCHECK 指令用于判断Docker容器的状态是否正常。

选项:

HEALTHCHECK 支持下列选项:

  • interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
  • timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
  • retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3 次。

举例:

代码语言:javascript
复制
  1 FROM nginx
  2 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
  3 HEALTHCHECK --interval=5s --timeout=3s \
  4 CMD curl -fs http://localhost/ || exit 1

设置了每 5 秒检查一次,如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。

提示:类似CMD , ENTRYPOINT 一样, HEALTHCHECK 也只可以出现一次,若存在多个HEALTHCHECK,只有最后一个生效。

参考链接:https://blog.csdn.net/wo18237095579/article/details/80540571

7.3 dockerfile最佳实践

  • 使用.dockerignore文件

为在docker build过程中更快上传和更加高效,可使用一个.dockerignore文件用来排除构建镜像时不需要的文件或目录。

  • 避免安装不必要的软件包

为了降低复杂性、依赖性、文件大小以及构建时间,应该避免安装额外的或不必要的包。

  • 每个容器都跑一个进程

在大多数情况下,一个容器应该只单独跑一个程序。解耦应用到多个容器使其更容易横向扩展和重用。

  • 最小化层

每执行一个指令,都会有一次镜像的提交,镜像是分层的结构,对于Dockerfile,应该找到可读性和最小化层之间的平衡。

  • 多行参数排序

如果可能,通过字母顺序来排序,这样可以避免安装包的重复并且更容易更新列表,另外可读性也会更强,添加一个空行使用\换行:

代码语言:javascript
复制
  1 RUN apt-get update && apt-get install -y \
  2   bzr \
  3   cvs \
  4   git \
  5   mercurial \
  6   subversion
  • 尽可能清理不必要的文件

使构建后的镜像尽可能的小。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-12-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 镜像基本操作
    • 1.1 搜索镜像
      • 1.2 下载(拉取)镜像
        • 1.3 列出(查看)本地镜像
          • 1.4 推送镜像
            • 1.5 导出镜像
              • 1.6 导入镜像
                • 1.7 删除镜像
                  • 1.8 设置镜像标签
                  • 二 docker文件系统
                    • 2.1 Linux文件系统简介
                      • 2.2 docker文件系统
                        • 2.3 docker镜像原理
                        • 三 镜像结构
                          • 3.1 image结构
                          • 四 Dockerfile、Docker镜像和Docker容器
                            • 4.1 关系
                            • 五 docker存储驱动
                              • 5.1 底层技术
                                • 5.2 AUFS
                                  • 5.3 OverlayFS
                                    • 5.4 Device mapper
                                      • 5.5 Btrfs
                                        • 5.6 ZFS
                                          • 5.7 存储驱动的对比及适应场景
                                            • 5.8 修改docker存储驱动类型
                                            • 六 创建镜像
                                              • 6.1 更新镜像并提交
                                                • 6.2 Dockerfile构建镜像举例
                                                • 七 Dockerfile详解
                                                  • 7.1 Dockerfile典型结构
                                                    • 7.2 Dockerfile相关指令
                                                      • 7.3 dockerfile最佳实践
                                                      相关产品与服务
                                                      容器服务
                                                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                      领券
                                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档