はじめまして。
株式会社アドグローブ ソリューション事業部エンジニアの藪内です。
今回は、DockerでDjango + Celeryを使った非同期メールを送信&受信する際の環境構築をご紹介します。
- 1. はじめに
- 2. Django プロジェクトの準備
- 3. 作成されるファイルのツリー
- 4. Docker Composeで環境を構築
- 5. Celeryタスクの実装
- 6. Djangoのカスタムコマンドでタスクをトリガー
- 7. MailHogでのメール受信
- 8. コンテナ起動
- 9. ローカルでのメール受信テスト
- 10. トラブルシューティング
- 11. まとめ
1. はじめに
Django と Celery を使用した非同期処理の導入は、時間のかかるタスク(例: メール送信など)を非同期で処理できるため非常に便利です。このブログでは、Docker 上で非同期メール送信を実現し、MailHog を使ってローカルでメールを受信する環境を構築します。さらに、Django のカスタムコマンドを使用してタスクをトリガーする方法も解説します。
2. Django プロジェクトの準備
Pythonのインストール
まず Python がインストールされているか確認します。インストールされていない場合、以下の手順でインストールしてください。
Windows:
- 公式サイトから最新のPythonをダウンロードしてインストールします。
- 「Add Python to PATH」にチェックを入れることを忘れずに。
Mac/Linux:
- MacではHomebrewを使ってインストールできます:
bash brew install python
- Linuxでは次のコマンドを使います:
bash sudo apt-get install python3
- MacではHomebrewを使ってインストールできます:
仮想環境の作成
なぜ仮想環境を使うのか?
Python の仮想環境(venv
)は、プロジェクトごとに依存パッケージを分離して管理するためのツールです。これにより、以下のようなメリットがあります。
パッケージの競合を防ぐ
複数のプロジェクトが異なるバージョンのライブラリやパッケージを必要とする場合があります。仮想環境を使うことで、各プロジェクトごとに異なるバージョンのパッケージをインストールし、システム全体に影響を与えずに使用できます。プロジェクトごとの依存関係の管理が容易
仮想環境では、プロジェクトに必要なライブラリだけをインストールするため、不要なパッケージがプロジェクトに含まれる心配がありません。また、プロジェクトを他の開発者と共有する際に、requirements.txt
に書かれたライブラリを簡単にインストールでき、環境を統一できます。システムの安全性向上
グローバル環境に依存パッケージを直接インストールするのではなく、仮想環境内で管理することで、システムの設定や他のアプリケーションに影響を与えることなくプロジェクトを運用できます。
仮想環境の作成方法
- 仮想環境の作成: 仮想環境はプロジェクトのルートディレクトリ内に作成します。以下のコマンドを実行して仮想環境を作成します。
python -m venv myenv
myenv
は仮想環境の名前です。任意の名前に変更しても問題ありません。
仮想環境の有効化: 仮想環境を作成した後、以下のコマンドを実行して有効化します。
- Windows:
myenv\Scripts\activate
- Mac/Linux:
source myenv/bin/activate
仮想環境が有効化された状態では、ターミナルのプロンプトが
(myenv)
のように変化します。 仮想環境を終了するには、以下のコマンドを使用します。- Windows:
deactivate
Djangoのインストール
仮想環境を有効化した状態で、次のコマンドを実行して Django、Celery、Redis をインストールします。
## 必要なパッケージをinstall pip install django celery redis ##requirements.txt ファイルを生成 pip freeze > requirements.txt
その後、Django プロジェクトを新規作成します。
django-admin startproject myproject cd myproject
次に、settings.py
に以下の Celery 設定を追加します。
また今回はコマンドからメール送信をテストするため、myprojectを INSTALLED_APPS
に追加しておきます。
# settings.py INSTALLED_APPS = [ ・ ・ ・ 'django.contrib.staticfiles', 'myproject', ] CELERY_BROKER_URL = 'redis://redis:6379/0' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json'
3. 作成されるファイルのツリー
以下は、このプロジェクトで作成されるファイルとディレクトリ構造です。
myproject/ │ ├── Dockerfile ├── compose.yml ├── manage.py ├── myproject/ │ ├── __init__.py │ ├── celery.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── tasks.py └── myapp/ ├── __init__.py ├── admin.py ├── apps.py ├── migrations/ │ └── __init__.py └── management/ └── commands/ └── send_test_email.py
Dockerfile
: Django アプリケーションを Docker コンテナで動作させるための設定。compose.yml
: Docker Compose の設定ファイル。Django、Celery、Redis、MailHogのサービスを定義。tasks.py
: Celery タスク(非同期メール送信)を定義。send_test_email.py
: Django のカスタムコマンドで、Celery タスクを実行するためのスクリプト。
4. Docker Composeで環境を構築
compose.yml
ファイルを作成し、Django アプリケーション、Redis、Celery、MailHogを含むDocker環境を定義します。
services: web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/app ports: - "8000:8000" depends_on: - redis redis: image: "redis:alpine" celery: build: . command: celery -A myproject worker --loglevel=info volumes: - .:/app depends_on: - redis mailhog: image: mailhog/mailhog ports: - "1025:1025" - "8025:8025"
Dockerfile
も作成します。
FROM python:3.9 WORKDIR /app COPY . /app RUN pip install -r requirements.txt
5. Celeryタスクの実装
Django プロジェクトにおける Celery の設定を行い、非同期でメールを送信するタスクを定義します。
celery.py
の作成
# myproject/celery.py import os from celery import Celery # DJANGO_SETTINGS_MODULE を明示的に設定 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') app = Celery('myproject') # Djangoの設定を読み込む app.config_from_object('django.conf:settings', namespace='CELERY') # Djangoアプリからタスクを自動で発見する app.autodiscover_tasks()
__init__.py
の設定
# myproject/__init__.py from .celery import app as celery_app __all__ = ('celery_app',)
メール送信タスクの定義
非同期でメールを送信するタスクを定義します。
# tasks.py from celery import shared_task from django.core.mail import send_mail @shared_task def send_email_task(to_email): send_mail( 'Test Subject', 'Here is the message.', 'from@example.com', [to_email], fail_silently=False, )
6. Djangoのカスタムコマンドでタスクをトリガー
次に、Django のカスタムコマンドを作成し、メール送信タスクをトリガーします。
カスタムコマンドの作成
management/commands/send_test_email.py
というファイルを作成します。
# management/commands/send_test_email.py from django.core.management.base import BaseCommand from myproject.tasks import send_email_task class Command(BaseCommand): help = 'Send a test email using Celery' def handle(self, *args, **kwargs): to_email = 'test@example.com' send_email_task.delay(to_email) self.stdout.write(self.style.SUCCESS(f'Email sent to {to_email}'))
このコマンドにより、次のコマンドでメール送信タスクを実行できます。 現段階ではDockerが起動していないためメール配送はされません。
python manage.py send_test_email
7. MailHogでのメール受信
MailHog は、ローカル開発環境でメールを受信し簡単に確認できるツールです。compose.yml
ですでに設定されていますが、Django のメール設定を以下のように変更します。
# settings.py EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'mailhog' EMAIL_PORT = 1025
8. コンテナ起動
ワーカーが起動すると添付画像のようにCeleryがready状態となります。
docker-compose up --build
先ほど作成したカスタムコマンドを実行してメール送信タスクをトリガーします。
## 別のターミナルからwebコンテナにbashで入りdangoのコマンドを実行する。 docker-compose exec web bash python manage.py send_test_email
9. ローカルでのメール受信テスト
MailHog の Web インターフェースにアクセスし、受信したメールを確認します。 無事MailHogのUI上にメールが送信されました。
http://localhost:8025
これで送信されたメールが受診していることを確認できました。
10. トラブルシューティング
よくある問題と対処法
- Redis が接続できない場合:
compose.yml
でdepends_on
を正しく設定し、Redis サービスが起動しているか確認します。 - メールが届かない場合: MailHog のポート設定が正しいか、
EMAIL_HOST
とEMAIL_PORT
の設定を再確認してください。 - コンテナが起動しない: 利用しているポートがすでに利用されている状態なを再確認してください。
11. まとめ
Docker 環境で Django + Celery を使った非同期メール送信の環境を構築し、カスタムコマンドでタスクをトリガーしました。MailHog を利用することで、ローカルでのメール送信と受信を簡単に確認でき、このセットアップでコマンドベースでメールが送信されていることや、受診状況を確認することができます。
こちらの環境を応用することで一括のメール送信することや、Celeryにはリトライのオプションを設定することもでき運用環境でも利用することができます。
この記事をご覧になったみなさんも、活かせそうな場面があればぜひ非同期処理を活用してみてください。 最後までお読みいただきありがとうございました。
アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています!
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。