404 Not Found

404 Not Found


nginx

「導入とパフォーマンスの最適化」

チャーリーがnode app.jsを使用してAPIを本番サーバーにデプロイした後、未処理の例外によりプロセスが頻繁にクラッシュし、無人運用中に長時間のサービス停止が発生していました。そこで彼は、自動再起動とクラスターモードを有効にするためにPM2を導入し、Dockerによるコンテナ化とNginxのリバースプロキシを組み合わせた結果、サービスの可用性を95%から99.9%へと向上させ、ようやく安眠できるようになりました。

学習内容:


1. PM2 プロセス管理

(1) なぜプロセスマネージャーが必要なのか?

本番環境では、Node.js プロセスは、未処理の例外、メモリリーク、またはシステムリソースの不足によりクラッシュすることがあります。node app.js で直接起動した場合、クラッシュ後にプロセスは再起動されないため、サービスが中断してしまいます。PM2 は Node.js 向けに最も広く利用されているプロセスマネージャーであり、自動再起動、ログ管理、ロードバランシング、および監視機能を提供しています。

(2) インストールと基本コマンド

BASH
npm install -g pm2
BASH
pm2 start app.js --name "my-api"
pm2 restart my-api
pm2 stop my-api
pm2 delete my-api
pm2 logs my-api
pm2 monit

(3) PM2の一般的なコマンドのクイックリファレンス

コマンド 機能 一般的な使用例
pm2 start app.js アプリを起動 初回デプロイ
pm2 restart <name> アプリを再起動 コードの更新後
pm2 reload <name> ダウンタイムゼロの再起動 本番環境の更新
pm2 stop <name> サービス停止中 メンテナンス中
pm2 delete <name> プロセスの削除 完全に削除
pm2 logs [name] ログを表示 トラブルシューティング
pm2 monit リアルタイム監視ダッシュボード リソース使用状況の監視
pm2 list プロセス一覧 実行状況の表示
pm2 describe <name> プロセスの詳細 詳細な診断
pm2 save プロセス一覧の保存 起動設定
pm2 startup 起動スクリプトを生成 サーバー再起動後に自動的に復元

▶ 例:PM2の起動と監視

BASH
pm2 start app.js --name "charlie-api" -i max
pm2 monit
pm2 save
pm2 startup
TEXT
┌─────┬──────────────┬─────────────┬─────────┬─────────┬──────────┐
│ id  │ name         │ mode        │ ↺       │ status  │ cpu      │
├─────┼──────────────┼─────────────┼─────────┼─────────┼──────────┤
│ 0   │ charlie-api  │ cluster     │ 15      │ online  │ 12%      │
│ 1   │ charlie-api  │ cluster     │ 2       │ online  │ 8%       │
│ 2   │ charlie-api  │ cluster     │ 0       │ online  │ 5%       │
│ 3   │ charlie-api  │ cluster     │ 1       │ online  │ 3%       │
└─────┴──────────────┴─────────────┴─────────┴─────────┴──────────┘

2. Dockerの基礎

(1) なぜDockerを使うのか

Dockerは、アプリケーションとその依存関係をコンテナイメージにパッケージ化し、開発、テスト、本番環境全体で一貫性を確保します。以前はローカルマシンで正常に動作していたチャーリーのコードも、Node.jsのバージョンの違いにより、サーバーにデプロイされた後にエラーが発生していましたが、Dockerによってこの問題は完全に解決されました。

(2) Dockerfileの作成

DOCKERFILE
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s \
  CMD node healthcheck.js

USER node

CMD ["node", "app.js"]

(3) Docker Compose によるマルチサービスのオーケストレーション

YAML
version: "3.8"

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MONGO_URI=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis
    restart: always
    healthcheck:
      test: ["CMD", "node", "healthcheck.js"]
      interval: 30s
      timeout: 3s
      retries: 3

  mongo:
    image: mongo:7
    volumes:
      - mongo-data:/data/db
    restart: always

  redis:
    image: redis:7-alpine
    restart: always

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - api
    restart: always

volumes:
  mongo-data:

(4) 導入方法の比較

