GCP Cloud Run Dockerfile

Cloud Runにした背景

私が作るプロダクトにはコンタクトフォームにnodemailerを使用しています。 node.js上でしか動作しない仕様なのでnext export系は全滅でした。 Github ActionsのAzure Web Static AppsやCloudflare Pagesなどは使ってみて動かなかったので除外されました。

3週間くらいかかった

環境変数につまずきすぎて3週間超えてしまった(もちろん他のこともやってた)。 Dockerとyamlの知識がなく環境変数を安全にデプロイするために必要な時間でした。 先の見えないビルドループから抜け出せたのでホッとしました。

これで一応月間3000000リクエストまでは0.4ドルで捌けるみたいです。

Dockerfile(Next.js in Cloud Build)

1# Install dependencies only when needed
2FROM node:lts-alpine AS deps
3
4RUN apk add --no-cache libc6-compat
5WORKDIR /app
6COPY package.json package-lock.json ./ 
7RUN npm ci
8
9# Rebuild the source code only when needed
10FROM node:lts-alpine AS builder
11
12ARG _CONTENTFUL_SPACE_ID
13ARG _CONTENTFUL_DELIVERY_TOKEN
14ARG _NEXT_PUBLIC_GA_ID
15ARG _MAIL_USER
16ARG _MAIL_PASS
17ARG _MAIL_TO
18
19ENV NEXT_PUBLIC_CONTENTFUL_SPACE_ID=$_CONTENTFUL_SPACE_ID \
20    NEXT_PUBLIC_CONTENTFUL_DELIVERY_TOKEN=$_CONTENTFUL_DELIVERY_TOKEN \
21    NEXT_PUBLIC_GA_ID=$_NEXT_PUBLIC_GA_ID \
22    NEXT_PUBLIC_MAIL_USER=$_MAIL_USER \
23    NEXT_PUBLIC_MAIL_PASS=$_MAIL_PASS \
24    NEXT_PUBLIC_MAIL_TO=$_MAIL_TO
25
26WORKDIR /app
27COPY . .
28COPY --from=deps /app/node_modules ./node_modules
29RUN npm run build
30
31# Production image, copy all the files and run next
32FROM node:alpine AS runner
33
34WORKDIR /app
35ENV NODE_ENV production
36RUN addgroup -g 1001 -S nodejs
37RUN adduser -S nextjs -u 1001
38
39COPY --from=builder /app/next.config.js ./
40COPY --from=builder /app/public ./public
41COPY --from=builder --chown=node:node /app/.next ./.next
42COPY --from=builder /app/node_modules ./node_modules
43COPY --from=builder /app/package.json ./package.json
44USER nextjs
45EXPOSE 3000
46CMD ["npm", "start"]

ハマりポイント

m1チップからのDockerイメージだとbuildコマンドの引数に --platform linux/amd64を付けないといけない。 これは最初にContainer Registryにpushするときに必要(m(x)チップなら)

amd64はつまりx86_64と同じみたいで、使ってるPCのCPUアーキテクチャを引数でGCPのマシンに合わせる必要があります。 M1 MacでARMとIntelのターミナルを切り替えて使う (Homebrew 3以降の場合)


1COPY --from=builder --chown=node:node /app/.next ./.next

--chown=node:nodeとしてroot権限エラー回避


1FROM node:lts-alpine AS builder

ローカルのビルドは成功するにもかかわらず、ここのすぐ下,WORKDIR /appの前にARGとENVを記述しないとCloud Buildで設定した環境変数を吸わなかったです。 ここで他のところに記述してもローカルでイメージを焼いてlocalhost:3000で見ても問題なく動く、なのにCloud BuildからDocker imageに渡す場合この場所に記述しないとだめです。


・npmを使用しているならnpm installの代わりにnpm ciを使う ・dockerignoreで不要なファイルをはじく

#さいごに

リクエストが上がりにくい小規模な個人ブログではわざわざAWSやGCPを導入する必要はほぼないかもしれませんが、ぜひみんなも勉強としてやってみましょう!!

ここらへんの従量課金系サービスでよいところはドメインからCICDからコンソールから通信量やメモリCPU使用量のインフラ管理まですべてを一貫して行えることです。 私はGoogleドメインを使いたかったので今回GCPを使ってみました。 ここまでみてくれてありがとうございました! node.jsアプリでDockerfileを作る人の参考になれれば幸いです!

Google Cloud 料金計算ツール

3大クラウドサービス(Azure/AWS/GCP)のコンテナサービスをさわって比較してみた