🐁

Vercel に Go サーバーを無料でデプロイできるんです!

2024/07/06に公開

はじめに

個人開発で使っていたのですが Gopher の集いにて Vercel で Go の開発ができることを話したら意外と知られていなかったのでご紹介します。
(貧乏エンジニアリングだと言って似たような記事を以前お見かけしていた場合、それはきっと私の残像が書いたものです。)

Vercel とは

https://vercel.com/

いわゆる PaaS ( Platform as a Service ) です。
Vercel 社が Next.js を開発していることもあり、静的サイトや SPA ホスティングを簡単にできるサービスの印象が強いですが、 Functions や Postgres などを備えているのでサーバーの構築もできちゃいます。
Next.js のイメージから TypeScript と思われますが Go もデプロイできます。

準備 & version

Vercel アカウントを作成します。

https://vercel.com/signup

無料で使いたいので Hobby 版を選択します。

各種操作を行うために Vercel CLI をインストールします。

node --version
v20.15.0

いくつかインストールの方法はありますが npm にてインストールします。

npm i -g vercel
vercel -v
Vercel CLI 34.3.0
34.3.0

プロジェクトを開始するために Vercel にログインしておきます。

❯ vercel login

Vercel CLI 34.3.0
? Log in to Vercel 
● Continue with GitHub 
○ Continue with GitLab 
○ Continue with Bitbucket 
○ Continue with Email 
○ Continue with SAML Single Sign-On

開発のために Go をインストールしておきます。

https://go.dev/doc/install

go version
go version go1.22.5 darwin/arm64

Functions のデプロイ

https://vercel.com/docs/functions/runtimes/go

公式ドキュメントの通りに進めれば簡単にデプロイまで辿りつきます。

mkdir <project>
cd <project>
go mod init <project>
mkdir api
touch api/index.go
index.go
package api

import (
	"fmt"
	"net/http"
)

func Handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "<h1>Hello from Go!</h1>")
}
touch vercel.json
vercel.json
{
  "build": {
    "env": {
      "GO_BUILD_FLAGS": "-ldflags '-s -w'"
    }
  }
}

ここまで準備ができたら CLI を使ってデプロイします。

vercel --prod
Vercel CLI 34.3.0
? Set up and deploy “~/<project>”? yes
? Which scope do you want to deploy to? <account>
? Link to existing project? no
? What’s your project’s name? <project>
? In which directory is your code located? ./
Local settings detected in vercel.json:
No framework detected. Default Project Settings:
- Build Command: `npm run vercel-build` or `npm run build`
- Development Command: None
- Install Command: `yarn install`, `pnpm install`, `npm install`, or `bun install`
- Output Directory: `public` if it exists, or `.`
? Want to modify these settings? no
🔗  Linked to <account>/<project> (created .vercel and added it to .gitignore)
🔍  Inspect: https://vercel.com/<account>/<project>/<random> [2s]
✅  Production: https://<project>.vercel.app [2s]

完全に好みの問題ですが、私は GitHub との連携はせず常にローカルから明示的にデプロイコマンドを実行しています。とくにこだわりがあるというわけでもないです。

curl https://<project>.vercel.app/api
<h1>Hello from Go!</h1>

こんな感じで簡単に Go サーバーが構築できちゃいます!

Postgres と接続

https://vercel.com/docs/storage/vercel-postgres

Hobby プランだとアカウントあたり1つの Postgres が作成できます。

Postgres を作成するとプロジェクトから下記画像のように Connect ができるようになります。

Connect を行うと環境変数に各種値が設定されます。これらの値を Go 側から読み込んで Postgres に接続するようにします。

実装すると以下のようになります。

index.go
package handler

import (
	"context"
	"fmt"
	"net/http"
	"os"

	"github.com/jackc/pgx/v5/pgxpool"
)

func Handler(w http.ResponseWriter, r *http.Request) {
	pool, err := GetPool(r.Context(), GetDSN())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)

		return
	}

	defer pool.Close()

	fmt.Fprintf(w, "<h1>Hello from Go!</h1>")
}

func GetDSN() string {
	return "postgres://default:" + os.Getenv("POSTGRES_PASSWORD") + "@" + os.Getenv("POSTGRES_HOST") + ":5432/" + os.Getenv("POSTGRES_DATABASE") + "?sslmode=require"
}

func GetPool(
	ctx context.Context,
	dsn string,
) (*pgxpool.Pool, error) {
	conn, err := pgxpool.ParseConfig(dsn)
	if err != nil {
		return nil, err
	}

	pool, err := pgxpool.NewWithConfig(ctx, conn)
	if err != nil {
		return nil, err
	}

	if err := pool.Ping(ctx); err != nil {
		return nil, err
	}

	return pool, nil
}

ドライバーとして pgx を選択していますが Postgres なので pq でも接続できるはずです。

注意点

go mod vendor をするとデプロイに失敗します。(めんどくさいので原因追求していないです。)

Error: Command failed: go build -ldflags -s -w -o /tmp/1a06585b/bootstrap /vercel/path0/main__vc__go__.go

お片付け

vercel project rm <project-name>

おわりに

今回は軽くご紹介するくらいで終わりにします。
ルーティングどうやるんだとかパスパラメータ使えるんだっけ?とかほかにも紹介できることがあるので気が向いたら記事書きます。

あと、Storage として Blob, KV, Edg Config があるので触っておきます。(いまのところ使う予定がないので未検証)

貧乏エンジニアリング(いかに無料で開発をするか) の醍醐味はいかに自分に縛りを設けるかです。
みなさん Go で開発をしたい場合はぜひ Cloudflare × workers を使いましょう!w

今回実装したコードは以下に置いておきます。

https://github.com/otakakot/sample-go-vercel

Discussion