-
Notifications
You must be signed in to change notification settings - Fork 0
MS_VSToolsForDocker
- 戻る
-
Visual Studio 系
- Visual Studio Tools for Docker
- Visual Studio Kubernetes Tools
- Visual Studio Code Docker extension(
MS_VSCodeDockerExtension.md)
- Desktop 系
-
Visual Studio 系
-
Hyper-V コンテナ(若しくは Microsoft Azure Containers)
+ Docker for Windows を使用して、
ASP.NET Core の Linux コンテナ上でのデバッグ実行が可能。 -
Linux 上での ASP.NET Coreの開発 や
ASP.NET Coreのデプロイ を考えていてココに行き着いた。 -
運用環境へのデプロイについては、専任のエンジニアに相談する必要があるものと思われる。
移行メモ(誤字・体裁): 移行元の「思われれる」を「思われる」に修正した。
また概要 1 項目目の行頭が PukiWiki の
エスケープ記法('+)で始まっていたため整形した。
補足(本ページの位置付けと、現在との差分): 本ページは
2017〜2020 年にかけての検証記録であり、
「手順1〜7」という形で試行錯誤がそのまま残されている。
前提が大きく変わっているため、先に差分を示す。【本ページ執筆時の前提】 ・Windows 10 Pro + Hyper-V ・Docker for Windows(MobyLinuxVM) ・.NET Core 2.0 / VS 2017 ・イメージは microsoft/aspnetcore 【現在の前提】★ ・【WSL2 backend】が既定 → Hyper-V 上の MobyLinuxVM ではない → Windows 10/11 Home でも動く ★ ・【Docker Desktop】に改称 → 一定規模以上の企業は【有償】★ (従業員 250 名以上 or 年商 1000 万ドル以上) → 代替として [Rancher Desktop for Windows](MS_RancherDesktop) / [Podman Desktop for Windows](MS_PodmanDesktop) ・イメージのレジストリが移動した ★★ microsoft/aspnetcore(Docker Hub) → 【mcr.microsoft.com/dotnet/aspnet】 microsoft/aspnetcore-build → 【mcr.microsoft.com/dotnet/sdk】 → 本ページ中の FROM 行は 【そのままでは動かない】★【本ページを読む価値】★ ・「なぜこの設定が要るのか」という 【つまずきの記録】としての価値が高い → ボリューム共有、ポート固定、 ホストへの接続、設定ファイルの配置 → これらは【今も同じ場所でつまずく】 ・手順6の「単体使いを研究する」は IDE の自動化を剥がして 【素の docker コマンドで理解する】試みであり、 現在でも有効な学び方である ★
-
Win 10 Pro
-
Hyper-V の有効化
-
.NET Core 2.0
-
VS 2017 Community
(VS 2019 以降は Visual Studio Kubernetes Tools の
「前提環境」を参照)
- Docker for Windows
- Visual Studio Tools for Docker
https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vs-containers-tools-extensions
補足(拡張機能は VS に統合された): 現在は
Marketplace から個別に入れる必要はない。【現況】★ ・VS 2019 / 2022 では 【「ASP.NET と Web 開発」ワークロード】に コンテナ ツールが含まれる ・インストーラの個別コンポーネントに 【「コンテナー開発ツール」】がある → 本節の Marketplace リンクは 旧 VS 2017 向けであり、現在は不要 【VS が提供する機能】 ・Dockerfile / docker-compose の【自動生成】 ・コンテナ内での【デバッグ実行】(F5)★ ・【コンテナー ウィンドウ】 → 実行中のコンテナ、ログ、 ファイル システム、環境変数を GUI で見られる ・ACR / Docker Hub への発行
以下の手順で検証・評価した。
ASP.NET Core MVC アプリケーションの作成
- Docker(
DNET_Docker.md)サポートなし - 認証なし
- プロジェクトを作成した後にプロジェクトを右クリックして
Docker(DNET_Docker.md)サポートを追加
(VS2019 では、「コンテナー オーケストレーター」を選択。後述の「手順5」を参照)

-
Hyper-V コンテナ 上で動作する OS(Windows or Linux)を選択
(ここでは Linux を選択)。

-
Docker for Windows のインストール
(ダウンロードに少々時間がかかる)

-
Docker for Windows のインストール・ウィザード
(Docker(DNET_Docker.md)≒ Linux コンテナなので
下の Check Box は外しておく)

- Docker for Windows のインストール完了

- デバッグのドロップダウン・リストから Docker(
DNET_Docker.md)を選択した状態で
デバッグ実行しようとすると、以下のエラー・メッセージが表示されるが、
Docker CE for Windows(Docker Community Edition for Windows)
(Docker for Windows を参照)は
インストール済みであるので、PC の再起動を行ってみる。

- 再起動後、Hyper-V 上に Linux VM を確認できる(MobyLinuxVM)。

- 再度デバッグ実行を行うと、以下のエラー・メッセージが表示される。

- エラー・メッセージが以下のように変更される
(Docker(DNET_Docker.md)が実行されていないとのこと)。

- 暫く経つと、以下のダイアログが表示された。
OK を押下して再起動する(再起動に少々時間がかかる)。

- 再起動を行うと、以下のダイアログボックスが表示される
(なお、ココでサインアップ・サインインはしなくてもイイ)。

- この時点で、以下の docker コマンドを cmd から実行すると、
docker コマンドが適切に実行され結果が返り、
Docker(DNET_Docker.md)(のクライアント)が実行されていることを確認する。
> docker version
> docker run hello-world
- デバッグ実行を開始すると、以下の cmd が起動し「何か」がダウンロードされ、

※ 後々、「from microsoft/aspnetcore」でググって、
コンパイル済みの ASP.NET Core アプリケーションを実行するための
公式の Docker Image をダウンロードしていたことが解った。
https://hub.docker.com/r/microsoft/aspnetcore/
- 次いで、以下のエラー・メッセージが表示されるので、

- メッセージ通り、Docker for Windows の設定で、
ボリューム共有を有効にする。
Docker for Windows の画面は
タスクトレイ (Task tray) から起動する。

-
管理者アカウントの Credential の入力を求められるので入力を行う。
-
設定完了後、再度デバッグ実行を行うと、以下のダイアログが表示されるので、
[アクセスを許可する] ボタンを押下し、
VPNKit と言う組込み VPN ツールのリスニング・ポートを開放する。

- これにより、アプリケーションが Hyper-V コンテナ 内の
Docker(DNET_Docker.md)(Linux コンテナ)で起動し、デバッグが開始される。
補足(「ボリューム共有」でつまずく理由と、現在の状況): 手順13〜14 の
エラーは、Docker for Windows の最も有名なつまずきどころだった。【何が起きていたか】★ ・VS のデバッグ実行は 【ソースやデバッガをホストからコンテナへ ボリューム マウントして渡す】 → C ドライブの共有を有効にしていないと マウントできず失敗する ・共有の有効化には 【Windows アカウントの資格情報】が必要 → SMB でホストのドライブを MobyLinuxVM に見せていたため ★ 【トラブルの温床だった理由】 ・【パスワード変更のたびに壊れる】★ → 「昨日まで動いていたのに」の典型 ・ドメイン アカウント / MFA だと設定できない ・Windows Update 後に共有設定が外れる 【WSL2 backend では不要になった】★★ ・WSL2 では SMB を使わない → 【ドライブ共有の設定項目そのものが消えた】 ・ただし前述のとおり /mnt/c 越しの I/O は【遅い】ため、 ソースは WSL 側に置くのが望ましい → [WSL上での.NET Core開発](MS_DotNetCoreOnWSL) 参照【VPNKit について】 ・Docker for Windows が ホストとコンテナのネットワークを繋ぐために使う 【ユーザー空間のネットワーク スタック】 ・ファイアウォールの許可を求められるのはこのため → 詳細は Docker for Windowsのネットワーク設定(`MS_DockerForWindowsNetwork.md`)
-
ここまでの手順で、ソリューションに「docker-compose」が追加されているのを確認する。
-
この「docker-compose」が、スタートアップ・プロジェクトに設定されていることを確認する。
-
デバッグ実行を開始する
(ドロップダウン・リストに「Docker」が選択されていることを確認する)。 -
ブレークポイントを設定して実行すると、
以下のように、適切にデバッグ実行されていることを確認できる。

- 本当に Linux 上で動いているか心配なので、念のため、確認する。
※ 確認方法は WSL上での.NET Core開発 の
「OS バージョンの確認」を参照。

Docker(DNET_Docker.md)側でライブラリのデバッグをする場合、
ライブラリの PDB が、
「完全(full)」ではなくて、「ポータブル(portable)」である必要がある。
補足(PDB のタイプ): この一行は短いが、
クロスプラットフォーム デバッグの要点である。【PDB の 3 形式】★ full … 【Windows 専用】の従来形式 → Linux 上の vsdbg が読めない ★ portable … 【クロスプラットフォーム】の新形式 → .NET Core 以降の【既定】 embedded … PDB を DLL の中に埋め込む → ファイルが 1 つで済む → コンテナ配布と相性がよい ★ 【設定】 <PropertyGroup> <DebugType>portable</DebugType> <!-- or embedded --> </PropertyGroup> 【つまずく場面】★ ・.NET Framework 時代の 【クラス ライブラリを流用】したとき → 既定が full のまま → 【そのライブラリだけブレークポイントが効かない】 ・「シンボルが読み込まれていません」と出たら まず DebugType を疑う ★ 【関連:Source Link】 ・PDB に【ソースの取得元(Git のコミット)】を 埋め込む仕組み → NuGet パッケージの中まで ステップ実行できるようになる ★
-
より実践的な開発環境を構成したい。
- Web サーバ:Docker(
DNET_Docker.md)側の
Kestrel(ASP.NET CoreのWebサーバ を参照)で動作する。 - DB:ホスト側の DB で動作する。
- Web サーバ:Docker(
-
後者の DB へのアクセスが可能かどうか DBMS アプリケーションを使用して確認する。
(DBMS アプリケーションとしては、ASP.NET Core 対応された
Open 棟梁テンプレートを使用する。)
※ 平たく言って、Open 棟梁テンプレートを Docker で動かす。
- 早速エラーが発生。DB アクセス以前に設定ファイルへのアクセスができない。

- 以下のように調査すると、
プロジェクト内のファイルがカレント・ディレクトリ(/app)に
デプロイされることが解る。

-
従って、
-
プロジェクト内にファイルを配置し、
(「リンクとして追加」の設定は NG、「出力ディレクトリにコピー」の設定は不要)
これを読み取る方向性で対応するか、 -
旧 Azure PaaS 時と同様に、埋め込まれたリソースで対応できる。
設定の仕方は、以下の「Azure Web Apps」で動作させる方法が参考になる。- Open 棟梁の使い方(実践編)第6回 - OSSコンソーシアム
https://www.osscons.jp/joywo3d7c-537/#_537
- Open 棟梁の使い方(実践編)第6回 - OSSコンソーシアム
-
補足(設定ファイルの扱いはコンテナ化の核心): この節でつまずいたことは、
コンテナ化における最も重要な設計変更である。【なぜファイルが見つからないのか】★ ・ホスト(Windows)でのパス感覚が通用しない → コンテナ内の作業ディレクトリは【/app】 → 相対パスの基準が変わる ・publish に含まれないファイルは 【イメージに入らない】 → csproj の <Content Include="..." CopyToOutputDirectory="..." /> または <EmbeddedResource> が必要 【原文の 2 案の評価】 ・案①(プロジェクト内にファイルを配置) → 素直。現在もこれでよい ・案②(埋め込みリソース) → 確実だが【設定を変えるのに再ビルドが要る】★ 【現在の定石:設定はファイルに持たせない】★★ ・【環境変数】で上書きする ASPNETCORE_ENVIRONMENT=Production ConnectionStrings__Default=... → 【二重アンダースコア】が階層の区切り ★ → docker-compose の environment: で渡す ・【シークレット】 - Docker secrets / Kubernetes Secret - Azure Key Vault → 接続文字列やパスワードを イメージに焼き込まない ★★ ・appsettings.json は 「既定値」だけを持ち、 環境ごとの値は外から与える 【Twelve-Factor App の III. 設定】★ 「設定は環境変数に格納する」 → コンテナ化とは、この原則に従うこと → 【同じイメージを全環境で使い回せる】 → 詳細は [Visual Studio Kubernetes Tools](MS_VSKubernetesTools) の 「ココまでで解った事」も参照
ホスト側の DB で動作させようとしたが、ハマりどころが多かったのでメモ。
-
ホストの IP アドレスは、10.0.75.1 になる。
- Docker Desktop 2.2.0 から 10.0.75.1 は使用できなくなっている
(Docker for Windowsのネットワーク設定(MS_DockerForWindowsNetwork.md)を参照)。
- Docker Desktop 2.2.0 から 10.0.75.1 は使用できなくなっている
-
Windows 認証ではなく、SQL Server 認証の接続文字列を使用する。
- 必要に応じて設定する。
- OFF にして通ったら、その後、ON にして絞るのがイイ。
移行メモ(誤字): 移行元の「必要時応じて設定する」を
「必要に応じて設定する」に修正した。
Express の場合は、SQL Server 構成マネージャーの設定も必要になる。
移行メモ(誤字): 移行元の「設定も必要にある」を
「設定も必要になる」に修正した。
- つながらない! - SQL Server Express
(つながらない! の該当節を参照) - networking - How to connect to docker host from container on Windows 10 (Docker for Windows) - Stack Overflow
https://stackoverflow.com/questions/40746453/how-to-connect-to-docker-host-from-container-on-windows-10-docker-for-windows
補足(コンテナからホストへ接続する現在の方法): 「10.0.75.1」は
もう使えないので、現行の手段を示す。【host.docker.internal】★★ ・Docker Desktop(Windows / macOS)が 【自動的に解決してくれる特別な名前】 Server=host.docker.internal,1433;... ・Linux 版 Docker では既定で解決されないが、 compose で追加できる extra_hosts: - "host.docker.internal:host-gateway" 【SQL Server Express 側で必要な設定】★ 本ページが挙げる 3 点は【今も全部必要】である。 ① SQL Server 構成マネージャー → 【TCP/IP プロトコルを有効化】★ → 既定で無効になっている → Express は【動的ポート】なので 固定ポート(1433)に変更するか、 SQL Server Browser を起動する ② Windows ファイアウォール → 1433/TCP(と 1434/UDP)を開ける ③ SQL Server 認証(混合モード)を有効化 → コンテナは Windows ドメインに参加していないため 【Windows 認証は使えない】★ → 原文の指摘どおり → 詳細は [SQL Server Express](MS_SQLServerExpress) / [つながらない!](MS_ConnectionFailure)【そもそもホストの DB を使わない方がよい】★★ ・「アプリはコンテナ、DB はホスト」は 【中途半端】で、環境差の原因になる ・現在の定石 → 【DB もコンテナにする】 mcr.microsoft.com/mssql/server:2022-latest (Developer Edition が無償で使える) → 手順4で作者自身が PostgreSQL をコンテナ化しており、 【最終的に正しい方向へ進んでいる】★ → テストなら【Testcontainers】が便利 (テストのたびに使い捨ての DB を立てる)
以下は、ASP.NET Core MVC の Open 棟梁テンプレートの
変更点のスクショです。
(設定ファイル読み込み方法に「埋め込まれたリソース」を採用した場合)

Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))を使用して、
コンテナ・オーケストレーションを行う。
-
Web サーバを、Kestrel(ASP.NET CoreのWebサーバ を参照)から
nginx(DNET_nginx.md)プロキシ経由に変更する。 -
Docker Hub から、ASP.NET Core + nginx(
DNET_nginx.md)の
イメージ・ファイルを取得する(「nginx:latest」と「aspnetcore:latest」)。 -
上記の2つのコンテナを作成・管理する場合、
Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))を利用する。
移行メモ(誤字): 移行元の「2つのコンテナを作成を・管理する場合」を
「2つのコンテナを作成・管理する場合」に修正した。
-
ホスト(VPNKit?の 8888)
- -> nginx-proxy(
DNET_nginx.md)コンテナ (nginx の 80) - -> ASP.NET Core コンテナ
(Kestrel(ASP.NET CoreのWebサーバ を参照)の 5000)と
ブリッジする。
- -> nginx-proxy(
-
各コンテナは、それぞれ独立した IP アドレスを持っており、
後述の docker コマンドで調べることができる。
前述の手順1と同じ。
複数のコンテナを扱うので、そろそろ管理コマンド・ツールを理解する。
(Docker(DNET_Docker.md)の該当節を参照)
-
docker image
- docker image ls
- docker image rm image xxxxxxxxxxxx
-
docker ps
-
docker inspect id xxxxxxxxxxxx
-
, etc.
補足(現在の docker コマンドの書き方): 挙げられているコマンドは
一部が古い書式なので補っておく。【正しい書式】★ docker image ls (OK) docker image rm <IMAGE ID> ← 【image を重ねない】★ ※ 原文の "docker image rm image xxxx" は image という名前のイメージを消そうとする形になる docker ps (OK。docker container ls と同義) docker inspect <ID> ← 【id を付けない】★ ※ 原文の "docker inspect id xxxx" も同様 【よく使うもの】 docker ps -a … 停止中も含めて一覧 docker logs -f <ID> … ログを追う ★ docker exec -it <ID> bash … コンテナに入る ★★ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <ID> … IP だけ取り出す ★ docker system df … 使用容量 docker system prune -a … 不要なものを一括削除 ★ → 開発機のディスクが逼迫したらこれ 【compose 側】 docker compose up -d … 起動(v2 は【スペース区切り】)★ docker compose logs -f docker compose down -v … 停止+ボリューム削除 ※ 旧 docker-compose(ハイフン)は v1。 現在は【docker compose】(プラグイン)が標準 ★
(Kitematic(DNET_Kitematic.md)を参照)
-
Kitematic(
DNET_Kitematic.md)は GUI の Docker(DNET_Docker.md)管理ツール。 -
Windows 環境からは、以下のように Docker for Windows の
タスクトレイ (Task tray) の Context Menu からダウンロードする。


-
インストールは zip 解凍で OK。
-
解凍フォルダの exe を起動する。
補足(Kitematic は廃止された): この GUI ツールは
現在は提供されていない。【Kitematic の現況】★ ・Docker が 2015年に買収した GUI クライアント ・【2020年頃に Docker Desktop から削除】された ・GitHub リポジトリも【アーカイブ済み】 【現在の代替】★ ・【Docker Desktop の GUI】★★ → コンテナ、イメージ、ボリューム、 ログ、ターミナルがすべて内蔵された → Kitematic の役割を吸収した ・【VS / VS Code のコンテナー ウィンドウ】 → IDE から直接見られる ・【Portainer】 → Web UI。リモートの Docker / Swarm も管理できる ・【LazyDocker】 → ターミナル UI。軽量 ・Rancher Desktop / Podman Desktop → Docker Desktop の代替(GUI 込み)
Update-Package を実行する。
(Kestrel については ASP.NET CoreのWebサーバ を参照)
Program.cs に以下の行を追加する。
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://0.0.0.0:5000/") // ← ココを追加 localhost や 127.0.0.1 だとダメ。
.Build();補足(
0.0.0.0でなければならない理由): コメントの
「localhost や 127.0.0.1 だとダメ」は極めて重要なので、
理由を明示しておく。【なぜダメなのか】★★ ・127.0.0.1 は【そのコンテナ自身】を指す → コンテナの中から見た localhost → 【外(他のコンテナ、ホスト)からは繋がらない】 ・0.0.0.0 は「すべてのインターフェース」 → コンテナに割り当てられた IP でも受ける → nginx コンテナから届く ★ ┌─ コンテナ ────────┐ │ 127.0.0.1:5000 ← ここだけ │ ✕ 外から不可 │ 172.17.0.3:5000 │ ○ 0.0.0.0 なら受ける └───────────────┘ 【現在の書き方】★ ・コードに書かず【環境変数】で指定する ASPNETCORE_URLS=http://+:5000 → docker-compose の environment: に置く → 【同じイメージを別ポートで動かせる】 ・公式イメージの既定 → .NET 8 以降は【8080】が既定になった ★ (非 root 実行のため 1024 未満を避けた) → 古い Dockerfile を流用すると 「80 で待っているつもりが 8080」でハマる
Docker ファイル(Dockerfile)の編集
ASP.NET Core コンテナ
既定の Docker ファイル(Dockerfile)を修正
- 変更前
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0 AS build
WORKDIR /src
COPY WebApplication1.sln ./
COPY WebApplication1/WebApplication1.csproj WebApplication1/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/WebApplication1
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]-
変更後
-
aspnetcore:2.0 ---> latest と変更
(試しに変更しただけなので変更しなくても良い) -
EXPOSE 80 ---> 5000 と変更
これは、結局、後述の Docker Compose ファイルが優先される。
-
FROM microsoft/aspnetcore:latest AS base
WORKDIR /app
EXPOSE 5000
FROM microsoft/aspnetcore-build:latest AS build
WORKDIR /src
COPY WebApplication1.sln ./
COPY WebApplication1/WebApplication1.csproj WebApplication1/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/WebApplication1
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]補足(この Dockerfile は現在そのままでは動かない): 構造(マルチステージ
ビルド)は今も正しいが、イメージ名が変わっている。【イメージ名の移行】★★ microsoft/aspnetcore:2.0(Docker Hub) → 【mcr.microsoft.com/dotnet/aspnet:8.0】 microsoft/aspnetcore-build:2.0 → 【mcr.microsoft.com/dotnet/sdk:8.0】 ※ Microsoft は 2018〜2019年に 公式イメージを【MCR(Microsoft Container Registry)】へ 移行した → Docker Hub 側は 「MCR を見よ」という案内だけになった ★ 【現在の Dockerfile(.NET 8)】★ FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 8080 USER $APP_UID # ← 【非 root 実行】★ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"] RUN dotnet restore "WebApplication1/WebApplication1.csproj" COPY . . WORKDIR "/src/WebApplication1" RUN dotnet build -c Release -o /app/build FROM build AS publish RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "WebApplication1.dll"]【`latest` タグを使ってはいけない】★★ ・原文は「試しに」と断っているが、 実運用では【必ずバージョンを固定する】 → latest は【いつの間にか中身が変わる】 → 「昨日のビルドは通ったのに」の原因 → 再現性が失われる ・可能なら【ダイジェスト(sha256:...)で固定】する 【`COPY .csproj` を先に書く理由】★ ・Docker のレイヤ キャッシュを効かせるため → csproj だけ先にコピーして restore → ソースを変えても 【restore はキャッシュが効く】★ → ビルドが劇的に速くなる ・原文の Dockerfile もこの構造になっており、 【VS の自動生成が正しく設計されている】 【EXPOSE は「宣言」でしかない】★ ・原文の「結局 Docker Compose が優先される」は 正しい理解である ・EXPOSE は【ドキュメント的な意味】しかなく、 実際の公開は docker run -p / compose の ports: で決まる ★
(nginx については nginx(DNET_nginx.md)を参照)
nginx フォルダに Dockerfile ファイル(Dockerfile)を作成する。
※ nginx フォルダは、
後述の Docker Compose ファイル(docker-compose.yml)と同じ階層に作成。
FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/default.confnginx フォルダに default.conf を作成する。
※ nginx フォルダは、
後述の Docker Compose ファイル(docker-compose.yml)と同じ階層に作成。
(nginxでASP.NET Coreをホストする(DNET_NginxHostASPNETCore.md)の該当節を参照)
server {
listen 80;
server_name example.com *.example.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
}
}server {
listen 80;
server_name localhost;
location / {
proxy_pass http://xxx.xxx.xxx.xxx:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
}
}※ xxx.xxx.xxx.xxx には、
-
以下コマンドを使用して、
ASP.NET Core コンテナの IPAddress として取得する。- docker ps
- docker inspect id xxxxxxxxxxxx
-
若しくは、後述の Docker Compose ファイルの links に記載したサービス名を指定する。
links:
- webapplication1補足(IP を直書きしてはいけない): 2 つ挙げられた選択肢のうち、
後者(サービス名)が唯一の正解である。【なぜ IP 直書きがダメか】★★ ・コンテナの IP は【再起動のたびに変わる】 → docker compose down / up で別の IP になる → nginx.conf を書き直す羽目になる ・原文が併記している「サービス名」が正しい ★ 【Docker の内蔵 DNS】★ ・同じネットワークに属するコンテナは 【サービス名で名前解決できる】 proxy_pass http://webapplication1:5000; ・compose が自動でネットワークを作り、 サービス名を DNS に登録する → 【links は不要】(後述) 【nginx 特有の落とし穴】★★ ・nginx は【起動時に proxy_pass の名前を解決し、 その結果をキャッシュする】 → 相手コンテナが再作成されて IP が変わると 【502 Bad Gateway のまま復旧しない】★ ・対策 resolver 127.0.0.11 valid=10s; # Docker の内蔵 DNS set $upstream http://webapplication1:5000; proxy_pass $upstream; # ← 変数にすると # 都度解決される ★ → これは実運用で必ず踏む問題【リバース プロキシを挟む場合の ASP.NET Core 側の設定】★ ・そのままだと Request.Scheme が常に http になり、 リダイレクトが壊れる → 【ForwardedHeaders ミドルウェア】が必要 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); ※ 【UseForwardedHeaders は最初に置く】★ ※ KnownProxies / KnownNetworks を設定しないと 既定では信用されない ・nginx 側も proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; を送る必要がある → 原文の設定にはこれが【含まれていない】ため、 HTTPS 終端する場合は追加が必要 ★
Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))ファイル
(docker-compose.yml)の編集
version: '3'
services:
webapplication1:
image: webapplication1
build:
context: .
dockerfile: /WebApplication1/Dockerfileversion: '3'
services:
nginx-proxy:
image: nginx-proxy
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- "8888:80"
links:
- webapplication1
webapplication1:
image: webapplication1
build:
context: ./WebApplication1
dockerfile: Dockerfile
ports:
- "5000:5000"Docker ファイル(Dockerfile)には様々な設定が可能。
-
Dockerfile を使用する場合、
build に context と dockerfile を指定する。 -
Dockerfile が必要ない場合、
build はサボって image をそのまま利用することも可能。
-
ports
- ポートを公開(expose)する。
- 「ホスト : コンテナ」で、ホストとポートを指定する。
- コンテナのポートのみ指定(ホスト側のポートはランダム)。
- 公式のイメージでは、記載がなくてもデフォルト・ポートが公開(expose)される。
- ポートを公開(expose)する。
-
links
- コンテナ内の /etc/hosts に指定したサービス名が追加される。
- サービス名とリンク・エイリアス(サービス : エイリアス)の指定も可能。
-
volumes
- ホストのディレクトリをマウントする。
- 再デプロイせずにローカルファイルの変更を反映できる。
- また、データストアのデータファイルにも使用できる。
補足(
linksは非推奨。versionも不要になった): この節の記述は
Compose file v1〜v3 初期の知識であり、現在は変わっている。【links は非推奨(legacy)】★★ ・Compose v2 以降、 サービスは【同じネットワークに自動参加】し、 サービス名で解決できる → 【links は書く必要がない】 → 書いても害はないが、 「起動順の制御」だと誤解されやすい ・起動順を制御したいなら depends_on: db: condition: service_healthy ← 【これ】★ ※ 素の depends_on は 「起動した」だけで 「受付可能になった」を保証しない ★ ※ healthcheck: を定義して初めて機能する 【version: は不要になった】★ ・Compose Specification(v2 CLI)では 【version キーは無視され、警告が出る】 → 現在は書かないのが正しい 【ports の注意】★ ・"8888:80" は【ホストの 8888 を全インターフェースに開く】 → 同一 LAN の他マシンから見える → 開発機では "127.0.0.1:8888:80" と書くと 【ローカルだけに限定できる】★ 【volumes の 2 種類】★ ・【バインド マウント】(./data:/data) → ホストのパスを直接見せる → 開発時のホット リロードに便利 → 【Windows ホストでは遅い】★ ・【名前付きボリューム】(mydata:/data) → Docker が管理する領域 → 【性能が良く、移植性も高い】★ → 本番のデータ永続化はこちら
前述の手順3に
- Session ストアの KVS(Redis)と
- Data ストアの DBMS(PostgreSQL)の
コンテナを追加してみる。
-
永続化の方法には、
- ホストのディレクトリにマウントする方法
- データコンテナを使う方法
- 起動時に都度、初期化する方法
がある。
-
それぞれ、その用途から、
-
KVS(Redis)には、「ホストのディレクトリにマウントする方法」
(1つの負荷分散クラスタの Session ストアとして利用するため) -
DBMS(PostgreSQL)には、「起動時に都度、初期化する方法」
(ココでは、主に、テスト自動化での利用を検討しているため)
を採用する。
-
補足(「用途で永続化方式を分ける」判断は的確): この使い分けは
コンテナ運用の要点をよく捉えている。【3 方式の現在の呼び方】★ ・ホストのディレクトリにマウント → 【バインド マウント】 ・データコンテナを使う → 【データ ボリューム コンテナ】 → 【現在は非推奨】★ (名前付きボリュームが同じことをより簡潔に実現する) ・起動時に都度初期化 → 【エフェメラル(使い捨て)】 【現在の推奨】★ ・永続化が要る → 【名前付きボリューム】★ volumes: - redisdata:/data volumes: redisdata: ・開発中のソース共有 → バインド マウント ・テスト用 → 使い捨て(原文の判断どおり)★ 【「テスト自動化のために毎回初期化」という発想】★★ ・これは現在【Testcontainers】として ライブラリ化されている → テストのたびに 本物の DB コンテナを起動し、 終わったら破棄する → 【モックより信頼できるテスト】が書ける ★ → 本ページの着眼点が 後年ライブラリとして一般化した例と言える

