九、部署 Deno 应用
部署是任何应用的关键部分。 我们可能会构建一个很棒的应用,遵循最佳实践,并编写测试,但最终,当它到达用户面前时,这才是它证明自己价值的地方。 因为我们希望这本书是一个关于应用所有不同阶段的旅程,所以我们将使用关于应用部署的这一章来结束这个循环。
请注意,我们没有——将来也不会提到部署是软件开发的最后阶段,而是将其作为将多次运行的周期的一个阶段。 我们真的相信部署不应该是每个人都害怕的事情。 相反,我们将它们视为我们向用户提供功能的激动人心的时刻。 这是大多数公司在现代软件项目中看待部署的方式,我们是这方面的真正倡导者。 部署应该是常规的、自动化的、易于操作的。 它们是向用户提供功能的第一步,而不是最后一步。
为了在应用中实现这种敏捷性和迭代速度,本章将重点学习容器以及如何使用它们部署 Deno 应用。
我们将利用容器化的好处来创建一个独立的环境来安装、运行和分发应用。
随着本章的继续,我们将学习如何使用 Docker 与git
一起创建一个自动化的工作流,以便在云环境中部署我们的 Deno 应用。 然后,我们将调整应用加载配置的方式,以支持基于环境的不同配置。
在本章结束时,我们将使应用在云环境中运行,并有一个自动化的流程,使我们能够发布它的迭代。
在本章中,你将熟悉以下主题:
- 为应用准备环境
- 为 Deno 应用创建
Dockerfile
- 在 Heroku 中构建和运行应用
- 配置应用以进行部署
技术要求
本章使用的代码可以在以下 GitHub 链接中找到:
https://github.com/PacktPublishing/Deno-Web-Development/tree/master/Chapter09
为应用准备环境
应用运行的环境总是对它有很大的影响。 “It works on my machine”的主要原因之一。 多年来,开发人员一直在创建尽可能减少这种情况的解决方案。 这些解决方案可以从自动为应用运行提供新的干净实例,到创建包含应用所依赖的所有内容的更完整的包。
我们可以参考虚拟机(虚拟机)或容器作为实现这一目标的方法。 两者都是同一问题的不同解决方案,但有一个共同点:资源隔离。 两者都试图将应用与其周围环境隔离开来。 这有很多原因,从安全性、自动化到可靠性。
容器是为应用提供包的一种现代方式。 现代软件项目使用它们来提供一个容器映像,其中包含了应用运行所需的几乎所有内容。
如果你不知道什么是容器,我将提供一个来自 Docker(一个容器引擎)官方网站的定义:
“容器是一个标准的软件单元,它打包了代码和它的所有依赖,所以应用从一个计算环境快速可靠地运行到另一个。”
为了使应用易于部署,我们将使用 Docker 为我们的 Deno 应用创建这个隔离层。
最终目标是创建一个映像,开发人员可以使用它来部署和测试应用的特定版本。 要使用 Docker 实现这一点,我们需要配置应用将运行的运行时。 这是在一个名为Dockerfile
的文件中定义的。
这就是我们接下来要学习的内容。
为 Deno 应用创建 Dockerfile
Dockerfile
将允许我们指定创建一个新的 Docker 映像所需的内容。 该映像将提供一个包含应用的所有依赖项的环境,该环境既可用于开发目的,也可用于生产部署。
在本节中,我们将学习如何为 Deno 应用创建一个 Docker 映像。 Docker 提供了一个基本映像,它基本上就是带有隔离的容器运行时,称为alpine
。 我们可以使用该映像、配置它、安装所需的所有工具和依赖项(即 Deno),等等。 然而,我认为我们不应该在这里重新发明轮子,因此我们使用了一个 Docker 社区形象。
即使这个映像解决了我们的许多问题,我们仍然需要根据我们的用例对它进行调整。 Dockerfiles 可以被组合,这意味着它们可以扩展其他 Docker 映像的功能,这就是我们将要使用的。
重要提示
你可以想象,我们不会深入探讨 Docker 的基本原理,因为这本身就是一本书。 如果您对 Docker 感兴趣,可以从官方文档(https://docs.docker.com/get-started/)的入门指南开始。 但是,如果您目前对 Docker 不是很满意,也不要担心,因为我们将充分解释它,让您理解我们在这里做什么。
在我们开始之前,请确保按照以下链接中列出的步骤在您的机器上安装 Docker Desktop:https://docs.docker.com/get-docker/。 在您安装并启动它之后,我们就拥有了创建第一个 Docker 映像所需的一切! 让我们按照以下步骤创建它:
- 创建一个
Dockerfile
在我们的项目的根。 -
As mentioned, we'll use an image from the community that already has Deno installed—
hayd/deno
(https://hub.docker.com/r/hayd/deno).该图像的版本控制方式与 Deno 相同,因此我们将使用版本
1.7.5.
。来自 Docker 的FROM
命令允许我们扩展图像,指定其名称和版本标签,如下代码片段所示:FROM hayd/alpine-deno:1.7.5
-
The next thing we need to do is to define, inside the container, the folder we'll be working on.
Docker 容器提供了一个 Linux 文件系统,默认的
workdir
是它的根(/
)。 来自 Docker 的WORKDIR
命令将允许我们从同一文件系统中的一个文件夹中工作,使事情更整洁一些。 命令可以在这里看到:WORKDIR /app
-
Now, we'll need to copy some files into our container image. With the help of the
COPY
command, we'll copy only the files we need for the installation step. In our case, these are thesrc/deps.ts
andlock.json
files, as illustrated in the following snippet:COPY lock.json . COPY src/deps.ts ./src/deps.ts
来自 Docker 的
COPY
命令允许我们指定一个文件从本地文件系统(第一个参数)复制到容器映像(最后一个参数),当前是app
文件夹。通过划分我们的工作流并只复制我们需要的文件,我们允许 Docker 只在涉及的文件发生变化时缓存和重新运行部分步骤。
-
Having the files inside the container, we now need to install the application dependencies. We'll use
deno cache
to do this, as follows:RUN deno cache --lock=lock.json --unstable ./src/deps.ts
因为我们正在安装不稳定的依赖项(比如
deno-mongo
),并且还使用了lock
文件,所以我们必须传递额外的标志。Docker 的
RUN
命令使我们能够在容器中运行这个特定的命令。 -
Dependencies installed, we now need to copy the application's code into the container. One more time, we'll use Docker's
COPY
command for that, as shown here:COPY . .
这将从当前的本地文件夹复制所有内容到容器内的
workdir
(/app
文件夹)。 -
The last thing we'll need to do for our image to work out of the box is introduce a command that will run whenever someone "executes" this image. We'll use Docker's
CMD
command to do this, as illustrated in the following snippet:CMD ["deno", "run", "--allow-net", "--unstable", "--allow-env", "--allow-read", "--allow-write", "--allow-plugin", "src/index.ts" ]
该命令接受一组命令和参数,当有人试图运行我们的映像时将执行这些命令和参数。
这应该就是定义 Deno 应用 Docker 映像所需要的全部内容! 拥有这些功能将使我们能够以在生产环境中运行代码的方式在本地运行代码,这在调试和调查生产环境问题时是一个很大的优势。
我们唯一缺少的是生成工件的实际步骤。
我们将使用来自 Docker命令行界面(CLI)的build
命令来构建映像。 我们将使用-t
标志来设置标签。 按照以下步骤生成工件:
-
Inside the project folder, run the following command to generate the tag for the image:
$ docker build -t museums-api:0.0.1 .
你可以使用任何你想要的图像名称(我在这个例子中使用了
museums-api
),并选择你想要的版本(0.0.1
在例子中)。这将产生以下输出:
$ docker build -t museums-api:0.0.1 . Sending build context to Docker daemon 11.35MB Step 1/7 : FROM hayd/alpine-deno:1.7.5 … Step 2/7 : WORKDIR /app … Step 3/7 : COPY lock.json . … Step 4/7 : COPY src/deps.ts ./src/deps.ts … Step 5/7 : RUN deno cache --lock=lock.json --unstable ./src/deps.ts … Step 6/7 : COPY . . … Step 7/7 : CMD ["deno", "run", "--allow-net", "--unstable", "--allow-env", "--allow-read", "--allow-write", "--allow-plugin", "src/index.ts" ] … Successfully built c3fa043b1440 Successfully tagged museums-api:0.0.1
我们有图像,
museums-api:0.0.1
。 我们现在可以在私有的映像注册表中发布它,或者使用公共的映像注册表,比如 Docker Hub。 我们将在后面设置的持续集成(CI)管道将被配置为自动执行此构建步骤。我们现在可以做的是在本地运行这个映像,以验证一切都按照预期工作。
-
To run the image locally, we'll use the Docker CLI
run
command.当我们处理一个 web 应用时,我们需要暴露它运行的端口(在应用的
configuration
文件中设置)。 我们将告诉 Docker 使用-p
标志将容器端口绑定到我们机器的端口,如下面的代码片段所示:$ docker run -p 8080:8080 museums-api:0.0.1 Download https://deno.land/std@0.83.0/encoding/hex.ts Download https://deno.land/std@0.83.0/hash/mod.ts Download https://deno.land/std@0.83.0/hash/_wasm/hash.ts Download https://deno.land/std@0.83.0/hash/hasher.ts Download https://deno.land/std@0.83.0/hash/_wasm/wasm.js Download https://deno.land/std@0.83.0/encoding/hex.ts Download https://deno.land/std@0.83.0/encoding/base64.ts Check file:///app/src/index.ts INFO downloading deno plugin "deno_mongo" from "https://github.com/manyuanrong/deno_mongo/releases/download/v0.13.0/libdeno_mongo.so" INFO load deno plugin "deno_mongo" from local "/app/.deno_plugins/deno_mongo_3bbff9a1cd76f3d988b3ca28c7163c3f.so" Application running at http://localhost:8080
这将执行
museums-api
映像的0.0.1
版本,将8080
容器端口绑定到8080
主机端口。 现在我们可以转到http://localhost:8080
,查看应用正在运行。
稍后,我们将在 CI 系统中使用此映像定义,该系统将在代码更改时创建映像并将其推入生产环境。
拥有一个包含应用的 Docker 映像可以有多种用途。 其中之一是本章的目标:部署它; 然而,同样的 Docker 映像也可以用于运行和调试特定版本的应用。
让我们学习如何在应用的特定版本中运行终端,这是一个非常常见的调试步骤。
在集装箱内运行终端
我们可以用 Docker 映像做的另一件有用的事情是在它里面执行一个终端。 这可能用于调试目的或在应用的特定版本中尝试一些东西。
我们可以像前面一样使用相同的命令,并使用两个不同的标志。
我们将使用-it
标志,这将允许我们有一个交互式连接到图像内部的终端。 我们还将作为参数发送要首先在图像中执行的命令的名称。 在本例中,它是标准的 Unix shellsh
,您可以在以下示例中检查:
$ docker run -p 8080:8080 -it museums-api:0.0.1 sh
这将运行museums-api:0.0.1
映像,将其8080
端口绑定到主机上的8080
端口,并使用交互式终端在其中执行sh
命令,如下面的代码片段所示:
$ docker run -p 8080:8080 -it museums-api:0.0.1 sh
/app # ls
Dockerfile certificate.pem config.staging.yaml index.html lock.json
README.md config.dev.yaml heroku.yml key.pem src
注意,shell 最初打开的文件夹就是我们定义的WORKDIR
文件夹,所有文件都在那里。 在前面的示例中,我们还在执行ls
命令。
由于我们在这个容器上附加了一个交互式 shell,我们可以使用它来运行一个 Deno 命令,例如,如下面的代码片段所示:
/app # deno --version
deno 1.7.2 (release, x86_64-unknown-linux-gnu)
v8 8.9.255.3
typescript 4.1.3
/app #
这为开发和调试提供了一整套可能性,因为我们将能够检查应用在特定版本中的运行情况。
这部分我们已经讲完了。 在这里,我们已经探索了容器化,介绍了 Docker 以及它如何让我们创建一个“应用包”。 这个包将负责应用周围的环境,确保它将在任何有 Docker 运行时的地方运行。
在下一节中,我们将使用相同的包在云环境中部署本地构建的映像。 我们走吧!
在 Heroku 中构建和运行应用
正如我们在本章开始时提到的,我们最初的目标是用一种简单、自动化和可复制的方式部署应用。 在上一节中,我们创建了容器映像作为该映像的基础。 下一步是创建管道,在有更新时构建和部署我们的代码。 我们将使用git
作为真相和机制的来源来触发管道构建。
我们将部署代码的平台是 Heroku。 这是一个旨在简化开发人员和公司在部署过程中的任务的平台,它提供了一组工具,消除了常见的障碍,如提供机器和设置大型 CI 基础设施。 通过使用这样一个平台,我们可以更专注于应用和 Deno,这也是本书的目的。
在这里,我们将使用之前创建的Dockerfile
,并对其进行设置,以便在 Heroku 上部署和运行。 我们将看到设置应用在那里运行是多么容易,稍后我们还将探讨如何通过环境变量定义配置值。
在我们开始之前,请确保您已经创建了一个帐户,并安装了 Heroku CLI,然后我们继续一步一步的指导,通过这里提供的两个链接:
现在我们已经创建了一个帐户并安装了 CLI,我们可以开始在 Heroku 中设置我们的项目了。
在 Heroku 中创建应用
在这里,我们将介绍在 Heroku 中验证和创建应用所需的步骤。 我们差不多准备开始了,但还有一件事我们得先说清楚。
重要提示
由于 Heroku 使用git
作为事实来源,因此您将而不是能够在本书的文件存储库中执行以下过程,因为它已经是一个包含应用多个阶段的 Git 存储库。
我建议您将应用文件复制到图书库之外的文件夹中,然后从那里开始这个过程。
你可以复制最新版本的应用从第八章,【T5 -单元测试和集成测试】(https://github.com/PacktPublishing/Deno-Web-Development/tree/master/Chapter08/sections/7-final-tested-version/museums-api),这是一个我们将使用。
现在,文件已经复制到一个新文件夹(主存储库外),让我们按照以下步骤部署Dockerfile
并在 Heroku 上运行:
- 我们要做的第一件事是登录 CLI,运行
heroku login
。 这将打开一个浏览器窗口,您可以在其中插入您的用户名和密码,如下面的代码片段所示: - 由于 Heroku 的部署是基于
git
的,由于我们现在在一个不是 Git 仓库的文件夹中,我们需要初始化它,如下所示: -
Then, we will create our application in Heroku by using
heroku create
, as follows:$ heroku create Creating app... done, boiling-dusk-18477 https://boiling-dusk-18477.herokuapp.com/ | https://git.heroku.com/boiling-dusk-18477.git
您可能已经注意到,在创建应用时,Heroku CLI 会自动在当前文件夹中创建一个 Git 存储库。 Heroku 自动创建了一个名为
heroku
的远程存储库,我们必须在这里推送代码以触发部署过程。
如果您在运行上述命令后进入 Heroku Dashboard,您会注意到那里有一个新应用。 当应用被创建时,Heroku 在控制台上打印一个 URL; 然而,由于我们还没有配置任何东西,我们的应用还不可用。
接下来我们需要做的是配置 Heroku,以便它知道应该在每个部署中构建和执行我们的映像。
构建并运行 Docker 镜像
默认情况下,Heroku 只是试图通过运行代码来使应用可用。 对于许多语言来说,这是可能的,你可以在 Heroku 文档中找到相关指南。 因为我们希望使用容器来运行应用,所以这个过程需要更多的配置。
Heroku 提供了一组特性,允许我们通过一个名为heroku.yml
的文件定义代码发生变化时发生的情况。 这就是我们现在要创建的,如下所示:
- 在存储库的根目录下创建一个
heroku.yml
文件,并在那里添加以下代码行,这样它就可以使用 Docker 构建我们的映像,使用我们在上一节中创建的Dockerfile
: -
Now, in the same file, add the following lines of code to define the command that will be executed by Heroku to run the application:
build: docker: web: Dockerfile run: web: deno run --allow-net --unstable --allow-env --allow-read --allow-write --allow-plugin src/index.ts
您可能会注意到,这正是我们在
Dockerfile
中定义的命令,这是正确的。通常,Heroku 会从
Dockerfile
运行命令来执行映像,并且也会工作。 碰巧 Heroku 不以 root 身份运行这些命令,这是安全最佳实践。 在当前阶段,无论何时您想要使用插件(一个不稳定的特性),Deno 都需要根特权。由于我们的应用使用插件连接和 MongoDB,我们需要在
heroku.yml
上明确定义这个命令,以便它以 root 权限运行,并在 Deno 启动应用时工作。 -
The next thing we'll have to do is to set the application type to
container
, informing Heroku that's how we want this application to run. The code for this is shown in the following snippet:$ heroku stack:set container Setting stack to container... done
这就是 Heroku 配置文件。 还有许多其他的选项,可以添加,如上所述的文档(https://devcenter.heroku.com/articles/build-docker-images-heroku-yml heroku-yml-overview),用来做一些更具体的,但这是我们当前的用例。
我们需要做的下一件事情是添加所有的文件从这个新的存储库(包括
heroku.yml
文件)到版本控制,并将其推到 Heroku,以便它开始构建。 -
添加所有文件,以确保
git
正在跟踪它们: -
Commit all the files with a message, as follows:
$ git commit -m "Configure heroku" (root-commit) 9340446] Configure heroku 34 files changed, 1465 insertions(+) create mode 100644 …
我们使用的
-m
标志是一个命令,它允许我们创建一个带有简短语法的消息的提交。 -
Now, it's a matter of pushing the files to the
heroku
remote.这应该会触发 Docker 映像的构建过程,因为您可以签入日志。 在最后阶段,这个图像被推入 Heroku 的内部图像注册表,如下面的代码片段所示:
$ git push heroku master Enumerating objects: 42, done. Counting objects: 100% (42/42), done. Delta compression using up to 8 threads Compressing objects: 100% (41/41), done. Writing objects: 100% (42/42), 2.87 MiB | 1.22 MiB/s, done. Total 42 (delta 0), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: === Fetching app code remote: remote: === Building web (Dockerfile) remote: Sending build context to Docker daemon 7.865MB remote: Step 1/7 : FROM hayd/alpine-deno:1.7.2 remote: 1.3.0: Pulling from hayd/alpine-deno …
在这里,您可以看到,它开始构建,
Dockerfile
,遵循所有步骤指定,正如我们在本地构建图像时所发生的,如下代码片段所示:remote: === Pushing web (Dockerfile) remote: Tagged image "5c154f3fcb23f3c3c360e16e929c22b62847fcf8" as "registry.heroku.com/boiling-dusk-18477/web" remote: Using default tag: latest remote: The push refers to repository [registry.heroku.com/boiling-dusk-18477/web] remote: 6f8894494a30: Preparing remote: f9b9c806573a: Preparing
它应该能工作,对吧? 嗯……,不是真的。 我们还需要配置一些东西,但我们快完成了。
请记住,我们的应用依赖于配置,而配置的一部分来自环境。 Heroku 没有办法知道我们需要哪些配置值。 我们仍然需要配置一些设置以使应用工作,这就是我们接下来要做的。
配置用于部署的应用
我们现在有一个应用,当代码被推送到git
时,就会启动构建映像并部署它的过程。 我们的应用目前已经部署,但它实际上并没有工作,这是因为它缺乏配置。
您可能注意到的第一件事是,我们的应用总是从开发中加载配置文件config.dev.yml
,它不应该这样做。
当我们第一次实现时,我们认为不同的环境会有不同的配置,我们是对的。 当时,我们不需要为多个环境配置,我们使用dev
作为默认配置。 让我们解决这个问题。
还记得当我们创建加载配置的函数时,我们显式地为环境使用了一个参数吗? 我们当时没有使用它,但是我们留下了一个默认值。
请看以下来自src/config/index.ts
的代码片段:
export async function load(
env = "dev",
): Promise<Configuration> {
我们需要做的是更改它,使它支持多个环境。 所以,让我们按照以下步骤来做:
-
Go back into
src/index.ts
and make sure we're sending the environment variable namedDENO_ENV
to theload
function, as illustrated in the following code snippet:const config = await loadConfiguration(Deno.env.get("DENO_ENV"));
这将使应用在开发时运行良好,因为
DENO_ENV
没有定义,并且允许我们在生产中加载不同的配置文件。 -
Create the production configuration file,
config.production.yml
.目前,除了
port
之外,它与config.dev.yml
没有太大区别。 让我们在产品的9001
端口运行它,如下所示:web: port: 9001
为了在本地测试,我们可以将
DENO_ENV
变量设置为production
运行应用,如下所示:$ DENO_ENV=production deno run --allow-net --unstable --allow-env --allow-read --allow-write --allow-plugin src/index.ts Application running at http://localhost:9001
如果你在 Windows 上运行,你需要使用不同的语法来设置环境变量(比如
DENO_ENV
)。 我们提到如何在第七章【4】【5】,HTTPS,提取配置,和在浏览器中 Deno,在【显示】部分访问秘密值。在运行它之后,我们可以确认它正在加载正确的文件,因为应用端口现在是
9001
。
通过刚刚实现的内容,我们现在能够根据环境控制加载哪些配置值。 这是我们已经在本地测试过的,但我们还没有在 Heroku 上做过。
我们已经解决了部分问题——根据环境加载不同的配置文件,但是应用依赖于来自环境的其他配置值。 这些是机密值,如JSON Web Token(JWT)密钥或 MongoDB 凭据。
有许多方法可以做到这一点,所有的云提供商都提供了一个解决方案。 在 Heroku 中,我们可以通过使用config
命令做到这一点,如下所示:
-
Define the MongoDB credential variables, the JWT key, and the environment using the
heroku config:set
command, as follows:$ heroku config:set MONGODB_PASSWORD=your-password MONGODB_USERNAME=your-username JWT_KEY=your-jwt-key DENO_ENV=production Setting MONGODB_PASSWORD, MONGODB_USERNAME, JWT_KEY, DENO_ENV and restarting boiling-dusk-18477... done, v7 DENO_ENV: production JWT_KEY: your-jwt-key MONGODB_PASSWORD: your-password MONGODB_USERNAME: your-username
请注意,我们还定义了
DENO_ENV
变量,以便应用在 Heroku 中运行时知道它是生产环境。如果你不使用自己的 MongoDB 集群和对其凭证有问题,你可以回到第六章,添加身份验证和连接到数据库,我们创建了一个 MongoDB 集群在 MongoDB 地图集。
如果你使用的是不同的集群,记住它是在
config.production.yml
的配置文件中定义的,而不是在环境中定义的,因此你需要在配置文件中添加你的集群 URL 和数据库,如下所示:*… mongoDb: clusterURI: <add your cluster url> database: <add your database name>*
* 再次,我们将添加我们的更改到git
,如下: And then, we'll push the changes to Heroku to trigger the deployment process, as follows:
```
$ git push heroku master
…
remote: Verifying deploy... done.
To https://git.heroku.com/boiling-dusk-18477.git
9340446..36a061e master -> master
```
它应该是工作的。 如果我们现在去 Heroku 仪表板(https://dashboard.heroku.com/),然后到我们的应用的仪表板([https://dashboard.heroku.com/apps/boiling -黄昏- 18477](https://dashboard.heroku.com/apps/boiling-dusk-18477),就我而言),然后单击**打开应用**按钮,应该开放我们的应用,对吗?
还没有,但我们差不多到了——我们还需要解决一件事。*
*## 从环境获取应用端口
在运行 Docker 映像时,Heroku 有一些特殊之处。 它不允许我们设置应用运行的端口。 它是指定一个端口的应用应该运行,然后定向超文本传输协议(HTTP)和超文本传输协议安全(【显示】HTTPS)交通从应用的 URL。 如果还是觉得奇怪,别担心——我们会做到的。
**如您所知,我们在config.production.yml
文件中明确定义了应用将要运行的端口。 我们需要适应这一点。
Heroku 定义应用应该在哪个端口上运行的方法是设置PORT
环境变量。 以下链接记录了这一点:
https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime
你可能会从标题中知道我们接下来要做什么。 我们将改变我们的应用,使来自环境的 web 服务器端口覆盖配置文件中定义的端口。
回到应用中的src/config/index.ts
,确保它正在从环境中读取PORT
变量,覆盖来自文件的配置。 代码可以在以下代码片段中看到:
type Configuration = {
web: {
port: number;
};
cors: {
…
export async function load(
env = "dev",
): Promise<Configuration> {
const configuration = parse(
await Deno.readTextFile(`./config.${env}.yaml`),
) as Configuration;
return {
...configuration,
web: {
...configuration.web,
port: Number(Deno.env.get("PORT")) ||
configuration.web.port,
},
…
通过这种方式,我们可以确保从PORT
环境变量中读取变量,并使用配置文件中的值作为默认值。
而这应该是让我们的应用在 Heroku 顺利运行的全部!
再一次,我们可以通过去测试这个 Heroku 仪表板(https://dashboard.heroku.com/apps/boiling -黄昏- 18477),单击打开应用按钮,或者你可以直接通过 url 我来说,这是https://boiling——黄昏- 18477. - herokuapp.com/【5】。
重要提示
如果您正在使用 MongoDB 地图集,正如我们在第六章,添加身份验证和连接到数据库,并允许您的应用访问数据库,您需要配置它使连接“任何地方”。 如果你要将应用展示给用户,这是不推荐的做法,因为我们使用的是 Heroku 的 Free Tier。 它运行在一个共享的集群,我们没有办法知道什么固定互联网协议(【显示】IP)地址的机器运行应用,我们需要这样做。**
下面的链接演示了如何配置网络访问数据库:https://docs.atlas.mongodb.com/security/ip-access-list。 请确保您在 MongoDB Atlas 网络访问屏幕中点击ALLOW ACCESS FROM ANYWHERE**。
这是网络接入屏幕的样子:
图 9.1 - MongoDB Atlas 网络访问界面
在此之后,我们的应用应该按照预期工作; 您可以尝试执行一个注册用户(连接到数据库)的请求,并检查是否一切正常,如下面的代码片段所示:
$ curl -X POST -d '{"username": "test-username-001", "password": "testpw1" }' -H 'Content-Type: application/json' https://boiling-dusk-18477.herokuapp.com/api/users/register
{"user":{"username":"test-username-001","createdAt":"2020-12-19T16:49:51.809Z"}}%
如果您得到了与前一个类似的响应,那么您就万事俱备了! 我们设法在云环境中配置和部署我们的应用,并创建了一种自动向用户发布更新的方法。
为了执行最终测试以检查代码是否成功部署,我们可以尝试更改部分代码并再次触发部署过程。 让我们做它! 进行如下:
- 将
src/web/index.ts
中的"Hello World"
消息更改为"Hello Deno World!"
,如下代码片段所示: - 将此更改添加到版本控制中,如下所示:
-
将其推入 Heroku 的
git
远程存储库,如下:$ git push heroku master Enumerating objects: 9, done. Counting objects: 100% (9/9), done. Delta compression using up to 8 threads Compressing objects: 100% (5/5), done. Writing objects: 100% (5/5), 807 bytes | 807.00 KiB/s, done. Total 5 (delta 4), reused 0 (delta 0) remote: Compressing source files… Done … remote: Verifying deploy... done. To https://git.heroku.com/boiling-dusk-18477.git
-
如果我们现在访问应用 URL(在我们的示例中是https://boiling-dusk-18477.herokuapp.com/),您应该得到
Hello Deno World
消息。
这个意味着我们的应用已经成功部署。 因为我们使用的云平台提供的功能比我们在这里学到的要多,所以我们可以探索其他 Heroku 特性,比如日志记录。
在 Heroku Dashboard(https://dashboard.heroku.com/)的打开 app按钮旁边,有一个More按钮。 其中一个选项是查看日志,如下截图所示:
图 9.2 - Heroku Dashboard 中的更多应用选项
如果单击此处,将出现实时显示日志的界面。 你可以尝试通过打开你的应用在一个不同的标签(通过点击打开应用按钮)。
你会看到日志立即更新,像这样的东西应该出现在那里:
2020-12-19T17:04:23.639359+00:00 app[web.1]: GET http://boiling-dusk-18477.herokuapp.com/ - 1ms
当您希望非常轻松地监控应用的运行情况时,这是非常有用的。 日志功能是在自由层中提供的,但是还有更多的功能你可以探索,比如Metrics,我们在这里就不做了。
如果你想详细了解你的应用是什么时候被谁部署的,你也可以使用 Heroku Dashboard 的Activity部分,如下面的截图所示:
图 9.3 - Heroku Dashboard 应用选项
然后你会看到最新部署的日志,这是 Heroku 的另一个非常有趣的特性,如下面的截图所示:
图 9.4 - Heroku Dashboard 应用中的 Activity 选项卡
关于在云环境中部署应用的部分到此结束。
我们将重点放在应用和能够且将能够独立于代码运行的平台重用的主题上。 我们已经迭代了加载配置的应用逻辑,以便它可以根据环境加载不同的配置。
然后,我们学习了如何将带有秘密配置值的环境变量发送到应用,最后我们探索了本例选择的平台 heroku 上的日志记录——就是这样。
我们设法让我们的应用运行起来,并围绕它创建了一个完整的基础设施,这将使未来的迭代能够轻松地交付给我们的用户。 希望我们已经完成了您下次决定部署 Deno 应用时也将经历的一些阶段。
小结
我们差不多完成了! 本章通过部署我们的应用来完成开发阶段的循环。 我们从构建一个非常简单的应用,到添加功能,再到添加测试,最后到部署它。
在这里,我们了解了如何在应用中使用容器化的一些好处。 我们开始学习 Docker(首选的容器运行时),并迅速转向为应用创建映像。 在整个过程中学习了一些 Docker 命令,我们也体验到了准备部署一个 Deno 应用是多么容易。
创建这个 Docker 映像使我们能够以一种可复制的方式安装、运行和分发应用,并创建一个包含应用所需一切内容的包。
随着本章的继续,我们开始探索如何使用这个应用包在云环境中部署它。 我们从配置这个分步指南 Heroku 所选择的云平台开始,这样它就会在每次应用更改时重新构建并运行我们的代码,在git
和 Heroku 文档的帮助下,我们非常容易地完成了它。
随着自动化管道的配置,我们理解了将配置值发送到应用的必要性。 这些相同的配置值(我们在前面的章节中实现过)需要通过两种不同的方式发送到应用,即通过配置文件和环境。 我们解决了这些需求中的每一个,首先迭代应用代码,以便根据环境加载不同的配置,然后学习如何在 Heroku 上的应用中设置配置值。
我们最终让我们的应用完美地运行,并完成了本章的目标:有一个可复制的、自动化的方式将代码部署给我们的用户。 与此同时,我们了解了 Docker 以及在发布代码时容器化和自动化的好处。
这差不多就是这本书的目标了。 我们决定把这变成一个构建应用的旅程,分别经历它的所有阶段,并根据需要解决它们。 这是部署它的最后一个阶段,希望为您结束从第一行代码到部署的循环。
下一章将集中讨论当涉及到 Deno 时接下来会发生什么,对运行时和您个人来说都是如此。 我希望这让你成为了一名 Deno 爱好者,你和我一样对它和它打开的可能性的世界感到兴奋。*
版权属于:月萌API www.moonapi.com,转载请注明出处