An Easy Hands-On Guide to Trying Docker with Visual Studio
Experience Docker Easily: Instant Web Server Startup, Lightweight Web App Development, and OS Image Execution
6ストックでDockerのOSイメージ体験を追加。
→ 追加しました:任意のOSイメージを動かしてアプリケーションを実行する。
アドベントカレンダーを完走するシリーズ。
今回はDockerを簡単に体験するための記事
手順そのものはLinuxやVSCodeでも大差がないとみられる
序文
Docker を使うと、Webアプリを“どの環境でも同じように動く小さな箱”にまとめて実行できます。この記事では、真っさらな Windows 上で 1 時間以内にそれを体験します。(もろもろ入れたら90分はかかるかも)
参考記事
準備中。近日中に追加予定。
Git(Webアプリ制作)
※スターを常に募集しております。
とにかくSTARを。
Visual Studio 2022 .net9.0
※Pushに失敗していたのでやり直しました。
動かない場合はコメントへ。
参考までに
この記事の手順で作成した場合の推定所要時間
約60~90分
環境構築
Windows11 Home
にアクセスして「Download Docker Desktop」
Windows用のものを選ぶだけです。
installすると再起動されます。
Hellow Docker
docker run hello-world
Webサーバーを一瞬で立ててみる
所用時間:10分ぐらい。
次は「nginx」を使って、ローカルにWebサーバーを立てます。
docker run -d -p 8080:80 nginx
-d はバックグラウンド実行
-p 8080:80 はポート転送(ホスト8080→コンテナ80)
ブラウザで
http://localhost:8080
にアクセスしてみましょう。
Nginxのウェルカムページが出たら、あなたのPCでWebサーバーが動いています!
が表示される。
コンテナを止めて、片づける
docker ps
docker stop <コンテナID>
- 削除
docker rm <コンテナID>
FAQ Docker
◆ 簡単にWebサーバー立てて、自作のWebアプリをデプロイできるってこと?
Yes。
普通なら、Webサーバーを立てるには
「Nginxをインストール → 設定ファイルを書く → HTMLを置く
Dockerはこの手順を簡略化・半自動化出来ます。
◆ 実用的なものは作れるの?
フルに実用レベルです。
Dockerは「おもちゃ」ではなく、
Google、Amazon、Netflix、GitHubなど本番でがっつり使っているレベルの技術です。
たとえば:
Webアプリ:React + Node.js + Nginx構成
APIサーバー:.NET / Flask / FastAPI / Go など
DB連携:PostgreSQL / MySQL / Redis も全部コンテナで動かせる
CI/CD:GitHub Actions や Jenkins でDockerイメージを自動ビルド・デプロイ
つまり「Dockerで作ったもの」は、そのまま本番に持っていけるのです。
特にクラウド(AWS, Azure, GCP)では「Dockerコンテナで動かす前提」になっているサービスが多いです。
例:ECS, App Runner, Cloud Run, Azure Container Appsなど。
◆負荷や性能面はどうなの?
- Dockerは“軽い仮想化”
Dockerは仮想マシンではなく、プロセスの分離技術です。
つまり、OSごと起動しない。
必要なのは「プロセスの分離(namespace)」と「リソース制限(cgroup)」だけ。
→ 起動は数秒、CPU・メモリのオーバーヘッドは非常に小さい。
→ 仮想マシン(VM)よりずっと軽く、ほぼネイティブ性能に近いです。
CPU負荷が顕著に増えることはほぼありません。
ただし、I/O(ファイルアクセス)や大量メモリ処理を伴うアプリでは、
ボリュームマウント(-vオプション)経由だと若干遅くなることがあります。
2 運用での注意点
-
コンテナは永続データを持たない → DBなどは別ボリューム管理が必要
-
リソース制限を設定しないと、複数コンテナがCPUを取り合うこともある
-
ログ管理はホスト側で集約する設計にする(Docker単体では貧弱)
まとめ
| 項目 | Dockerの評価 |
|---|---|
| 実用性 | ◎(企業・商用利用が当たり前) |
| パフォーマンス | ○〜◎(VMより軽い、ほぼネイティブ) |
| 導入難度 | 低(イメージ化で依存解消) |
| 注意点 | 永続化・ログ・リソース管理 |
最小構成のWebアプリを作ろう
所用時間:最短で60分程度。
インストール時間を除く。
- 要件
-
FlowChartを作成する
-
.NETアプリをDocker化
-
docker runで立ち上がる -
短時間で実装出来るように最小構成にする
-
DataBaseは使うが、永続化させない
-
認証機能を付けない
-
1.プロジェクト作成
分かりやすいのでVisual Studio2022を使用するものとします。
「新しいプロジェクトの作成」
→ テンプレート: [ASP.NET Core Web API]

