MIXI DEVELOPERS NOTE
🧂

Dockerを用いたDiscordBOTの環境構築をGCE上でやってみた

2022/08/29に公開1

注意点

まんてらはバックエンド系の経験が非常に薄いです!(なんならGCPは初経験)
参考にする時は気を付けて下さい!

何するの?

Google Compute Engine上で、DiscordのBOTをDockerを使って動作させてみたい!
とりあえず、Discordサーバーのテキストチャンネルで何か発言したらその内容をオウム返しするBOTを作って見る!

ざっくり何したの?

Discordでの操作

  1. アプリケーションを作成する
  2. BOTの設定をする
  3. OAuth2の設定をして任意のサーバーにBOTを突っ込む
  4. アクセストークンを得る

GCPでの操作

  1. Google Cloudでプロジェクトを作成
  2. Compute EngineでVMインスタンスを作成
  3. SSHの設定をする(理由はよくわかってない)
  4. ファイアウォールの設定をする
  5. Dockerを使える様にする
  6. Dockerfileとdocker-compose.ymlを作ってビルドする
  7. pythonを書く
  8. 実行!

Discordでの操作

1. アプリケーションを作成する

DiscordのBOTはアプリケーションって単位で動いてるみたい。
この後の設定をする感じ、どうやらBOT以外のものも作れるっぽい

  1. ここにアクセス
  2. 右上の《New Application》を押下。
  3. 任意の名前をNAMEに入力して、《Create》を押下
  4. とりあえずこんな画面になったらおっけ

2.BOTの設定をする

  1. 画面左にある《BOT》を押下
  2. 《Add Bot》を押下して、確認が出るので《Yes,do it!》を押下
  3. 《MESSAGE CONTENT INTENT》にチェックを入れる

3. OAuth2の設定をして任意のサーバーにBOTを突っ込む

BOTの権限とBOTをサーバーに追加する為の手段を設定する。

  1. 画面左にある《OAuth2》→《General》を押下
  2. Redirectsで《Add Redirect》を押下する
  3. BOTの招待完了後に表示させたいURLを入力する。(何故かは分からないが、これをしないとBOTにメッセージを読ませる事が出来ない)
  4. Default Authorization LinkのAUTHORIZATION METHODで《In-app Authorization》を選択
  5. SCOPESで《bot》を選択
  6. BOT PERMISSIONSで《Read Messages/View Channels》と《Send Messages》にチェックを入れる
  7. 大体こんな感じ
  8. 画面左の《OAuth2》→《URL Generator》を押下
  9. SCOPESで《bot》と《messages.read》を選択
  10. SELECT REDIRECT URLに3.で追加したURLを選択する
  11. BOT PERMISSIONSで《Read Messages/View Channels》と《Send Messages》にチェックを入れる
  12. 大体こんな感じになる
  13. GENERATED URLを《Copy》する
  14. コピーしたURLにアクセスし、任意のサーバーにBOTを招待する

4. アクセストークンを得る

  1. 画面左の《Bot》を押下
  2. 《Reset Token》を押下し、トークン情報をリセットする
  3. 新しいトークンが表示されるので、《Copy》して、誰にも分からない所に控える。このトークン情報が外部に漏れると誰でもBOTを操作出来てしまうので注意!!!

GCPでの操作

1. Google Cloudでプロジェクトを作成

  1. ここにアクセス
  2. 画面左上の画像の赤丸部分を押下
  3. 《新しいプロジェクト》を押下し、任意のプロジェクト名を入力して《作成》する

2. Compute EngineでVMインスタンスを作成

  1. 《VMを作成》を押下
  2. Compute Engine APIを《有効にする》を押下
  3. 以下の設定を行い、VMインスタンスを作成する
  • 任意の名前を入力
  • マシンタイプは《e2-micro(2 vCPU、1GBメモリ)》(多分そこまでスペックは必要無いと思う)
  • ブートディスクで《変更》を押下し、OSを《Ubuntu》に設定、バージョンを《Ubuntu 20.04 LTS x86/64, amd64 focal image built on 2022-08-23, supports Shielded VM features》に設定(ローカルテスト時に使用していた環境。他のOSが好きな人は別のでも良いかもしれないけど、以降の解説に責任を持ちません)
  1. 上記の設定後、一番下の《作成》を押下

