🐁

クレカ不要!Lambda × Go を無料でスケジューリングしよう! a. k. a. Netlify Functions

2025/03/02に公開

はじめに

貧乏エンジニアリングシリーズ最新作です!

https://zenn.dev/otakakot/articles/9e9269a87aafeb

どこか Web ホスティングするのに、なにかサービスないかなあって探していたら、Netlify というサービスを見つけました。

https://www.netlify.com/

こちらのサービスも以前 Vercel で紹介したように無料で Go サーバーを構築することができたので紹介します。
ただ、サーバーを構築するだけだったら公式ドキュメントを参照すれば簡単にできたので実装を少し工夫してスケジュールで動かしてみます。

Netlify とは

https://docs.netlify.com/platform/what-is-netlify/

公式サイトによるとフレームワークに依存しない「持続可能な Web アーキテクチャ」と説明されています。
あらゆる Web フロントエンドフレームワークに対応しています。

http://docs.netlify.com/frameworks/

Netlify はこれだけでなくサーバレス関数も提供しています。

https://docs.netlify.com/functions/overview/

サーバレス関数には TypeScript, JavaScript そして Go が対応しています。

準備 & version

Netlify アカウントを作成します。
以下のリンクにアクセスして作成できます。

https://app.netlify.com/signup

私は GitHub アカウントにてサインアップしました。

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

node --version
v22.11.0
npm --version
11.1.0

npm にてインストールします。

npm install netlify-cli -g
netlify --version
netlify-cli/19.0.0 darwin-arm64 node-v22.11.0

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

netlify login

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

https://go.dev/doc/install

go version
go version go1.24.0 darwin/arm64

実装

Functions

Neflify は AWS Lambda と互換性のあるサーバーレス関数にて動作します。
(というかたぶん Lambda で動いています。)
ディレクトリ構成や実装については下記のページをご参照ください。

https://docs.netlify.com/functions/lambda-compatibility/?fn-language=go

公式ドキュメントのサンプルコードは Lambda の Request と Response を扱う実装になっています。
このままでもよいですが、実装しやすいように net/http で実装できるようにします。
「します。」といっても @fujiwara さんが作成されている ridge ライブラリを活用するだけです。

https://github.com/fujiwara/ridge

package main

import (
	"net/http"

	"github.com/aws/aws-lambda-go/lambdacontext"
	"github.com/fujiwara/ridge"
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ctx, _ := lambdacontext.FromContext(r.Context())

		w.Write([]byte(ctx.AwsRequestID))
	})

	ridge.Run(":8080", "/", mux)
}

Scheduled Functions

スケジュールで動かすために Scheduled Functions を利用します。

https://docs.netlify.com/functions/scheduled-functions/

ただし、こちらは TypeScript or JavaScript でしか実装できません。
実装をシンプルにするために以下のようにして Fetch API にて先ほど実装した Functions を呼び出すだけにしています。

export default async (_) => {
    await fetch(process.env.URL + '/.netlify/functions/<function>', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({}),
    })
}

※ Functions のエンドポイントは環境変数から取得できます。[1]
※ Functions のパスは /.netlify/functions/<function> となります。

スケジュールは netlify.toml にて設定します。

[functions."cron"]
schedule = "@hourly"

※ ファイル名に合わせて functions.<> を設定します。今回は cron.mjs というファイル名なので functions."cron" となっています。
@hourly は1時間ごとに起動する 0 * * * * と同等です。

デプロイ

最終的にディレクトリは以下のようになっています。

.
├── go.mod
├── go.sum
├── netlify
│   └── functions        // Functions を配置するディレクトリ
│       ├── cron.mjs     // スケジュールにて起動する関数
│       └── job          // API 名
│           └── main.go  // API にて起動する関数
└── netlify.toml         // cron の設定ファイル

準備ができたら Netlify CLI にてデプロイします。

https://cli.netlify.com/commands/deploy/

❯ netlify deploy --prod  
This folder isn't linked to a site yet
? What would you like to do? +  Create & configure a new site
? Team: otakakot
? Site name (leave blank for a random name; you can change it later): <project>

Site Created

Admin URL: https://app.netlify.com/sites/<accouht>
URL:       https://<project>.netlify.app
Site ID:   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Linked to <project>
Please provide a publish directory (e.g. "public" or "dist" or "."):
? Publish directory YOUR_BASE_DIRECTORY
Deploy path:        YOUR_BASE_DIRECTORY
Functions path:     YOUR_BASE_DIRECTORY/netlify/functions
Configuration path: YOUR_BASE_DIRECTORY/netlify.toml
Deploying to main site URL...
⠋ Uploading blobs to deploy store...

Netlify Build                                                 
────────────────────────────────────────────────────────────────

❯ Version
  @netlify/build 29.58.10

❯ Flags
  deployId: xxxxxxxxxxxxxxxxxxxxxxx
  open: false
  prod: true
  prodIfUnlocked: false
  skipFunctionsCache: false

❯ Current directory
  YOUR_BASE_DIRECTORY

❯ Config file
  YOUR_BASE_DIRECTORY/netlify.toml

❯ Context
✔ Finished uploading blobs to deploy store
✔ No cached functions were found
✔ Finished hashing 5 files and 2 functions
✔ CDN requesting 5 files and 2 functions
✔ Finished uploading 7 assets
✔ Deploy is live!

Build logs:         https://app.netlify.com/sites/<account>/deploys/xxxxxxxxxxxxxxxxxxxxxxx
Function logs:      https://app.netlify.com/sites/<account>/logs/functions
Edge function Logs: https://app.netlify.com/sites/<account>/logs/edge-functions
Unique deploy URL:  https://xxxxxxxxxxxxxxxxxxxxxxxx--<account>.netlify.app
Website URL:        https://<project>.netlify.app

動作確認

デプロイし払い出されたエンドポイント + Functions のパスにて動作確認にて実行できます。

curl https://<project>.netlify.app/.netlify/functions/job
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

また、設定された時間になるとスケジュールにて関数が起動します。

Mar 2, xx:00:19 PM: cde4ea92 Duration: 530.33 ms	Memory Usage: 97 MB	Init Duration: 317.65 ms

この様子は Function logs にて確認できます。

https://docs.netlify.com/functions/logs/

ほかにも Netlify CLI はローカル環境での動作確認もサポートされています。

❯ netlify functions:serve                                                         
◈ Ignored shared env var: API_KEY (defined in site settings)
◈ Ignored general context env var: LANG (defined in process)

   ┌─────────────────────────────────────────────────┐
   │                                                 │
   │   ◈ Server now ready on http://localhost:9999   │
   │                                                 │
   └─────────────────────────────────────────────────┘

◈ Loaded function cron
◈ Loaded function job

おわりに

Cloudflare Workers, Vercel Functions と並ぶくらい Go が使いやすい無料のデプロイ環境を見つけました。

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

https://github.com/otakakot/sample-go-netlify-schedule

脚注
  1. https://docs.netlify.com/functions/environment-variables/ ↩︎

Discussion