本文是《Docker必知必会系列》第二篇,原文发布于个人博客:悟尘记。
构建并运行镜像
要构建一个容器,需要做很多的工作,设置很多的配置,如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么经常被提及的无法重复、镜像构建透明性、体积等问题就都会解决。 这个脚本就是 Dockerfile。
准备 Dockerfile 文件
下载示例项目,请在终端中运行以下命令:
curl -LO https://github.com/dockersamples/node-bulletin-board/archive/master.zip
unzip master.zip
cd node-bulletin-board-master/bulletin-board-app
该
node-bulletin-board
项目是一个简单的公告板应用程序,使用 Node.js 编写。在此示例中,假设您编写了此应用程序,现在正尝试对其进行容器化。
Dockerfile
描述如何为容器组装专用文件系统,并且还可以包含一些元数据,这些元数据描述了如何基于该镜像运行容器。公告板应用程序 Dockerfile
内容如下:
# Use the official image as a parent image.
FROM node:current-slim
# Set the working directory.
WORKDIR /usr/src/app
# Copy the file from your host to your current location.
COPY package.json .
# Run the command inside your image filesystem.
RUN npm install
# Inform Docker that the container is listening on the specified port at runtime.
EXPOSE 8080
# Run the specified command within the container.
CMD [ "npm", "start" ]
# Copy the rest of your app's source code from your host to your image filesystem.
COPY . .
编写 Dockerfile 是容器化应用程序的第一步,这些 Dockerfile 命令是构建镜像的步骤。 这个步骤如下:
- 使用
FORM
指定基于已经存在的node:current-slim
基础镜像构建。这是一个由 nodejs 官方构建的镜像。 - 使用
WORKDIR
指定所有后续操作均从镜像文件系统中的/usr/src/app
目录中执行(而不是主机的文件系统中)。 - 将文件
package.json
从主机复制到镜像中的当前位置(.)(复制到 ``/usr/src/app/package.json`) - 在镜像文件系统中运行命令
npm install
(读取package.json
以确定并安装应用程序依赖) - 将应用的其余源代码从主机复制到镜像文件系统。
这些步骤与在主机上设置和安装应用程序所采取的步骤几乎相同。但是,将它们保存为
Dockerfile
可以使您在可移植的隔离 Docker 镜像中执行相同的操作。
上面的步骤构建了我们镜像的文件系统,但是 Dockerfile 中还有其他几行。
CMD
指令在镜像中指定一些元数据,该元数据描述了如何基于该镜像运行容器。在本示例中该图像的容器化过程是npm start
。EXPOSE 8080
通知 Docker 该容器在运行时监听 8080 端口。
上面是组织一个简单的 Dockerfile 的方法。始终以 FROM
命令开头,然后按照步骤构建您的私有文件系统,并以任何元数据规范作为结束。 Dockerfile 指令比上面看到的要多。有关完整列表,请参阅 Dockerfile 参考。
构建并测试镜像
现在您已经有了一些源代码和一个 Dockerfile,现在该构建您的第一个镜像,并确保从其启动的容器能够按预期工作。让我们构建您的公告板图像:
docker build --tag bulletinboard:1.0 .
您将看到 Docker 逐步完成 Dockerfile 中的每条指令,并逐步构建镜像:
Sending build context to Docker daemon 45.57kB
Step 1/7 : FROM node:current-slim
current-slim: Pulling from library/node
48839397421a: Pull complete
cbb6511d79bf: Pull complete
04ec6202052a: Pull complete
29c5eab4674c: Pull complete
8df5bb5f8d2e: Pull complete
Digest: sha256:c92fad90875a6ce7251c72701f9c88e1e3f3efc2eb1d7d1ffb2184204e4f7d98
Status: Downloaded newer image for node:current-slim
---> 6d9a17519d40
Step 2/7 : WORKDIR /usr/src/app
---> Running in 9dfd5c099558
Removing intermediate container 9dfd5c099558
---> 6062c6d2e488
Step 3/7 : COPY package.json .
---> 2ddc37525da9
Step 4/7 : RUN npm install
---> Running in 6ce3fed8ecd7
> ejs@2.7.4 postinstall /usr/src/app/node_modules/ejs
> node ./postinstall.js
Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN vue-event-bulletin@1.0.0 No repository field.
npm WARN The package morgan is included as both a dev and production dependency.
added 91 packages from 168 contributors and audited 221 packages in 16.854s
found 0 vulnerabilities
Removing intermediate container 6ce3fed8ecd7
---> 38a27fea6567
Step 5/7 : EXPOSE 8080
---> Running in c7528a178327
Removing intermediate container c7528a178327
---> 97f454f32f95
Step 6/7 : CMD [ "npm", "start" ]
---> Running in 72a6340e3d58
Removing intermediate container 72a6340e3d58
---> 0a90efca7ea9
Step 7/7 : COPY . .
---> 84c4f69e2893
Successfully built 84c4f69e2893
Successfully tagged bulletinboard:1.0
将镜像作为容器运行
根据您的新镜像启动一个容器:
docker run --publish 8000:8080 --detach --name board bulletinboard:1.0
这里有几个常见的标志:
--publish
要求 Docker 将主机端口 8000 上传入的流量转发到容器的端口 8080。容器具有自己的专用端口集,因此,如果要从网络访问某个端口,则必须以这种方式将流量转发到该端口。否则,作为默认的安全状态,防火墙规则将阻止所有网络流量到达您的容器。--detach
要求 Docker 在后台运行此容器。--name
指定一个名称,您可以使用该名称在后续命令中引用您的容器,在这种情况下为board
。
还要注意,您没有指定容器要运行的程序。您不必这样做,因为在构建 Dockerfile 时使用了
CMD
指令。Docker 知道在容器启动时会自动运行npm start
程序。在的浏览器中访问您的应用程序
localhost:8000
,您应该看到公告板应用程序已启动并正在运行。对公告板容器正常工作感到满意后,可以将其删除:
docker rm --force board
该
--force
选项将删除正在运行的容器。如果停止容器运行,docker stop board
则无需使用--force
。