フリーキーズ | 独学プログラミング

Docker環境変数・シークレット管理と安全な設定|初心者向け完全ガイド

リンドくん

リンドくん

たなべ先生、Dockerでアプリを動かすとき、データベースのパスワードとかってどう管理すればいいんですか?コードに直接書いちゃダメですよね...

たなべ

たなべ

素晴らしい質問だね!その疑問を持つこと自体が、セキュリティ意識が高い証拠だよ。
実は、Dockerには環境変数やシークレットという仕組みがあって、パスワードやAPIキーといった機密情報を安全に管理できるんだ。今日はその方法をしっかり学んでいこうか。

プログラミングを学び、アプリケーションをDockerで動かし始めると、必ずぶつかる壁があります。
それが「機密情報をどう管理するか」という問題です。

データベースのパスワード、APIキー、各種トークンなど、アプリケーションには様々な機密情報が必要になります。
これらをコードに直接書き込んでしまうと、GitHubなどにうっかり公開してしまったり、チーム内で共有する際にセキュリティリスクが生じたりします。

この記事では、Dockerにおける環境変数とシークレットの管理方法について、初心者の方でも実践できるよう、基礎から丁寧に解説していきます。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

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

リンドくん

リンドくん

そもそも、なぜ環境変数を使う必要があるんですか?普通に設定ファイルに書けばいいんじゃ...

たなべ

たなべ

それがね、実は大きな問題があるんだ。
例えば、開発環境と本番環境で違うデータベースを使いたい場合、どうする?設定ファイルをいちいち書き換えるの?それって面倒だし、間違いの元だよね。

環境変数を使うべき理由

環境変数を使用することで、以下のような重要なメリットが得られます。

  • 環境ごとに設定を切り替えられる - 開発環境、ステージング環境、本番環境など、異なる環境で異なる設定を簡単に切り替えられます。コードを一切変更せず、環境変数を変えるだけで済むのです。
  • 機密情報をコードから分離できる - パスワードやAPIキーなどの機密情報をコードに書かないことで、Gitリポジトリに誤って含めてしまうリスクを回避できます。
  • チーム開発がスムーズになる - 各開発者が自分のローカル環境に合わせた設定を持てるため、チームメンバー間での設定の衝突を防げます。
  • 設定の一元管理が可能 - 設定を1箇所で管理できるため、変更が必要になった際の修正が容易になります。

これらの理由から、現代のアプリケーション開発では環境変数の使用が標準的なプラクティスとなっています。
特にDockerを使ったコンテナ環境では、環境変数は必須のスキルと言えるでしょう。

Dockerでの環境変数の基本的な使い方

docker runコマンドでの環境変数の設定

最もシンプルな環境変数の設定方法は、docker runコマンドに-eオプションを使うことです。

docker run -e DB_PASSWORD=mypassword123 -e API_KEY=abc123xyz myapp

この方法は手軽ですが、コマンドラインに機密情報が残ってしまうため、本番環境での使用は推奨されません。練習やテスト目的での使用に留めましょう。

Dockerfileでの環境変数の定義

DockerfileではENV命令を使って環境変数を定義できます。

FROM node:20

# デフォルト値を設定
ENV NODE_ENV=production
ENV PORT=3000

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

EXPOSE 3000
CMD ["node", "server.js"]

ここで重要なのは、機密情報をDockerfileに書いてはいけないということです。
Dockerfileはイメージに含まれるため、イメージを配布すると機密情報も一緒に配布されてしまいます。

Dockerfileで設定するのは、以下のような公開しても問題ない設定値やデフォルト値のみにしましょう。

  • アプリケーションのポート番号
  • 実行環境の種別(development/production)
  • タイムゾーン設定

.envファイルを使った環境変数管理

より実践的な方法として、.envファイルを使った環境変数の管理があります。

まず、プロジェクトのルートディレクトリに.envファイルを作成します。

# データベース設定
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_db
DB_USER=myapp_user
DB_PASSWORD=super_secret_password

# API設定
API_KEY=your_api_key_here
API_SECRET=your_api_secret_here

# アプリケーション設定
NODE_ENV=development
PORT=3000

そして、docker runコマンドで--env-fileオプションを使って読み込みます。

docker run --env-file .env myapp

重要な注意点: .envファイルには機密情報が含まれるため、必ず.gitignoreに追加して、Gitリポジトリに含めないようにしましょう。

.env
.env.local
.env.*.local

代わりに、.env.exampleというサンプルファイルを用意しておくと、チームメンバーが参考にできて便利です。

# データベース設定
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_db
DB_USER=myapp_user
DB_PASSWORD=<your_password_here>