3. SSHの設定をする

これを設定する理由は良く分かってないので、有識者が居れば教えて欲しい。
普通にインスタンス一覧の接続欄のSSHをクリックして接続すれば良いのでは…?
ポートを変更するとセキュリティが高まるらしいけど、ポートをしらみつぶしにアクセスされたら元も子もない気がする。

  1. 画面左上の《≡》を押下し、リストから《Compute Engine》→《VMインスタンス》を押下
  2. 作成したVMインスタンスのリストが表示されるので、《SSH》を押下
  3. VMをコマンドで操作出来る様にするウィンドウが出て来るので、下記の操作を行ってSSHの設定を行う
  • 下記コマンドでSSH鍵の作成を行う。実行すると色々聞かれるけど全部エンターでスキップして良い
ssh-keygen -t rsa
  • 下記コマンドで作成したSSH秘密鍵を読み取り専用にする
chmod 400 ~/.ssh/id_rsa
  1. 続いてポート番号の変更を行う
  • 下記コマンドで設定ファイルをバックアップする
sudo cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config.org
  • 下記コマンドでポート番号の変更を行う。(ポート番号が22のままだと不正アタックの標的にされるらしい。)
sudo sed -i -e "s/#Port 22/Port 変更したい任意のポート番号/g" /etc/ssh/sshd_config
  • 下記コマンドでSSHサービスを再起動する。
sudo systemctl restart sshd.service

4. ファイアウォールの設定をする

3.の作業でSSHの接続が出来るポート番号が変更された為、先ほど行った手段でSSHに接続が出来なくなっている。設定を変更して接続が出来る様にする。

  1. 画面左上の《≡》を押下し、リストから《VPC ネットワーク》→《ファイアウォール》を押下
  2. VPC ファイアウォール ルールの《default-allow-ssh》を押下する。
  3. 画面上部の《編集》を押下する
  4. プロトコルとポートのTCPのポートに先ほど任意に設定したポート番号を入力し、保存を押下する。
  5. 画面左上の《≡》を押下し、リストから《Compute Engine》→《VMインスタンス》を押下
  6. VMインスタンスのリストにある、インスタンス名を押下する
  7. SSHの右側にある《▼》を押下し、《ブラウザウィンドウでカスタムポートを開く》を押下する
  8. 出て来たダイアログに先ほど設定したポート番号を入力する。
  9. コマンド操作が出来るウィンドウが表示されるので、以降これを使って作業を行う。

5. Dockerを使える様にする

  1. 下記コマンドでaptのパッケージインデックスを更新する。
 sudo apt-get update
 sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
  1. 下記コマンドで、Dockerの公式GPG鍵を追加する
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  1. 下記コマンドで、安定版のDockerをダウンロードする
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. 下記のコマンドでaptのパッケージインデックスを更新する
sudo apt-get update
  1. 下記コマンドでDockerをインストール(途中で何か聞かれるのでとりあえず《Y》)
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. 下記コマンドでdockerの操作権限を与える(このままだとdockerコマンドを打つ為にsudoを付ける必要があって面倒)
sudo gpasswd -a $(whoami) docker
  1. 下記コマンドでdocker.sockにグループでの書き込み権限を付与する
sudo chgrp docker /var/run/docker.sock
  1. dockerを再起動する
sudo service docker restart
  1. 下記コマンドでターミナルを終了させる
  2. もう一度SSHからターミナルに接続する
  3. 下記コマンドで「CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES」と表示されたらDockerのセットアップ完了
docker ps

6. Dockerfileとdocker-compose.ymlを作る

  1. ローカルPCで下記ファイル名と内容を作成する。
