GoogleCloudのVMを用いて、DiscordのBOTを構築する

箇条書き
学生の頃からクラウドには興味があったものの、料金体系がよくわからず諦めていた。
最近、社会人になり余剰金がそれなりに出来たため改めてクラウドについて触る機会があったため今回、GoogleCloudのVM作成からコーディングを用いたDiscordBOTの作成までまとめます。


生成AIがまとめたバージョンもあるのでこちらの２回目以降に確認するならこちらの方がわかりやすいかも？
https://qiita.com/masafy/items/b405c42c1cd5a6b75647

# はじめに
## GoogleCloudとは？
検索すればどういうものかは出てきますが、一言で言うと「クラウド上のインフラ・サービス群」です。
なので、GoogleCloud=VMということではないので注意が必要です。
（ただ、自分はほとんどVMの機能しか使わないです）

また、GoogleCloud上では"VM"というよりかはcomputeEngineの機能の一部にVMのインスタンス作成のサービスがあるイメージの様子です。
なので、途中でcomputeEngineという表現も出てきますが、VM関連の設定というイメージを持っていただければと。

## Discordとは？
チャットができるコミュニケーションツールです。
最近はゲーマー以外にも、シンプルに社会人サークルの間でもそのコミュニケーションツールとしてDiscordが使われているようです。
確かに無料で使えるのでいいですよね。

ほかにも、discordはdiscord portalというものがありこれの設定をして開発をしていきます。
https://discord.com/developers/docs/intro

# GoogleCloudの構築
下記リンクにアクセス。
https://console.cloud.google.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/add631ef-de44-4f42-a035-3bf3658492a9.png)
これが、googleCloudのホーム画面です。
これから、**プロジェクトの作成**→**computerEngineの項目に移動**→**VMインスタンス作成**→**インスタンスの設定内容を選択**→**VMインスタンス起動**→**sshログイン**の流れで進めていきます。

## プロジェクトの作成
左上のGoogleCloudと書かれたロゴの右側の３つポチをクリックし、"新しいプロジェクト"をクリックします。
プロジェクトの名前はなんでも大丈夫です。あとで見直した時にわかるようにするといいと思います。
入力できればそのまま作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/3b2e5e0e-7d05-4b5f-92ef-d9a67c59f883.png)

なお、作成には３０秒ほど時間がかかります。
無事に作成が完了すると赤枠の部分のように自分の設定したprj名になると思います。
![スクリーンショット 2025-04-19 5.06.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/aadce97f-06da-4a0e-8408-ee4f4b45b5cf.png)

## computerEngineの項目に移動
VMを作成するために、ページを移動します。
移動する際は、検索窓から「computer」と検索すると一番上に「compute engine」という項目がでますのでそれをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/db4a6468-d79d-4bfc-962b-d23513c7d5ee.png)

移動するとこのような画面になります。
compute engineと表示されている右側のピンマークをクリックすると固定化できて後々アクセスしやすくなるのでやっておくと便利です。
このままインスタンスの作成をクリックします。
「Compute Engine API」というページが出てくれば、APIは有効にしてください。
![スクリーンショット 2025-04-19 5.15.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/47dc2b72-1063-4403-9410-f13916398d8a.png)

## VMインスタンス作成と設定
ここがメインのVMの設定です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/c98976c3-396b-482b-ac91-dc477e55054b.png)

今回、テストで作成しており、**VScodeのリモートウインドウなど重いことはしない想定**です。
よって、汎用のシリーズE2、マシンタイプはプリセットの共有コアのe2-microを選びましょう。
![スクリーンショット 2025-04-19 5.29.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/ab9af689-85e8-4204-bf01-37d01517ed3a.png)
ずっと起動させていても、月に7ドルしかかからず、どんな感じなんだろう？と触ってみたい方におすすめというかこれ一択だと思っています。
左側に出ているのが想定する見積書みたいなものとなります。

