22
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerを簡単に体験する:即席Webサーバー起動・簡易Webアプリ開発・WSL上からアプリ(Gimp)起動

22
Last updated at Posted at 2025-11-15
Page 1 of 34

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

Hellow Dockar が出る。
image.png


Webサーバーを一瞬で立ててみる

所用時間:10分ぐらい。

次は「nginx」を使って、ローカルにWebサーバーを立てます。

docker run -d -p 8080:80 nginx

-d はバックグラウンド実行
-p 8080:80 はポート転送(ホスト8080→コンテナ80)

DownLoadが始まる
image.png

ブラウザで
http://localhost:8080

にアクセスしてみましょう。
Nginxのウェルカムページが出たら、あなたのPCでWebサーバーが動いています!

image.png

が表示される。


コンテナを止めて、片づける

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など。


◆負荷や性能面はどうなの?

  1. 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]
image.png

を選択。

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でインストール。

image.png


事前準備

Visual Studio Installer を開き、

[変更] → [ワークロード] の中で以下にチェック:

☑ ASP.NET と Web 開発
☑ Azure の開発
ちなみに3.24GB消費。

初期設定

image.png


構成図のフロー


FlowsController.csの作成

これは FlowNode の一覧を返す API を作るクラス。

  • HTTP リクエストを受け取る
  • DB(Model) を呼ぶ
  • 最終的に JSON を返す

ノードデータは DB ではなく 静的 List に保持しているので、アプリを再起動すると初期状態(Start, Middle, End の 3 ノード)に戻ります。

FlowsController.cs
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の書き換え

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サポートの追加]
    image.png

image.png

  • Dockerファイルを以下の様に書き換える

image.png


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 フォルダを作成して配置

※アイコンが自動的に変わる
image.png

  • index.html
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
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上で良い)

image.png

プロジェクト直下のディレクトリに移動
ここでは
例:C:\TestCode\FlowApp\FlowApp 

image.png

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つ表示されるようになった

image.png


以下追記

任意のOSイメージを動かしてアプリケーションを実行する。

Windows上でWSL2内のDockerコンテナを動作させます。

OSはubuntu-24.04を使用し、とりあえずGimpとします。

  • デモ動画。
    スライドモード不可。

生活感を出してみました。


Docker Desktopを設定する

Docker Desktop を起動
Settings → Resources → WSL Integration
✅ Ubuntu-22.04 を ON
Apply & Restart

image.png


「Docker を使わず」GIMP を出す(超重要)

WSLg が正常に動いているかを検証するための手順です。これが通らない場合、Docker経由で動かす手順が動作しません(面倒なら飛ばしても構いません)

WSL
sudo apt update
sudo apt install -y gimp
gimp

gimpが表示されれば正常。


Docker Fileをビルドする。

Dockerfile に依存パッケージや設定を明示しておくと、誰がどのマシンでビルドしても同じ環境が作れます。

GIMPを含むX11クライアントをコンテナに入れ、表示(Xサーバ)をホストOS(Windows)に任せた結果、最小設定でGUIが起動します。

※かなり時間が掛かります。私の環境では 434.7s(7分)かかりました。

WSL上
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イメージが起動します。

image.png

UsernameとPasswordを設定します。

Ubuntuに入れます。
image.png

docker pull ubuntu:22.04

image.png

ポイント

  • wsl --install -d Ubuntu-22.04 は WSL 上に Ubuntu 22.04 をインストールする作業

  • Docker Desktop は WSL2 バックエンドを使ってコンテナを動かす

  • Dockerfile をビルドしておけば、GIMP はコンテナ内に含まれる

  • 実際の描画はホストの X11/WSLg が担当するので、GUI 表示だけはホスト環境に依存

Docker Desktop は必須ではなく、あくまで GUI で Docker を操作するための補助ツールです。
実際の GIMP やその他アプリは、コンテナ内で完結して動作します。


コンテナを起動する

WSL上
# ホストの 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を起動するには

Powershell
wsl

1 Dockerが動いているか

Clientだけ出て Server が無い場合、Docker Desktopは未起動。

PowerShell
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コンテナであること)

wsl上
sheephuman@sheephuman:/mnt/c/Users/shinc$
docker info | grep -i "OSType"

# 出力結果
OSType: linux

3 DISPLAY 環境変数が定義されているか

WSL上
sheephuman@sheephuman:/mnt/c/Users/shinc$
echo $DISPLAY
:0

これが空なら、Xサーバの所在が未定義。


4 X11 の Unix socket が存在するか

WSL上
sheephuman@sheephuman:/mnt/c/Users/shinc$
ls /tmp/.X11-unix
X0

5 その socket をマウントできているか(権限)

WSL上
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サーバがクライアント接続を許可しているか

WSL上
/mnt/c/Users/shinc$ xhost

# 出力結果
access control disabled, clients can connect from any host
SI:localuser:wslg

注:これは X11 のアクセス制御そのものが無効 という状態。

以下のcommandで簡単に改善できます

WSL
xhost -          # まず全拒否
xhost +local:    # ローカルプロセスのみ許可

# 出力結果
access control enabled, only authorized clients can connect
non-network local connections being added to access control list

image.png


7 コンテナから DISPLAY を見られるか(環境変数伝播)

WSL上
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 が見えるか

WSL
 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以前)

簡易なテスト用アプリ(xClock)を動かします。
image.png

WSL
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を使っているかの確認(参考)

WSL
echo $WAYLAND_DISPLAY
wayland-0

如何でしたか?

最後までお読みいただきお疲れ様でした。
これのどこが軽い記事なんだよ
皆さまのお役に立てたら幸いです 
知るかFcuking

思った以上に面倒な代物なので、なるべく簡単な構成にさせていただきました(WEBアプリ作成時)。

Gitリポジトリが動かない場合はコメントください。

OSイメージから任意アプリを起動する場合、WSL2を経由しないと困難なことが分かりました。方法があるかもしれないけど。

動作手順は本稿を参照してください(基本的にTerminal上でコマンドが必要)

22
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?