カテゴリ ベアメタル展開 Docker 展開 クラウドサービス展開
環境の一貫性 低い 優れている 優れている
展開速度 遅い 速い 最も速い
運用の複雑さ
リソース利用率 オンデマンド
拡張性の柔軟性 低い 良い 非常に良い
コスト
ユースケース 小規模プロジェクト 中・大規模プロジェクト エンタープライズレベルのプロジェクト
学習曲線

▶ 例:Docker イメージの作成と実行

BASH
docker build -t charlie-api:1.0 .
docker run -d -p 3000:3000 --env-file .env charlie-api:1.0
docker-compose up -d
docker-compose logs -f api

3. 環境変数の管理

(1) なぜ環境変数が必要なのか?

データベースのアドレス、ポート番号、パスワードなどの設定は、環境(開発、テスト、本番)によって異なります。これらの設定をコードにハードコーディングすると、セキュリティ上のリスクが生じ、環境間の切り替えが困難になります。環境変数を使用することで、Twelve-Factor App の方法論に沿って、設定とコードを分離することができます。

(2) dotenv および .env ファイル

JAVASCRIPT
const dotenv = require('dotenv');

dotenv.config({ path: `.env.${process.env.NODE_ENV || 'development'}` });

const config = {
  port: parseInt(process.env.PORT, 10) || 3000,
  mongoUri: process.env.MONGO_URI,
  jwtSecret: process.env.JWT_SECRET,
  redisUrl: process.env.REDIS_URL,
  logLevel: process.env.LOG_LEVEL || 'info',
};

module.exports = config;

(3) 本番環境の構成戦略

TEXT
.env                # Default Configuration(Do not submit Git)
.env.development    # Development Environment
.env.test           # Test Environment
.env.production     # Production Environment(Through CI/CD Inject,Do not commit to the code repository)

(4) 環境変数の管理方法の比較

手法 セキュリティ 柔軟性 チームでの共同作業 活用事例
.env ファイル 良好 一般的なプロジェクト
システム環境変数 不良 導入の容易さ
Dockerのシークレット 良好 Docker環境
K8s Secrets 優秀 Kubernetes
クラウドプラットフォーム設定センター 優秀 クラウドネイティブプロジェクト

▶ 例:マルチ環境設定の読み込み

JAVASCRIPT
const path = require('path');
const dotenv = require('dotenv');

const env = process.env.NODE_ENV || 'development';

const envFile = path.resolve(process.cwd(), `.env.${env}`);
dotenv.config({ path: envFile });

if (env === 'development') {
  dotenv.config({ path: path.resolve(process.cwd(), '.env') });
}

const required = ['MONGO_URI', 'JWT_SECRET'];
const missing = required.filter(key => !process.env[key]);

if (missing.length) {
  throw new Error(`Missing required env vars: ${missing.join(', ')}`);
}

module.exports = {
  env,
  port: parseInt(process.env.PORT, 10) || 3000,
  mongoUri: process.env.MONGO_URI,
  jwtSecret: process.env.JWT_SECRET,
  redisUrl: process.env.REDIS_URL,
  logLevel: process.env.LOG_LEVEL || 'info',
};

4. クラスタモード

(1) なぜクラスターが必要なのか?

Node.js はシングルスレッドであるため、1つのCPUコア上で実行できるインスタンスは1つだけです。クラスターモードでは、cluster モジュールを使用して複数のワーカープロセスを作成し、マルチコアCPUを最大限に活用することで、スループットと可用性を大幅に向上させます。

(2) クラスタ・モジュールの仕組み

マスタープロセスは、ポートでのリスニングとリクエストの分配を担当し、ワーカープロセスは実際のビジネスロジックを処理します。複数のワーカープロセスが同じポートを共有することで、負荷分散を実現しています。

(3) クラスタの手動設定

JAVASCRIPT
const cluster = require('cluster');
const os = require('os');
const http = require('http');