Dockerfile
FROM python:3
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN python -m pip install numpy
RUN python -m pip install discord.py
docker-compose.yml
version: "3"
services:
  python:
    restart: always
    build: .
    container_name: "python3"
    working_dir: "/root/"
    tty: true
    volumes:
      - ./app:/root/opt
  code:
    image: codercom/code-server
    restart: always
    ports:
      - "8443:8443"
    volumes:
      - ./app:/home/coder/project
  1. 画面右上の《アップロードマーク》を押下
  2. 先ほど作った2つのファイルをアップロードする
  3. 下記コマンドでDockerを実際に立ち上げるDirectoryを作成する
mkdir 任意のディレクトリ名
  1. 下記コマンドで作成したフォルダにアップロードしたファイルを移動させる
mv Dockerfile さっき作ったディレクトリ名
mv docker-compose.yml さっき作ったディレクトリ名
  1. 下記コマンドでさっき作ったディレクトリに移動する
cd さっき作ったディレクトリ名
  1. 下記コマンドでDockerfileをビルドしてDocker Imageを作成する。(C#でいうクラスみたいなやつを作成する。実行環境のテンプレートを作成する感じ)
docker build -t 任意のイメージ名 .
  1. 下記コマンドでdocker-compose.ymlをビルドする
docker compose build --no-cache
  1. 下記コマンドでdocker composeを実行する
docker compose up -d

7. pythonを書く

  1. ローカルPCで下記ファイル名と内容のものを作成(「BOTのトークン文字列を入力」には、「# Discordでの操作」の「## 4. アクセストークンを得る」で取得したトークンを入力)
main.py
import discord

intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)

@client.event
async def on_ready():
    print(f'We have logged in as {client.user}')

@client.event
async def on_message(message):
    if message.author == client.user:
        return
    await message.channel.send(message.content)
    if message.content.startswith('$hello'):
        await message.channel.send('Hello!')

client.run('BOTのトークン文字列を入力')
  1. ターミナル上でmain.pyファイルをアップロード
  2. 下記コマンドでmain.pyを作業環境にアップロードする
    (アップロード先は常に/home/ユーザー名のディレクトリになる為ディレクトリ移動する)
cd ../

(何故かsudoじゃないと権限なくて移動出来ない)

sudo mv main.py chibitera-chan/app/

8. 実行!

  1. 実行させたdocker containerのCONTAINER IDを取得する必要があるので、下記コマンドを実行して、起動させたIMAGEのCONTAINER IDを控える
docker container ls
  1. 下記コマンドを入力して実行中のContainer内に入って作業する
docker exec -it 控えたCONTAIENR ID bash
  1. 下記コマンドで作業フォルダに入る(移動先にmain.pyがある)
cd opt/
  1. 下記コマンドを実行して、main.pyを実行させる
python main.py
  1. BOTの居るサーバーで発言すると、BOTがオウム返ししてくれるぞ!!!やった!!!

参考にしたサイト一覧

https://qiita.com/escapade/items/959addfcfc3d58ad3f89
https://qiita.com/takapp/items/abcf1f56285ba601b701
https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/ubuntu/
https://tech.librastudio.co.jp/entry/index.php/2018/07/14/post-1924/
https://discordpy.readthedocs.io/ja/latest/quickstart.html

Tips

裏でPythonを実行させ続けるには

下記コマンドでいけるらしい

nohup python main.py &

でも終了させる方法が分からない
下記コマンドでプロセスIDを取得して、

ps u

下記コマンドでプロセスをKILLしても

kill -KILL PID

オウム返しは止まるが、BOTがログイン状態のままな事がある。

なんでや…

おかね

恐らく無料枠の中でGCPを使ってるはずはなのに請求が来てた

でも、よくよく見ると…

支払金額がマイナスになってる…?

なんやこれ…?

MIXI DEVELOPERS NOTE
MIXI DEVELOPERS NOTE

Discussion

sakusyasakusya

GCE上でDiscordのBotを入れようとして四苦八苦している所、友人にここを教えてもらいました。
とても参考になりましたが、1点躓いた部分があります。

Dockerfileの1行目、

FROM python:3

になっていますが、現状では最新バージョンの3.12が適用されてしまい、うまく動作しない状態でした。

ここを、例えば

FROM python:3.9.10-buster

のようにバージョンまで指定するとうまく動きました。
まだDocker Imageの作成が成功した段階ですが、取り急ぎ参考までに。