を選択。
2.NuGetパッケージを追加
Visual Studio の ソリューションエクスプローラー → 右クリック → NuGetパッケージの管理
で以下を追加します:
※表示されない場合は一度閉じて、Visual Studioを.sln経由で再起動してください。
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Sqlite
Microsoft.EntityFrameworkCore.InMemory //← 検証用
※.net9.0の場合はVersion 9.x.xx で合わせると安定
※Microsoft.EntityFrameworkCore、Microsoft.EntityFrameworkCore.Sqliteは
パッケージ Microsoft.EntityFrameworkCore 10.0.0 は net9.0 (.NETCoreApp,Version=v9.0) と互換性がありません。 パッケージ Microsoft.EntityFrameworkCore 10.0.0 がサポートするもの: net10.0 (.NETCoreApp,Version=v10.0)
とあるので、9.0.11でインストール。
初期設定
構成図のフロー
FlowsController.csの作成
これは FlowNode の一覧を返す API を作るクラス。
- HTTP リクエストを受け取る
- DB(Model) を呼ぶ
- 最終的に JSON を返す
ノードデータは DB ではなく 静的 List に保持しているので、アプリを再起動すると初期状態(Start, Middle, End の 3 ノード)に戻ります。
using Microsoft.AspNetCore.Mvc;
namespace FlowApp.Controllers
{
[ApiController]
[Route("[controller]")]
public class FlowsController : ControllerBase
{
// メモリ上にノードを保持(初期 3 ノード)
private static readonly List<FlowNode> nodes = new List<FlowNode>
{
new FlowNode { Label = "Start", X = 50, Y = 50 },
new FlowNode { Label = "Middle", X = 125, Y = 50 },
new FlowNode { Label = "End", X = 200, Y = 50 }
};
// GET /flows
[HttpGet]
public IEnumerable<FlowNode> Get() => nodes;
// POST /flows
[HttpPost]
public ActionResult<FlowNode> Post([FromBody] FlowNode node)
{
if (node == null) return BadRequest();
nodes.Add(node); // 新しいノードを追加
return Ok(node);
}
}
// FlowChart のノード情報
public class FlowNode
{
public string Label { get; set; }
public int X { get; set; }
public int Y { get; set; }
}
}
FlowDbContext.csの作成
“データベースとの会話を担当する層”
DbContext は Entity Framework Core の心臓部。
アプリ内で扱うデータを ― クラスとして表現したもの(FlowNode)を ―
実際の DB へ読み書きする仲介役
WPFのInotifyPropertyChangedみたいなもの。
using FlowApp.Controllers;
using Microsoft.EntityFrameworkCore;
namespace FlowApp.Data
{
public class FlowDbContext : DbContext
{
public FlowDbContext(DbContextOptions<FlowDbContext> options)
: base(options) { }
public DbSet<FlowNode> Nodes => Set<FlowNode>();
}
}
Program.csの書き換え
using FlowApp.Controllers;
using FlowApp.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Controllers(デフォルト)
builder.Services.AddControllers();
// OpenAPI(デフォルト)
builder.Services.AddOpenApi();
// ▼ InMemory DB を追加
builder.Services.AddDbContext<FlowDbContext>(opt =>
opt.UseInMemoryDatabase("FlowDb"));
var app = builder.Build();
// 静的ファイルを有効化
app.UseStaticFiles();
// OpenAPI(デフォルト)
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
// HTTPS リダイレクトは Docker で邪魔になるのでオフ
// app.UseHttpsRedirection();
// 認証は使わないので削除
// app.UseAuthorization();
// ▼▼ Minimal API 追加 ▼▼
// GET 全ノード取得
app.MapGet("/flow/node", async (FlowDbContext db) =>
{
return await db.Nodes.ToListAsync();
});
// POST ノード追加
app.MapPost("/flow/node", async (FlowDbContext db, FlowNode node) =>
{
db.Nodes.Add(node);
await db.SaveChangesAsync();
return Results.Ok(node);
});
// Controllers も有効化したまま
app.MapControllers();
// アプリ起動
app.Run();
Dockerfile の作成
プロジェクト直下に Dockerfile を作ります。
- Dockerファイルを以下の様に書き換える
# デバッグ用ベースイメージ
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
# ビルド用ステージ
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# プロジェクトファイルだけコピーして restore
COPY ["FlowApp/FlowApp.csproj", "FlowApp/"]
RUN dotnet restore "./FlowApp/FlowApp.csproj"
# 残りのソースコードをコピー
COPY . .
WORKDIR "/src/FlowApp"
RUN dotnet build "./FlowApp.csproj" -c $BUILD_CONFIGURATION -o /app/build
# 公開用ステージ
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FlowApp.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# 実行用ステージ
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FlowApp.dll"]
Docker イメージ作成
ターミナルでプロジェクト直下から実行
docker build -t flowapp .
- 成功した場合
docker imagescommandでflowAppが表示される
PS C:\TestCode\FlowApp\FlowApp> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
+ flowapp latest 77eecbb50d23 4 minutes ago 384MB
nginx latest 1beed3ca46ac 11 days ago 225MB
hello-world latest f7931603f70e 3 months ago 20.3kB
wwwroot フォルダを作成して配置
- index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>FlowChart Viewer</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<h1>FlowChart</h1>
<canvas id="flowCanvas" width="800" height="600"></canvas>
<script src="js/flow.js"></script>
</body>
</html>
- flow.js
async function loadFlows() {
const canvas = document.getElementById('flowCanvas');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = "14px sans-serif";
try {
const res = await fetch('/flows');
const items = await res.json();
if (items.length === 0) {
ctx.fillText("Loading [読み込み中...]", 10, 20);
return;
}
items.forEach(item => {
const x = item.X ?? item.x;
const y = item.Y ?? item.y;
const label = item.Label ?? item.label;
ctx.fillStyle = "lightblue";
ctx.fillRect(x, y, 100, 50);
ctx.strokeRect(x, y, 100, 50);
ctx.fillStyle = "black";
ctx.fillText(label, x + 10, y + 25);
// 座標を矩形上に表示
ctx.fillStyle = "red";
ctx.font = "12px sans-serif";
ctx.fillText(`(${x}, ${y})`, x + 10, y + 45); // 矩形下部に座標
});
} catch (e) {
ctx.fillStyle = "red";
ctx.fillText("Error fetching data", 10, 20);
}
}
// 初回ロード
loadFlows();
// 10秒ごとに更新
setInterval(loadFlows, 10000);
プロジェクト構成の確認
強調表示が追加した部分。
ソリューション 'FlowApp' (1/1 プロジェクト)
└─ FlowApp
├─ Connected Services
├─ Properties
+ ├─ wwwroot
+ │ ├─ js
+ │ │ └─ flow.js
+ │ └─ index.html
├─ 依存関係
├─ Controllers
+ │ ├─ FlowsController.cs
│ └─ WeatherForecastController.cs ← defaultで入ってるデモ用のクラス
├─ appsettings.json
├─ Dockerfile
├─ FlowApp.http
+ ├─ FlowDbContext.cs
├─ Program.cs
└─ WeatherForecast.cs
ビルドする
docker build -t flowapp .
Visual Studio等のIDEで編集したものを反映させるには再度ビルドする必要がある。
ビルド前にコンテナをstopし、削除しなければならない。
面倒なら以下をPowerShellでまとめて実行すればOK。
docker build -t flowapp .
docker stop flowapp-container
docker rm flowapp-container
docker run -d -p 5000:8080 -v ${PWD}/wwwroot:/app/wwwroot --name flowapp-container flowapp
確認用コマンド
docker version : docker Desktopが起動しているか確認
docker images : 起動中のDoceker image
docker logs flowapp-container : flowapp-containerがLighthen(受信状態?)しているか確認するためのログcommand。
実行手順と結果
Docker-Desktopを起動(Windows11上で良い)
プロジェクト直下のディレクトリに移動
ここでは
例:C:\TestCode\FlowApp\FlowApp
docker run -d -p 5000:8080 --name flowapp-container flowapp
でHttpでローカル起動。
PowerShellでNodeを3つ追加するコマンド
$nodes = @(
>> @{ Label="Start"; X=50; Y=50 },
>> @{ Label="Middle"; X=125; Y=50 },
>> @{ Label="End"; X=200; Y=50 }
>> )
を実行しておく
ブラウザ上で
http://localhost:5000/index.html
にアクセス
nodeが3つ表示されるようになった
以下追記
任意のOSイメージを動かしてアプリケーションを実行する。
Windows上でWSL2内のDockerコンテナを動作させます。
OSはubuntu-24.04を使用し、とりあえずGimpとします。
- デモ動画。
スライドモード不可。
生活感を出してみました。
Docker Desktopを設定する
Docker Desktop を起動
Settings → Resources → WSL Integration
✅ Ubuntu-22.04 を ON
Apply & Restart
「Docker を使わず」GIMP を出す(超重要)
WSLg が正常に動いているかを検証するための手順です。これが通らない場合、Docker経由で動かす手順が動作しません(面倒なら飛ばしても構いません)
sudo apt update
sudo apt install -y gimp
gimp
gimpが表示されれば正常。
Docker Fileをビルドする。
Dockerfile に依存パッケージや設定を明示しておくと、誰がどのマシンでビルドしても同じ環境が作れます。
GIMPを含むX11クライアントをコンテナに入れ、表示(Xサーバ)をホストOS(Windows)に任せた結果、最小設定でGUIが起動します。
※かなり時間が掛かります。私の環境では 434.7s(7分)かかりました。
sheephuman@sheephuman:/mnt/c/Users/shinc$
cat <<EOF > Dockerfile.gimp
# ベースイメージとして Ubuntu 22.04 を使用
FROM ubuntu:22.04
# コンテナ内で GIMP と X11 クライアントツールをインストール
RUN apt-get update && apt-get install -y gimp x11-apps
# コンテナ起動時に実行するコマンド(GIMP を起動)
CMD ["gimp"]
EOF
そのあとDocker fileをビルド
docker build -t my-gimp -f Dockerfile.gimp .
WSLを起動してUbuntuをインストール
Terminal(PowerShell)上で
wsl をPoweshell上で起動。
このとき、Docker Desktop上のWSLが使われています。
wsl上で
wsl --install -d Ubuntu-22.04
install後、Ubuntuイメージが起動します。
UsernameとPasswordを設定します。
docker pull ubuntu:22.04
Docker Desktop は必須ではなく、あくまで GUI で Docker を操作するための補助ツールです。
実際の GIMP やその他アプリは、コンテナ内で完結して動作します。
コンテナを起動する
# ホストの X11 Unix socket をコンテナに共有(GIMP が画面に描画できるように)
# DISPLAY 環境変数をコンテナに渡す(どの X サーバに接続するかを指定)
# 起動するイメージ名
docker run -it \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-e DISPLAY=$DISPLAY \
my-gimp
- Docker DeskTopが起動中の場合のcommand(オプション)
Windows11で動作確認済み。
# Docker コンテナで GIMP を起動する際の設定例(WSLg 環境向け)
# - X11 と Wayland の socket をマウントして GUI を表示
# - DISPLAY, WAYLAND_DISPLAY, XDG_RUNTIME_DIR, PULSE_SERVER を設定して描画と音声を有効化
docker run -it \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-v /run/desktop/mnt/host/wslg:/mnt/wslg \
-e DISPLAY=:0 \
-e WAYLAND_DISPLAY=wayland-0 \
-e XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir \
-e PULSE_SERVER=/mnt/wslg/PulseServer \
my-gimp
--rmオプションを付けると永続しませんが(閉じると消えてしまう)、テスト環境では面倒です。
Docker イメージ(コンテナ)には画面(ディスプレイ)がないため、
ホスト OS(Windows 側で動作している X11 環境)を通して、イメージ内のX11(Linux の画面表示プロトコル)に描画を委譲します。
確認事項
WSLを起動するには
wsl
1 Dockerが動いているか
Clientだけ出て Server が無い場合、Docker Desktopは未起動。
docker version
# 以下出力結果
Client:
Version: 28.5.1
API version: 1.51
Go version: go1.24.8
Git commit: e180ab8
Built: Wed Oct 8 12:19:16 2025
OS/Arch: windows/amd64
Context: desktop-linux
Server: Docker Desktop 4.50.0 (209931)
Engine:
Version: 28.5.1
API version: 1.51 (minimum version 1.24)
Go version: go1.24.8
Git commit: f8215cc
Built: Wed Oct 8 12:17:24 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.27
GitCommit: 05044ec0a9a75232cad458027ca83437aae3f4da
runc:
Version: 1.2.5
GitCommit: v1.2.5-0-g59923ef
docker-init:
Version: 0.19.0
GitCommit: de40ad0
2 コンテナを起動できるか(Linuxコンテナであること)
sheephuman@sheephuman:/mnt/c/Users/shinc$
docker info | grep -i "OSType"
# 出力結果
OSType: linux
3 DISPLAY 環境変数が定義されているか
sheephuman@sheephuman:/mnt/c/Users/shinc$
echo $DISPLAY
:0
これが空なら、Xサーバの所在が未定義。
4 X11 の Unix socket が存在するか
sheephuman@sheephuman:/mnt/c/Users/shinc$
ls /tmp/.X11-unix
X0
5 その socket をマウントできているか(権限)
heephuman@sheephuman:/mnt/c/Users/shinc$ ls -ld /tmp/.X11-unix
drwxrwxrwx 2 root root 60 Dec 20 16:50 /tmp/.X11-unix
6 Xサーバがクライアント接続を許可しているか
/mnt/c/Users/shinc$ xhost
# 出力結果
access control disabled, clients can connect from any host
SI:localuser:wslg
7 コンテナから DISPLAY を見られるか(環境変数伝播)
docker run --rm -e DISPLAY=$DISPLAY ubuntu env | grep DISPLAY
DISPLAY=:0
※ない場合は自動的にそのOSがインストールされるようです。
-e DISPLAY=$DISPLAY でホストの DISPLAY をコンテナに渡している
ubuntu env | grep DISPLAY で確認した結果、コンテナ内でも DISPLAY=:0 と表示
つまり GIMP や x11-apps がどの X サーバに接続すればよいか、コンテナが認識できている
8 コンテナから X11 socket が見えるか
docker run --rm \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
ubuntu:24.04 ls /tmp/.X11-unix
Unable to find image 'ubuntu:24.04' locally
24.04: Pulling from library/ubuntu
Digest: sha256:c35e29c9450151419d9448b0fd75374fec4fff364a27f176fb458d472dfc9e54
Status: Downloaded newer image for ubuntu:24.04
X0
9 最小Xクライアントで描画テスト(GIMP以前)
docker run --rm -it \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
ubuntu:24.04 \
bash -c "apt-get update && apt-get install -y x11-apps && xclock"
10 Waylandを使っているかの確認(参考)
echo $WAYLAND_DISPLAY
wayland-0
如何でしたか?
最後までお読みいただきお疲れ様でした。
これのどこが軽い記事なんだよ
皆さまのお役に立てたら幸いです
知るかFcuking
思った以上に面倒な代物なので、なるべく簡単な構成にさせていただきました(WEBアプリ作成時)。
Gitリポジトリが動かない場合はコメントください。
OSイメージから任意アプリを起動する場合、WSL2を経由しないと困難なことが分かりました。方法があるかもしれないけど。
動作手順は本稿を参照してください(基本的にTerminal上でコマンドが必要)

















