Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker 学习笔记 #48

Open
zhongdeming428 opened this issue Feb 6, 2020 · 0 comments
Open

Docker 学习笔记 #48

zhongdeming428 opened this issue Feb 6, 2020 · 0 comments

Comments

@zhongdeming428
Copy link
Owner

太久没更新博客了,之前一直非常忙碌,也没有心情更新博客。现在终于稳定了,也开始有心情学习了。

很久之前就已经学习了如何使用 Docker,但是一直没有输出一个自己的学习笔记,过了一段时间之后好像又会丢掉一些东西。现在复习了一波之后赶紧记录一下,让自己有一个系统的知识体系。整篇文章由浅入深,适合有一点 Docker 基础但是还没有形成知识体系的童鞋阅读。

本文不涉及如何安装 Docker,如有需要请自己查找。

一、Docker 简介

Docker 是 2013 年 dotCloud 公司基于 Golang 实现的开源软件,后来 dotCloud 公司改名为 Docker Inc。现在 Docker 已经在 GitHub 上开源,由全世界开发者共同维护。目前主流操作系统基本都已支持 Docker。

Docker 基于 Linux 的多种技术提供了高效、快捷、轻量的容器方案,大大提升了工作人员及机器的工作效率,降低了各种环境兼容问题的发生几率,将传统的 SSH 部署方式转变为 DevOps 自动部署。可以说是引起了行业革命,大大地解放了生产力,所以 Docker 从开源起就广受开发及运维人员的青睐,开源没多久就有许多大型企业宣布将大力支持 Docker。到我写这篇文章的时候 Docker 已经是如日中天,尤其是大型公司对于 Docker 的使用已经相当的深入,几万十几万的实例正在生产环境一刻不停的运行着。不仅运维需要学习 Docker 如何使用,后端前端也需要学习。

那么 Docker 为什么这么火呢?它能带给我们什么?我们为什么要学习 Docker?

首先,Docker 带给我们最直接的好处就是轻量、快速。

传统的虚拟化方式我们都知道是虚拟机,可以在一台物理机上运行多个操作系统的虚拟环境。通过虚拟机技术我们也可以在不同的物理机上实现基本一致的环境。但是问题在于虚拟机技术太重了,安装一台虚拟机以及每次启动关闭虚拟机的时间都非常久,这对于追求高效的我们是不可接受的。

所以 Docker 最大的优势就是快、就是轻。结合 Linux 的 Union FS 技术,可以实现镜像的分层打包,这样 Docker 就变得尽可能的轻量了。基于 Linux 的 Control Group、namespace 及 Docker 共享系统内核的技术,使得 Docker 可以非常快速的实现一个虚拟的隔离环境,因为它不用像虚拟机一样构造一些虚拟的硬件然后运行一个独立且完善的操作系统,所有的 Docker 实例都是直接使用物理机的内核,容器内部没有自己的内核和虚拟硬件,所以运行速度、安装速度、启动速度都是非常快的。

也正因为如此,所以 Docker 对于物理机的资源利用率也比传统的虚拟机高很多,迁移也非常的快速。

另外,Docker 提供更加独立且一致的运行环境,让我们可以一次配置,到处运行。无需考虑环境的兼容问题,有利于实施 CI、CD。

此外,Docker 自身采用分层存储技术,维护和扩展非常容易,而且支持共有镜像库和私有镜像库的部署,镜像管理镜像非常简单,不用再担心你的”配置信息“散落在各个角落。

image

上图对比了传统了虚拟化技术和 Docker 的虚拟化技术,很容易看出来为什么 Docker 更加轻量,快速,对于物理机的压榨更加高效。

二、Docker 基本概念

Docker 的基本概念不多,也很好掌握,就只有三个。之后的命令讲解也会基于这三个维度展开,稍微会有一些扩展。

2.1 Docker 镜像

Docker 镜像(Image),可以理解为编程语言中的 Class 类,是一种用于生成容器实例的模板,是创建 Docker 容器的基础。

Docker 镜像不仅像类一样可以生成实例(容器),而且可以实现类之间的继承(镜像分层),一个镜像可以基于另一个镜像实现,而底层的基础镜像是共用的。

2.2 Docker 容器

Docker 镜像是类的话,我们的容器就可以理解为类的实例对象,它基于 Docker 镜像产生。