if (cluster.isPrimary) {
  const numCPUs = os.cpus().length;
  console.log(`Master ${process.pid} is running`);
  console.log(`Forking ${numCPUs} workers...`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died. Restarting...`);
    cluster.fork();
  });
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Handled by worker ${process.pid}\n`);
  }).listen(3000);

  console.log(`Worker ${process.pid} started`);
}

(4) PM2 クラスターモード

PM2には、コードを変更することなく有効化できるクラスタ機能が組み込まれています:

BASH
pm2 start app.js -i max
pm2 start app.js -i 4

▶ 例:クラスタモードの性能比較

BASH
node single.js &
ab -n 10000 -c 100 http://localhost:3000/
TEXT
Single process:
  Requests per second:    3254.21 [#/sec]

Cluster (4 workers):
  Requests per second:    11280.67 [#/sec]

5. パフォーマンス分析

(1) console.time を使った基本的なタイミング

パフォーマンスを測定する最も簡単な方法で、処理が遅い箇所を素早く特定するのに最適です:

JAVASCRIPT
app.get('/api/users', async (req, res) => {
  console.time('fetch-users');
  const users = await User.find().lean();
  console.timeEnd('fetch-users');
  res.json(users);
});

(2) パフォーマンスフック:正確な測定

Node.js に組み込まれている perf_hooks モジュールは、高精度なタイミング機能を提供します:

JAVASCRIPT
const { performance, PerformanceObserver } = require('perf_hooks');

const obs = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
  });
});
obs.observe({ type: 'measure', buffered: true });

function measureAsync(label, fn) {
  return async (...args) => {
    performance.mark(`${label}-start`);
    const result = await fn(...args);
    performance.mark(`${label}-end`);
    performance.measure(label, `${label}-start`, `${label}-end`);
    return result;
  };
}

const fastQuery = measureAsync('db-query', async () => {
  return await User.find().lean();
});

(3) Clinic.js プロフェッショナル診断

Clinic.js は、Node.js が推奨する公式のパフォーマンス診断ツールキットです:

BASH
npm install -g clinic
clinic doctor -- node app.js
clinic flame -- node app.js
clinic bubbleprof -- node app.js

(4) 性能最適化戦略の比較

戦略 ツール/手法 適用可能なシナリオ 難易度 有効性
タイミング解析 console.time クイック検索
正確な測定 perf_hooks クリティカルパス
CPU分析 クリニック・フレイム CPU負荷が高い
イベントループ 診療医 I/O ブロッキング
メモリリーク heapdump / memwatch メモリ関連の問題
負荷テスト オートキャノン / ab キャパシティプランニング
APMモニタリング New Relic / Datadog 継続的モニタリング

▶ 例:負荷テストにおけるオートキャノンの使用

BASH
npm install -g autocannon
autocannon -c 100 -d 10 http://localhost:3000/api/health
TEXT
┌─────────┬──────┬──────┬───────┬──────┬───────┬───────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg   │ Stdev │ Max   │
├─────────┼──────┼──────┼───────┼──────┼───────┼───────┼───────┤
│ Latency │ 2 ms │ 4 ms │ 12 ms │ 18ms │ 5 ms  │ 3 ms  │ 45 ms │
└─────────┴──────┴──────┴───────┴──────┴───────┴───────┴───────┘

Requests/sec: 18523.6

6. ヘルスチェックのエンドポイント

(1) なぜ健康診断が必要なのでしょうか?

コンテナオーケストレーションシステム(Docker、K8s)やロードバランサーは、サービスが正常に稼働しているかどうかを把握する必要があります。ヘルスチェックエンドポイントは、サービスの状態を検知するための標準化されたインターフェースを提供し、自動的な障害検知やトラフィックの切り替えを可能にします。

(2) 基本健康診断

JAVASCRIPT
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

(3) 詳細なヘルスチェック

JAVASCRIPT
app.get('/health', async (req, res) => {
  const checks = {
    server: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
  };

  try {
    await mongoose.connection.db.admin().ping();
    checks.database = 'ok';
  } catch (err) {
    checks.database = 'error';
  }

  try {
    await redisClient.ping();
    checks.redis = 'ok';
  } catch (err) {
    checks.redis = 'error';
  }

  const isHealthy = checks.database === 'ok' && checks.redis === 'ok';
  res.status(isHealthy ? 200 : 503).json(checks);
});