前述の手順3と同じ。
- redis フォルダに redis 設定ファイルを追加
※ redis フォルダは、
前述の Docker Compose ファイル(docker-compose.yml)と同じ階層に作成。- redis.conf を作成し、外部から接続可能に設定する。
bind 0.0.0.0
- 前述の Docker Compose ファイル(docker-compose.yml)へ追記
以下のセクションを追加する。- redis:
redis:
image: redis
volumes:
- ./redis/data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server --appendonly yes
ports:
- "6379:6379"
restart: always- /data をマウントすると良い
- appendonly yes がないとデータが作られない
- webapplication1:
links にサービス名を記載する。
links:
- redis補足(Redis を外部公開する際の注意):
bind 0.0.0.0と
ports: 6379:6379の組み合わせは、開発機では便利だが危険である。【危険な理由】★★ ・Redis は【既定で認証がない】 ・0.0.0.0 バインド + ホストのポート公開 → 同一 LAN の誰でも読み書きできる ・過去に【インターネットに露出した Redis】が 大量に侵害された事例がある → データ窃取、暗号通貨マイナーの設置 → Redis 側も【protected-mode】を 既定で有効にする対応を入れた ★ 【安全にする】 ・パスワードを設定する command: redis-server --requirepass ${REDIS_PASSWORD} ・ホストに公開しない(コンテナ間だけで使う)★ → ports: を書かなければ 同じネットワークのコンテナからは繋がる → デバッグ時だけ "127.0.0.1:6379:6379" にする 【appendonly について】★ ・Redis の永続化は 2 方式 RDB(既定)… 定期的にスナップショット AOF(appendonly)… 書き込みを追記ログに残す ★ → AOF の方が【データ損失が少ない】 → 原文が appendonly yes を指定しているのは妥当 ・「これがないとデータが作られない」という記述は、 正確には「/data に appendonly.aof が 作られない」の意 → RDB のみだと dump.rdb が保存タイミングで作られる
WSL から、redis-cli をインストールして確認する。
- "Ubuntu 18.04 LTS on Windows 10" の場合、
以下の準備が必要だった。
sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe"- インストール
sudo apt-get install redis-tools- 動作確認
$ redis-cli -h 127.0.0.1
127.0.0.1:6379> set mystr1 "abc"
OK
127.0.0.1:6379> get mystr1
"abc"
127.0.0.1:6379>
※ ASP.NET Coreの分散キャッシュ のほうが新しい。
-
NuGet
(既定で Microsoft.AspNetCore.All に含まれる)- Microsoft.AspNetCore.Session
- Microsoft.Extensions.Caching.Redis.Core
-
以下を実装する。
- Startup.cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
namespace WebApplication1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Redisを設定
services.AddDistributedRedisCache(option =>
{
option.Configuration = "redis";
option.InstanceName = "redis";
});
// Sessionを使用する。
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
// Sessionを使用する。
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}- HomeController.cs
public IActionResult Index()
{
HttpContext.Session.SetString("TestId", DateTime.Now.ToString());
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page. " + HttpContext.Session.GetString("TestId");
return View();
}- 参考
- ASP.NET CoreのCache・SessionにRedisを使う - kikki's tech note
http://kikki.hatenablog.com/entry/2016/11/16/090000 - ASP.NET Core のセッションとアプリケーションの状態 | Microsoft Docs
https://learn.microsoft.com/ja-jp/aspnet/core/fundamentals/app-state
- ASP.NET CoreのCache・SessionにRedisを使う - kikki's tech note
補足(パッケージと API が変わっている): このコードは
.NET Core 2.0 世代のものであり、現在は書き方が違う。【パッケージの変更】★ Microsoft.Extensions.Caching.Redis.Core → 【非推奨】 Microsoft.Extensions.Caching.Redis → 【非推奨】(.NET Core 3.x まで) 【Microsoft.Extensions.Caching.StackExchangeRedis】★ → 現在の推奨(.NET Core 3.0 以降) 【API の変更】 services.AddDistributedRedisCache(...) → 【services.AddStackExchangeRedisCache(...)】★ 【現在の書き方(.NET 8 最小 API)】 builder.Services.AddStackExchangeRedisCache(o => { o.Configuration = builder.Configuration .GetConnectionString("Redis"); // "redis:6379" o.InstanceName = "app:"; }); builder.Services.AddSession(o => { o.IdleTimeout = TimeSpan.FromMinutes(30); o.Cookie.HttpOnly = true; o.Cookie.IsEssential = true; // ← 【要注意】★ }); ... app.UseSession(); // UseRouting と UseEndpoints の間 ★【つまずきどころ】★ ① 【UseSession の位置】 → UseRouting の後、 MapControllers の前に置く → 順序を誤ると 「Session has not been configured」例外 ② 【Cookie.IsEssential】 → GDPR 同意機能を使っていると、 同意前は Cookie が発行されない → セッションが【毎回切れる】★ ③ 【Session はキャッシュであって永続ストアではない】 → 消えても動くように設計する ④ 【option.Configuration = "redis"】 → ポート省略時は 6379 が使われる → 明示するなら "redis:6379"【なぜ分散キャッシュが要るのか】★ ・既定のセッションは【インメモリ】 → コンテナを複数立てると 【リクエストごとに別のセッションになる】★ → 原文が「1 つの負荷分散クラスタの Session ストアとして利用」と書いているのは まさにこの理由 ・併せて【データ保護の鍵】も共有が必要 → [ASP.NET Coreのデータ保護](MS_ASPNETCoreDataProtection)
- 画面

- redis-cli
127.0.0.1:6379> keys *
1) "redis69ed5ead-0115-372b-8ef7-665bc769e747"
2) "mystr1"
補足(
keys *は本番で使ってはいけない): 確認には便利だが、
運用中の Redis に対して実行すると危険である。【なぜ危険か】★★ ・Redis は【シングル スレッド】 ・keys * は【全キーを走査する】 → キーが数百万あると その間【他の全リクエストが待たされる】★ → 事実上のサービス停止 【代替】★ ・【SCAN】… カーソルで少しずつ走査する SCAN 0 MATCH app:* COUNT 100 ・DBSIZE … 件数だけ知りたい場合 ・INFO keyspace 【キー名の設計】 ・原文の出力を見ると InstanceName("redis")+ セッション ID という形になっている ・実務では 【区切り文字を入れる】と見やすい InstanceName = "app:session:" → SCAN MATCH で絞り込みやすくなる ★
- postgres フォルダに postgres 設定ファイルを追加
※ postgres フォルダは、
前述の Docker Compose ファイル(docker-compose.yml)と同じ階層に作成。- 初期化用 SQL を ./postgres/init/init.sh に作成
psql -U postgres << "EOSQL"
CREATE DATABASE postgres;
\c postgres;
--------------------
-- TABLE: Shippers
--------------------
CREATE TABLE Shippers(
ShipperID integer NOT NULL,
CompanyName VARCHAR(40) NOT NULL,
Phone VARCHAR(24),
CONSTRAINT PK_Shippers PRIMARY KEY (ShipperID)
);
--------------------
-- Sequence: ShipperID
--------------------
CREATE SEQUENCE TS_ShipperID;
--------------------
-- INSERT
--------------------
INSERT INTO Shippers (ShipperID, CompanyName, Phone) VALUES(nextval('TS_ShipperID'), 'Speedy Express', '(503) 555-9831');
INSERT INTO Shippers (ShipperID, CompanyName, Phone) VALUES(nextval('TS_ShipperID'), 'United Package', '(503) 555-3199');
INSERT INTO Shippers (ShipperID, CompanyName, Phone) VALUES(nextval('TS_ShipperID'), 'Federal Shipping', '(503) 555-9930');
EOSQL- 前述の Docker Compose ファイル(docker-compose.yml)へ追記
以下のセクションを追加する。- postgres:
postgres:
image: postgres
volumes:
#- ./postgres/data:/var/lib/postgresql/data
- ./postgres/init:/docker-entrypoint-initdb.d
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=seigi@123
ports:
- "5432:5432"
restart: always- webapplication1:
links にサービス名を記載する。
links:
- redis
- postgres補足(
docker-entrypoint-initdb.dの仕組みと注意): この初期化方式は
公式イメージが提供する便利な仕組みだが、落とし穴がある。【仕組み】★ ・PostgreSQL 公式イメージは、 起動時に /docker-entrypoint-initdb.d/ 配下の 【*.sql / *.sh / *.sql.gz】を アルファベット順に実行する ・MySQL / SQL Server 等も同様の仕組みを持つ 【最大の注意点】★★ ・【データ ディレクトリが空のときだけ実行される】 → 2 回目以降の起動では【実行されない】 → 「SQL を直したのに反映されない」の原因 ★ → 作り直すには docker compose down -v (-v でボリュームも削除) ・原文が volumes の ./postgres/data を 【コメントアウトしている】のは、 「毎回初期化したい」という意図に合致している ★ (永続化するとこの仕組みが 1 回しか動かないため) 【POSTGRES_DB について】 ・原文の SQL は CREATE DATABASE postgres しているが、 【postgres データベースは既定で存在する】 → 通常はエラーになる → 環境変数 POSTGRES_DB=mydb を使う方が素直 ★【パスワード直書きの問題】★★ - POSTGRES_PASSWORD=seigi@123 → 【compose ファイルに平文】で残る → Git にコミットされる 【対策】 ・.env ファイルに逃がす(.gitignore に追加)★ POSTGRES_PASSWORD=${POSTGRES_PASSWORD} ・【Docker secrets】 POSTGRES_PASSWORD_FILE=/run/secrets/db_password ・本番は Key Vault 等から注入【健全性チェックを入れる】★ postgres: healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s retries: 10 webapplication1: depends_on: postgres: condition: service_healthy → 【アプリが DB より先に起動して落ちる】 という典型的な問題を防げる ★
WSL から、postgresql-client をインストールして確認する。
- インストール
sudo apt-get install postgresql-client- 動作確認
$ psql -h 127.0.0.1 -d postgres -U postgres -c "select * from shippers"
Password for user postgres:
shipperid | companyname | phone
-----------+------------------+----------------
1 | Speedy Express | (503) 555-9831
2 | United Package | (503) 555-3199
3 | Federal Shipping | (503) 555-9930
(3 rows)
-
NuGet:Npgsql
-
以下を実装する。
- HomeController.cs
public IActionResult About()
{
string count = "";
using (var con = new NpgsqlConnection("HOST=postgres;DATABASE=postgres;USER ID=postgres;PASSWORD=seigi@123;"))
{
con.Open();
var cmd = new NpgsqlCommand(@"select count(*) from shippers", con);
count = cmd.ExecuteScalar().ToString();
}
ViewData["Message"] = "Your application description page. " + count + "件";
return View();
}補足(このコードの改善点): 動作確認用としては十分だが、
実務では 3 点直す必要がある。【① 接続文字列をコードに直書きしない】★★ → appsettings.json / 環境変数から取る var cs = _config.GetConnectionString("Default"); → 環境変数なら ConnectionStrings__Default=Host=postgres;... → 【パスワードがソースに残らない】 【② 同期 API を使っている】★ ・ASP.NET Core では【非同期】が原則 await con.OpenAsync(); var count = await cmd.ExecuteScalarAsync(); → 待つ間スレッドを解放できる → スレッド プール枯渇を防ぐ 【③ 接続の生成方法】 ・Npgsql は【接続プール】を内蔵しているので using で都度 new しても問題ない ・ただし現在は 【NpgsqlDataSource】(Npgsql 7.0 以降)が推奨 ★ builder.Services.AddNpgsqlDataSource(cs); → DI で注入して使う 【HOST=postgres という指定について】★ ・これは【compose のサービス名】であり、 Docker の内蔵 DNS が解決する ・前述の nginx の proxy_pass と同じ発想 → 【正しい書き方】である ★
- 画面

