唐突にdiscordbotにChat-Gptを乗せたくなった。
GW終わりを目標にやっていこうと思う。
とりあえず今回は環境構築にいてかいていく。
環境について
基本的に私は作成したアプリなどはすべてDockerに乗せて運用をするので今回もその例にもれずにやっていくことにする。
運用するマシンはひとまず自宅で動いている開発マシン1号※を使用することに。そのうち速攻飽きて転がしているラズパイ4(もうメモリが何GBのモデルかも覚えていない…)で運用するかもしれない。
※開発マシン1号:
数年前に中国の通販で買ったVesaマウントできる小型のPC。
CPU:i7-8565U
メモリ:16GB
と, 普段の開発をするうえでは特に困らないスペックで重宝している。
割と頻繁にOSを入れ替えて色々遊んだりもしている。
ディレクトリ構成
├── devEnv
│ ├── Dockerfile
│ ├── createuser.sh
│ └── docker-compose.yml
├── production
│ ├── Dockerfile_gpt
│ └── docker-compose.yml
└── src
├── README.md
└── discord_bot
└── gpt
├── README.md
├── constants.py
├── gptbot.py
├── openaiUtil.py
└── pyproject.toml
devEnvフォルダ内のdocker-compose.ymlで開発環境コンテナを,
productionフォルダ内のdocker-composeで実行環境コンテナを作成する。
src/discord_bot
配下に作成するbotのプロジェクト事にフォルダを作成している。
botプロジェクトを増やす事にdevEnv,production内のDockerfileを増やしていく形を取っている。
ひとまず今はchat-gptのdiscordbot分のみ。
開発用コンテナ作成
開発はpetry(python)を使用する。
ひとまずの開発環境としてptyon系のコンテナを準備
FROM debian:bookworm-slim
# コンテナ内で操作するユーザー情報, ローカルマシンのユーザーと合わせる。
ARG UID=1000
ARG GID=1000
RUN apt-get update && apt-get install -y \
curl \
git \
vim \
zip \
unzip \
build-essential \
pipx \
gosu \
python3-dev \
libsqlite3-dev\
&& rm -rf /var/lib/apt/lists/*
COPY createuser.sh /usr/bin/createuser.sh
RUN chmod +x /usr/bin/createuser.sh
ENTRYPOINT ["/usr/bin/createuser.sh"]
# 作業ディレクトリの設定
WORKDIR /app
CMD pipx ensurepath && pipx install poetry && exec bash
なんか色々入れてるのはとりあえず思いついたものを入れただけで全て必要なわけではない。
というか多分pipxとgosuだけでとりあえず大丈夫だったと思う。
コンテナ内のユーザについて, ROOT以外のユーザを使用するようにした。
セキュリティーが~とか色々あるらしいが1番の理由は, rootユーザでDocker内開発をすると, ファイル操作したあとに, マウント元のローカルでのファイル所有者もかわって操作しづらくなるから。
createuser.sh
内で実行用ユーザーを作成し, gosuでコマンド実行ユーザーを変更するようにした。
#!/bin/bash
USERID=${USER_ID}
GROUPID=${GROUP_ID}
echo "Create User = $USERID. Group = $GROUPID"
groupadd -g $GROUPID dockeruser
useradd -m -s /bin/bash -u $USERID -g $GROUPID dockeruser
exec /usr/sbin/gosu dockeruser "$@"
このDockerfileを呼び出すdocker-compose.ymlは
version: '3.8'
services:
dev:
build: .
image: discordbot_dev
environment:
- USER_ID=1000
- GROUP_ID=1000
volumes:
- ../src/discord_bot:/app
tty: true
実行環境用コンテナ作成
実行環境は軽量なDockerイメージにしたかったのでマルチステージビルドを活用し
- poetryからreqirements.txtを出力するステージ
- pipでパッケージ類をインストールするステージ
- 軽量なdistrolessでbotを実行するステージ
の3段活用とすることにした。 一応動くようにしたDockerfileが
# 1.依存関係をexportするステージ
FROM python:3.11-slim-bookworm as exporter
LABEL stage=exporter
WORKDIR /app
ENV POETRY_VERSION=1.8.2
RUN apt-get update && apt-get install -y pipx
RUN pipx install poetry
COPY ./src/discord_bot/gpt/pyproject.toml ./src/discord_bot/gpt/poetry.lock* /app/
# PATH 環境変数の設定
ENV PATH /root/.local/bin:$PATH
# reqirements.txtの出力
RUN pipx inject poetry poetry-plugin-export && poetry export -f requirements.txt --output requirements.txt --without-hashes
# 2.パッケージをインストールするステージ
FROM python:3.11-slim-bookworm as builder
LABEL stage=builder
COPY --from=exporter /app/requirements.txt /app/
WORKDIR /app
RUN pip install --user -r requirements.txt
# アプリケーションのソースコードもここでコピー
COPY ./src/discord_bot/gpt /app
# 3.実行ステージ
FROM gcr.io/distroless/python3-debian12
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app /app
WORKDIR /app
# PYTHONPATHを設定
ENV PYTHONPATH=/root/.local/lib/python3.11/site-packages
#gcr.io/distroless/python3-debian12のEntryPointはpythonなのでコマンドで直接ファイルを指定する。
CMD ["gptbot.py"]
となっている。
特にハマったのが最終的な実行ステージ部分。
最初はpoetryでパッケージをインストールしたあとに, その仮想環境, .venvフォルダごとコピーして.venv内のpythonを実行しようとしたがうまくいかず…
内部を確認してみると
lrwxrwxrwx 1 dockeruser dockeruser 19 Apr 25 12:49 python -> /usr/bin/python3.11
lrwxrwxrwx 1 dockeruser dockeruser 6 Apr 25 12:49 python3 -> python
lrwxrwxrwx 1 dockeruser dockeruser 6 Apr 25 12:49 python3.11 -> python
となっており, 仮想環境内にはpythonの実態はなくシンボリックリンクだった。
そのため, reqirements.txt出力し, pip install
する方向に変更した。