(4) 準備状態と稼働状態の分離

本番環境では、ヘルスチェックは通常、「稼働状態(プロセスが稼働しているかどうか)」と「応答状態(トラフィックを受け入れる準備ができているかどうか)」の2種類に分類されます:

JAVASCRIPT
app.get('/healthz', (req, res) => {
  res.json({ status: 'alive' });
});

app.get('/readyz', async (req, res) => {
  try {
    await mongoose.connection.db.admin().ping();
    await redisClient.ping();
    res.json({ status: 'ready' });
  } catch {
    res.status(503).json({ status: 'not ready' });
  }
});

▶ 例:Dockerのヘルスチェックスクリプト

JAVASCRIPT
const http = require('http');

const options = {
  hostname: 'localhost',
  port: process.env.PORT || 3000,
  path: '/healthz',
  timeout: 2000,
};

const req = http.request(options, (res) => {
  if (res.statusCode === 200) {
    process.exit(0);
  } else {
    process.exit(1);
  }
});

req.on('error', () => process.exit(1));
req.on('timeout', () => { req.destroy(); process.exit(1); });
req.end();

7. Nginxのリバースプロキシ

(1) なぜNginxが必要なのか?

Nginxはリバースプロキシとして機能し、SSL終端、負荷分散、静的リソースの配信、リクエストのスロットリングなどの機能を提供します。Node.jsはビジネスロジックに重点を置き、Nginxはネットワーク層の最適化を担当します。それぞれが独自の役割を果たしています。

(2) Node.js の本番環境展開アーキテクチャ

100%
graph LR
    Client[Client] --> Nginx[Nginx Reverse Proxy<br/>:80/:443]
    Nginx --> PM2[PM2 Cluster Management]
    PM2 --> W1[Worker 1<br/>:3000]
    PM2 --> W2[Worker 2<br/>:3000]
    PM2 --> W3[Worker 3<br/>:3000]
    PM2 --> W4[Worker 4<br/>:3000]
    W1 --> DB[(MongoDB)]
    W2 --> DB
    W3 --> Redis[(Redis)]
    W4 --> Redis

(3) Nginxの設定