VS2019 で素のプロジェクト・テンプレートを
生成して Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))を
やってみた。
(前述の手順4までは、VS2017 で実行している)
- 手順25

- 手順26

- 手順27

- 手順28

VS2019 では、「コンテナー オーケストレーター」が追加されている。
-
VS2017 では「Docker サポート」で
Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))が
構成されていたが、 -
VS2019 の「Docker サポート」では Docker File が追加されるダケになった。
-
VS2017 の既定の Docker Compose を VS2019 で使用する場合は、
「コンテナー オーケストレーター」の Docker Compose を選択する必要がある。
補足(この分離は妥当な設計変更だった): VS2017 → VS2019 の変更は、
「1 コンテナ」と「複数コンテナ」を分けたということである。【VS2019 以降の 2 つのメニュー】★ ・【Docker サポートの追加】 → Dockerfile だけを追加する → 単一コンテナで完結する場合はこれで十分 ・【コンテナー オーケストレーターのサポートの追加】★ → Docker Compose → Service Fabric(後に削除) → 【.NET Aspire】(VS 2022 17.9 以降)★ 【なぜ分けたのか】 ・VS2017 は常に docker-compose を作っていたため、 1 コンテナしかないのに 【余計なプロジェクトが増える】状態だった ・「Docker 化したいだけ」と 「複数コンテナを束ねたい」は別の要求 ★ 【現在の選択肢(VS 2022)】★ ・単一コンテナ → Docker サポート ・複数コンテナ → Docker Compose ・.NET 中心の分散アプリ → 【.NET Aspire】★★ → C# で構成を記述し、 ダッシュボードでログ・トレースを見られる → compose や K8s マニフェストも生成できる → 詳細は [Visual Studio Kubernetes Tools](MS_VSKubernetesTools) の 「Visual Studio 2026」の補足を参照
こちらでは、Docker ファイルを分析する。
Dockerファイル(DNET_Dockerfile.md)を参照。
Dockerファイル(DNET_Dockerfile.md)の該当節を参照。
前述の「Docker Compose ファイルの編集」を参照。
- docker-compose.yml
version: '3.4'
services:
webapplication1:
image: ${DOCKER_REGISTRY-}webapplication1
build:
context: .
dockerfile: WebApplication1/Dockerfile- docker-compose.override.yml
カスタマイズはコチラに入れろの意味らしい。
version: '3.4'
services:
webapplication1:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "80"
- "443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro-
environment:
環境変数の値を設定する。- ASPNETCORE_ENVIRONMENT:最近、既定で使われて無い感ある。
- ASPNETCORE_URLS=https:使い所が不明感ある。
-
ports:
- コンテナ・ポートの指定
- ホスト・ポートはランダムに指定される。
-
volumes:
不明(要調査)
補足(「不明(要調査)」への回答): 作者が保留にした 3 点は、
いずれも明確な役割があるので補っておく。【① override ファイルの仕組み】★ ・docker compose は 【docker-compose.yml と docker-compose.override.yml を自動的に合成する】 → 前者:全環境共通(ビルド定義など) → 後者:【開発環境固有】の上書き ・本番では override を使わず、 docker-compose.prod.yml を明示指定する docker compose -f docker-compose.yml \ -f docker-compose.prod.yml up → VS が「カスタマイズはコチラに」と促すのは 【この設計に沿っている】★ 【② ${DOCKER_REGISTRY-} という記法】★ ・「DOCKER_REGISTRY が未設定なら空文字」の意 → ローカルでは "webapplication1" → CI では "myacr.azurecr.io/webapplication1" → 【同じファイルでローカルと CI を兼ねる】ための工夫 【③ volumes の 2 行の意味】★★ - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro → 【ユーザー シークレット】をコンテナに見せる → 接続文字列や API キーを イメージに焼き込まずに開発できる ★ - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro → 【開発用の HTTPS 証明書】を見せる → dotnet dev-certs https --trust で作ったもの → これがないと https://+:443 が起動に失敗する ★ ・末尾の :ro は【読み取り専用マウント】 → つまり ② の ASPNETCORE_URLS=https と この volumes は【セット】であり、 「使い所が不明」ではなく 【開発時に HTTPS を使うための仕掛け】である ★【ASPNETCORE_ENVIRONMENT について】 ・「既定で使われて無い感」とあるが、 現在も【中核的な環境変数】である → Development / Staging / Production → appsettings.{Environment}.json の選択 → 開発者例外ページの出し分け ★ ・.NET 6 以降は 【DOTNET_ENVIRONMENT】も併用される (汎用ホストの場合) ・本番で Development のまま動かすと 【スタック トレースが露出する】★★ → 事故として非常に多い
-
生成されたプロジェクトに Docker サポートを追加する。
-
テストの意味合いも含め、コンテナ・ポートを 5000 に変更する。
- Dockerfile
EXPOSE 80 → EXPOSE 5000 に変更する。
- Dockerfile
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 5000
EXPOSE 443- Program.cs
UseUrls メソッドでエンドポイントを変更する。
webBuilder.UseStartup<Startup>()
.UseUrls("http://0.0.0.0:5000/");-
以下を実行してビルドする。
- ソリューションのルート・フォルダに移動して、
>cd ...\WebApplication1
- 以下のコマンドで Dockerfile でビルドする。
>docker build -f WebApplication1/DockerFile -t dotnetapp-dev .
- ビルドの結果(コンテナ・イメージ)を確認する。
>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dotnetapp-dev latest beccad7e863b 14 minutes ago 212MB
-
コンテナの実行と動作確認
- 以下のコマンドでコンテナを実行する。
コンテナ・ポート(5000)を、ホスト・ポート(8888)にマッピング
- 以下のコマンドでコンテナを実行する。
>docker run --rm -p 8888:5000 dotnetapp-dev
-
以下の URL でコンテナにアクセスする。
http://localhost:8888 -
参考
- DockerでASP.NET CoreのWebアプリケーションを実行する方法 | .NETコラム
https://www.fenet.jp/dotnet/column/environment/2005/
- DockerでASP.NET CoreのWebアプリケーションを実行する方法 | .NETコラム
補足(この節の学び方は正しい): IDE の自動化を剥がして
素のdocker build/docker runで確かめるという進め方は、
コンテナを理解する最短経路である。【押さえるべき対応関係】★ VS の F5(Docker)は、内部で概ね次を行っている ① docker build(デバッグ用のステージまで) ② docker run(ボリューム マウント+ vsdbg を注入) ③ vsdbg にアタッチ → 手動でやってみると 【どこで失敗しているか切り分けられる】★ 【-f のパス指定に注意】★ docker build -f WebApplication1/DockerFile -t dotnetapp-dev . ↑ ・最後の "." は【ビルド コンテキスト】 → この配下のファイルが docker デーモンに送られる → Dockerfile 内の COPY はここが基準 ・-f で指定した Dockerfile の場所とは【別物】★ → 混同すると 「COPY で見つからない」エラーになる ・【.dockerignore を置く】★ → bin/ obj/ .git/ node_modules/ を除外 → 転送量が激減し、ビルドが速くなる 【--rm について】 ・終了時にコンテナを自動削除する ・付けないと停止済みコンテナが溜まる ★ → docker ps -a で確認、 docker container prune で掃除【現在のバージョン(本文は .NET Core 3.1)】★ mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim ↓ ・【dotnet/core/ の "core" が取れた】★ mcr.microsoft.com/dotnet/aspnet:8.0 ・タグの例 8.0 … Debian ベース(既定) 8.0-alpine … 【軽量】(約 1/3)★ 8.0-noble … Ubuntu 24.04 ベース 8.0-jammy-chiseled … 【最小限】。シェルすら無い ★★ → 攻撃面が小さく、起動も速い → デバッグはしにくい
-
生成されたプロジェクトに「コンテナー オーケストレーター」の
Docker Compose(Dockerコンポーズ(DNET_DockerCompose.md))を選択して追加。 -
docker-compose.yml と docker-compose.override.yml が生成されるのでマージする。
(マージすると言いつつ、以下の部分を修正してある。)- 環境変数は削除する(使用しないので)
- ビルドは削除する(前述の「Dockerファイル単体使い」で生成されたイメージを
使用するので)。 - コンテナ・ポート(5000)を、ホスト・ポート(8888)にマッピング
version: '3.4'
services:
webapplication1:
image: dotnetapp-dev:latest
ports:
- "8888:5000"
- "443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro-
コンテナの実行と動作確認
- 以下のコマンドでコンテナを実行する。
docker-compose up -d
- 以下の URL でコンテナにアクセスする。
http://localhost:8888
補足(
buildを消してimageだけにする使い方): この構成は
実務でも重要な形である。【2 つの使い方】★ ・【build あり】(開発) build: { context: ., dockerfile: ... } → compose up のたびにビルドされる ・【image のみ】(デプロイ)★ image: myregistry/app:1.2.3 → 【CI が作ったイメージを引いて動かすだけ】 → 本番の compose ファイルはこの形になる → 原文が「前段で生成されたイメージを使用する」と している構成は、 【デプロイ時の形を先取りしている】★ 【イメージのタグ運用】★ ・latest は使わない(前述) ・CI で myapp:${GIT_SHA} myapp:1.2.3 のように固定する → 「どのコードが動いているか」が特定できる ★
-
平たく言って、
- 前述の手順2の Open 棟梁テンプレートを、
- 前述の手順4の Docker Compose(Dockerコンポーズ(
DNET_DockerCompose.md))で
動かす。
-
...そう思ったけど、面倒なのでやってない(出来るという情報はキャッチしている)。
-
後日、Visual Studio Kubernetes Tools の手順8の
Docker Compose → Kubernetes(DNET_Kubernetes.md)の流れの中で、
実施する運びとなった。
- daisukenishino2/EvaluateAspNetCoreOnDocker:
Docker で ASP.NET Core を評価する。(Evaluate ASP.Net Core on Docker.)
https://github.com/daisukenishino2/EvaluateAspNetCoreOnDocker
https://github.com/daisukenishino2/EvaluateAspNetCoreOnDocker/tree/master/MVC_Sample
- 前述の手順2のサンプル
https://github.com/daisukenishino2/EvaluateAspNetCoreOnDocker/tree/master/WebApplication1
- 前述の手順3、手順4のサンプル
「docker-compose」をスタートアップ・プロジェクトに指定する。

