ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Litestream 入りの Dockerfile 作る

Litestream を Dockerfile に同梱して node のなんか動かすやつです。ここでは Next.js & Prisma 構成のサーバー動かします。

主な必要なファイル

  1. Dockerfile
  2. litestream.yml
  3. entrypoint.sh

1. Dockerfile

FROM node:18-alpine as builder

ADD . /app
WORKDIR /app
ADD https://github.com/benbjohnson/litestream/releases/download/v0.3.9/litestream-v0.3.9-linux-amd64-static.tar.gz litestream.tar.gz
RUN tar -xzf litestream.tar.gz -C ./
RUN npm install
RUN npx prisma generate
RUN npm run build


FROM node:18-alpine

COPY --from=builder /app/next.config.js /next.config.js
COPY --from=builder /app/public /public
COPY --from=builder /app/package.json /package.json
COPY --from=builder /app/.next/static /.next/static
COPY --from=builder /app/.next/standalone /
COPY --from=builder /app/litestream /usr/local/bin/litestream
COPY --from=builder /app/litestream.yml /etc/litestream.yml
COPY --from=builder /app/entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
  • litestream のバイナリダウンロードして解凍して、COPY で実行できる場所におきます
  • restore したかったので entrypoint.sh にいろいろ書きます
  • builder や COPY の部分は物によっていろいろ違いがあると思います
  • npx prisma generate で node:18-alpine 用の sqlite3 入ります、後述の schema.prisma の設定が必要

2. litestream.yml

dbs:
  - path: /tmp/db.sqlite # Database to replicate from
    replicas:
      - url: s3://mybkt/litestream # S3-based replication
        endpoint: http://172.17.0.2:9000
        sync-interval: 1s
  • ここでは minio を使う想定です、endpoint は minio 起動した時に表示されたものを入れました

3. entrypoint.sh

#!/bin/sh
set -e

if [ -f /tmp/db.sqlite ]; then
  rm /tmp/db*
fi

litestream restore /tmp/db.sqlite
litestream replicate -exec "node ./server.js"
  • /tmp/db.sqlite にある想定、あったら一旦削除して restore します
  • exec で replicate しつつスクリプトを実行できるようです
  • /bin/sh と/bin/bash 間違えてハマりました

という感じです。まだ何も作っていない状態だったら以下の感じで諸々入れていけばいいかなと思います。

諸々の入れ方

Next.js

$ npx create-next-app next-prisma-litestream --typescript
$ cd next-prisma-litestream

next.config.js 作成

module.exports = {
  output: 'standalone',
}

Prisma

$ npm install --save-dev prisma
$ npx prisma init

.env を修正して sqlite の db を指定 (/tmp/db.sqlite にした)

DATABASE_URL="file:/tmp/db.sqlite"

prisma/schema.prisma も修正

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

// 動作確認のための適当なテーブル
model test {
  id Int @id @default(autoincrement())
  value String
}
  • node:alpine-18 を使う場合 binaryTargets に linux-musl-openssl-3.0.x を入れろとエラーで言われたので入れました

マイグレーション実行

$ npx prisma migrate dev

適当なエンドポイント作る

pages/api/hello.ts

import type { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

type Data = {
  id: number;
  value: string;
};

const Hello = (req: NextApiRequest, res: NextApiResponse<Data[]>) => {
  prisma.test
    .create({
      data: { value: new Date().toISOString() },
    })
    .then(() => prisma.test.findMany())
    .then((v) => res.status(200).json(v));
};
export default Hello;

動作確認

minio 起動して Web 画面からバケット作っておきます (mybkt にしました)

$ docker run --rm -p 9000:9000 -p 9001:9001 -v /tmp/minio:/data minio/minio:latest server /data --console-address ":9001"

Dockerfile をビルドして実行します

$ docker build -t ushumpei/next-prisma-litestream:latest .
$ docker run  --tty --interactive --rm -p3000:3000 --env LITESTREAM_ACCESS_KEY_ID=minioadmin --env LITESTREAM_SECRET_ACCESS_KEY=minioadmin ushumpei/next-prisma-litestream:latest
  • LITESTREAM_ACCESS_KEY_ID, LITESTREAM_SECRET_ACCESS_KEY に minio の認証渡します、実際の s3 使う場合は AWS の認証渡します
$ open http://localhost:3000/api/hello

データ表示されてる感じです、再起動しても残る

感想

  • litestream は複数の writer 対応していないことを結構調べてから知った
  • Lambda & container では無理そう
  • ECS on EC2 なら大丈夫そうだけどインスタンス料金はかかる、同時起動制御とかも
  • Fargate?
  • Cloud Run はどんな感じなんだろう?
  • Dockerfile のマルチビルド初めて書いた
  • docker のネットワーク全然わからない、雰囲気で書いている
  • node:slim-18 とかで書きたかったけどちょっとやってダメだったのでやめました
  • litefs は consul server (?) を常時起動する必要がある?