ほかにも選択する項目はありますが、今回は割愛します。
このまま作成をしましょう。

:::note info
VScodeのリモートウインドウは、使いやすいですが今回のe2-microではそこまで高いスペック環境ではないため途中でセッションが保てなくなります。
もしも行いたい場合は、ここではマシンタイプはプリセットの標準のe2-standard-2以上を選択すると動作します。
この辺りは色々なVMを作っては削除してみたいなのを繰り返して操作感を確認してもいいかなと思います。
:::

無事にVMを構築できると、この画面のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/ebedde17-dc13-46a8-b714-f993df4feedd.png)

## sshログイン
まず、ブラウザ上でSSHのログインを行います。
ログインに３０秒ほど時間がかかり、尚且つ初回であれば認証を求められると思います。
ログインが完了すれば、ユーザ名の確認を行ないましょう。
基本的に自分のgmailのエイリアスの部分になっていると思います。
![スクリーンショット 2025-04-19 5.48.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/9366116f-4065-4a7b-82bd-b803b62d739e.png)

続いて、ローカル環境でssh鍵の作成を行います。
![スクリーンショット 2025-04-19 5.54.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/084960de-4e2e-4528-ab48-7aaa60a44591.png)
```terminal
ssh-keygen -t rsa -f ~/.ssh/gcp_key -C [USERNAME]
```
無事にSSH鍵の作成が完了したら、作成できたインスタンスの編集の項目からSSHの公開鍵について登録を行います。
```terminal
cat ~/.ssh/gcp_key.pub
```
画像では最初から３つの認証鍵が入力されていますが、これは人によると思っています。
項目の追加から公開鍵の追加、保存を行います。
![uploading...0](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/36c954e8-6029-413e-9012-da1c8b6296ea.png)

無事に登録が完了すれば、以下のコマンドでsshでローカルからログインを行います。
```terminal
ssh -i ~/.ssh/gcp_key [USERNAME]@34.123.42.9
```

このようにログインが完了すれば成功となります
![スクリーンショット 2025-04-19 6.18.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/3ca2f71c-11ab-4db1-a193-1cc5ef9fe706.png)

# discordBOTの作成
## python環境の構築と仮想の設定
VM上での作業に入ります。まずPythonが入っているか確認しましょう。

```terminal
python3 --version
```
基本的に Ubuntu 系であれば入っているはずです。無い場合は以下でインストール。

```terminal
sudo apt update
sudo apt install python3 python3-pip
```

Pythonではライブラリのバージョン管理や依存関係を整理するために、**仮想環境（venv）**を使うのが一般的です。
特に複数のプロジェクトを管理する際に、他のプロジェクトに影響を与えずに開発できます。

作業フォルダを作成します。
```terminal
mkdir discord-bot
```
以下のコマンドで仮想環境を作成します（discord-bot-env は任意の名前）。
```terminal
python3 -m venv discord-bot-env
```
これで discord-bot-env/ フォルダが作成され、中に独立したPython環境ができます。
仮想環境の有効化は以下のコマンドを実行
```terminal
source discord-bot-env/bin/activate
```
実行後、プロンプトの前に (discord-bot-env) のように表示されれば仮想環境に入っています。
この状態で以下のようにライブラリをインストールすれば、この環境だけに適用されます
```terminal
pip install discord.py
```
仮想環境の終了には、以下で仮想環境から抜けられます：
```terminal
deactivate
```

## pythonサンプルコード
```bot.py
# bot.py
import discord

# あなたのBotトークンをここに貼り付けてください
TOKEN = 'あなたのボットトークン'

# メッセージ内容を取得できるようにIntentを明示的に有効化
intents = discord.Intents.default()
intents.message_content = True

# Intentを指定してClientを作成
client = discord.Client(intents=intents)

@client.event
async def on_ready():
    print(f'{client.user} としてログインしました')

@client.event
async def on_message(message):
    # 自分自身や他のBOTのメッセージには反応しない
    if message.author.bot:
        return

    # 「こんにちは」と言われたら返す
    if message.content == "こんにちは":
        await message.channel.send("こんにちは！")

# BOTの起動
client.run(TOKEN)

```

