这是关于使用Docker容器的分为两部分的系列之一。 在这一部分中,我们将重点介绍运行映像的多种方法和选项,以及主机如何与Docker容器进行交互。
在第二部分中,我们将介绍列出,启动,停止和重新启动容器,以及在正在运行的容器上执行命令。 Docker映像是部署的单位。 运行映像时,您将实例化一个Docker容器,该容器在其自己的隔离环境中针对文件系统,网络和进程树运行单个进程。
Docker容器非常灵活,可以支持许多用例,这些用例对于其他技术(如虚拟机和裸机服务器)而言过于繁重,复杂和/或昂贵。
在开始之前,请确保已在您的环境中正确安装了Docker。 根据安装方式和用户的不同,您可能需要以sudo身份运行它。 我将跳过sudo。
运行图像
您可以通过运行映像来启动Docker容器。 有几种运行容器的方法,这些方法会影响管理所有容器的难易程度。 容器启动时,通常会运行Dockerfile中定义的命令。 这是hello-world容器的Dockerfile:
FROM scratch
COPY hello /
CMD ["/hello"]
该命令仅运行构建映像时复制到容器根目录的“ hello”二进制文件。
前景与独立
容器可以在其阻塞的前台运行,直到进程退出并且容器停止运行。 在前台模式下,容器将其输出打印到控制台,并且可以读取标准输入。 在分离模式下(当您提供-d标志时),控件立即返回,并且容器
运行未命名的容器
运行容器的最简单方法是: docker run <image id or name>
。
使用此命令运行容器时,Docker将为其分配一个由两个随机词组成的名称。 例如: docker run hello-world
。
如果您已经有了hello-world映像,那么Docker将运行它。 如果不这样做,它将从官方Docker存储库DockerHub中提取它,然后运行它。 输出应如下所示:
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.
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 work-flows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
显示消息后,hello程序退出,该消息终止容器内运行的进程并结束容器运行。 如果您要连接到该容器,检查日志或其他任何内容,该容器仍会粘住。 要查看容器,可以运行以下命令:
docker ps -a --format "table {{.ID}}\t{{.Status}}\t{{.Names}}"
CONTAINER ID STATUS NAMES
8e2e491accb5 Exited (0) 2 minutes ago clever_liskov
稍后我将解释如何列出容器和所有相关选项。 现在,让我们关注“名称”部分。 Docker会自动生成名称“ clever_liskov”,并且出于任何目的(例如重新启动,删除它或执行命令),我都必须使用它或容器ID来引用该容器。
运行命名容器
有时使用容器ID或自动生成的名称很不方便。 如果您经常与一个容器进行交互,而您又经常重新创建一个容器,那么它将获得一个不同的ID和自动生成的名称。 此外,名称将是随机的。
Docker通过提供“ --name <container name>”命令行参数来使您在运行容器时为其命名。 在简单的情况下,每个图像只有一个容器,可以用图像命名容器: docker run --name hello-world hello-world
。
现在,如果我们看一下该过程(我之前删除了clever_liskov ),我们将看到该容器名为hello-world:
docker ps -a --format "table {{.ID}}\t{{.Names}}"
CONTAINER ID NAMES
f6fe77b3b6e8 hello-world
命名容器有几个好处:
- 您在交互和脚本中使用的容器都有一个稳定的名称。
- 您可以选择一个有意义的名称。
- 在进行交互工作时,可以选择一个简短的名称以方便使用。
- 这样可以防止您意外地拥有多个具有相同图像的容器(只要您始终提供相同的名称)。
让我们看看最后一个选项。 如果我尝试使用相同的“ hello-world”名称再次运行相同的运行命令,则会收到清晰的错误消息:
docker run --name hello-world hello-world
docker: Error response from daemon: Conflict. The container name
"/hello-world" is already in use by container
f6fe77b3b6e8e77ccf346c32c599e67b2982893ca39f0415472c2949cacc4a51.
You have to remove (or rename) that container to be able to reuse
that name.
See 'docker run --help'.
运行自动删除图像
默认情况下,容器会粘在周围。 有时,您不需要它们。 您无需手动删除退出的容器,而是使容器自行消失。 --rm
命令行参数可以达到目的: docker run --rm hello-world
。
运行不同的命令
默认情况下,Docker运行用于构建映像的Dockerfile中指定的命令(如果未找到命令,则直接运行入口点)。 您始终可以通过在run命令末尾提供自己的命令来覆盖它。 让我们在busybox映像上运行ls -la
( hello-world映像没有ls
可执行文件):
docker run busybox ls -la
total 44
drwxr-xr-x 18 root root 4096 Mar 18 17:06 .
drwxr-xr-x 18 root root 4096 Mar 18 17:06 ..
-rwxr-xr-x 1 root root 0 Mar 18 17:06 .dockerenv
drwxr-xr-x 2 root root 12288 Mar 9 00:05 bin
drwxr-xr-x 5 root root 340 Mar 18 17:06 dev
drwxr-xr-x 2 root root 4096 Mar 18 17:06 etc
drwxr-xr-x 2 nobody nogroup 4096 Mar 9 00:05 home
dr-xr-xr-x 85 root root 0 Mar 18 17:06 proc
drwxr-xr-x 2 root root 4096 Mar 9 00:05 root
dr-xr-xr-x 13 root root 0 Mar 18 17:06 sys
drwxrwxrwt 2 root root 4096 Mar 9 00:05 tmp
drwxr-xr-x 3 root root 4096 Mar 9 00:05 usr
drwxr-xr-x 4 root root 4096 Mar 9 00:05 var
与主机互动
Docker容器在自己的小世界中运行隔离的进程。 但是提供对主机的访问通常是必要且有用的。
将环境变量传递给容器
Docker容器不会自动继承运行它们的主机进程的环境。 使用-e
命令行标志运行容器时,需要为容器显式提供环境变量。 您可以传递多个环境变量。 这是一个例子:
docker run --rm -it -e ENV_FROM_HOST="123" busybox
/ # env
HOSTNAME=8e7672bce5a7
SHLVL=1
HOME=/root
ENV_FROM_HOST=123
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
/ #
第一行运行busybox容器, 向其传递ENV_FROM_HOST变量,然后在运行env
的容器内部显示ENV_FROM_HOST设置正确。
您也可以使用主机环境变量。 这将设置几个主机环境变量,并在run命令中使用它们:
$ export VAR_1=1
$ export VAR_2=2
$ docker run --rm -it -e VAR_1="$VAR_1" -e VAR_2="$VAR_2" busybox
在容器内,它们现在可见:
/ # env | grep VAR
VAR_1=1
VAR_2=2
挂载主机目录
最有用的交互之一是挂载主机目录。 这允许几个有趣的用例:
- 在同一主机上运行的容器之间的共享存储。
- 使用主机环境和工具以及容器中的文件查看和编辑文件。
- 超出容器生存期的主机级持久性。
在这里,我在主机上创建了一个文件: $ echo "Yeah, it works!" > ~/data/1.txt
$ echo "Yeah, it works!" > ~/data/1.txt
然后,我运行busybox映像,将〜/ data目录安装到容器中的/ data并在屏幕上显示文件内容:
$ docker run --rm -v ~/data:/data busybox cat /data/1.txt
Yeah, it works!
我在这里使用了cat /data/1.txt
命令。
将端口公开给主机
如果使用EXPOSE在Dockerfile中公开端口,则只有其他Docker容器才能访问该端口。 要使其在主机上可访问,您需要使用-p
命令行参数。 语法为-p <host port>:<exposed container port>
。
这里正在运行nginx映像,该映像公开了端口80,并使用-p
命令行参数使它在端口9000的主机上可见:
docker run --name nginx --rm -d -p 9000:80 nginx
请注意,与之前执行某些任务并完成的命令不同,nginx容器将继续运行并监听传入的请求。 让我们验证一下nginx确实已经启动并正在运行,并且可以响应端口9000上的请求。与curl相比,我更喜欢出色的httpie HTTP客户端,它可以从命令行访问Web服务器和服务:
http HEAD localhost:9000
HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: keep-alive
Content-Length: 612
Content-Type: text/html
Date: Sun, 19 Mar 2017 07:35:55 GMT
ETag: "58a323e4-264"
Last-Modified: Tue, 14 Feb 2017 15:36:04 GMT
Server: nginx/1.11.10
结论
运行Docker映像以创建容器的方法有很多,并且有很多选项。 每种组合都支持特定用途。 在使用Docker容器来完全掌握细节并使用最佳方法启动容器时,这非常有用。
此外,附加主机卷以及公开和发布端口可实现与主机的紧密集成以及多种使用场景。 在第二部分中,我们将深入研究管理一堆容器并利用Docker提供的全部功能。