次いで、デバッグで、「Docker Compose」を指定して、実行する。

移行メモ(図のキャプション): 上記 2 つの図は、移行元では
いずれもキャプションが「手順1」となっていた
(手順1の図とは別物)。
内容に合わせて見出しと同じ文言に変更した。
-
c# - Remote debugging asp.net core on linux server - Stack Overflow
https://stackoverflow.com/questions/42483122/remote-debugging-asp-net-core-on-linux-server -
Windows 10 に Docker for Windows をインストール|No IT No Life - おすぎやん サーバの設計・構築
https://server-network-info.blogspot.jp/2017/09/windows-10-docker-for-windows.html
-
Visual Studio Tools for Docker と ASP.NET Core
https://learn.microsoft.com/ja-jp/aspnet/core/host-and-deploy/docker/visual-studio-tools-for-docker -
Docker Compose と ASP.NET Core を使用した複数コンテナーのチュートリアル - Visual Studio
https://learn.microsoft.com/ja-jp/visualstudio/containers/tutorial-multicontainer -
Visual Studio Tools for Docker (Windows 上の Visual Studio) を使用
https://learn.microsoft.com/ja-jp/dotnet/architecture/containerized-lifecycle/design-develop-containerized-apps/visual-studio-tools-for-docker- ローカルの Docker コンテナーでアプリをデバッグする
https://learn.microsoft.com/ja-jp/visualstudio/containers/edit-and-refresh - リモート Docker ホストへの ASP.NET Core Linux Docker コンテナーのデプロイ
https://learn.microsoft.com/ja-jp/visualstudio/containers/hosting-web-apps-in-docker
- ローカルの Docker コンテナーでアプリをデバッグする
- Docker for Windowsを使用したASP.NET Core のデバッグ実行
http://kiyokura.hateblo.jp/entry/2016/10/19/225243
- Docker for Windowsをインストールする
https://st40.xyz/one-run/article/314/ - Dockerでよく利用するコマンドまとめ
https://st40.xyz/one-run/article/317/ - Dockerでnginx + ASP.NET Core 2.0のWebサーバ環境を構築する
https://st40.xyz/one-run/article/318/
-
Visual Studio Tools for Docker が ASP.NET CoreのDockerデバッグ実行している仕組みを追ってみた
http://tech.tanaka733.net/entry/research-docker-debug-in-visual-studio-tools-for-docker -
Visual Studio から AzureやWindows以外のdocker containerで走るASP.NET Core をリモートデバッグする
http://tech.tanaka733.net/entry/remote-debug-aspnetcore-on-docker-from-visual-studio -
VisualStudio 2017 RC3 から .NET Core on RHEL にリモートデバッグする
http://tech.tanaka733.net/entry/remote-debug-dotnetcore-on-rhel-from-vs2017rc3 -
.NET Core がLinuxでどのように動いているか、
またわれわれはどのようにデバッグするのか
Issue #8 · uzulla/y8-2017-spring-talks
https://github.com/uzulla/y8-2017-spring-talks/issues/8
Dockerコンポーズ(DNET_DockerCompose.md)の該当節に移動。
-
マイクロソフト系技術情報 Wiki
- Docker for Windows
- Visual Studio Kubernetes Tools
- Visual Studio Code Docker extension(
MS_VSCodeDockerExtension.md) - Azure Container Instances (ACI)
-
開発基盤部会 Wiki
- Docker(
DNET_Docker.md) - Dockerコマンド(
DNET_DockerCommand.md) - Dockerファイル(
DNET_Dockerfile.md) - Dockerレジストリ(
DNET_DockerRegistry.md) - Dockerコンポーズ(
DNET_DockerCompose.md)
- Docker(
-
ASP.NET CoreのLinux開発環境についての考察(WSL or Docker)
https://www.osscons.jp/jotmuz8dq-537/ -
Open棟梁 @ ASP.NET CoreをDockerで動作確認しました。
https://www.osscons.jp/joerypz9u-537/ -
複数のDockerコンテナを使ったASP.NET Core検証環境を構築してみました。
https://www.osscons.jp/joq3nj6gs-537/
移行メモ(リンク切れ): 本ページの
docs.microsoft.comは
Microsoft Learn へ統合されており、
現行の URL に差し替えられるものは置き換えた
(vs-azure-tools-docker-*の 2 件は
visualstudio/containers/配下へ移動している)。
またhub.docker.com/r/microsoft/aspnetcore/は
MCR への移行に伴い非推奨の案内のみとなっている。
server-network-info.blogspot.jp/st40.xyz/
kikki.hatenablog.comなどの個人サイトは、
現在の到達性を保証できない。記録として残す。
Tags: 移行, .NET開発, .NET Core, Hyper-V, 仮想化, コンテナ, IaC
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。