编辑此页面

部署到 Heroku

在本指南中,您将学习如何将基于 Quarkus 的 Web 应用程序作为 Web dyno 部署到 Heroku。

本指南涵盖

  • 更新 Quarkus HTTP 端口

  • 安装 Heroku CLI

  • 将应用程序部署到 Heroku

  • 将应用程序作为容器镜像部署到 Heroku

    • 使用 Docker

    • 使用 Podman

  • 将原生应用程序作为容器镜像部署到 Heroku

先决条件

要完成本指南,您需要

  • 所有方式大约需要 1 小时

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 如果您想使用它,可以选择 Quarkus CLI

  • 一个 Heroku 帐户。您至少需要一个 Eco 帐户才能部署应用程序。

  • 已安装 Heroku CLI

简介

Heroku 是一个平台即服务 (PaaS),使开发人员能够在云中完全构建、运行和运营应用程序。 它支持多种语言,如 Java、Ruby、Node.js、Scala、Clojure、Python、PHP 和 Go。 此外,它还提供了一个容器注册表,可用于部署预构建的容器镜像。

可以使用不同的方式使用 Heroku 运行 Quarkus 应用程序

  • 作为在 Heroku 环境定义的容器中运行的普通 Java 程序

  • 作为在 Quarkus 构建过程定义的容器中运行的容器化 Java 程序

  • 作为在 Quarkus 构建过程定义的容器中运行的容器化原生程序

所有这三种方法都需要注意 Heroku 分配给它的用于处理流量的端口。 幸运的是,有一个动态配置属性可以实现这一点。

通用项目设置

本指南将采用使用 Quarkus 工具创建的简单应用程序作为输入

CLI
quarkus create app org.acme:getting-started-with-heroku
cd getting-started-with-heroku

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=getting-started-with-heroku
cd getting-started-with-heroku

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数用双引号括起来,例如 "-DprojectArtifactId=getting-started-with-heroku"

此命令将在 getting-started-with-heroku 目录中创建一个新的 REST 应用程序。

让我们将此应用程序创建为一个 Git 存储库

  1. 更改到应用程序目录:cd getting-started-with-heroku

  2. 初始化一个新的 Git 存储库:git init -b main

  3. 将所有文件添加到存储库:git add .

  4. 提交文件:git commit -a -m 'Initial copy of getting-started'

Heroku 可以对存储库中的更改做出反应,运行 CI 并在您的代码更改时重新部署您的应用程序。 因此,我们从一个有效的存储库开始。

另外,请确保您的 Heroku CLI 工作正常

heroku --version
heroku login

准备 Quarkus HTTP 端口

Heroku 选择一个随机端口并将其分配给最终运行您的 Quarkus 应用程序的容器。 该端口作为环境变量在 $PORT 下可用。 在所有部署方案中,使 Quarkus 了解它的最简单方法是使用以下配置

quarkus.http.port=${PORT:8080}

这可以理解为:“如果定义了 $PORT 变量,则侦听该端口,否则像往常一样侦听 8080。” 运行以下命令将其添加到您的 application.properties

echo "quarkus.http.port=\${PORT:8080}" >> src/main/resources/application.properties
git commit -am "Configure the HTTP Port."

部署存储库并在 Heroku 上构建

第一种变体使用 Quarkus Maven 构建来创建 quarkus-app 应用程序结构,其中包含可运行的“fast-jar”以及 Heroku 构建基础设施中所需的所有库,然后部署该结果,另一种变体使用本地构建过程来创建优化的容器。

对于第一种变体,您的应用程序的根目录中需要两个额外的文件

  • system.properties 用于配置 Java 版本

  • Procfile 用于配置 Heroku 如何启动您的应用程序

Quarkus 需要 JDK 17,因此我们首先指定它

echo "java.runtime.version=17" >> system.properties
git add system.properties
git commit -am "Configure the Java version for Heroku."

我们将部署一个 Web 应用程序,因此我们需要在 Heroku Procfile 中配置 web 类型,如下所示

echo "web: java \$JAVA_OPTS -jar target/quarkus-app/quarkus-run.jar" >> Procfile
git add Procfile
git commit -am "Add a Procfile."

您的应用程序应该已经可以通过存储库根目录中的 heroku local web 运行。 您需要在之前运行 mvn package 才能成功创建可运行的 jar。

现在让我们在您的帐户中创建一个应用程序并将该存储库部署到它

heroku create

这将在您的 Heroku 帐户中创建一个远程存储库,并且它还应该已将一个 heroku 远程 URL 添加到您的本地存储库,您可以使用 git remote -v 查看它

