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

Docker

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

前回は「Docker Compose前編」で、PythonアプリとRedisの、2つのDockerイメージを起動しました。

片方のターミナルでredisサーバーを立ち上げて、別のターミナルからpingを打つ、という連携を確認しました。

今回は、「Docker Compose中編」をお届けします。

PythonからRedisにアクセスする

前回は、重複URL(同じURLに何度もアクセスすること)など気にせず、スクレイピングをぶん回していました。

ここからは、「PythonアプリがRedisを使って、アクセスしたURLの重複を高速にチェックする」という機能を実装してみましょう。

まず、scraper.pyを以下のように修正します。

# scraper.py
```python
import requests
from bs4 import BeautifulSoup
import redis

def smart_scraper():
    # Redisサーバーに接続(Composeならサービス名でOK)
    r = redis.Redis(host='redis', port=6379, db=0)

    response = requests.get("https://books.toscrape.com/")
    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']

        # 既に取得済みかどうか、Redisでチェック
        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")

if __name__ == "__main__":
    smart_scraper()
```

そして、「redis」というライブラリをPythonアプリに追加します。DockerfileのRUN pip installredisを加えます。

```dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY scraper.py .
RUN pip install requests beautifulsoup4 redis
CMD ["python", "scraper.py"]
```

Redisを起動する(復習)

それでは、「Redisを使うPythonアプリ」と「Redis」の両方を、Docker上(別々のターミナルを使用)起動してみましょう。

今回は「1つずつ docker run で起動」してみます。

  1. まず新しいターミナルを起動します。(画面省略)
  2. Redisが起動しているか確認します。
docker ps

わたしは、2日前から起動していたようです。

もし起動していない方は、前回のブログを読んで起動してください。

Pythonアプリを起動する(別ターミナル)

  1. Redisとは別で、新しいターミナルを起動します。(画面省略)
  2. さきほど作成したDockerfileからイメージを作ります。
docker build -t scraper-app .

次に、そのイメージを実行します。

docker run --rm --name scraper-app --network bridge scraper-app

そうすると、エラーメッセージが出て、処理が終了すると思います。これは「host=’redis’ が見つからない」という意味です。

Pythonアプリ側からすると、突然出てきた「host=’redis’って何?」という状態です。「redis」というホスト名は、同じDockerネットワーク内でしか通らないからです。

同じネットワーク内に載せて起動する

まず、Docker上にネットワークを作成します。

docker network create app-net

そして、「test-redis」ではなく、「redis」という名前で新しくコンテナを作成/起動します。その際に、オプションとしてネットワークを指定します。

docker run --rm -d --name redis --network app-net redis:7

最後に、Pythonアプリを実行します。

docker run --rm --name scraper-app --network app-net -v "${PWD}:/app" scraper-app

無事、取得できました。

そのまま、もう一度、Pythonアプリを実行してみましょう。

一度アクセスしたURLは、Redis上のデータベースに書き込まれているので、スキップされます。高速です。便利ですね。

しかしながら、このように docker run で1つずつコンテナを起動したり、ネットワークを作成するのは面倒ですよね。そこで登場するのが Docker Compose です。

Docker Composeとは

Docker Composeは、複数コンテナの起動やネットワーク設定を 1つのYAMLファイルにまとめて管理 できる仕組みです。

これまで手動でやっていた「Redis起動 → アプリ起動 → ネットワーク接続」を、1コマンドでまとめて起動できます。

実際にやってみましょう。

まず、すべてのコンテナを停止したいので、すべてのコンテナを確認しましょう。(復習)

docker ps -a

コンテナを停止しましょう。

#個別のコンテナを停止
docker stop コンテナ名

#すべてのコンテナを停止
docker stop $(docker ps -q)

docker-compose.ymlを作る

まず、同じプロジェクト内(今回はデスクトップです)に「docker-compose.yml」ファイルを作ります。メモ帳からで構いません。

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

docker compose up で起動

ymlファイルを読み込んで、ymlファイルの中に書かれているサービスをビルド(必要なら)して起動するのが、docker composeコマンドです。

ターミナルで実行しましょう。

docker compose up --build

デスクトップにcsvファイルが出力されました。

Docker Compose up内で処理を止める

docker compose up 内の処理を止めるには、キーボードで「Ctrl + C」を押下します。ログの追跡を止めつつ、起動中のコンテナにも停止シグナルを送ります。

docker compose down で停止

停止するときは以下です。

docker compose down

まとめ

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

次回は、最終回です。お楽しみに。

参考資料

このシリーズの目次

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