## discordの設定
Discord Developer Portal にアクセスします。
https://discord.com/developers/applications

「New Application」からアプリケーションを作成（名前は任意）します。
![スクリーンショット 2025-04-19 10.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/b26830e3-daf0-4979-aba3-5d2eb6a2dd69.png)

左メニューの「Bot」から「Reset Token」をクリックします。
「TOKENをコピー」して先ほどのコードの TOKEN = '...' に貼り付けます。
![スクリーンショット 2025-04-19 10.54.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/fe13bd04-7cfe-41e0-99b3-8e7158fbea90.png)

「Privileged Gateway Intents」で"Message Content Intent"にチェックします。
また、botの権限についても"send message"と"Read Message History"の権限を付与します。
![スクリーンショット 2025-04-19 10.58.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/624ec2a1-8502-492e-9205-a80841b7f9ba.png)

「OAuth2 > URL Generator」で"bot"にチェックします。
また、bot権限でした内容と同じ"send message"と"Read Message History"の権限を付与します。
![スクリーンショット 2025-04-19 11.04.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/965c3634-8f46-4395-9340-e3e09bd4d8b2.png)

表示されたURLをブラウザに貼り付けて、自分のサーバーにBOTを招待します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/d60e7d7a-ce12-413e-98a6-83ad4fa90d8e.png)

無事に招待できたら、bot.pyを実行！
```terminal
python3 bot.py
```

## 運用
無事にここまでくれば、あとはdiscordで動作確認をするだけです。
このように、こんにちはといえば、即こんにちはと返してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/195c3f3b-5065-496d-a13c-ace12e08bdd5.png)

コーディングによってはスレッドで返信をしてくれたり、もしくはopenAIと連携したりと可能性は広がるかなと思います。

このbotはterminalで動かしていれば、このterminalを動かしている間だけしかbotは起動できないです。
ずっと起動させておきたいと言う人が大半だと思うので起動確認できれば**nohup**というコマンドを使って、ターミナルを閉じてもログアウトしてもずっと起動させることができます。
```terminal
nohup python3 bot.py &
```

ログの状況を確認したい場合はこのように、tailコマンドを用います。
```terminal
tail -f nohup.out
```

ほかにも、 BOTを停止したい場合はこのようにbot.pyというプロセスの確認を行い、そのプロセスIDをkillすることで止めることができます。
```terminal
ps aux | grep bot.py
kill 12345
```
# 環境の削除
ここまで、discordの簡易的なAPPを作成しました。
環境をクローズするときは、このまま放置するとgoogleCloud上はお金がかかってしまいます。
その環境削除について記載します。

方法はすごいシンプルでgoogleCloudからIAMと管理と検索欄で検索し、設定からシャットダウンをするだけ。
![スクリーンショット 2025-04-19 11.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/a2b767a3-2a2c-41ce-b306-59231b605e77.png)

prjを削除することで、Compute Engineは削除されるのはもちろん、インスタンスを作成する時に自動で作られる"ディスク・スナップショット"、"外部IPアドレス"、"Cloud Storage"などが削除されます。
これを行うことで、ここからの課金は全てSTOPします。

警告はでますが、このまま削除します。
![スクリーンショット 2025-04-19 11.42.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196891/9563077b-fbab-45d7-b304-7c9995c4326d.png)

googleCloudは作るのも簡単で削除するのも簡単で、尚且つ無料枠などもあるので自分は重宝しています。

以上で構築から削除まで終わりです

# 最後に
無事にbotはできたと思います
お疲れ様でした！

amazonのほしいものリストを公開しています。
ご褒美をくれると中の人は喜びます。
https://www.amazon.jp/hz/wishlist/ls/27TAD8AQG471K?ref_=wl_share