Heroku スターターガイド (.NET)
はじめに
このチュートリアルを実施して、Heroku プラットフォームの旧世代である Cedar にサンプル .NET アプリをデプロイします。Heroku Private Spaces でのみ利用可能な Fir 世代にアプリをデプロイするには、こちらのガイドに従ってください。
このチュートリアルでは、以下が用意されていることを前提としています。
- 確認済みの Heroku アカウント
- Eco dyno プランのサブスクリプション (推奨)
- .NET SDK 9.0 以降がローカルにインストールされている - お使いの OS とアーキテクチャに合わせた最新の「Build apps - SDK」インストーラは、.NET 9.0 のダウンロードページからダウンロードできます。
dyno とデータベースを使用してこのチュートリアルを完了した場合、使用量のカウントに入ります。低料金プランを使用してこのチュートリアルを完了することをお勧めします。資格のある学生の皆様は、新しい Heroku for GitHub Students プログラムを通じてプラットフォームクレジットを申請できます。
設定する
Heroku Command Line Interface (CLI) をインストールします。CLI は、アプリの管理やスケール、アドオンのプロビジョニング、ログの表示、ローカルでのアプリの実行に使用できます。
Heroku CLI には、一般によく使われている Git というバージョン管理システムが必要です。Git がまだインストールされていない場合は、先に進む前に次の手順を完了してください。
ご使用のプラットフォーム用のインストーラをダウンロードし、実行してください。
Heroku CLI のその他のインストールオプションについては、こちらを参照してください。
インストール後、コマンドシェルで heroku
コマンドを使用できます。
Heroku CLI にログインするには、heroku login
コマンドを使用します。
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
このコマンドにより、Web ブラウザで Heroku ログインページが開きます。ブラウザですでに Heroku にログインしている場合は、ページの Log In
(ログイン) ボタンをクリックします。
この認証は、heroku
と git
コマンドが正常に動作するために必要な操作です。
Heroku CLI のインストールや使用に問題がある場合は、アドバイスとトラブルシューティングステップについて、Heroku CLI のメイン記事を参照してください。
外部の HTTP/HTTPS サービスへの接続にプロキシを使用するファイアウォールを利用している場合は、heroku
コマンドを実行する前に、ローカルの開発環境で HTTP_PROXY
または HTTPS_PROXY
環境変数を設定してください。
サンプルアプリを複製する
Heroku を初めて使う場合は、 Heroku が提供するサンプルアプリを使ってこのチュートリアルを行うことをお勧めします。
デプロイする既存のアプリを用意してある場合は、 代わりにこの記事に従います。
サンプルアプリをコピーしてコードのローカルバージョンを取得します。以下のコマンドをローカルのコマンドシェルまたはターミナルで実行します。
$ git clone https://github.com/heroku/dotnet-getting-started.git
$ cd dotnet-getting-started
これで、シンプルなアプリを格納した、正常な Git リポジトリを準備できました。これには、Frontend.csproj
ASP.NET Core プロジェクトを参照する GettingStarted.sln
ソリューションファイルが含まれています。
Procfile を定義する
Procfile は、アプリのルートディレクトリにあるテキストファイルです。このファイルを使ってアプリの起動時に実行するコマンドを明示的に宣言します。
サンプルアプリの Procfile
は、次のようになっています。
web: cd Frontend/bin/publish/; ./Frontend --urls http://*:$PORT
# Uncomment this `release` process if you are using a database, so that the efbundle
# migrations (compiled after building the application) are run as part of app deployment,
# using Heroku's Release Phase feature:
# https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli#efbundle
# https://devcenter.heroku.com/articles/release-phase
# release: Frontend/bin/publish/efbundle
この Procfile では、単一のプロセスタイプの web
と、その実行に必要なコマンドを宣言しています。web
という名前は、このプロセスタイプが Heroku の HTTP ルーティングスタックにアタッチし、デプロイ後に Web トラフィックを受信することを宣言しているため重要です。ここで使用されているコマンドは、公開されている ASP.NET Core Web アプリを実行し、PORT
環境変数を使用して、アプリケーションがリスンする URL を渡します。
アプリを作成する
Eco にサブスクライブしている場合、アプリではデフォルトで Eco dyno が使用されます。それ以外の場合は、デフォルトで Basic dyno が使用されます。Eco dyno プランは、アカウント内のすべての Eco dyno で共有されます。これは、多数の小さいアプリを Heroku にデプロイする予定がある場合にお勧めします。詳細は、こちらを参照してください。資格のある学生の皆様は、Heroku for GitHub Students プログラムを通じてプラットフォームクレジットを申請できます。
Heroku でアプリを作成して、ソースコードを受け取るプラットフォームを準備します。
$ heroku create
Creating app...
Creating app... done, whispering-river-68900
https://whispering-river-68900-8c6eb3ace75c.herokuapp.com/ | https://git.heroku.com/whispering-river-68900.git
アプリを作成すると、 という名前の Git リモートも作成され、ローカルのリポジトリ設定に追加されます。Git リモートは、他のサーバー上で稼働するリポジトリのバージョンです。アプリに関連付けられた、Heroku でホストされる特別なリモートにコードをプッシュすることにより、アプリをデプロイできます。
Heroku によってランダムなアプリ名 (このケースでは whispering-river-68900
) が生成されます。独自のアプリ名を指定できます。
アプリをデプロイする
dyno を使用してこのチュートリアルを完了した場合、使用量のカウントに入ります。コストを抑制するために、完了したらすぐにアプリを削除し、データベースも削除してください。
コードをデプロイします。このコマンドは、サンプルリポジトリの main
ブランチを heroku
リモートにプッシュし、次に Heroku にデプロイします。
$ git push heroku main
remote: Updated 43 paths from 5ef5e31
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Building on the Heroku-24 stack
remote: -----> Determining which buildpack to use for this app
remote: -----> .NET app detected
remote: -----> SDK version detection
remote: Detected .NET solution: `/tmp/build_28da475e/GettingStarted.sln`
remote: Inferring version requirement from `/tmp/build_28da475e/GettingStarted.sln`
remote: Detected version requirement: `^9.0`
remote: Resolved .NET SDK version `9.0.202` (linux-amd64)
remote: -----> SDK installation
remote: Downloading SDK from https://download.visualstudio.microsoft.com/download/pr/c2220b38-c512-4447-b564-a18048d14327/965cdfe500a937c2d28bc9d2db45cd1f/dotnet-sdk-9.0.202-linux-x64.tar.gz .... (1.3s)
remote: Verifying SDK checksum
remote: Installing SDK
remote: -----> Restore .NET tools
remote: Tool manifest file detected
remote: Running `dotnet tool restore --tool-manifest /tmp/build_28da475e/.config/dotnet-tools.json`
remote:
remote: Tool 'dotnet-ef' (version '8.0.14') was restored. Available commands: dotnet-ef
remote:
remote: Restore was successful.
remote:
remote: Done (1.8s)
remote: -----> Publish app
remote: Running `dotnet publish /tmp/build_28da475e/GettingStarted.sln --runtime linux-x64 "-p:PublishDir=bin/publish" --artifacts-path /tmp/build_artifacts`
remote:
remote: Determining projects to restore...
remote: Restored /tmp/build_28da475e/Frontend/Frontend.csproj (in 9.16 sec).
remote: Frontend -> /tmp/build_artifacts/bin/Frontend/release_linux-x64/Frontend.dll
remote: Frontend -> /tmp/build_28da475e/Frontend/bin/publish/
remote: Publishing executable database migration bundle
remote: Build started...
remote: Build succeeded.
remote: Building bundle...
remote: Done. Migrations Bundle: /tmp/build_28da475e/Frontend/bin/publish/efbundle
remote: Don't forget to copy appsettings.json alongside your bundle if you need it to apply migrations.
remote:
remote: Done (24.6s)
remote: -----> Process types
remote: Detecting process types from published artifacts
remote: Found `web`: bash -c cd Frontend/bin/publish; ./Frontend --urls http://*:$PORT
remote: Procfile detected
remote: Skipping process type registration (add process types to your Procfile as needed)
remote: -----> Done (finished in 31.0s)
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 117.9M
remote: -----> Launching...
remote: Released v3
remote: https://whispering-river-68900-8c6eb3ace75c.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/whispering-river-68900.git
* [new branch] main -> main
ログに示されている URL でアプリにアクセスします。次のショートカットを使って Web サイトを開くこともできます。
$ heroku open
ログを表示する
Heroku では、すべてのアプリと Heroku のコンポーネントの出力ストリームから集約した時系列イベントのストリームとして、ログが扱われます。Heroku は、すべてのイベントに単一のストリームを提供します。
実行中のアプリに関する情報を表示するには、ログ記録コマンドの 1 つである heroku logs --tail
を使います。
$ heroku logs --tail
2025-04-04T01:35:45.744471+00:00 app[api]: Initial release by user developer@example.com2025-04-04T01:35:45.744471+00:00 app[api]: Release v1 created by user developer@example.com2025-04-04T01:35:45.934551+00:00 app[api]: Enable Logplex by user developer@example.com2025-04-04T01:35:45.934551+00:00 app[api]: Release v2 created by user developer@example.com2025-04-04T01:35:49.000000+00:00 app[api]: Build started by user developer@example.com2025-04-04T01:36:35.440777+00:00 app[api]: Release v3 created by user developer@example.com2025-04-04T01:36:35.440777+00:00 app[api]: Deploy 6077c4f0 by user developer@example.com2025-04-04T01:36:35.455296+00:00 app[api]: Scaled to web@1:Eco by user developer@example.com2025-04-04T01:36:36.000000+00:00 app[api]: Build succeeded
2025-04-04T01:36:42.071305+00:00 heroku[web.1]: Starting process with command `cd Frontend/bin/publish/; ./Frontend --urls http://*:5908`
2025-04-04T01:36:42.884637+00:00 app[web.1]: warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
2025-04-04T01:36:42.884667+00:00 app[web.1]: No XML encryptor configured. Key {21711fa1-1636-4efc-aba0-5fc2ee2e809f} may be persisted to storage in unencrypted form.
2025-04-04T01:36:42.926692+00:00 app[web.1]: info: Microsoft.Hosting.Lifetime[14]
2025-04-04T01:36:42.926694+00:00 app[web.1]: Now listening on: http://[::]:5908
2025-04-04T01:36:42.928041+00:00 app[web.1]: info: Microsoft.Hosting.Lifetime[0]
2025-04-04T01:36:42.928042+00:00 app[web.1]: Application started. Press Ctrl+C to shut down.
2025-04-04T01:36:42.928653+00:00 app[web.1]: info: Microsoft.Hosting.Lifetime[0]
2025-04-04T01:36:42.928653+00:00 app[web.1]: Hosting environment: Production
2025-04-04T01:36:42.928653+00:00 app[web.1]: info: Microsoft.Hosting.Lifetime[0]
2025-04-04T01:36:42.928653+00:00 app[web.1]: Content root path: /app/Frontend/bin/publish
2025-04-04T01:36:43.202406+00:00 heroku[web.1]: State changed from starting to up
2025-04-04T01:36:44.464140+00:00 heroku[router]: at=info method=GET path="/" host=whispering-river-68900-8c6eb3ace75c.herokuapp.com request_id=e768c5fa-3e23-0800-eda4-1ddd83e8d87d fwd="123.456.789.0" dyno=web.1 connect=6002ms service=81ms status=200 bytes=10739 protocol=http1.1 tls=true tls_version=unknown
ログメッセージをさらに生成するには、ブラウザでアプリを更新します。
ログのストリーム出力を停止するには、Control+C
を押します。
ローカルの変更をプッシュする
このステップでは、アプリへのローカルの変更を Heroku にデプロイします。
console
テンプレートを使用して新しい .NET プロジェクトを作成するには、そのプロジェクトをソリューションファイル (GettingStarted.sln
) に追加します。
$ dotnet new console -o bgworker
The template "Console App" was created successfully.
Processing post-creation actions...
Restoring ./dotnet-getting-started/bgworker/bgworker.csproj:
Determining projects to restore...
Restored ./dotnet-getting-started/bgworker/bgworker.csproj (in 36 ms).
Restore succeeded.
$ dotnet sln add bgworker
Project `bgworker/bgworker.csproj` added to the solution.
次は、このローカルの変更を Heroku にデプロイします。
Heroku へのデプロイは、ほとんどの場合、このパターンで行います。まず、変更したファイルをローカルの Git リポジトリに追加します。
$ git add .
変更内容をリポジトリにコミットします。
$ git commit -m "Added bgworker"
[main f6b2236] Added bgworker
3 files changed, 39 insertions(+), 1 deletion(-)
create mode 100644 bgworker/Program.cs
create mode 100644 bgworker/bgworker.csproj
前と同じ方法でデプロイします。
$ git push heroku main
コンソールを起動する
One-off dyno で、heroku run
コマンドを使ってコマンド (通常はアプリの一部を構成するスクリプトやアプリケーション) を実行できます。アプリの環境でインタラクティブな bash
セッションを実行することもできます。
$ heroku run bash
Running bash on whispering-river-68900...
Running bash on whispering-river-68900... up, run.2093
~ $ dotnet --list-runtimes
Microsoft.AspNetCore.App 9.0.3 [/app/.heroku/cnb/dotnet/layers/runtime/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 9.0.3 [/app/.heroku/cnb/dotnet/layers/runtime/shared/Microsoft.NETCore.App]
~ $ ls -C
Frontend LICENSE.txt README.md docker-compose.yml
GettingStarted.sln Procfile app.json
~ $ exit
Error connecting to process
というエラーが表示された場合は、ファイアウォールを設定します。
bash シェルの準備ができたら、dyno と同じ環境でコマンドを実行できます。たとえば、dotnet --list-runtimes
ではインストール済みのランタイムを表示し、ls
では作業ディレクトリ内のファイルを表示します。コンソールを終了するには、exit
と入力します。
データベースをプロビジョニングする
サンプルアプリにはデータベースが必要です。Elements Marketplace から入手可能なアドオンである Heroku Postgres データベースをプロビジョニングします。アドオンは、ログ記録、モニタリング、データベースなど、アプリケーションですぐに使える追加サービスを提供するクラウドサービスです。
essential-0
Postgres のサイズのコストは月額 5 ドルで、分単位で課金されます。このチュートリアルの最後で、データベースを削除して、コストを最小限に抑えるように求められます。Private Space の本番アプリでは、private-0
以降などのプライベートデータベースプランを使用することをお勧めします。
$ heroku addons:create heroku-postgresql:essential-0 --confirm whispering-river-68900 -- --region us
Creating heroku-postgresql:essential-0 on whispering-river-68900...
Creating heroku-postgresql:essential-0 on whispering-river-68900... ~$0.007/hour (max $5/month)
Database should be available soon
postgresql-regular-63143 is being created in the background. The app will restart when complete...
Use heroku addons:info postgresql-regular-63143 to check creation progress
Use heroku addons:docs heroku-postgresql to view documentation
次のコマンドを実行して、データベースがプロビジョニングされるのを待ちます。
$ heroku pg:wait
そのコマンドが終了すると、Heroku アプリは Postgres データベースにアクセスできるようになります。DATABASE_URL
環境変数には、アプリが接続するように設定されている認証情報が格納されています。addons
コマンドを使用して、プロビジョニングされたすべてのアドオンを確認できます。
$ heroku addons
Add-on Plan Price Max price State
──────────────────────────────────────────── ─────────── ──────────── ───────── ───────
heroku-postgresql (postgresql-regular-63143) essential-0 ~$0.007/hour $5/month created
└─ as DATABASE
The table above shows add-ons and the attachments to the current app (whispering-river-68900) or other apps.
データベースを使う
アプリの環境設定を一覧表示すると、アプリがデータベースに接続するときに使用する URL (DATABASE_URL
) が表示されます。
$ heroku config
DATABASE_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd
...
Heroku には、さらに詳細を表示する pg
コマンドもあります。
$ heroku pg
=== DATABASE_URL
Plan: essential-0
Status: Available
Connections: unknown/20
PG Version: 16.4
Created: 2025-04-04 01:37
Data Size: unknown usage / 1 GB (In compliance)
Tables: 0/4000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
Continuous Protection: Off
Add-on: postgresql-regular-63143
デプロイしたサンプルアプリにはデータベース機能が備わっています。それには、アプリの /movies
ページで使用されるムービーのコントローラーとデータベースモデルがあります。このページにアクセスするには、アプリの URL に /movies
を追加するか、Heroku の open
コマンドを使用します。
$ heroku open movies
その URL にアクセスすると、エラーページが表示されます。heroku logs
を使用して、次のようなエラーメッセージを確認します。
...
app[web.1]: fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
app[web.1]: Failed executing DbCommand (24ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
app[web.1]: SELECT m."Id", m."Genre", m."Price", m."ReleaseDate", m."Title"
app[web.1]: FROM "Movie" AS m
app[web.1]: fail: Microsoft.EntityFrameworkCore.Query[10100]
app[web.1]: An exception occurred while iterating over the results of a query for context type 'GettingStarted.Data.GettingStartedMovieContext'.
app[web.1]: Npgsql.PostgresException (0x80004005): 42P01: relation "Movie" does not exist
...
このエラーは、データベースへの接続は成功したものの、Movie
テーブルが見つからなかったことがわかります。Frontend/bin/publish/efbundle
を実行して、そのエラーを解決できます。アプリケーションをデプロイすると、サンプルアプリによって efbundle
実行可能ファイルがすでに作成されています (詳細は Frontend/Frontend.csproj
ファイルを確認してください)。この実行可能ファイルを使用してデータベースを移行できます。
Heroku でこのコマンドを実行するには、次のように One-off dynoで実行します。
$ heroku run Frontend/bin/publish/efbundle
Running Frontend/bin/publish/efbundle on ⬢ whispering-river-68900... up, run.4436
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (41ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT EXISTS (
SELECT 1 FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname='public' AND
c.relname='__EFMigrationsHistory'
)
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT EXISTS (
SELECT 1 FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname='public' AND
c.relname='__EFMigrationsHistory'
)
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (35ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT EXISTS (
SELECT 1 FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname='public' AND
c.relname='__EFMigrationsHistory'
)
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT "MigrationId", "ProductVersion"
FROM "__EFMigrationsHistory"
ORDER BY "MigrationId";
Applying migration '20240216004219_InitialCreate'.
info: Microsoft.EntityFrameworkCore.Migrations[20402]
Applying migration '20240216004219_InitialCreate'.
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (18ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "Movie" (
"Id" INTEGER GENERATED ALWAYS AS IDENTITY,
"Title" TEXT,
"ReleaseDate" DATE NOT NULL,
"Genre" TEXT,
"Price" NUMERIC NOT NULL,
CONSTRAINT "PK_Movie" PRIMARY KEY ("Id")
);
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20240216004219_InitialCreate', '8.0.10');
Done.
ここで、アプリの /movies
ページにもう一度アクセスすると、ムービーのレコードを一覧表示して作成できます。
Postgres がローカルでインストールされている場合、データベースと直接対話することもできます。たとえば、次のように psql
を使ってデータベースに接続し、クエリを実行できます。
$ heroku pg:psql
d8slm9t7b5mjnd=> \x
d8slm9t7b5mjnd=> select * from "Movie";
-[ RECORD 1 ]----------------
Id | 1
Title | Blade Runner
ReleaseDate | 1982-06-25
Genre | Science Fiction
Price | 19.99
...
詳細は、「Heroku PostgreSQL」を参照してください。
環境設定を定義する
Heroku では、暗号鍵や外部リソースのアドレスなどのデータを環境設定に保存して、設定を外部に置くことができます。
設定変数を環境変数としてアプリケーションに公開します。
これを実証するために、Frontend/Program.cs
を変更して、HELLO_FROM
環境変数の値を使用して挨拶を返す単純な /hello
エンドポイントを追加します。
// ...
app.MapGet("/hello", () => $"Hello from {Environment.GetEnvironmentVariable("HELLO_FROM")}!");
app.Run();
dotnet run --project Frontend -e "HELLO_FROM=Me"
でアプリを実行し、http://localhost:5289/hello にアクセスすると、「Hello from Me!」が表示されます。
Heroku で環境設定を設定するには、次のコマンドを実行します。
$ heroku config:set HELLO_FROM=Heroku
Setting HELLO_FROM and restarting whispering-river-68900...
Setting HELLO_FROM and restarting whispering-river-68900... done, v5
HELLO_FROM: Heroku
heroku config
を使用して、アプリの環境設定を表示します。
$ heroku config
HELLO_FROM: Heroku
...
このアクションの変更を確認するには、変更したアプリケーションを Heroku にデプロイします。
アプリを削除する
アカウントからアプリを削除します。使用したリソースに対してのみ課金されます。
このアクションにより、アプリケーションとそれに関連付けられているすべてのアドオンが完全に削除されます。
$ heroku apps:destroy
次のコマンドでアプリが消えたことを確認できます。
$ heroku apps --all
次のステップ
ここまで、.NET アプリを設定してデプロイし、ログを表示して、コンソールを起動する方法を説明しました。
詳細については、次を参照してください。