2
2

コンテナ同士で通信させる

Posted at

はじめに

こちらの記事で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

docker-compose.yml
version: '3'

services:
  bot:
    build: .
    command: python main.py
    volumes:
      - .:/bot
    env_file:
     - .env
    networks:
      - mynetwork

networks:
   mynetwork:
     external: true

.dockerignore

.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

requirements.txt
py-cord==2.5.0
python-dotenv==1.0.1
requests

main.py

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

.env
TOKEN = yourtoken

どのようにコンテナ間を通信させるか

ここからが本題なのです。

コンテナ間を通信させるには、dockerネットワーク機能を使う必要があります。
dockerのブリッジネットワークを使用することで、同一dockerホスト上でのコンテナ間通信を可能にすることができるそうです。
さらに、.ymlファイルに自分で定義したブリッジネットワークを使うことで、IPアドレスで接続先を決めるのではなく、コンテナ名で接続先を解決することができます。

複数ホストで動かす場合は、オーバレイネットワークを使うそうです。

まず、コマンドでネットワークを作成します。mynetworkはネットワーク名です。

docker network create mynetwork

dockerのネットワークドライバは標準でブリッジになっています。

そして、djangoのDockerfileを入力します。

docker-compose.yml
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のデータベースにsordgunを登録していたので、それをdiscord内で取得できるか試してみます。

スクリーンショット 2024-05-31 16.26.15.png

getリクエストで取得できました。

最後に

エラーコードを検索にかけたり、gptに聞くだけだと解決しませんでしたし、dockerネットワークの理解するきっかけができたので良かったです。

今ちょうど大学の授業と書籍でネットワークの学習をしてる途中で公式ドキュメントを見ても理解できなかった部分が多かったので、個人としてネットワークの理解の重要度がかなり上がりました。

djangoのコードはこちらです。

discord botのコードはこちらです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2