# API設定
API_KEY=<your_api_key_here>
API_SECRET=<your_api_secret_here>

Docker Composeでの環境変数管理

リンドくん

リンドくん

複数のコンテナを使うときは、どう管理すればいいんですか?

たなべ

たなべ

そういうときこそDocker Composeの出番だよ!複数のコンテナの環境変数を一元管理できて、とても便利なんだ。

docker-compose.ymlでの基本的な設定

Docker Composeを使うと、複数のコンテナの環境変数を効率的に管理できます。

version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - PORT=3000
      - DB_HOST=db
    env_file:
      - .env
    depends_on:
      - db

  db:
    image: postgres:18
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

この例では、以下の3つの方法で環境変数を設定しています。

  1. 直接指定: NODE_ENV=productionのように値を直接書く
  2. env_file: .envファイルから環境変数を読み込む
  3. 変数展開: ${DB_NAME}のように.envファイルの変数を参照する

環境ごとに設定を切り替える

開発環境と本番環境で設定を切り替えたい場合、複数の.envファイルを用意します。

DB_HOST=localhost
DB_NAME=myapp_dev
NODE_ENV=development
DEBUG=true
DB_HOST=production-db-server.example.com
DB_NAME=myapp_prod
NODE_ENV=production
DEBUG=false

そして、docker-compose.ymlで環境に応じたファイルを指定します。

services:
  web:
    env_file:
      - .env.${ENV:-development}

起動時に環境を指定できます。

# 開発環境で起動
ENV=development docker compose up

# 本番環境で起動
ENV=production docker compose up

Docker Secretsによる機密情報の安全な管理

リンドくん

リンドくん

環境変数だと、まだ少し不安な気がします...もっと安全な方法はないんですか?

たなべ

たなべ

セキュリティ意識が高いね!
本番環境ではさらに安全なDocker Secretsという仕組みがあるんだ。

Docker Secretsとは

Docker Secretsは、Docker Swarmモードで使用できる、機密情報を安全に管理するための仕組みです。以下のような特徴があります。

  • 暗号化された状態で保存される
  • 必要なコンテナにのみ配信される
  • メモリ上にマウントされ、ディスクには書き込まれない

Docker Secretsの使い方

まず、シークレットを作成します。

# ファイルからシークレットを作成
echo "super_secret_password" | docker secret create db_password -

# または、ファイルから読み込む
docker secret create db_password ./db_password.txt

次に、docker-compose.ymlでシークレットを使用します。

version: '3.8'

services:
  web:
    image: myapp
    secrets:
      - db_password
      - api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    external: true
  api_key:
    external: true

アプリケーション側では、シークレットファイルを読み込むコードを書きます。

const fs = require('fs');

// シークレットファイルから読み込む
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();
const apiKey = fs.readFileSync('/run/secrets/api_key', 'utf8').trim();

// データベース接続に使用
const dbConfig = {
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: dbPassword,
  database: process.env.DB_NAME
};

この方法により、機密情報がコンテナのログや環境変数一覧に表示されることを防げます

開発環境でのシークレット管理

Docker Secretsは本来Docker Swarmモード用の機能ですが、docker-composeでも簡易的に使用できます。

version: '3.8'

services:
  web:
    image: myapp
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

この場合、./secrets/db_password.txtファイルを作成し、パスワードを記述しておきます。このファイルも.gitignoreに追加することを忘れないでください。

実践的なセキュリティベストプラクティス

1. .gitignoreの徹底

機密情報を含むファイルは必ず.gitignoreに追加しましょう。

# 環境変数ファイル
.env
.env.local
.env.*.local

# シークレットファイル
secrets/
*.secret
*.key
*.pem

# 設定ファイル(機密情報を含む場合)
config.production.json

2. サンプルファイルの用意

チームメンバーが参考にできるよう、サンプルファイルを用意しておきましょう。

# データベース設定
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_db
DB_USER=myapp_user
DB_PASSWORD=<paste_your_password_here>

# API設定
API_KEY=<paste_your_api_key_here>
API_SECRET=<paste_your_api_secret_here>

# アプリケーション設定
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug

READMEファイルにセットアップ手順も記載しておくと親切です。

環境構築手順

  1. .env.exampleをコピーして.envファイルを作成
  2. .envファイルを編集して、実際の値を設定
  3. Dockerコンテナを起動
cp .env.example .env
docker-compose up

3. 環境変数のバリデーション

アプリケーション起動時に、必要な環境変数が設定されているか確認するコードを書きましょう。

// config/env-validator.js
const requiredEnvVars = [
  'DB_HOST',
  'DB_PORT',
  'DB_NAME',
  'DB_USER',
  'DB_PASSWORD',
  'API_KEY'
];

