TiDBローカル環境構築⑤
TiDBのローカル環境の構築を5回目行なっていきます。
前回TiDB環境のDjango構築が出来ましたが、今回はDockerでREST APIの構築を行っていきます。
コンテナ環境のツリー構成
DB構築時のツリー構造は以下のようにしてます。
今回はcoreフォルダの追加とその配下のファイル追加、後はapi/Dockerfileの編集、api/entrypoint.shの追加、setting.pyの変更を行いました。
.
├── .env.api
├── docker-compose.yml
└── src
├── infra
│ └── db
│ ├── Dockerfile
│ ├── data
│ │ └── test_db.sql
│ ├── docker-compose.yml
│ └── entrypoint.sh
└── www
└── api
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
├── project
│ ├── core
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── manage.py
│ └── project
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── requirements.txt
ソースコードを作成
各ファイルの追加と編集を行います。
Python 3.11-slim をベースに、依存パッケージと仮想環境を構築し、entrypoint.sh でアプリ起動準備を行う Django 用 Docker イメージを作成する設定に変更しました。
FROM python:3.11-slim
WORKDIR /app/project
RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd && rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./
RUN python -m venv /venv \
&& /venv/bin/pip install --no-cache-dir -r requirements.txt
COPY . .
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENV VIRTUAL_ENV=/venv
ENV PATH="/venv/bin:${PATH}"
EXPOSE 8000
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/bin/bash"]
Django アプリ起動前にDB接続待機とマイグレーションを実行するスクリプトを作成します。
#!/bin/sh
set -e
echo "Waiting for DB..."
until nc -z "$DB_HOST" "$DB_PORT"; do
sleep 1
done
echo "Running migrations..."
python manage.py makemigrations core || true
python manage.py migrate --noinput
exec "$@"
./src/www/api/project/core/init.pyはパッケージとして認識させるための空ファイルの為何も書いてませんが、作成します。
Django管理画面の作成を行います。
from django.contrib import admin
from .models import Customer
@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ("id", "name", "email", "created_at")
search_fields = ("name", "email")
ordering = ("-id",)
Djangoアプリ「core」の設定クラスを定義し、デフォルトの主キー型をBigAutoFieldに設定して一ます。
from django.apps import AppConfig
class CoreConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "core"
顧客の名前・メールアドレス・作成日時を管理するCustomerモデルを定義し、文字列表現に名前とメールを返す処理になります。
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.name} <{self.email}>"
Customerモデルの全フィールドをシリアライズ・デシリアライズするためのCustomerSerializerを定義します。
from rest_framework import serializers
from .models import Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ["id", "name", "email", "created_at"]
CustomerViewSetをルーターに登録し、/customersエンドポイントを提供するURL設定を定義します。
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CustomerViewSet
router = DefaultRouter()
router.register(r"customers", CustomerViewSet)
urlpatterns = [
path("", include(router.urls)),
]
CustomerモデルのCRUD機能を提供するViewSetを定義し、新しい順でデータを取得する設定を実装しました。
from rest_framework import viewsets
from .models import Customer
from .serializers import CustomerSerializer
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all().order_by("-id")
serializer_class = CustomerSerializer
setting.pyにREST APIのモジュールの追加を行います。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 新しく追加
'core', # 新しく追加
]
# 新しく追加
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"],
}
これは、Django のAPI エンドポイント /api/ を紐づけるルーティング設定を追加します。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# 新しく追加
path("api/", include("core.urls"))
]
上記でREST API環境の構築は完了しました。
以下コマンドを実行し、API用のコンテナにアクセスします。
docker exec -it ubuntu-dev-container sh
以下のコマンドでDjangoのサーバーを起動します。
python manage.py runserver 0.0.0.0:8000
別ターミナル開きます。
テストで以下のコマンドを実行します。
curl -X POST http://127.0.0.1:8000/api/customers/ \
-H "Content-Type: application/json" \
-d '{"name":"テスト三郎","email":"saburo@example.com"}'
サーバーのログで以下が出力されてたら疎通OKになりました
[10/Aug/2025 23:43:51] "POST /api/customers/ HTTP/1.1" 201 106
詰まった箇所
./src/www/api/entrypoint.sh で exec "$@" を記載しない場合、DB待機とマイグレーション処理が終わった時点でシェルスクリプトが終了し、フォアグラウンドで動くメインプロセスが存在しなくなるため、Docker コンテナは数秒後に停止してしまいます。
まとめ
- 目的:TiDBローカル環境でDjango REST APIをDocker上に構築
- 変更点:core アプリ追加、Dockerfile 編集、entrypoint.sh 作成、settings.py 修正
- Dockerfile:Python仮想環境構築+依存インストール+起動スクリプト組み込
- entrypoint.sh:DB待機→マイグレーション→アプリ起動(exec "$@" 必須)
- アプリ実装:Customer モデルとCRUD APIを作成し /api/customers/ で操作可能に
- 動作確認:curl でPOSTし201レスポンスでOK
- 注意点:exec "$@" を書かないとコンテナが自動終了
Discussion