はじめに
こちらの記事でdjangoでapiを作ったので、それを受け取る用のdiscord botを作成したのですが、
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /api/Item/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xffff8654ecf0>: Failed to establish a new connection: [Errno 111] Connection refused'))
というエラーが出てしまいました。
これは、localhostのポート8000番に接続しようとしたけど、拒否されたというエラーです。
この原因を調べたところ、djangoとdiscord botをdockerで動かしており、コンテナ間で通信させることが必要であったからでした。
なので、今回はdjangoで作成したapiをdiscord botで受け取れるようにしてみようと思います。
discord botの準備
apiにgetリクエストを送ったら、djangoのdbにあるItemの名前をbotに打ってもらうものを作ろうと思います。
今回は、Dockerで開発環境を構築しました.
ディレクトリ構造はこちらです。
.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── main.py
└── requirements.txt
ファイルの中身は以下の通りになっています。
Dockerfile
FROM python:3.12.2
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
WORKDIR /bot
COPY requirements.txt /bot/
RUN pip install --no-cache-dir -r requirements.txt
COPY . /bot/
docker-compose.yml
version: '3'
services:
bot:
build: .
command: python main.py
volumes:
- .:/bot
env_file:
- .env
networks:
- mynetwork
networks:
mynetwork:
external: true
.dockerignore
# Node.js dependencies
node_modules
npm-debug.log
# Python dependencies
__pycache__
*.pyc
*.pyo
*.pyd
Pipfile
Pipfile.lock
venv
# Logs
logs
*.log
# System files
.DS_Store
Thumbs.db
# IDEs and editors
.vscode
.idea
*.swp
# Git
.git
.gitignore
# Docker
Dockerfile
.dockerignore
# Other
.env
requirements.txt
py-cord==2.5.0
python-dotenv==1.0.1
requests
main.py
import discord
import os
import requests
TOKEN = os.getenv('TOKEN')
intents = discord.Intents.all()
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print("wakeup")
@client.event
async def on_message(message):
if message.content.startswith("!getItem"):
# 最初のリクエストで取得したURLを使って次のリクエストを送信
response = requests.get("http://djangoapitest-web-1:8000/storage/api/Item/")
data = response.json()
for item in data:
await message.channel.send(f"{item['name']}")
client.run(TOKEN)
.env
TOKEN = yourtoken
どのようにコンテナ間を通信させるか
ここからが本題なのです。
コンテナ間を通信させるには、dockerネットワーク機能を使う必要があります。
dockerのブリッジネットワークを使用することで、同一dockerホスト上でのコンテナ間通信を可能にすることができるそうです。
さらに、.yml
ファイルに自分で定義したブリッジネットワークを使うことで、IPアドレスで接続先を決めるのではなく、コンテナ名で接続先を解決することができます。
複数ホストで動かす場合は、オーバレイネットワークを使うそうです。
まず、コマンドでネットワークを作成します。mynetwork
はネットワーク名です。
docker network create mynetwork
dockerのネットワークドライバは標準でブリッジになっています。
そして、djangoのDockerfile
を入力します。
version: '3'
services:
web:
build: .
volumes:
- .:/code
working_dir: /code/ApiTest/
ports:
- 8000:8000
command: python manage.py runserver 0.0.0.0:8000
#ここから下を追加
networks:
- mynetwork
networks:
mynetwork:
external: true
ネットワークは下の部分で登録していて
networks:
- mynetwork
.yml
ファイルの外部にあるmynetwork
ネットワークを探すように下で設定しています。
networks:
mynetwork:
external: true
djangoとdiscord botの.yml
ファイルの両方に書くことで、コンテナ間通信が可能になります。
実際にgetリクエスト送ってみる
djangoのデータベースにsord
とgun
を登録していたので、それをdiscord内で取得できるか試してみます。
getリクエストで取得できました。
最後に
エラーコードを検索にかけたり、gptに聞くだけだと解決しませんでしたし、dockerネットワークの理解するきっかけができたので良かったです。
今ちょうど大学の授業と書籍でネットワークの学習をしてる途中で公式ドキュメントを見ても理解できなかった部分が多かったので、個人としてネットワークの理解の重要度がかなり上がりました。
djangoのコードはこちらです。
discord botのコードはこちらです。