function validateEnv() {
  const missing = requiredEnvVars.filter(varName => !process.env[varName]);
  
  if (missing.length > 0) {
    console.error('❌ 以下の環境変数が設定されていません:');
    missing.forEach(varName => console.error(`  - ${varName}`));
    console.error('\n.envファイルを確認してください。');
    process.exit(1);
  }
  
  console.log('✅ すべての必要な環境変数が設定されています');
}

module.exports = { validateEnv };
// server.js
require('dotenv').config();
const { validateEnv } = require('./config/env-validator');

// 環境変数の検証
validateEnv();

// アプリケーションの起動
const app = require('./app');
// ...

4. 権限の最小化

コンテナに必要最小限の権限のみを与えることで、セキュリティリスクを減らせます。

services:
  web:
    image: myapp
    user: "1000:1000"  # 非rootユーザーで実行
    read_only: true    # ファイルシステムを読み取り専用に
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true

5. 定期的なシークレットのローテーション

本番環境では、パスワードやAPIキーを定期的に更新することをおすすめします。自動化できる場合は、CI/CDパイプラインに組み込むのも良いでしょう。

よくある間違いとトラブルシューティング

リンドくん

リンドくん

環境変数を設定したのに、アプリで読み込めないことがあるんですが...

たなべ

たなべ

それ、初心者がよくハマるポイントだね!いくつか確認すべきことがあるから、一緒に見ていこう。

問題① 環境変数が反映されない

症状: .envファイルを変更したのに、コンテナ内で反映されない

解決法

# コンテナを再ビルドして起動
docker compose up --build

# または、完全にクリーンにしてから起動
docker compose down
docker compose up

環境変数はコンテナ起動時に読み込まれるため、変更後は必ずコンテナを再起動する必要があります。

問題② 引用符の扱い

症状: パスワードにスペースや特殊文字が含まれていて、正しく読み込めない

解決法

# ❌ 間違い(引用符が値に含まれてしまう)
DB_PASSWORD="my password"

# ✅ 正しい(引用符は不要)
DB_PASSWORD=my password

# ✅ スペースを含む場合
DB_PASSWORD=my password with spaces

.envファイルでは、基本的に引用符は不要です。値にスペースが含まれていても、そのまま書けば正しく読み込まれます。

問題③ docker-composeでの変数展開

症状: ${変数名}の形式で書いたのに、展開されない

解決法

# ❌ 間違い(シェル変数として認識される)
environment:
  - DB_PASSWORD=${DB_PASSWORD}

# ✅ 正しい(.envファイルから読み込まれる)
environment:
  POSTGRES_PASSWORD: ${DB_PASSWORD}

また、展開したい変数が.envファイルに存在することを確認しましょう。

問題④ コンテナ間での環境変数の共有

症状: webコンテナの環境変数をdbコンテナで使いたいが、うまくいかない

解決法

各コンテナは独立した環境変数を持っています。共有するには、明示的に設定する必要があります。

services:
  web:
    env_file:
      - .env
    environment:
      - DB_HOST=db  # dbサービスを参照

  db:
    env_file:
      - .env  # 同じ.envファイルを読み込む

または、環境変数を外部から両方のコンテナに渡す設計にします。

まとめ

リンドくん

リンドくん

環境変数とシークレット管理、だいぶ理解できました!でも、結局どれを使えばいいんでしょうか?

たなべ

たなべ

基本的には.envファイルで環境変数を管理して、特に重要な機密情報はDocker Secretsを使うという使い分けがおすすめだよ。
そして何より、決してコードに機密情報を書かないことが最も大切なんだ。

この記事では、Dockerにおける環境変数とシークレットの管理方法について解説してきました。重要なポイントをおさらいしましょう。

環境変数を使うべき理由

  • 環境ごとに設定を切り替えられる
  • 機密情報をコードから分離できる
  • チーム開発がスムーズになる

基本的な管理方法

  • .envファイルで環境変数を管理
  • .gitignore.envを追加して、Gitリポジトリから除外
  • .env.exampleをサンプルとして用意

より安全な管理方法

  • Docker Secretsで機密情報を暗号化
  • 権限の最小化
  • 定期的なシークレットのローテーション

Dockerでの環境変数管理は、最初は少し複雑に感じるかもしれません。
しかし、これらのプラクティスを身につけることで、セキュアで保守性の高いアプリケーションを構築できるようになります。

特に、チーム開発や本番環境へのデプロイを考えると、適切な環境変数管理は避けて通れないスキルです。今日学んだ内容を、ぜひご自身のプロジェクトで実践してみてください。

この記事をシェア

関連するコンテンツ