[Docker]ノンプログラマーのためのDocker入門 Docker Compose後編

Docker

どうも、ケニー(tsujikenzo)です。このシリーズでは、Docker入門をお届けしています。

前回は「Docker Compose中編」で、Docker Composeで複数のコンテナの起動と連携を、YMLファイルで指定しました。便利ですね。

今回は、最終回です。Docker Composeの応用編をお届けします。

取得したデータを永続化(Redis/PostgreSQL などの実データやログを保存)する

コンテナは使い捨てが前提なので、停止・削除すると中のデータも消えてしまいます。 なので「保存場所(コンテナ内/外)」を理解する必要があります。

取得したデータを永続化するということは、「コンテナが消えてもデータが消えない場所に保存する」ということです。

保存場所の選択肢は大きく3つです。

  • コンテナの中に保存する
  • ホスト(PC)側に保存する(例: C:\Users\Kenzo\Desktop\data
  • ボリュームに保存する(Dockerが場所を決めて管理する)

実運用では、DBやログのように「自然に増え続けるデータ」を扱うため、 コンテナの外に保存する仕組みが必須になります。

ボリュームとは

ボリュームは、コンテナのライフサイクルと独立してデータを残せる保存領域です。
コンテナを削除しても、ボリュームを消さない限りデータは残ります。

代表的な使いどころ

  • RedisやPostgreSQLなど → /data や /var/lib/postgresql/data をマウント
  • アプリのCSV → .:/app のようにローカルへ出力

ボリュームの使い方

docker-compose.yml で volumes を指定すればOKです。

services:
  app:
    build: .
    depends_on:
      - redis
  redis:
    image: redis:7
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

volumes:
  redis-data:
  • volumes: セクションでボリューム名を定義します。
  • Redisコンテナの /data をボリュームにマウントします。

ボリュームを消したい場合

docker compose down -v

-v を付けると関連ボリュームも削除されます)

Pythonアプリの取得数を500件に増やそう

それでは、scraper.py を修正して、ページネーション(複数ページの順次リクエスト)に対応し、500件以上の書籍タイトルを取得できるようにします。

import requests
from bs4 import BeautifulSoup
import redis

def smart_scraper(max_books=500):
    r = redis.Redis(host='redis', port=6379, db=0)
    base_url = "https://books.toscrape.com/"
    current_url = base_url
    books_fetched = 0

    while current_url and books_fetched < max_books:
        response = requests.get(current_url)
        soup = BeautifulSoup(response.text, 'html.parser')
        books = soup.find_all('article', class_='product_pod')
        for book in books:
            title = book.h3.a['title']
            detail_url = book.h3.a['href']

            if r.sismember('visited_urls', detail_url):
                print(f"スキップ: 既に取得済み {title}")
                continue

            print(f"取得中...: {title}")
            r.sadd('visited_urls', detail_url)
            with open("results.csv", "a") as f:
                f.write(f"{title}\n")
            books_fetched += 1

            if books_fetched >= max_books:
                break

        next_btn = soup.find('li', class_='next')
        if next_btn and books_fetched < max_books:
            next_href = next_btn.a['href']
            if current_url == base_url:
                current_url = base_url + next_href
            else:
                import urllib.parse
                current_url = urllib.parse.urljoin(current_url, next_href)
        else:
            break

if __name__ == "__main__":
    smart_scraper()
  • max_books=500 で最大500冊だけ取得します(必要に応じて数値を調整してください)。
  • 「次のページ」がなくなるまでページネーションし、タイトルをcsvファイルに追記します。
  • Redisで重複チェックしますので、途中で中断→再実行しても、既に取得済みのURLはスキップされます。

実行する

それでは、実行してみましょう。docker compose up –build で起動(コンテナ内で scraper.py が動く)します。

データは取れているようです。

ボリュームの確認

一度、Ctrl+Cでコンテナを停止しましょう。

以下のコマンドで、ボリューム一覧を確認します。

docker volume ls

ボリュームが作成されているようです。

ボリュームの詳細は、以下のコマンドで確認できます。

docker volume inspect desktop_redis-data

詳細の中の「Mountpoint」 が実際の保存先(この場合、わたしのローカルPC)です。

ちなみに、SCARDSRANDMEMBERなどのRedisコマンドで、データベースの操作が可能です。(今回は割愛します)

環境変数の使い方(.env)

よく使う設定値(APIキーや接続先URLなど)は、.envファイルでまとめて管理できます。

Docker Composeは自動で.envを読み込むので、コードに直接書かずに済むのが便利です。

たとえば、今回の図書サイトのURLを `.env` に書くと以下のようになります。

BASE_URL=https://books.toscrape.com/

.env は 自動で読み込まれますが、コンテナに渡すかどうかで、用途が違います。

  • 自動で読む .env: Composeファイル内の変数置換
  • コンテナに渡す: env_file: .env(または environment:)が必要
#docker-compose.yml
services:
  app:
    build: .
    env_file:
      - .env
    depends_on:
      - redis
  redis:
    image: redis:7
    ports:
      - "6379:6379"

つまり、Pythonアプリ内で記述していたスクレイピング先のURLを削除して、.envファイルのBASE_URLを使うなら、docker-compose.yml内に記述する必要があるということです。

まとめ

以上で、「ノンプログラマーのためのDocker入門 Docker Compose後編」をお送りしました。

ここまで理解していれば、AIにも指示が出せるかと思います。

時代の変化に振り落とされないように、ついていきましょう!

参考資料

このシリーズの目次

タイトルとURLをコピーしました