EvenChan's Ops.

使用 Docker 加速开发工作流

字数统计: 1.5k阅读时长: 6 min
2020/10/09

在开发工作流中使用 Docker 可以极大提高生产力,它消除了"它在我机器上都可以运行"这类典型的错误,在不同的机器上运行也只需要一个 Docker 守护进程,而不需要其他组件。

什么是 Docker

Docker 是一个可以运行容器平台,为了运行这些容器,Docker 使用了操作系统级的虚拟化技术,你可以把容器看作是一个轻量级版本的虚拟机。

你在 Docker 平台上运行的所有容器都是相互隔离的。要启动一个容器,你需要一个 Docker 镜像,这个镜像是你的容器的模板,你可以从 Docker Hub 中获取已经预定义的镜像,或者通过编写 Dockerfile 文件来配置自己的镜像。

为什么要 Docker 化开发工作流

上面我已经提到了在你的开发环境中使用 Docker 的好处。这是一个事实,它摆脱了典型的”它在我的机器上可以工作”的问题,除此之外,还有其他一些好处:

  • 让团队成员之间的开发工作流程更加标准化
  • 如果你也使用 Docker 进行部署,则减少了针对生产环境的 bug(生产和开发之间的配置可以很相似)。

开始

首先创建一个新的文件夹,将我们的项目放在其中,然后我创建一个 Dockerfile 文件:

1
2
$ mkdir node-docker && cd node-docker
$ touch Dockerfile

我们将在 Dockerfile 中配置一个 express 应用,内容如下所示:

1
2
3
4
5
6
7
FROM node:latest

WORKDIR /usr/src/app
COPY package*.json ./
ENV PORT 5000

RUN npm cache clear --force && npm install

FROM 是告诉 Docker 从 Docker Hub 获取一个名为 node(版本:latest)的镜像。

WORKDIR 设置所有即将执行的命令的目录。

COPY 的作用就是复制文件到 WORDIR 中来。

ENV 在容器中设置一个环境变量,名称为 PORT,值为 5000

RUN 执行我们传递进来的命令,在这里会清除 npm 缓存,然后安装package.json 中的所有依赖项。

ENTRYPOINT 会在 Docker 容器启动的时候执行你在这里插入的命令。

现在,我们已经准备好了我们的 Dockerfile 文件,我们需要一个简单的 express 应用,可以在容器内运行。为此,我们创建两个新的文件。

1
$ touch server.js package.json

package.json 文件中新增两个依赖关系,一个是 express,另外一个是nodemon。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "node-docker",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "nodemon server.js"
},
"author": "Jakob Klamser",
"license": "MIT",
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}

express 应用在点击主页面时,返回一个简单的 HTML。对应的 server.js 内容如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const express = require('express');

const app = express();

const PORT = process.env.PORT || 5000;

app.get('/', (req, res) => {
res.send(`
<h1>Express + Docker</h1>
<span>This projects runs inside a Docker container</span>
`);
});

app.listen(PORT, () => {
console.log(`Listening on port ${PORT}!`);
});

在我们开始将 MongoDB 容器与我们的 express 容器一起设置之前,我们希望将一些文件从运行的容器中排除,这个时候就可以使用 .dockerignore 来进行配置,.dockerignore 文件的语法与 .gitignore 文件完全相同。

1
2
3
4
5
6
7
8
9
10
# Git
.git
.gitignore

# Docker
Dockerfile
docker-compose.yml

# NPM dependencies
node_modules

最后同样重要的是我们需要定义一个 docker-compose.yml。这个文件将包含两个不同容器,同时运行 express 应用和 MongoDB,先创建这个文件。

1
$ touch docker-compose.yml

然后配置如下所示的该文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3'
services:
api:
build: .
ports:
- "5000:5000"
depends_on:
- mongo
volumes:
- "./:/usr/src/app"
- "reserved:/usr/src/app/node_modules"
mongo:
image: "mongo"
ports:
- "27017:27017"
volumes:
reserved:

version: 定义了我们要使用的 docker-compose 的版本,版本3和版本2之间有不少差异,所以在选择版本时要注意!

services: 这是定义服务的部分,这里我们定义了 express api 和 mongo 两个服务。

build & image: build 告诉 Docker 从 Dockerfile 中构建一个镜像。在我们的例子中,我们希望它使用当前目录下的 Dockerfile,这就是为什么我们把.作为一个参数,因为这定义了当前的目录。image 告诉 Docker 从 Docker Hub 中拉取一个已经存在的镜像。

ports & volumes: 如 ports 的名字所示,我们在这里定义端口,冒号是一个映射操作符,我们将容器的5000端口映射到主机系统的5000端口,在本例中,我们就可以在容器之外访问应用程序。同样的道理也适用于 MongoDB 的端口映射。volumes 也做类似的事情,我们将本地代码的目录映射到容器的 WORKDIR 中,这样一来,如果我们修改了源代码中的任何内容,容器就会立即做出反应。

reserved: 这是一个特殊的卷,如果本地的 node_modules 文件夹存在,则不会覆盖容器内部的 node_modules 文件夹。

然后现在我们可以运行如下所示的命令,Docker 将根据我们的 Dockerfile 文件配置创建一个镜像,然后同时运行两个容器(api和mongo)。

1
$ docker-compose up

如果你想停止这些容器,可以执行下面的命令:

1
$ docker-compose down

总结

这里我们只是介绍的一个简单的 Docker 开发环境配置,当然也可以很容易地进行扩展。如果你想改变数据库或添加一个 Nginx 来渲染你的前端,只需在 docker-compose.yml 中添加一个新的服务或改变一个现有的服务即可。当然同样地我们也可以很容易地对 .Net Core、Java 或者 Golang 应用进行 Docker 容器化。

原文链接:https://klamser.dev/dockerize-your-development-environment-for-nodejs

CATALOG
  1. 1. 什么是 Docker
  2. 2. 为什么要 Docker 化开发工作流
  3. 3. 开始
  4. 4. 总结