It技術

T3 Stack + Koyeb + NeonでWebアプリの爆速デプロイ


結論

  1. T3 Stack + Koyeb + Neonを使うとWebアプリを簡単にデプロイできる
  2. T3 Stackを使うと、BE・FEともにTypescriptで開発でき、通信もtRPCで簡単にできる
  3. Koyebを使うとDockerイメージのデプロイを簡単にできる
  4. Neonを使うと簡単にpostgres データベースを用意できる

前がき

先日T3 Stack + Koyeb + Neonを使ってみたのですが、想像以上に簡単にNext.js アプリの開発+デプロイ環境を用意できたので、その方法を共有したいと思います。

T3スタックとは?

T3スタックは、Next.jsの開発環境を提供してくれるテンプレートです。

TypeScript、Next.js、tRPC、Prisma、Tailwind CSSなどを組み合わせることで、すぐに開発を始めることができるようになっています。

私が感動したのは、以下の点です。

  • バックエンド・フロントエンドの開発を両方ともTypescriptで行える
    • tRPCを使うことで、関数を呼び出すような手軽さでバックエンドとの通信を行うことができます。
    • アプリのドメイン部分をTypescriptで書いておけば、バックエンド・フロントエンドの双方から参照できる
  • 環境変数をzodでガッチガチに固めている
    • 環境変数からどんな値を読み込むかをzodを使って定義づけしています。これにより、環境変数の設定ミスがあればアプリの起動時にエラーが発生し簡単にミスに気づくことができます。

Koyebとは?

Koyebは最近注目されているPaaSの1つです。DockerイメージやGitリポジトリから簡単にアプリケーションをデプロイすることができます。

今回は

  • UIがとても親切
  • フリープランで十分にアプリが運用できそう

という理由から、Koyebにお世話になることにしました 🙇

https://www.koyeb.com/

Neonとは?

Neonはデータベースのセットアップを簡単に行えるDBaaSです。トップページがおしゃれで好きです。

  • ブランチ機能を使うことで簡単にプレビュー用・テスト用のDBを用意できる。
  • UIがリッチ
    • SQLエディタがついてる
    • UIが親切で設定がしやすい

といった点が決め手となり、今回採用させていただきました。

デプロイ方法

1. T3スタック セットアップ

基本的にT3のドキュメントに沿っていく形になります。

https://create.t3.gg/ja/usage/first-steps

開発用のDBのセットアップについても手厚くサポートされており、

  • アプリケーションのルートディレクトリにある start-database.shを実行することで開発用のデータベースが立ち上がります。
  • package.jsonにprisma clientの操作用スクリプトが用意されています。

作成したアプリは後ほどKoyebへデプロイするため、githubにpushしておきます。

2. Neonセットアップ

Neonを使って本番環境向けのDBを用意します。

以下の手順で本番用の

  1. トップページからアカウントを作ります。

    https://neon.tech/

  2. 新しくプロジェクトを作ります。

  3. Project DashboardにDB接続用の文字列が表示されるのでメモしておきます。

3. Dockerfileの用意

今回はT3 StackのアプリをDockerイメージにしてKoyeb上にデプロイします。

公式にDockerfileの用意方法が書かれているので、そちらを流用させていただきます。

https://create.t3.gg/en/deployment/docker

私はデプロイと同時にマイグレーションも実行するように少し修正しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# ./Dockerfile

##### DEPENDENCIES

FROM --platform=linux/amd64 node:20-alpine AS deps
RUN apk add --no-cache libc6-compat openssl
WORKDIR /app

# Install Prisma Client - remove if not using Prisma

COPY prisma ./

# Install dependencies based on the preferred package manager

COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml\* ./

RUN \
    if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
    elif [ -f package-lock.json ]; then npm ci; \
    elif [ -f pnpm-lock.yaml ]; then npm install -g pnpm && pnpm i; \
    else echo "Lockfile not found." && exit 1; \
    fi

##### BUILDER

FROM --platform=linux/amd64 node:20-alpine AS builder

RUN apk add --no-cache libc6-compat openssl

ARG AUTH_SECRET
ARG DATABASE_URL
ARG NODE_ENV

ENV AUTH_SECRET=$AUTH_SECRET
ENV DATABASE_URL=$DATABASE_URL
ENV NODE_ENV=$NODE_ENV

WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# ENV NEXT_TELEMETRY_DISABLED 1


RUN \
    if [ -f yarn.lock ]; then SKIP_ENV_VALIDATION=1 yarn build; \
    elif [ -f package-lock.json ]; then SKIP_ENV_VALIDATION=1 npm run build; \
    elif [ -f pnpm-lock.yaml ]; then npm install -g pnpm && SKIP_ENV_VALIDATION=1 pnpm run build; \
    else echo "Lockfile not found." && exit 1; \
    fi

RUN  cp -r -u .next/server .next/standalone/.next &&\
     cp -r -u .next/static .next/standalone/.next &&\
     cp -r -u public .next/standalone

COPY ./entrypoint.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh

EXPOSE 3000
ENV PORT 3000

CMD ["./entrypoint.sh"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/sh

# ./entrypoint.sh

set -eu

echo "Running database migrations..."
if [ -f yarn.lock ]; then SKIP_ENV_VALIDATION=1 yarn db:migrate; \
elif [ -f package-lock.json ]; then SKIP_ENV_VALIDATION=1 npm run db:migrate; \
elif [ -f pnpm-lock.yaml ]; then npm install -g pnpm && SKIP_ENV_VALIDATION=1 pnpm run db:migrate; \
else echo "Lockfile not found." && exit 1; \
fi

echo "Starting the application..."
cd ./.next/standalone/ && node ./server.js

4. Koyebへのデプロイ

  1. Koyebでアカウントを作成します。

    koyeb.com

  2. 「Create Service」→「Web service」→ Github を選択し、アプリケーションがあるgithubのリポジトリを選択します。

  3. Choose instance and regionsでお好きなインスタンスを選択します。Freeを1つのサービスだけ選択できるので、私はFreeを選択しました。

  4. Review and deployの画面では

    1. SourceはGithubで、ブランチはデプロイに使うブランチを選択してください。
    2. Builderは「Dockerfile」を選択してください。これによりプロジェクト直下にあるDockerfileからイメージが作られ、デプロイされます。
    3. Environment variablesは以下を指定してください。
      1. AUTH_SECRET=適当な値
      2. DATABASE_URL=<Neon DB本番環境への接続文字列>
      3. NODE_ENV=production
    4. Exposed portsは3000を指定してください。
  5. Deployボタンを押します。

  6. しばらく待つと、ダッシュボードに表示されているリンクからアプリケーションにアクセスできるようになります。

感想

開発環境やデプロイの仕組みの構築は、エンジニアとしては楽しい点ではありつつも、毎回悩み、ある意味本筋とは関係のない作業時間であったので、より開発に集中できて良いなあと思いました。

本当に便利な時代になったなと思います。