Docker 容器是一个轻量级的沙箱(Sandbox),能够隔离应用,使多个应用运行在同一台物理机上,但是应用内部没有感知,认为它们是运行在一个独立的机器上。

镜像自身是只读的,创建容器的时候会在镜像的最上层新建一个可写层,镜像本身不发生变化。

2.3 Docker 仓库

Docker 仓库用于集中管理 Docker 镜像,可以理解为我们的 npm 或者 GitHub。我们可以在 Docker Hub 上下载镜像,也可以上传我们自己的镜像到 GitHub 提供给别的开发者下载。

Docker Hub 也支持 npm 那样的私有仓库搭建,许多公司会在自己内部搭建一个 Docker 镜像仓库,对公司内部的镜像进行管理。

2.4 Docker Hello World

现在我们知道 Docker 的三个概念了,我们现在尝试从 Docker 仓库拉取一个镜像,然后在本地运行 Docker 容器吧。

通过 docker search 命令我们可以搜索 Docker Hub 公有库上的镜像。

我们搜索一下 hello-world 试试:

$ docker search hello-world

结果如下:

NAME                                       DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
hello-world                                Hello World! (an example of minimal Dockeriz…   1090                [OK]
kitematic/hello-world-nginx                A light-weight nginx container that demonstr…   136
tutum/hello-world                          Image to test docker deployments. Has Apache…   65                                      [OK]
dockercloud/hello-world                    Hello World!                                    17                                      [OK]
crccheck/hello-world                       Hello World web server in under 2.5 MB          11                                      [OK]
vad1mo/hello-world-rest                    A simple REST Service that echoes back all t…   3                                       [OK]
ppc64le/hello-world                        Hello World! (an example of minimal Dockeriz…   2
...

可以看到 search 命令给我们列出了搜索结果的名称、描述、star 数等信息,我们可以自行选择搜索结果,然后使用 docker pull 命令进行下载:

docker pull hello-world

拉取成功之后可以通过 docker image ls 查看下载的镜像信息。

接下来使用 docker run 命令运行我们的镜像:

$ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

当你看到上方信息的时候,说明 hello-world 镜像已经成功运行啦!

三、Dockerfile 基本语法

3.1 docker commit

通过第二节我们知道了 Docker 的三个概念,所以现在我们就慢慢开始学习如何使用 Docker。要想运行一个自己的容器,首先我们要有一个自己的镜像,那么我们如何制作一个镜像呢?

第一种方法就是使用 docker commit 命令,这个命令的简介如下:

Usage:	docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

Options:
  -a, --author string    Author (e.g., "John Hannibal Smith
                         <[email protected]>")
  -c, --change list      Apply Dockerfile instruction to the
                         created image
  -m, --message string   Commit message
  -p, --pause            Pause container during commit (default true)

它可以基于一个容器的修改创建一个新的镜像,这是什么意思呢?

比如我们现在运行一个基于 nginx 镜像创建的容器:

$ docker run -p 80:80 --name my-ng nginx

运行 docker ps 查看我们运行中的容器:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                              NAMES
bb182db11e7c        nginx               "nginx -g 'daemon of…"   58 seconds ago      Up 57 seconds       0.0.0.0:80->80/tcp                 my-ng

可以看到 my-ng 已经跑起来了,那我们访问本机的 80 端口查看页面:

image

得到如上所示的 nginx 欢迎页。

现在我们不喜欢这个页面,我们要更改一下它的内容,那我们直接进入容器修改 /usr/share/nginx/html/index.html 网页的内容即可。

首先输入 docker exec -it my-ng bash 进入容器。

然后找到我们的 /usr/share/nginx/html/index.html 文件,修改其内容:

$ echo "Hello World" > index.html

然后退出容器,重新访问 localhost 查看效果:

$ curl localhost
Hello World

说明此时容器内容已经做了更改,那我如果我们想要以后运行的 nginx 容器都使用这个基础页面,我们就应该基于当前修改创建一个新的镜像了。这时 docker commit 闪亮登场:

$ docker commit -m "modify index.html of nginx" my-ng new-ng

然后使用 docker image ls 查看我们刚刚新建的镜像:

$ docker image ls
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
new-ng                               latest              660bca868911        4 seconds ago       126MB

可以看到 new-ng 已经创建了。

那我们基于它运行一个新的容器吧。

$ docker run -p 80:80 new-ng

重新访问 80 端口:

$ curl localhost
Hello World

这就说明我们的新镜像的欢迎页都是我们修改之后的内容。我们成功地基于 my-ng 容器创建了一个符合我们需求的镜像。

通过上面的例子我们知道了 docker commit 可以基于容器制作镜像,但是这并不是推荐以及常用的做法,因为这个命令很容易造成镜像臃肿,一个简单的修改可能会引起其他多处地方的变动。另外 commit 命令制作的镜像是一个”黑箱镜像“,除了制作镜像的人以外其他人都不知道镜像修改了什么地方,所以不利于对于镜像的维护与扩展。

更多的情况下,commit 命令用于将一个容器的变动提交到另一个镜像,可以用于容器调试以及事故现场的保护。尽量不要用 commit 命令制作常用镜像。

3.2 Dockerfile

我们更加常用的,也是官方推荐的镜像制作方法是使用 Dockerfile。你应该经常在一些开源项目的根目录下见到一个 Dockerfile 文件,这就是用于制作镜像的配置文件。

Dockerfile 由一行行的命令语句组成,而且支持 # 开头的注释,其基本语法如下:

# Comment
INSTRUCTION arguments

一般而言,Dockerfile 由三部分组成,包括基础镜像指令、镜像的操作指令以及容器内进程的启动指令。

一个基本的 Dockerfile 示例如下:

FROM mhart/alpine-node

COPY ./src /data/src
WORKDIR /data/src
RUN ["npm", "install"]
EXPOSE 3000

CMD ["node", "index.js"]

可以看到其中包括了 FROM 命令指定基础镜像为 mhart/alpine-nodeCOPYWORKDIRRUNEXPOSE 等指令指定镜像的一些操作,最后的 CMD 指定容器启动进程时需要执行的命令。

接下来我们对 Dockerfile 的这些指令进行讲解。

3.2.1 FROM

FROM 的基本语法如下:

FROM <image>[:<tag>]

image 是镜像名称,tag 是镜像的版本,比如我们之前例子中的 nginx:latest

FROM 指令表示基于指定的基础镜像开始下一阶段的构建,并且为之后的构建指令指明了基础镜像,一个符合要求的 Dockerfile 必须以 FROM 开头(除了 ARG 指令可以在它之前)。

如果我们不需要任何的基础镜像,我们可以指定 FROM 为 scratch

FROM scratch

使用这个基础镜像,接下来的指令都作为镜像的第一层存在。

3.2.2 COPY

COPY 的基本语法如下:

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

该命令用于将当前上下文(后面会讲)路径中指定的文件或文件夹(src)复制到容器内制定的路径(dest),并且会保留原来文件的元信息,比如权限信息、更改时间信息等。第二种示例适合于路径中含有空格的情况。

其中 --chown 的作用跟 bash 指令中的 chown 一致,用于修改文件权限。但是该指令只能在 Linux 下使用,Windows 下构建镜像时不能配置这一项。

值得注意的是 src 可以是相对路径,当他们是相对路径的时候,解析的基础路径是 docker build 命令指定的当前上下文。dest 也可以是相对路径,当它为相对路径时,解析的基础路径是 WORKDIR 指令指定的工作路径。

src 可以指定多个,COPY 命令会将最后一个参数视为 dest,多个 src 都会被拷贝到 dest

dest 不存在时,Docker 会自动创建。

另外,COPY 指令支持通配符匹配文件,具体请参考 Docker 官网。

3.2.3 ADD

ADD 命令的基本语法与 COPY 类似:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

其功能也与 COPY 一致,但是新增了一些功能。

ADD 指令的 src 可以为 URL,此时 ADD 指令会到指定 URL 下载文件,然后复制到 dest 路径。

因为从 URL 下载的文件没有保留源文件的元信息,所以默认具有 600 权限(这里可以参考 chown 命令的解释,1/2/4 权限码-ugo 所有者等等)。下载文件的最后更新时间也会默认使用 HTTP 响应头中的 Last-Modified 字段。

如果 src 是一个本地压缩文件路径(identity, gzip, bzip2 或者 xz),则会被解压后复制到 dest。如果是一个压缩文件的 URL,则不会被解压缩。

dest 不存在的时候会被创建。

3.2.4 WORKDIR

WORKDIR 的基本语法:

WORKDIR /path/to/workdir

该指令用于指定工作路径,影响该指令之后的 RUN、CMD、COPY、ADD、ENTRYPOINT 等各种指令的路径解析。如果不存在该指令,则 Docker 会自动创建它。

Dockerfile 中可以多次使用 WORKDIR 指令,如果指定了相对路径,那么它会相对于上一条 WORKDIR 指令进行解析。

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

此时,RUN 指令的工作路径为 /a/b/c,因为后两条 WORKDIR 指令是相对路径,会相对于其上一条 WORKDIR 指令进行解析。

3.2.5 RUN

RUN 指令有两种语法:

RUN <command>
RUN ["executable", "param1", "param2"]

该指令将在当前镜像的上一层执行所有指令,然后将执行结果提交(commit),随后生成的镜像将用于下一层指令构建。所以我们应该知道 RUN 指令执行一次,就会提交一层镜像,我们应该减少生成的镜像,减少 Dockerfile 中 RUN 指令的出现次数。

第一种形式属于 shell 形式,第二种形式属于 exec 形式,使用 Nodejs 的同学应该见到过这两种形式的命令执行。两种形式存在区别,shell 形式会直接调用 shell 进行命令执行,而 exec 形式不会。因此 shell 形式被 shell 调用时会被 shell 进行处理,包括环境变量的替换等等。比如RUN echo $HOME,该指令运行时,实际上是 shell 对 $HOME 进行了处理,而不是 docker。当你使用 exec 形式的指令时,其内部的字符串不会被 shell 处理,而如果你需要被 shell 处理时,应该使用 RUN ["sh", "-c", "echo $HOME"] 的形式显式指定处理的程序。在讲解 CMD 命令和 ENTRYPOINT 命令时,还会讲一点两者的区别。具体请参考 Dockerfile CMD shell versus exec form

3.2.6 EXPOSE

该指令的基本语法:

EXPOSE <port> [<port>/<protocol>...]

该指令用于向 Docker 声明容器运行时占用的具体端口,protocol 可以是 tcp 或者 udp,默认是 tcp。

值得注意的是该指令并没有向外部暴露端口,它只是一种约定性的文档性质的指令,让开发人员和 Docker 了解该容器运行时使用的端口。使用 docker run -P ... 时,绑定的容器内的端口实际上就是 EXPOSE 指令指定的端口。

3.2.7 ENTRYPOINT

ENTRYPOINT 有两种语法形式:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

可以看到也是两种形式的命令执行形式。

ENTRYPOINT 指令允许你将 Docker 容器配置成一个可执行命令。

docker run -it 之后附加的命令参数会覆盖掉 CMD 指定的进程启动命令,并且如果你指定了 ENTRYPOINT 指令的话会将其附加到 ENTRYPOINT 指令的后方作为参数来执行。

如果运行 docker run -it 命令时没有指定命令参数,那么会将 CMD 指令作为参数附加给 ENTRYPOINT 指令执行。

这样的话可以让我们把容器变成一个可执行的命令工具,在 docker run -it 的时候给它传入参数,容器就可以实现不同的行为。

3.2.8 VOLUME

该指令的具体语法为:

VOLUME ["/data"]
VOLUME /var/log
VOLUME /var/log /var/db

该指令用于挂载匿名卷(volume)。卷用于存储文件及数据,可以理解为硬盘,它是独立于容器的。容器向卷中写入数据,容器退出及删除的时候我们的卷依然存在,所以卷可以有效地实现数据持久化。我们在运行容器的时候应该避免向容器存储层写入大量数据,应该保持容器的无状态化,基本上容器内动态产生的数据都不应该写入容器的存储层,而应该将数据保存到卷。

为了防止用户使用镜像的时候忘记挂载卷,我们可以使用该指令指定一个匿名的默认卷,当容器启动后会向卷内写入数据。当使用 docker run 指令启动容器的时候,我们可以使用 -v 选项覆盖默认卷。

还是之前的示例,我们新增一个 VOLUME 指令:

FROM mhart/alpine-node

COPY ./src /data/src
WORKDIR /data/src
VOLUME /data/src
RUN ["npm", "install"]
EXPOSE 3000

CMD ["node", "index.js"]

此时使用该镜像运行容器,应该会挂载内部的 /data/src 作为匿名卷,我们在当前目录构建一下:

$ docker build -t tmp .

然后运行我们的容器:

$ docker run -p 80:3000 tmp

然后我们使用 docker inspect 命令查看我们的容器信息:

$ docker inspect 347
# 容器名是 hash 缩写,docker 不要求写全,只需要能够定位到具体的 docker 容器就行

看到会打印出一大堆的 JSON 信息,然后我们找到对象里的一个 Mounts 属性:

"Mounts": [
  {
    "Type": "volume",
    "Name": "82d53d18bba2925261e256878f29880c26d3a8d4f88f0c3a00725441b3a31503",
    "Source": "/var/lib/docker/volumes/82d53d18bba2925261e256878f29880c26d3a8d4f88f0c3a00725441b3a31503/_data",
    "Destination": "/data/src",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
],

可以看到这是一个 local 类型的本地匿名卷,我们通过 docker volume inspect 查看其具体信息:

$ docker volume inspect 82d53d18bba2925261e256878f29880c26d3a8d4f88f0c3a00725441b3a31503

同样会打印出来一串 JSON 数据:

[
    {
        "CreatedAt": "2019-12-22T09:01:20Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/82d53d18bba2925261e256878f29880c26d3a8d4f88f0c3a00725441b3a31503/_data",
        "Name": "82d53d18bba2925261e256878f29880c26d3a8d4f88f0c3a00725441b3a31503",
        "Options": null,
        "Scope": "local"
    }
]

如果要删除卷,直接使用如下命令:

$ docker volume rm <volume>
3.2.9 ENV

该指令使用语法如下:

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

该指令用于指定环境变量,指定了环境变量后,其后的指令都可以直接使用这些环境变量。

比如:

ENV NODE_ENV=10.15.3
RUN nvm use $NODE_ENV &&\
		node scripts/build.js
3.2.10 ARG

该指令用户指定 Dockerfile 当前环境下使用到的变量。

语法如下:

ARG <name>[=<default value>]

可以理解为是定义变量的一个指令,而这个指令定义的变量可以在 build 命令构建镜像的时候使用 --build-arg <varname>=<value> 标签动态的传入参数。

3.2.11 USER

USER 指令的基本格式如下:

USER <user>[:<group>] or
USER <UID>[:<GID>]

用于设置当前用户或者用户组,会影响在它之后的 RUNCMDENTRYPOINT 等指令的执行。

3.2.12 HEALTHCHECK

该指令主要有以下两种语法格式:

HEALTHCHECK [OPTIONS] CMD command # 通过在容器中执行一条指令来检查容器的健康状况
HEALTHCHECK NONE # 清除所有的 healthcheck 指令,包括从上一层基础镜像继承的

这条指令用于检查容器是否还处于正常的工作状态,尤其适用于一些工作进程没有退出但是已经无法正常工作的应用。

Dockerfile 中添加了 HEALTHCHECK 指令之后,对应容器的运行状态会附加健康状态。该状态最开始是 starting,当通过健康检查之后会变为 healthy,当健康检查指令连续失败一定次数之后,会变为 unhealthy

OPTIONS 选项可以是如下几条:

--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--start-period=DURATION (default: 0s)
--retries=N (default: 3)

其中,interval 代表健康检查指令会在容器启动后的每一个 interval 时间段执行一次。

timeout 代表如果单次健康检查指令的执行时间超过了 timeout 指定时间的话,会被认为执行失败。

start-period 代表在容器启动后 start-period 时间之后才开始执行健康检查指令。

retries 代表重复执行 retries 次失败之后,会将容器标记为 unhealthy

一个 Dockerfile 只设置一条 HEALTHCHECK 指令,多次指定时只有最后一条会起作用。

指令执行的退出码对应检查状态情况如下:

0: success - 代表容器健康可用
1: unhealthy - 容器存在健康问题,影响使用
2: reserved - 不要使用这个退出码
3.2.13 ONBUILD

该指令语法结构如下:

ONBUILD [INSTRUCTION]

注意 ONBUILD 后面接的是 Dockerfile 语法中的指令,不是任意 command。

该指令用于指定一条构建指令,在以该镜像为基础的镜像构建的时候执行。也就是说包含这条指令的镜像构建的时候,其指定的指令并不会执行,而是会在继承该镜像的镜像构建的时候执行。其指定的指令会被延迟到下一个构建阶段。

3.2. 14 CMD

CMD 指令有三种形式:

CMD ["executable","param1","param2"] (exec 形式,推荐使用)
CMD ["param1","param2"] (作为默认参数传递给 ENTRYPOINT)
CMD command param1 param2 (shell 形式)

一个 Dockerfile 配置文件中只允许存在一条 CMD 指令,如果你制定了多条 CMD 指令,那么只有最后一条会执行。

CMD 指令的主要目的在于为可执行容器指定默认的启动指令。多数时候 CMD 是一条可执行的指令,比如 node index.jspython manage.py runserver 0.0.0.0:8000。有时候 CMD 也可以是纯参数,不包含可执行文件,但是你必须指定 ENTRYPOINT 指令,此时 CMD 参数会传递给 ENTRYPOINT 可执行指令。

如果用户通过 docker run -it 运行容器时在最后指定了执行命令,则会覆盖配置中的 CMD 指令。

3.2.15 LABEL

LABEL 指令语法如下:

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

它指定了一系列的键值对,添加到镜像上作为元数据。

示例如下:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

如果键值包含空格的话,就需要使用双引号括起来。

使用 LABEL 指令标记的镜像,实例化的容器可以通过 docker inspect 命令查看 Labels。

3.2.16 SHELL

该指令语法结构如下:

SHELL ["executable", "parameters"]

该指令必须写成 JSON 格式,用于指定构建时执行 shell 格式的命令所用到的 shell。在 Linux 下默认使用 ["/bin/bash", "-c"],Windows 下默认使用 ["cmd", "/S", "/C"]

3.2.17 STOPSIGNAL

该命令主要格式如下:

STOPSIGNAL signal

该指令用于设置发送给容器的系统调用退出命令,该命令可以是有效无符号数字(比如 9),也可以是信号名称(比如 SIGKILL)。

学习了 Dockerfile 的基本语法之后,我们就可以通过 docker build 命令来构建镜像了。

四、Docker 常用命令

Docker 提供了非常强大的命令行工具给我们使用,这一节将讲解一些非常常用且重要的 Docker 命令。

Docker 的配置文件存放在 ~/.docker 之下,可以通过 ls -a ~/.docker 查看:

config.json daemon.json

一般情况下是这两个配置文件。

在需要的时候我们可以修改这两个文件来设置 Docker 的一些行为。

4.1 制作镜像

制作镜像我们使用 docker build 命令。

比如我们有一个如下的 Dockerfile 文件:

FROM busybox

CMD [ "echo", "https://www.baidu.com" ]

随后我们可以在当前路径下打开终端,制作镜像:

$ docker build -t temp-busybox .

回车之后就会开始制作镜像。

上方的命令中,-t 代表指定镜像名称,所以制作出来的镜像名称就叫 temp-busybox

. 代表指定 Dockerfile 构建时候的上下文,而非 Dockerfile 所在的路径。指定的上下文会被上传到 Docker Daemon(Docker 是遵循 CS 架构,镜像构建过程在 Server 端完成,后续会有介绍)。

docker build 命令的语法结构如下:

$ docker build [OPTIONS] PATH | URL | -

指定上下文可以是 Git 仓库、targball 压缩包,或者是文件路径。

4.2 创建容器

可以使用 docker container create 命令创建一个新的容器:

$ docker container create [OPTIONS] IMAGE [COMMAND] [ARG...]

当然我们更常用的做法是使用 docker run 命令:

$ docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

可以在镜像名称后方添加命令,表示在容器启动后在其内部执行一条命令。这条命令会覆盖 CMD 指令指定的命令,如果有使用到 ENTRYPOINT 指令的话,还会作为参数传递给 ENTRYPOINT 执行。

4.3 在容器内执行命令

在容器内执行命令有两种方式,一种是上一节提到的 docker run 命令,还有一种是使用 docker exec 命令。这两者的区别在于 docker run 会创建新的容器,而 docker exec 只会在已经运行的容器内执行。

docker exec

$ docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]

4.4 停止运行中的容器

停止运行中的容器,我们使用 docker stop 命令:

$ docker container stop [OPTIONS] CONTAINER [CONTAINER...]

4.5 停止容器

4.6 查看容器输出

4.7 列出运行中的容器

五、Docker Compose

六、Docker Swarm

七、Docker Machine

八、Docker 基本原理

九、Docker 最佳实践

十、参考文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant