介绍 (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:
要遵循本教程,您将需要:
One Ubuntu 20.04 server, set up following this Initial Server Setup guide.
按照此初始服务器设置指南设置一台Ubuntu 20.04服务器。
Docker installed on your server, following Steps 1 and 2 of How To Install and Use Docker on Ubuntu 20.04.
遵循如何在Ubuntu 20.04上安装和使用Docker的步骤1和2,在您的服务器上安装Docker 。
Node.js and npm installed, following these instructions on installing with the PPA managed by NodeSource.
按照以下有关由NodeSource管理的PPA进行安装的说明,安装了 Node.js和npm。
A Docker Hub account. For an overview of how to set this up, refer to this introduction on getting started with Docker Hub.
Docker Hub帐户。 有关如何进行设置的概述,请参阅Docker Hub入门简介 。
第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:
添加有关项目的以下信息,包括其名称,作者,许可证,入口点和依赖项。 确保用您自己的姓名和联系方式替换作者信息:
{
"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对象,并将基本目录和端口定义为常量:
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
模块,然后我们将其用于创建app
和router
对象。 router
对象将执行应用程序的路由功能,并且当我们定义HTTP方法路由时,我们会将它们添加到该对象中以定义我们的应用程序将如何处理请求。
This section of the file also sets a couple of constants, path
and port
:
该文件的这一部分还设置了两个常量, path
和port
:
path
: Defines the base directory, which will be theviews
subdirectory within the current project directory.path
:定义基本目录,它将是当前项目目录中的views
子目录。port
: Tells the app to listen on and bind to port8080
.port
:告诉应用监听并绑定到端口8080
。
Next, set the routes for the application using the router
object:
接下来,使用router
对象设置应用程序的router
:
...
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
:
...
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
文件将如下所示:
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
信息页面的链接:
<!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
定义的路由匹配:
...
<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:
此外,我们还在巨型按钮中创建了指向鲨鱼信息页面的链接:
...
<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:
标头中还有一个指向自定义样式表的链接:
...
<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和自定义样式表,并向用户提供有关某些鲨鱼的详细信息:
<!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.html
和sharks.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:
添加以下代码,这将为我们的页面设置所需的颜色和字体:
.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
指令以设置应用程序的基本映像:
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/node
和app
目录中创建node_modules
子目录。 创建这些目录将确保它们具有我们想要的权限,这对于使用npm install
在容器中创建本地节点模块时非常重要。 除了创建这些目录,我们还将对节点用户设置其所有权:
...
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
:
...
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.json
和package-lock.json
(适用于npm 5+)文件:
...
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
之前将用户切换到节点 :
...
USER node
After copying the project dependencies and switching our user, we can run npm install
:
复制项目依赖项并切换我们的用户后,我们可以运行npm install
:
...
RUN npm install
Next, copy your application code with the appropriate permissions to the application directory on the container:
接下来,将具有适当权限的应用程序代码复制到容器上的应用程序目录:
...
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
并启动应用程序:
...
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如下所示:
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_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 port80
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之类的工具来创建多容器设置的信息,可以查看以下指南:
How To Provision and Manage Remote Docker Hosts with Docker Machine on Ubuntu.
For general tips on working with container data, check out:
有关使用容器数据的一般提示,请查看:
How To Share Data Between the Docker Container and the Host.
If you are interested in other Docker-related topics, please find our complete library of Docker tutorials.
如果您对其他与Docker相关的主题感兴趣,请找到我们完整的Docker教程库。