TEXT
upstream nodejs_backend {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    keepalive 64;
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate     /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/certs/api.example.com.key;

    location / {
        proxy_pass http://nodejs_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }

    location /health {
        proxy_pass http://nodejs_backend/health;
        access_log off;
    }

    location /static/ {
        alias /app/public/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
    limit_req zone=api burst=50 nodelay;
}

▶ 例:Docker における Nginx のリバースプロキシ設定

YAML
# docker-compose.yml Excerpt
nginx:
  image: nginx:alpine
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
    - ./ssl:/etc/ssl/certs:ro
  depends_on:
    api:
      condition: service_healthy
  restart: always

8. 包括的な例:デプロイメント構成の全体像

チャーリーは、すべてのデプロイ設定を単一のシステムに統合し、コードから本番環境までのプロセス全体を自動化しました。

▶ 例:プロジェクトのディレクトリ構造

TEXT
charlie-api/
├── app.js
├── healthcheck.js
├── config/
│   └── index.js
├── ecosystem.config.js
├── Dockerfile
├── docker-compose.yml
├── nginx.conf
├── .env.example
├── .dockerignore
└── package.json

▶ 例:PM2 の ecosystem.config.js

JAVASCRIPT
module.exports = {
  apps: [
    {
      name: 'charlie-api',
      script: 'app.js',
      instances: 'max',
      exec_mode: 'cluster',
      autorestart: true,
      watch: false,
      max_memory_restart: '512M',
      env_development: {
        NODE_ENV: 'development',
        PORT: 3000,
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 3000,
      },
      error_file: './logs/error.log',
      out_file: './logs/out.log',
      merge_logs: true,
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      max_restarts: 10,
      restart_delay: 4000,
      kill_timeout: 5000,
      listen_timeout: 10000,
    },
  ],
  deploy: {
    production: {
      user: 'deploy',
      host: 'api.example.com',
      ref: 'origin/main',
      repo: 'git@github.com:charlie/api.git',
      path: '/var/www/charlie-api',
      'pre-deploy-local': '',
      'post-deploy':
        'npm ci && pm2 reload ecosystem.config.js --env production',
      'pre-setup': '',
    },
  },
};

▶ 例:Dockerfile(マルチステージビルド向けに最適化)

DOCKERFILE
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build 2>/dev/null || true

FROM node:20-alpine AS production

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --from=builder /app ./

RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD node healthcheck.js

CMD ["node", "app.js"]

▶ 例:.env.example

TEXT
NODE_ENV=production
PORT=3000
MONGO_URI=mongodb://mongo:27017/charlie-api
REDIS_URL=redis://redis:6379
JWT_SECRET=your-secret-key-here
LOG_LEVEL=info
CORS_ORIGIN=https://example.com
RATE_LIMIT_WINDOW=60000
RATE_LIMIT_MAX=100

▶ 例:healthcheck.js

JAVASCRIPT
const http = require('http');

const req = http.request(
  {
    hostname: '127.0.0.1',
    port: parseInt(process.env.PORT, 10) || 3000,
    path: '/healthz',
    timeout: 2000,
  },
  (res) => {
    process.exit(res.statusCode === 200 ? 0 : 1);
  }
);

req.on('error', () => process.exit(1));
req.on('timeout', () => { req.destroy(); process.exit(1); });
req.end();

▶ 例:app.js 内のヘルスチェックエンドポイント

JAVASCRIPT
const express = require('express');
const mongoose = require('mongoose');
const config = require('./config');

const app = express();
app.use(express.json());

app.get('/healthz', (req, res) => {
  res.json({ status: 'alive', pid: process.pid });
});

app.get('/readyz', async (req, res) => {
  try {
    await mongoose.connection.db.admin().ping();
    res.json({ status: 'ready', pid: process.pid, uptime: process.uptime() });
  } catch {
    res.status(503).json({ status: 'not ready', pid: process.pid });
  }
});

app.get('/health', async (req, res) => {
  const checks = {
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    pid: process.pid,
  };

  try {
    await mongoose.connection.db.admin().ping();
    checks.database = 'ok';
  } catch {
    checks.database = 'error';
    checks.status = 'degraded';
  }

  const isHealthy = checks.database === 'ok';
  res.status(isHealthy ? 200 : 503).json(checks);
});

app.get('/api/users', async (req, res) => {
  console.time('fetch-users');
  const users = await mongoose.model('User').find().lean();
  console.timeEnd('fetch-users');
  res.json({ success: true, data: users });
});

mongoose.connect(config.mongoUri).then(() => {
  app.listen(config.port, () => {
    console.log(`Server running on port ${config.port} [${config.env}]`);
  });
});

process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down gracefully...');
  mongoose.connection.close();
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('SIGINT received, shutting down gracefully...');
  mongoose.connection.close();
  process.exit(0);
});

❓ よくある質問

Q DockerとPM2は併用できますか?
A はい、できますが、通常はどちらか一方を選択します。Node.jsはDockerコンテナ内で直接実行され、再起動はK8sまたはDocker Composeによって管理されます。一方、PM2はコンテナ化されていない環境でのデプロイに適しています。
Q クラウドサービスプラットフォームはどのように選べばよいですか?
A 小規模なプロジェクトにはVercelやRailway(設定不要)を、中規模のプロジェクトにはAWSやGCP(柔軟性が高いが複雑)を、中国でのプロジェクトにはAlibaba CloudやTencent Cloudを利用しましょう。予算やチームの経験に応じて選択してください。
Q よく使われているCI/CDツールにはどのようなものがありますか?
A GitHub Actions(GitHubとの連携が良好)、GitLab CI(セルフホスティングに便利)、Jenkins(エンタープライズ向けで、プラグインが豊富)、CircleCI(クラウドネイティブ)などです。
Q 本番環境の Node.js アプリケーションをどのように監視すればよいですか?
A PM2、New Relic、Datadog、または自前でホストした Prometheus と Grafana の組み合わせを使用して、CPU、メモリ、応答時間、エラー率を監視してください。
Q デプロイ後にヘルスチェックを実行するにはどうすればよいですか?
A { status: 'ok' } を返す /health エンドポイントを追加してください。DockerのHEALTHCHECKやK8sのlivenessProbeが、このエンドポイントに定期的にアクセスします。