starksm@Scotts-Mac-Studio getting-started % git remote -v
heroku	https://git.heroku.com/young-shelf-58876.git (fetch)
heroku	https://git.heroku.com/young-shelf-58876.git (push)

现在您可以将您的应用程序推送到 Heroku 并在浏览器中打开它。

git push heroku main
heroku open hello

该应用程序将具有一个生成的 URL,并且终端应该输出该 URL。 heroku open hello 打开您的默认浏览器以使用 '/hello' 上下文访问您的新应用程序。 该页面应输出文本“hello”。

要通过 curl 访问 REST 端点,请从 heroku info 命令获取应用程序 URL

heroku info | grep  "Web URL:"
APP_NAME=<https url info>
curl $APP_NAME/hello

当然,您也可以使用 Heroku CLI 将此存储库连接到您的 GitHub 帐户,但这不在本指南的范围之内。

作为容器部署

推送整个容器的优点是我们可以完全控制其内容,甚至可以选择部署一个在 GraalVM 上运行本机可执行文件的容器。

首先,登录到 Heroku 的容器注册表

heroku container:login

我们需要向我们的项目添加一个扩展,以添加构建容器镜像的功能

CLI
quarkus extension add container-image-docker
Maven
./mvnw quarkus:add-extension -Dextensions='container-image-docker'
Gradle
./gradlew addExtension --extensions='container-image-docker'

然后,让我们提交此更改

git add pom.xml
git commit -am "Add container-image-docker extension."

我们将要构建的镜像需要根据 Heroku 的注册表和部署进行命名。 我们通过 heroku info 获取生成的名称并将其传递给(本地)构建

APP_NAME=`heroku info | grep  "=== .*" |sed "s/=== //"`
./mvnw clean package\
  -Dquarkus.container-image.build=true\
  -Dquarkus.container-image.group=registry.heroku.com/$APP_NAME\
  -Dquarkus.container-image.name=web\
  -Dquarkus.container-image.tag=latest

推送和发布镜像

您现在可以推送镜像并发布它。

初始推送相当大,因为需要传输镜像的所有层。 以下推送将更小。

通过 Docker 推送

安装 Docker 后,这些步骤很简单

docker push registry.heroku.com/$APP_NAME/web
heroku stack:set container
heroku container:release web --app $APP_NAME

通过 Podman 推送

当您想使用 Podman 作为 Docker 的替代品时,您会遇到一些问题,因为 Heroku CLI 依赖于 Docker 并且不支持 OCI 格式。 但是,这些问题有可能的解决方案。

找不到 docker,请确保已安装 docker。

问题显然是 heroku-cli 找不到 docker。 这很容易解决,因为 podman cli 与 docker 兼容。 我们只需要创建一个从 podman 到 docker 的符号链接

sudo ln -s $(which podman) /usr/local/bin/docker
Error writing manifest: Error uploading manifest latest to registry.heroku.com/$APP_NAME/web: unsupported

为了通过 Podman 和 Heroku CLI 以所需的格式(v2s2 - Docker Image Manifest Version 2, Schema 2)推送和发布我们的应用程序,我们必须使用一种解决方法,而不是执行正常的 podman 推送(OCI 格式)。 还需要 skopeo

CONTAINER_DIR="target/container-dir"
mkdir $CONTAINER_DIR
podman push --format=v2s2 "registry.heroku.com/$APP_NAME/web" dir:$CONTAINER_DIR
skopeo --debug copy dir:$CONTAINER_DIR "docker://registry.heroku.com/$APP_NAME/web:latest"
heroku container:release web --app "$APP_NAME"
rm -rf $CONTAINER_DIR

检查日志

您可以并且应该检查日志,以查看您的应用程序现在是否确实从容器运行

heroku logs --app $APP_NAME --tail

在容器内部署为原生应用程序

当我们以容器形式部署我们的应用程序时,我们采取的最大优势是以原生编译的应用程序部署容器。 为什么? 因为当没有传入流量时,Heroku 将停止或休眠该应用程序。 原生应用程序将从休眠状态更快地唤醒。

该过程几乎相同。 我们选择在本地容器中编译本机镜像,这样我们就不必处理在本地安装 GraalVM 的问题

APP_NAME=`heroku info | grep  "=== .*" |sed "s/=== //"`
./mvnw clean package \
  -Dquarkus.container-image.build=true \
  -Dquarkus.container-image.group=registry.heroku.com/$APP_NAME \
  -Dquarkus.container-image.name=web \
  -Dquarkus.container-image.tag=latest \
  -Dnative \
  -Dquarkus.native.container-build=true

之后,再次使用 Docker 或 Podman(请参见上文)推送和发布,并检查日志。

相关内容