読み込み中...
Vercelは、Next.jsアプリケーションのホスティングに最適化されたプラットフォームです。本記事では、Vercelの機能を最大限活用し、ユーザーに影響を与えないゼロダウンタイムデプロイを実現する方法を詳しく解説します。
VercelはAtomic Deploymentsを採用しており、新しいバージョンが完全にデプロイされるまで、古いバージョンへのトラフィックを維持します。
デプロイの流れ:
プッシュ
2. Vercelがビルドを開始
3. 新しいバージョンが完全にビルド完了
4. トラフィックを瞬時に新バージョンに切り替え
5. 古いバージョンは一定期間保持(ロールバック可能)
{
"name": "my-next-app",
"version": "1.0.0",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}vercel.json の設定:
{
"git": {
"deploymentEnabled": {
"main": true,
"develop": true
}
},
"github": {
"autoAlias": true,
"autoJobCancelation": true,
"silent": false
}
}https://example.comhttps://branch-name.vercel.apphttps://app-name-git-branch-team.vercel.app# Vercel CLI で環境変数を設定
vercel env add NEXT_PUBLIC_API_URL production
vercel env add NEXT_PUBLIC_API_URL preview
vercel env add DATABASE_URL production
# 環境変数の確認
vercel env ls// lib/config.ts
export const config = {
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001',
databaseUrl: process.env.DATABASE_URL,
isDevelopment: process.env.NODE_ENV === 'development',
isProduction: process.env.VERCEL_ENV === 'production',
isPreview: process.env.VERCEL_ENV === 'preview',
}Vercelでは、トラフィックを段階的に新バージョンに移行できます。
{
"version": 2,
"routes": [
{
"src": "/(.*)",
"dest": "/$1",
"headers": {
"x-deployment-version": "v2"
},
"continue": true
}
]
}// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// 10%のユーザーを新バージョンに振り分け
const bucket = Math.random()
const isNewVersion = bucket < 0.1
const response = NextResponse.next()
if (isNewVersion) {
response.cookies.set('version', 'v2')
}
return response
}# デプロイ履歴の確認
vercel ls
# 特定のデプロイをプロダクションに昇格
vercel promote <deployment-url>
# 直前のデプロイにロールバック
vercel rollback// pages/api/hello.ts
import { NextRequest } from 'next/server'
export const config = {
runtime: 'edge',
}
export default async function handler(req: NextRequest) {
return new Response(
JSON.stringify({
message: 'Hello from Edge',
region: process.env.VERCEL_REGION,
}),
{
status: 200,
headers: {
'content-type': 'application/json',
},
}
)
}// pages/blog/[slug].tsx
export async function getStaticProps({ params }) {
const post = await getPost(params.slug)
return {
props: { post },
revalidate: 60, // 60秒ごとに再生成
}
}
export async function getStaticPaths() {
const posts = await getAllPosts()
return {
paths: posts.map((post) => ({
params: { slug: post.slug },
})),
fallback: 'blocking', // 新しいページはサーバーサイドで生成
}
}// pages/_app.tsx
import { Analytics } from '@vercel/analytics/react'
export default function MyApp({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Analytics />
</>
)
}import { sendMetric } from '@vercel/analytics'
export async function trackCheckout(amount: number) {
await sendMetric({
name: 'checkout',
value: amount,
tags: ['ecommerce'],
})
}{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=31536000; includeSubDomains"
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
}
]
}
]
}# Vercel CLIで環境変数を暗号化して保存
vercel env add SECRET_KEY production --sensitive
# GitHubシークレットと連携
vercel env pull .env.local// pages/api/deploy-hook.ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Vercelのデプロイフックを検証
const secret = req.headers['x-vercel-signature']
if (secret !== process.env.DEPLOY_HOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' })
}
// CMSの更新時に再デプロイをトリガー
await fetch(process.env.VERCEL_DEPLOY_HOOK_URL!, {
method: 'POST',
})
res.status(200).json({ message: 'Deployment triggered' })
}# Vercel Deploy Hookを作成
curl -X POST https://api.vercel.com/v1/integrations/deploy-hooks \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "Content Update Hook",
"ref": "main"
}'| 環境 | ブランチ | URL | 用途 |
|---|---|---|---|
| Production | main | example.com | 本番環境 |
| Staging | develop | staging.example.com | ステージング |
| Preview | feature/* | feature-name.vercel.app | 機能開発 |
{
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://api.example.com/:path*"
},
{
"source": "/blog/:slug",
"destination": "/blog/[slug]"
}
],
"redirects": [
{
"source": "/old-page",
"destination": "/new-page",
"permanent": true
}
]
}# 現在の使用量を確認
vercel billing
# 実行時間の確認
vercel logs --follow推奨される使い方:
避けるべき使い方:
# デプロイログの確認
vercel logs <deployment-url>
# ビルドログの詳細表示
vercel build --debug1. ビルドタイムアウト
{
"builds": [
{
"src": "package.json",
"use": "@vercel/next",
"config": {
"maxDuration": 60
}
}
]
}2. メモリ不足
// next.config.js
module.exports = {
experimental: {
// ビルド時のメモリ使用量を削減
workerThreads: false,
cpus: 1,
},
}Vercelでゼロダウンタイムデプロイを実現するポイント:
これらの機能を組み合わせることで、安全で高速なデプロイメントプロセスを構築できます。
コメント