Q: PM2とDocker、どちらを使うべきですか? A: 両者は互いに排他的ではありません。Dockerは環境の一貫性に関する問題を解決し、PM2はプロセス管理とクラスタリングを担当します。本番環境では、DockerとPM2を併用し、Dockerコンテナ内でPM2を実行して複数のプロセスを管理することをお勧めします。

Q: ダウンタイムゼロのデプロイを実現するにはどうすればよいですか? A: pm2 restartpm2 reload に置き換えてください。PM2 はワーカーを1つずつ再起動し、常に一部のインスタンスがオンライン状態を維持してリクエストを処理できるようにします。Docker 環境では、ブルーグリーンデプロイやローリングアップデートといった戦略を利用できます。

Q: クラスタモードにはどのような制限がありますか? A: クラスタモードでは、プロセスはメモリを共有しません。セッションはRedisなどの外部ストレージを使用して共有する必要があります。また、WebSocketsを使用する場合は、スティッキーセッションまたはPub/Subメッセージ同期と組み合わせて使用する必要があります。さらに、ファイルシステムのキャッシュはプロセスごとに独立しています。

Q: 本番環境をどのように監視すればよいですか? A: PM2 には pm2 monit リアルタイム監視機能と pm2 plus オンラインダッシュボードが用意されています。商用ソリューションとしては、New Relic、Datadog、Prometheus + Grafana などがあります。主要な指標には、CPU、メモリ、イベントループのレイテンシ、リクエストの応答時間などがあります。

Q: Docker イメージのサイズを縮小するにはどうすればよいですか? A: node:alpine ベースイメージを使用し、マルチステージビルドでコンパイル依存関係を分離し、.dockerignore 不要なファイルを除外し、npm ci --only=production 本番環境用の依存関係のみをインストールし、npm キャッシュをクリアします npm cache clean --force

Q: Nginxをリバースプロキシとして使用するメリットは何ですか? A: SSLオフロードによりNode.jsの暗号化処理の負荷が軽減されます。静的リソースはNginxが直接処理します。ロードバランシングによりリクエストが分散されます。レート制限によりDDoS攻撃が防止されます。gzip圧縮によりデータ転送量が削減されます。また、キャッシュによりレスポンスが高速化されます。


📖 まとめ

(1) このレッスンの要点

(2) 宿題

  1. PM2 を使用して Express プロジェクトを起動し、ecosystem.config.js を設定してクラスタモードを有効にし、pm2 monit を使用して実行状況を監視します。
  2. プロジェクト用の Dockerfile を作成し、マルチステージビルドを使用してイメージサイズを最適化し、docker-compose を使用して Node.js と MongoDB を同時に起動する
  3. 3つのヘルスチェックエンドポイント /health/healthz/readyz を実装し、Docker 内で HEALTHCHECK を設定します。
  4. autocannon を使用して API の負荷テストを実施し、シングルプロセスモードとクラスタモードのスループットの違いを比較してください。
  5. SSLの終端処理と負荷分散を実装するためのNginxのリバースプロキシ設定を作成し、ab または curl を使用して、プロキシ転送が正常に機能していることを確認します。

📝 練習問題

  1. このレッスンにあるすべてのコード例を完成させ、それぞれが正しく動作することを確認してください。
  2. 包括的な例を修正し、独自の拡張機能を追加する
  3. 公式ドキュメントを確認し、このレッスンで取り上げられていないAPIを1~2つ見つけ、それらのテストコードを作成してください。
  4. 振り返り:このレッスンで学んだことを、実際のプロジェクトにどのように活かしますか?
  5. このレッスンで学んだことと、これまでのレッスンの内容を組み合わせて、小さなプロジェクトを作成してみてください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%