如何在Ubuntu 20.04上使用Docker构建Node.js应用程序

介绍 (Introduction)

The Docker platform allows developers to package and run applications as containers. A container is an isolated process that runs on a shared operating system, offering a lighter weight alternative to virtual machines. Though containers are not new, they offer benefits — including process isolation and environment standardization — that are growing in importance as more developers use distributed application architectures.

Docker平台允许开发人员将应用程序打包和运行为容器 。 容器是在共享操作系统上运行的隔离进程,为虚拟机提供了更轻巧的选择。 尽管容器不是新事物,但它们提供的好处(包括流程隔离和环境标准化)随着越来越多的开发人员使用分布式应用程序体系结构而变得越来越重要。

When building and scaling an application with Docker, the starting point is typically creating an image for your application, which you can then run in a container. The image includes your application code, libraries, configuration files, environment variables, and runtime. Using an image ensures that the environment in your container is standardized and contains only what is necessary to build and run your application.

在使用Docker构建和扩展应用程序时,通常是从为应用程序创建映像开始,然后可以在容器中运行该映像。 该映像包括您的应用程序代码,库,配置文件,环境变量和运行时。 使用映像可确保容器中的环境是标准化的,并且仅包含构建和运行应用程序所需的环境。

In this tutorial, you will create an application image for a static website that uses the Express framework and Bootstrap. You will then build a container using that image and push it to Docker Hub for future use. Finally, you will pull the stored image from your Docker Hub repository and build another container, demonstrating how you can recreate and scale your application.

在本教程中,您将为使用Express Framework和Bootstrap的静态网站创建应用程序映像。 然后,您将使用该映像构建一个容器,并将其推送到Docker Hub以供将来使用。 最后,您将从Docker Hub存储库中提取存储的映像并构建另一个容器,演示如何重新创建和扩展应用程序。

先决条件 (Prerequisites)

To follow this tutorial, you will need:

要遵循本教程,您将需要:

第1步-安装应用程序依赖项 (Step 1 — Installing Your Application Dependencies)

To create your image, you will first need to make your application files, which you can then copy to your container. These files will include your application’s static content, code, and dependencies.

要创建图像,首先需要制作应用程序文件,然后可以将其复制到容器中。 这些文件将包含应用程序的静态内容,代码和依赖项。

First, create a directory for your project in your non-root user’s home directory. We will call ours node_project, but you should feel free to replace this with something else:

首先,在非root用户的主目录中为项目创建目录。 我们将调用我们的node_project ,但是您应该随意将其替换为其他内容:

  • mkdir node_project

    mkdir node_project

Navigate to this directory:

导航到此目录:

  • cd node_project

    cd node_project

This will be the root directory of the project.

这将是项目的根目录。

Next, create a package.json file with your project’s dependencies and other identifying information. Open the file with nano or your favorite editor:

接下来,使用项目的依赖项和其他标识信息创建package.json文件。 使用nano或您喜欢的编辑器打开文件:

  • nano package.json

    纳米package.json

Add the following information about the project, including its name, author, license, entrypoint, and dependencies. Be sure to replace the author information with your own name and contact details:

添加有关项目的以下信息,包括其名称,作者,许可证,入口点和依赖项。 确保用您自己的姓名和联系方式替换作者信息:

~/node_project/package.json
〜/ node_project / package.json
{
  "name": "nodejs-image-demo",
  "version": "1.0.0",
  "description": "nodejs image demo",
  "author": "Sammy the Shark <sammy@example.com>",
  "license": "MIT",
  "main": "app.js",
  "keywords": [
    "nodejs",
    "bootstrap",
    "express"
  ],
  "dependencies": {
    "express": "^4.16.4"
  }
}

This file includes the project name, author, and license under which it is being shared. Npm recommends making your project name short and descriptive, and avoiding duplicates in the npm registry. We’ve listed the MIT license in the license field, permitting the free use and distribution of the application code.

该文件包括项目名称,作者和与其共享的许可证。 Npm 建议使您的项目名称简短明了,并避免在npm Registry中重复。 我们已在“许可证”字段中列出了MIT许可证 ,允许免费使用和分发应用程序代码。

Additionally, the file specifies:

此外,文件指定:

  • "main": The entrypoint for the application, app.js. You will create this file next.

    "main" :应用程序的入口app.js 接下来,您将创建此文件。

  • "dependencies": The project dependencies — in this case, Express 4.16.4 or above.

    "dependencies" :项目依赖项-在这种情况下,为Express 4.16.4或更高版本。

Though this file does not list a repository, you can add one by following these guidelines on adding a repository to your package.json file. This is a good addition if you are versioning your application.

尽管此文件未列出存储库,但是您可以按照以下将存储库添加到package.json文件的准则进行添加 。 如果要对应用程序进行版本控制,这是一个很好的补充。

Save and close the file when you’ve finished making changes.

完成更改后,保存并关闭文件。

To install your project’s dependencies, run the following command:

要安装项目的依赖项,请运行以下命令:

  • npm install

    npm安装

This will install the packages you’ve listed in your package.json file in your project directory.

这将在项目目录的package.json文件中安装您列出的软件包。

We can now move on to building the application files.

现在,我们可以继续构建应用程序文件。

第2步-创建应用程序文件 (Step 2 — Creating the Application Files)

We will create a website that offers users information about sharks. Our application will have a main entrypoint, app.js, and a views directory that will include the project’s static assets. The landing page, index.html, will offer users some preliminary information and a link to a page with more detailed shark information, sharks.html. In the views directory, we will create both the landing page and sharks.html.

我们将创建一个网站,向用户提供有关鲨鱼的信息。 我们的应用程序将有一个主入口点app.js和一个包含项目静态资产的views目录。 登陆页面index.html将为用户提供一些初步信息,并提供一个指向页面的链接,其中包含更详细的shark信息sharks.html 。 在views目录中,我们将创建登录页面和sharks.html

First, open app.js in the main project directory to define the project’s routes:

首先,在主项目目录中打开app.js来定义项目的路线:

  • nano app.js

    纳米app.js

The first part of the file will create the Express application and Router objects, and define the base directory and port as constants:

该文件的第一部分将创建Express应用程序和Router对象,并将基本目录和端口定义为常量:

~/node_project/app.js
〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
const port = 8080;

The require function loads the express module, which we then use to create the app and router objects. The router object will perform the routing function of the application, and as we define HTTP method routes we will add them to this object to define how our application will handle requests.

require函数加载express模块,然后我们将其用于创建approuter对象。 router对象将执行应用程序的路由功能,并且当我们定义HTTP方法路由时,我们会将它们添加到该对象中以定义我们的应用程序将如何处理请求。

This section of the file also sets a couple of constants, path and port:

该文件的这一部分还设置了两个常量, pathport

  • path: Defines the base directory, which will be the views subdirectory within the current project directory.

    path :定义基本目录,它将是当前项目目录中的views子目录。

  • port: Tells the app to listen on and bind to port 8080.

    port :告诉应用监听并绑定到端口8080

Next, set the routes for the application using the router object:

接下来,使用router对象设置应用程序的router

~/node_project/app.js
〜/ node_project / app.js
...

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/', function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks', function(req,res){
  res.sendFile(path + 'sharks.html');
});

The router.use function loads a middleware function that will log the router’s requests and pass them on to the application’s routes. These are defined in the subsequent functions, which specify that a GET request to the base project URL should return the index.html page, while a GET request to the /sharks route should return sharks.html.

router.use函数加载了一个中间件函数 ,该函数将记录路由器的请求并将其传递给应用程序的路由。 这些在后续函数中定义,这些函数指定对基础项目URL的GET请求应返回index.html页面,而对/sharks路由的GET请求应返回sharks.html

Finally, mount the router middleware and the application’s static assets and tell the app to listen on port 8080:

最后,安装router中间件和应用程序的静态资产,并告诉应用程序监听端口8080

~/node_project/app.js
〜/ node_project / app.js
...

app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

The finished app.js file will look like this:

完成的app.js文件将如下所示:

~/node_project/app.js
〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/', function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks', function(req,res){
  res.sendFile(path + 'sharks.html');
});

app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

Save and close the file when you are finished.

完成后保存并关闭文件。

Next, let’s add some static content to the application. Start by creating the views directory:

接下来,让我们向应用程序中添加一些静态内容。 首先创建views目录:

  • mkdir views

    mkdir视图

Open the landing page file, index.html:

打开登录页面文件index.html

  • nano views/index.html

    nano views / index.html

Add the following code to the file, which will import Boostrap and create a jumbotron component with a link to the more detailed sharks.html info page:

将以下代码添加到该文件中,该文件将导入Boostrap并创建一个jumbotron组件,并带有指向更详细的sharks.html信息页面的链接:

~/node_project/views/index.html
〜/ node_project / views / index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <title>About Sharks</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="css/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</head>

<body>
    <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
        <div class="container">
            <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
            </button> <a class="navbar-brand" href="#">Everything Sharks</a>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav mr-auto">
                    <li class="active nav-item"><a href="/" class="nav-link">Home</a>
                    </li>
                    <li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="jumbotron">
        <div class="container">
            <h1>Want to Learn About Sharks?</h1>
            <p>Are you ready to learn about sharks?</p>
            <br>
            <p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
            </p>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <div class="col-lg-6">
                <h3>Not all sharks are alike</h3>
                <p>Though some are dangerous, sharks generally do not attack humans. Out of the 500 species known to researchers, only 30 have been known to attack humans.
                </p>
            </div>
            <div class="col-lg-6">
                <h3>Sharks are ancient</h3>
                <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                </p>
            </div>
        </div>
    </div>
</body>

</html>

The top-level navbar here allows users to toggle between the Home and Sharks pages. In the navbar-nav subcomponent, we are using Bootstrap’s active class to indicate the current page to the user. We’ve also specified the routes to our static pages, which match the routes we defined in app.js:

此处的顶级导航栏允许用户在“ 主页”和“ 鲨鱼”页面之间切换。 在navbar-nav子组件中,我们使用Bootstrap的active类向用户指示当前页面。 我们还指定了指向静态页面的路由,这些路由与我们在app.js定义的路由匹配:

~/node_project/views/index.html
〜/ node_project / views / index.html
...
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
   <ul class="nav navbar-nav mr-auto">
      <li class="active nav-item"><a href="/" class="nav-link">Home</a>
      </li>
      <li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
      </li>
   </ul>
</div>
...

Additionally, we’ve created a link to our shark information page in our jumbotron’s button:

此外,我们还在巨型按钮中创建了指向鲨鱼信息页面的链接:

~/node_project/views/index.html
〜/ node_project / views / index.html
...
<div class="jumbotron">
   <div class="container">
      <h1>Want to Learn About Sharks?</h1>
      <p>Are you ready to learn about sharks?</p>
      <br>
      <p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
      </p>
   </div>
</div>
...

There is also a link to a custom style sheet in the header:

标头中还有一个指向自定义样式表的链接:

~/node_project/views/index.html
〜/ node_project / views / index.html
...
<link href="css/styles.css" rel="stylesheet">
...

We will create this style sheet at the end of this step.

我们将在此步骤结束时创建此样式表。

Save and close the file when you are finished.

完成后保存并关闭文件。

With the application landing page in place, we can create our shark information page, sharks.html, which will offer interested users more information about sharks.

有了应用程序登录页面后,我们可以创建我们的shark信息页面sharks.html ,它将为感兴趣的用户提供有关sharks.html更多信息。

Open the file:

打开文件:

  • nano views/sharks.html

    nano views / sharks.html

Add the following code, which imports Bootstrap and the custom style sheet and offers users detailed information about certain sharks:

添加以下代码,这些代码将导入Bootstrap和自定义样式表,并向用户提供有关某些鲨鱼的详细信息:

~/node_project/views/sharks.html
〜/ node_project / views / sharks.html
<!DOCTYPE html>
<html lang="en">

<head>
    <title>About Sharks</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="css/styles.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</head>
<nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
    <div class="container">
        <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
        </button> <a class="navbar-brand" href="/">Everything Sharks</a>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav mr-auto">
                <li class="nav-item"><a href="/" class="nav-link">Home</a>
                </li>
                <li class="active nav-item"><a href="/sharks" class="nav-link">Sharks</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<div class="jumbotron text-center">
    <h1>Shark Info</h1>
</div>
<div class="container">
    <div class="row">
        <div class="col-lg-6">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-6">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    </div>
</div>

</html>

Note that in this file, we again use the active class to indicate the current page.

请注意,在此文件中,我们再次使用active类指示当前页面。

Save and close the file when you are finished.

完成后保存并关闭文件。

Finally, create the custom CSS style sheet that you’ve linked to in index.html and sharks.html by first creating a css folder in the views directory:

最后,首先在views目录中创建一个css文件夹,以创建已在index.htmlsharks.html链接到的自定义CSS样式表:

  • mkdir views/css

    mkdir视图/ css

Open the style sheet:

打开样式表:

  • nano views/css/styles.css

    纳米视图/css/styles.css

Add the following code, which will set the desired color and font for our pages:

添加以下代码,这将为我们的页面设置所需的颜色和字体:

~/node_project/views/css/styles.css
〜/ node_project / views / css / styles.css
.navbar {
    margin-bottom: 0;
}

body {
    background: #020A1B;
    color: #ffffff;
    font-family: 'Merriweather', sans-serif;
}

h1,
h2 {
    font-weight: bold;
}

p {
    font-size: 16px;
    color: #ffffff;
}

.jumbotron {
    background: #0048CD;
    color: white;
    text-align: center;
}

.jumbotron p {
    color: white;
    font-size: 26px;
}

.btn-primary {
    color: #fff;
    text-color: #000000;
    border-color: white;
    margin-bottom: 5px;
}

img,
video,
audio {
    margin-top: 20px;
    max-width: 80%;
}

div.caption: {
    float: left;
    clear: both;
}

In addition to setting font and color, this file also limits the size of the images by specifying a max-width of 80%. This will prevent them from taking up more room than we would like on the page.

除了设置字体和颜色,此文件还通过指定max-width为80%来限制图像的大小。 这样可以防止他们占用比我们在页面上想要的更多的空间。

Save and close the file when you are finished.

完成后保存并关闭文件。

With the application files in place and the project dependencies installed, you are ready to start the application.

准备好应用程序文件并安装项目依赖项之后,就可以启动应用程序了。

If you followed the initial server setup tutorial in the prerequisites, you will have an active firewall permitting only SSH traffic. To permit traffic to port 8080 run:

如果您按照先决条件中的初始服务器设置教程进行操作,则将有一个活动防火墙,仅允许SSH通信。 要允许流量进入端口8080运行:

  • sudo ufw allow 8080

    sudo ufw允许8080

To start the application, make sure that you are in your project’s root directory:

要启动该应用程序,请确保您位于项目的根目录中:

  • cd ~/node_project

    cd〜 / node_project

Start the application with node app.js:

使用node app.js启动应用程序:

  • node app.js

    节点app.js

Navigate your browser to http://your_server_ip:8080. You will load the following landing page:

将浏览器导航到http:// your_server_ip :8080 。 您将加载以下登录页面:

Click on the Get Shark Info button. The following information page will load:

单击获取鲨鱼信息按钮。 将加载以下信息页面:

You now have an application up and running. When you are ready, quit the server by typing CTRL+C. We can now move on to creating the Dockerfile that will allow us to recreate and scale this application as desired.

现在,您已启动并运行了一个应用程序。 准备就绪后,通过键入CTRL+C退出服务器。 现在,我们可以继续创建Dockerfile,该文件将允许我们根据需要重新创建和扩展此应用程序。

第3步—编写Dockerfile (Step 3 — Writing the Dockerfile)

Your Dockerfile specifies what will be included in your application container when it is executed. Using a Dockerfile allows you to define your container environment and avoid discrepancies with dependencies or runtime versions.

您的Dockerfile指定执行时将在应用程序容器中包含的内容。 使用Dockerfile可以定义容器环境,并避免依赖项或运行时版本之间的差异。

Following these guidelines on building optimized containers, we will make our image as efficient as possible by minimizing the number of image layers and restricting the image’s function to a single purpose — recreating our application files and static content.

遵循这些有关构建优化容器的准则 ,我们将通过最大程度地减少图像层数并将图像功能限制于一个目的(使我们重新创建应用程序文件和静态内容)来使图像尽可能高效。

In your project’s root directory, create the Dockerfile:

在项目的根目录中,创建Dockerfile:

  • nano Dockerfile

    纳米Dockerfile

Docker images are created using a succession of layered images that build on one another. Our first step will be to add the base image for our application that will form the starting point of the application build.

Docker映像是使用一系列相互构建的分层映像创建的。 我们的第一步将是为我们的应用程序添加基本映像 ,该映像将构成应用程序构建的起点。

Let’s use the node:10-alpine image, since at the time of writing this is the recommended LTS version of Node.js. The alpine image is derived from the Alpine Linux project, and will help us keep our image size down. For more information about whether or not the alpine image is the right choice for your project, please review the full discussion under the Image Variants section of the Docker Hub Node image page.

让我们使用node: 10-alpine图像 ,因为在编写本文时,这是Node.js推荐LTS版本alpine图像来自Alpine Linux项目,将有助于我们减小图像尺寸。 有关alpine图像是否适合您的项目的更多信息,请查看Docker Hub Node image页面Image Variants部分下的完整讨论。

Add the following FROM instruction to set the application’s base image:

添加以下FROM指令以设置应用程序的基本映像:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
FROM node:10-alpine

This image includes Node.js and npm. Each Dockerfile must begin with a FROM instruction.

该图像包括Node.js和npm。 每个Dockerfile必须以FROM指令开头。

By default, the Docker Node image includes a non-root node user that you can use to avoid running your application container as root. It is a recommended security practice to avoid running containers as root and to restrict capabilities within the container to only those required to run its processes. We will therefore use the node user’s home directory as the working directory for our application and set them as our user inside the container. For more information about best practices when working with the Docker Node image, check out this best practices guide.

默认情况下,多克尔节点图像包括非根节点的用户,您可以使用来避免运行你的应用程序容器为 。 建议的安全实践是避免以根用户身份运行容器,并将容器内的功能限制为仅运行其进程所需的功能 。 因此,我们将使用节点用户的主目录作为应用程序的工作目录,并将其设置为容器内的用户。 有关使用Docker Node映像时的最佳实践的更多信息,请查看此最佳实践指南

To fine-tune the permissions on our application code in the container, let’s create the node_modules subdirectory in /home/node along with the app directory. Creating these directories will ensure that they have the permissions we want, which will be important when we create local node modules in the container with npm install. In addition to creating these directories, we will set ownership on them to our node user:

要微调容器中应用程序代码的权限,让我们在/home/nodeapp目录中创建node_modules子目录。 创建这些目录将确保它们具有我们想要的权限,这对于使用npm install在容器中创建本地节点模块时非常重要。 除了创建这些目录,我们还将对节点用户设置其所有权:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

For more information on the utility of consolidating RUN instructions, read through this discussion of how to manage container layers.

有关合并RUN指令的实用程序的更多信息,请通读有关如何管理容器层的讨论

Next, set the working directory of the application to /home/node/app:

接下来,将应用程序的工作目录设置为/home/node/app

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
WORKDIR /home/node/app

If a WORKDIR isn’t set, Docker will create one by default, so it’s a good idea to set it explicitly.

如果未设置WORKDIR ,则Docker将默认创建一个WORKDIR ,因此最好进行显式设置。

Next, copy the package.json and package-lock.json (for npm 5+) files:

接下来,复制package.jsonpackage-lock.json (适用于npm 5+)文件:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
COPY package*.json ./

Adding this COPY instruction before running npm install or copying the application code allows us to take advantage of Docker’s caching mechanism. At each stage in the build, Docker will check whether it has a layer cached for that particular instruction. If we change package.json, this layer will be rebuilt, but if we don’t, this instruction will allow Docker to use the existing image layer and skip reinstalling our node modules.

在运行npm install之前添加此COPY指令或复制应用程序代码,使我们能够利用Docker的缓存机制。 在构建的每个阶段,Docker将检查它是否为该特定指令缓存了一层。 如果更改package.json ,则将重建该层,但如果不这样做,则此指令将允许Docker使用现有的图像层,并跳过重新安装节点模块的操作。

To ensure that all of the application files are owned by the non-root node user, including the contents of the node_modules directory, switch the user to node before running npm install:

为确保所有应用程序文件均由非根节点用户所有,包括node_modules目录的内容,请在运行npm install之前将用户切换到节点

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
USER node

After copying the project dependencies and switching our user, we can run npm install:

复制项目依赖项并切换我们的用户后,我们可以运行npm install

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
RUN npm install

Next, copy your application code with the appropriate permissions to the application directory on the container:

接下来,将具有适当权限的应用程序代码复制到容器上的应用程序目录:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
COPY --chown=node:node . .

This will ensure that the application files are owned by the non-root node user.

这将确保应用程序文件由非根节点用户拥有。

Finally, expose port 8080 on the container and start the application:

最后,暴露容器上的端口8080并启动应用程序:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
...
EXPOSE 8080

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

EXPOSE does not publish the port, but instead functions as a way of documenting which ports on the container will be published at runtime. CMD runs the command to start the application — in this case, node app.js. Note that there should only be one CMD instruction in each Dockerfile. If you include more than one, only the last will take effect.

EXPOSE不会发布端口,而是用作记录容器上哪些端口将在运行时发布的方式。 CMD运行命令以启动应用程序,在本例中为node app.js 请注意,每个Dockerfile中应该只有一条CMD指令。 如果包含多个,则只有最后一个才会生效。

There are many things you can do with the Dockerfile. For a complete list of instructions, please refer to Docker’s Dockerfile reference documentation.

您可以使用Dockerfile做很多事情。 有关说明的完整列表,请参考Docker的Dockerfile参考文档

The complete Dockerfile looks like this:

完整的Dockerfile如下所示:

~/node_project/Dockerfile
〜/ node_project / Dockerfile
FROM node:10-alpine

RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

WORKDIR /home/node/app

COPY package*.json ./

USER node

RUN npm install

COPY --chown=node:node . .

EXPOSE 8080

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

Save and close the file when you are finished editing.

完成编辑后,保存并关闭文件。

Before building the application image, let’s add a .dockerignore file. Working in a similar way to a .gitignore file, .dockerignore specifies which files and directories in your project directory should not be copied over to your container.

在构建应用程序映像之前,让我们添加一个.dockerignore文件.dockerignore以与.gitignore文件类似的方式工作, .dockerignore指定项目目录中的哪些文件和目录不应复制到容器中。

Open the .dockerignore file:

打开.dockerignore文件:

  • nano .dockerignore

    纳米.dockerignore

Inside the file, add your local node modules, npm logs, Dockerfile, and .dockerignore file:

在文件内部,添加本地节点模块,npm日志,Dockerfile和.dockerignore文件:

~/node_project/.dockerignore
〜/ node_project / .dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore

If you are working with Git then you will also want to add your .git directory and .gitignore file.

如果您使用的是Git,则还需要添加.git目录和.gitignore文件。

Save and close the file when you are finished.

完成后保存并关闭文件。

You are now ready to build the application image using the docker build command. Using the -t flag with docker build will allow you to tag the image with a memorable name. Because we are going to push the image to Docker Hub, let’s include our Docker Hub username in the tag. We will tag the image as nodejs-image-demo, but feel free to replace this with a name of your own choosing. Remember to also replace your_dockerhub_username with your own Docker Hub username:

现在,您可以使用docker build命令来构建应用程序映像了。 将-t标志与docker build一起使用将使您可以使用令人难忘的名称标记映像。 因为我们要将映像推送到Docker Hub,所以我们在标签中包含Docker Hub用户名。 我们将图像标记为nodejs-image-demo ,但是可以随意用自己选择的名称替换它。 记住还要用您自己的Docker Hub用户名替换your_dockerhub_username

  • sudo docker build -t your_dockerhub_username/nodejs-image-demo .

    sudo docker build -t your_dockerhub_username / nodejs-image-demo 。

The . specifies that the build context is the current directory.

. 指定构建上下文是当前目录。

It will take a minute or two to build the image. Once it is complete, check your images:

构建图像将需要一两分钟。 完成后,检查图像:

  • sudo docker images

    须藤码头工人图像

You will receive the following output:

您将收到以下输出:


   
   
Output
REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 8 seconds ago 73MB node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB

It is now possible to create a container with this image using docker run. We will include three flags with this command:

现在可以使用docker run使用该映像创建一个容器。 我们将在此命令中包含三个标志:

  • -p: This publishes the port on the container and maps it to a port on our host. We will use port 80 on the host, but you should feel free to modify this as necessary if you have another process running on that port. For more information about how this works, review this discussion in the Docker docs on port binding.

    -p :这将在容器上发布端口,并将其映射到我们主机上的端口。 我们将在主机上使用端口80 ,但是,如果在该端口上运行其他进程,则可以随意进行必要的修改。 有关其工作方式的更多信息,请查看Docker文档中有关端口绑定的讨论。

  • -d: This runs the container in the background.

    -d :这将在后台运行容器。

  • --name: This allows us to give the container a memorable name.

    --name :这使我们可以给容器起一个难忘的名称。

Run the following command to build the container:

运行以下命令来构建容器:

  • sudo docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

    sudo docker run --name nodejs-image-demo -p 80 :8080 -d your_dockerhub_username / nodejs-image-demo

Once your container is up and running, you can inspect a list of your running containers with docker ps:

容器启动并运行后,您可以使用docker ps检查正在运行的容器的列表:

  • sudo docker ps

    须藤码头工人ps

You will receive the following output:

您将收到以下输出:


   
   
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 8 seconds ago Up 7 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo

With your container running, you can now visit your application by navigating your browser to your server IP without the port:

在容器运行时,您现在可以通过浏览器导航到不带端口的服务器IP来访问应用程序:

http://your_server_ip

Your application landing page will load once again.

您的应用程序登录页面将再次加载。

Now that you have created an image for your application, you can push it to Docker Hub for future use.

现在,您已经为应用程序创建了映像,您可以将其推送到Docker Hub以供将来使用。

步骤4 —使用存储库处理图像 (Step 4 — Using a Repository to Work with Images)

By pushing your application image to a registry like Docker Hub, you make it available for subsequent use as you build and scale your containers. We will demonstrate how this works by pushing the application image to a repository and then using the image to recreate our container.

通过将应用程序映像推送到Docker Hub之类的注册表,您可以在构建和扩展容器时将其供以后使用。 我们将通过将应用程序映像推送到存储库,然后使用该映像重新创建我们的容器来演示其工作原理。

The first step to pushing the image is to log in to the Docker Hub account you created in the prerequisites:

推送映像的第一步是登录到您在先决条件中创建的Docker Hub帐户:

  • sudo docker login -u your_dockerhub_username

    sudo docker登录-u your_dockerhub_username

When prompted, enter your Docker Hub account password. Logging in this way will create a ~/.docker/config.json file in your user’s home directory with your Docker Hub credentials.

出现提示时,输入您的Docker Hub帐户密码。 以这种方式登录将使用Docker Hub凭据在用户的主目录中创建~/.docker/config.json文件。

You can now push the application image to Docker Hub using the tag you created earlier, your_dockerhub_username/nodejs-image-demo:

现在,您可以使用先前创建的标签your_dockerhub_username / nodejs-image-demo将应用程序映像推送到Docker Hub:

  • sudo docker push your_dockerhub_username/nodejs-image-demo

    sudo docker push your_dockerhub_username / nodejs-image-demo

Let’s test the utility of the image registry by destroying our current application container and image and rebuilding them with the image in our repository.

让我们通过销毁当前的应用程序容器和映像并使用存储库中的映像重建它们来测试映像注册表的实用程序。

First, list your running containers:

首先,列出您正在运行的容器:

  • sudo docker ps

    须藤码头工人ps

You will get the following output:

您将获得以下输出:


   
   
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 3 minutes ago Up 3 minutes 0.0.0.0:80->8080/tcp nodejs-image-demo

Using the CONTAINER ID listed in your output, stop the running application container. Be sure to replace the highlighted ID below with your own CONTAINER ID:

使用输出中列出的CONTAINER ID ,停止正在运行的应用程序容器。 请务必将下面突出显示的ID替换为您自己的CONTAINER ID

  • sudo docker stop e50ad27074a7

    须藤码头工人停止e50ad27074a7

List your all of your images with the -a flag:

使用-a标志列出所有图像:

  • docker images -a

    码头工人图像-a

You will receive the following output with the name of your image, your_dockerhub_username/nodejs-image-demo, along with the node image and the other images from your build:

您将收到以下输出,其中包含映像名称, your_dockerhub_username / nodejs-image-demo以及node映像和构建中的其他映像:


   
   
Output
REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 7 minutes ago 73MB <none> <none> 2e3267d9ac02 4 minutes ago 72.9MB <none> <none> 8352b41730b9 4 minutes ago 73MB <none> <none> 5d58b92823cb 4 minutes ago 73MB <none> <none> 3f1e35d7062a 4 minutes ago 73MB <none> <none> 02176311e4d0 4 minutes ago 73MB <none> <none> 8e84b33edcda 4 minutes ago 70.7MB <none> <none> 6a5ed70f86f2 4 minutes ago 70.7MB <none> <none> 776b2637d3c1 4 minutes ago 70.7MB node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB

Remove the stopped container and all of the images, including unused or dangling images, with the following command:

使用以下命令删除停止的容器和所有图像,包括未使用或悬空的图像:

  • docker system prune -a

    码头工人系统修剪-a

Type y when prompted in the output to confirm that you would like to remove the stopped container and images. Be advised that this will also remove your build cache.

在输出提示时输入y ,以确认您要删除停止的容器和图像。 请注意,这还将删除您的构建缓存。

You have now removed both the container running your application image and the image itself. For more information on removing Docker containers, images, and volumes, please review How To Remove Docker Images, Containers, and Volumes.

现在,您已经删除了运行应用程序映像的容器和映像本身。 有关删除Docker容器,映像和卷的更多信息,请查看如何删除Docker映像,容器和卷

With all of your images and containers deleted, you can now pull the application image from Docker Hub:

删除所有映像和容器后,您现在可以从Docker Hub中提取应用程序映像:

  • docker pull your_dockerhub_username/nodejs-image-demo

    docker pull your_dockerhub_username / nodejs-image-demo

List your images once again:

再次列出您的图片:

  • docker images

    码头工人图像

Your output will have your application image:

您的输出将包含您的应用程序映像:


   
   
Output
REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 11 minutes ago 73MB

You can now rebuild your container using the command from Step 3:

现在,您可以使用第3步中的命令来重建容器:

  • docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

    docker run --name nodejs-image-demo -p 80 :8080 -d your_dockerhub_username / nodejs-image-demo

List your running containers:

列出您正在运行的容器:

  • docker ps

    码头工人ps

   
   
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f6bc2f50dff6 your_dockerhub_username/nodejs-image-demo "node app.js" 4 seconds ago Up 3 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo

Visit http://your_server_ip once again to view your running application.

再次访问http:// your_server_ip以查看正在运行的应用程序。

结论 (Conclusion)

In this tutorial you created a static web application with Express and Bootstrap, as well as a Docker image for this application. You used this image to create a container and pushed the image to Docker Hub. From there, you were able to destroy your image and container and recreate them using your Docker Hub repository.

在本教程中,您使用Express和Bootstrap创建了一个静态Web应用程序,以及此应用程序的Docker映像。 您使用此映像创建了一个容器并将该映像推送到Docker Hub。 从那里,您可以销毁映像和容器,并使用Docker Hub存储库重新创建它们。

If you are interested in learning more about how to work with tools like Docker Compose and Docker Machine to create multi-container setups, you can look at the following guides:

如果您想了解更多有关如何使用Docker Compose和Docker Machine之类的工具来创建多容器设置的信息,可以查看以下指南:

For general tips on working with container data, check out:

有关使用容器数据的一般提示,请查看:

If you are interested in other Docker-related topics, please find our complete library of Docker tutorials.

如果您对其他与Docker相关的主题感兴趣,请找到我们完整的Docker教程库。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-build-a-node-js-application-with-docker-on-ubuntu-20-04

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值