ものぐさプログラマの為のWaypoint

公開:2020/10/19
更新:2020/10/20
7 min読了の目安(約6700字TECH技術記事

HashiCorpから新しいツール「Waypoint」が発表されました。個人的に、buildpacks を利用したDockerfileレスなビルドセットアップを学んでいた流れもあり、自身の理解も兼ねて記事にしました。

記事内ではWaypointの簡単な概要から、Goプロジェクトをビルド、最近私が愛用しているGoogle Cloud Runへのリリースまでを行います。

今回のサンプルリポジトリはこちら

Waypointとはなにか?

ぶら下がるインフラ(Docker, k8s, Serverless etc.. )やPaaSベンダに依存しない、ビルド・デプロイ・リリースが行える単一のワークフローを提供するもの。必要なものは、対象のソースコード、シンプルな構成ファイル、そして waypoint up のコマンドのみで実現出来ます。

現実に即してるなと思ったのであえてタイトルにも冠してますが、私自身がWaypointを好きになれそうな点が2つあります。

1つ目は上記の動画で説明がある通り、一般的にプログラマが辿る工程は

Write -> Test -> Build -> Deploy -> Release -> Operate -> Measure

となっており、左からプログラマは興味関心が高く、右に行くほど薄くなるという点です。これは全プログラマとは言わなくとも、多くのプログラマ(少なくとも私には)当てはまるのではないでしょうか。
デプロイされる先や、何で動いているかは興味を持つべき範囲なのはわかりますが、じゃあ積極的に知りたいか、学びたいかと言われると僕自身はちょっと…って思ってしまうんですよね。このように、アプリが何で、どこで動いているかに関わらず、アプリをビルド・デプロイ・リリースするための一貫した方法が欲しいというのはまさに私自身が思ってたことでした。(あとyamlが個人的に苦手)

2つ目に、Waypoint自体が方法論に固執していないことです。「すべき論」で語れば、ビルド、デプロイ、リリースというフェーズはCI/CDに組み込んでみたり、GitOpsをベースとしたアプローチを用いるべきかもしれませんが、Waypoint自体はCLIからの直接操作やChatOpsだったり、Waypointが提供するUIからだったりなど、チームやプロジェクトの状態によって一番良い方法が取れる柔軟性があります。

Waypointの使い方

Waypointインストールから、Goの簡単なプロジェクトのビルド、Google Cloud Runへのデプロイ、リリースまでの手順を一通り説明します。前述の通りWaypointはAmazon ECS/EKSやGoogle Cloud Runなど複数のPaaSベンダやサービスに適用出来ますので、公式ドキュメントをまず確認し、自身に一番沿った環境で実践することをお勧めします。

インストール

macOSかつDocker Desktopインストール済が前提です。

brew tap hashicorp/tap
brew install hashicorp/tap/waypoint

waypoint コマンドが使えるようになります。

次にサーバーをインストールします。

docker pull hashicorp/waypoint:latest
waypoint install -platform=docker -accept-tos

※重要
-accept-tosWaypoint URL Serviceを有効にするフラグです。詳細は左記ドキュメントと利用規約をよく読んでください。

Advertise Address: waypoint-server:9701
HTTP UI Address: localhost:9702

localhost:9702 にアクセスし、

Authenticate... をクリック。

waypoint token new

上記で発行されたトークンを貼り付けます。

GCP環境準備

GCPのプロジェクト作成とCloud Runの有効化は省きます。

GCPのプロジェクトからIAMと管理 > サービスアカウントを選択し、Waypointで利用するサービスアカウントを作成、名前は分かりやすい一意の名前をつけます。

ロールには「Cloud Run 管理者」を付与し、完了。

作成したサービスアカウントの一覧オプションから「鍵を作成」をクリックし、ファイルをダウンロード。

環境変数にGOOGLE_APPLICATION_CREDENTIALSをセットし、上記の鍵のパスをセット。

※鍵の細かい取り回しについては本筋ではないので省きますが、取り扱いに注意してください

Goのサンプルアプリを準備

せっかく(?)なのでWAFのFiberを使って見ましょう。

mkdir go-fiber-waypoint && cd go-fiber-waypoint
go mod init

main.go

package main

import (
	"log"
	"os"

	"github.com/gofiber/fiber/v2"
)

func main() {
	app := fiber.New()

	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("Hello, World!")
	})

	log.Fatal(app.Listen(":" + os.Getenv("PORT")))
}

PORTを環境変数から注入してください。direnvがおすすめ。

go run main.go
┌───────────────────────────────────────────────────┐ 
 │                    Fiber v2.1.0                   │ 
 │               http://127.0.0.1:8080               │ 
 │                                                   │ 
 │ Handlers ............. 2  Threads ............. 4 │ 
 │ Prefork ....... Disabled  PID ............. 34090 │ 
 └───────────────────────────────────────────────────┘ 

ローカルでアプリの起動は成功しました。

構成ファイルの作成

プロジェクトルートに waypoint.hcl を作成します。

project = "go-fiber-waypoint"

// アプリケーション
app "go-fiber-waypoint" {
  labels = {
    "service" = "go-fiber-waypoint"
  }

  // ビルド
  build {
    // buildpacksを利用
    use "pack" {}
    
    registry {
      // dockerのレジストリを設定
      use "docker" {
	// GCRへ
        image = "asia.gcr.io/${GCP_PROJECT_ID}/go-fiber-waypoint"
        tag   = "latest"
      }
    }
  }

  // デプロイ
  deploy {
   // Cloud Runを利用
    use "google-cloud-run" {
      // GCPプロジェクト
*       project = "${GCP_PROJECT_ID}"
      // 東京リージョン
      location = "asia-northeast1" 

    // Cloud Run固有の設定
      capacity {
        memory                     = 128
        cpu_count                  = 1
        max_requests_per_container = 10
        request_timeout            = 300
      }

      auto_scaling {
        max = 2
      }
      
    }
  }

  // リリース
  release {
    use "google-cloud-run" {}
  }
}

さて、この状態まで出来たら、waypointのセットアップ及び実行を行います。丁寧でありがたかったのは、事前にwaypoint.hclを解析してinitの時点で、GCPの接続で足りないAuthn部分の設定などをエラー吐いてくれます。

waypoint init
waypoint up

» Building...
Creating new buildpack-based image using builder: heroku/buildpacks:18
✓ Creating pack client
✓ Building image
 │ [exporter] Reusing layer 'heroku/go:profile'
✓ Injecting entrypoint binary to image

Generated new Docker image: go-fiber-waypoint:latest
...
* » Deploying...
» Releasing...

The deploy was successful! A Waypoint deployment URL is shown below. This
can be used internally to check your deployment and is not meant for external
traffic. You can manage this hostname using "waypoint hostname."

   Release URL: ${ $CLOUDRUN_URL }
Deployment URL: ${ $WAYPOINT_URL_SERVICE }

このように表示されたのち、Release URLを開いてCloud Run上にアプリが開いていたら成功です。

コードを変更し再デプロイ

main.goを変更してみましょう。

	app.Get("/", func(c *fiber.Ctx) error {
		// return c.SendString("Hello, World!")
		return c.SendString("Hello, Waypoint!")
	})

waypoint.hclのbuildも変更してみます、デフォルトのbuildpackspacks{})はheroku/buildpacks:18が使われるようです。distrolessを使いたいのでpaketobuildpacks/builder:tinyを指定してみましょう。

    // buildpacksを利用
    use "pack" {
      builder="paketobuildpacks/builder:tiny"
    }

さて、この状態で再度 waypoint upを再度実行します。

   Release URL: ${ $CLOUDRUN_URL }
Deployment URL: ${ $WAYPOINT_URL_SERVICE --v2 }

URLにアクセス出来て正常稼働していれば成功です。

UI上からプロジェクトの状況を確認

waypoint uiで、ブラウザからプロジェクトの状態を確認出来る管理画面が表示されます。

プロジェクトの削除

waypoint destroy で削除可能。Cloud Runのようなサービス上でリリースされている場合は、稼働中ということで削除が出来ないようになっているようです。

感想

ある程度直感的かつ、デプロイまで一括して管理してくれるのは助かるの一言です。hclファイル自体今回初めて触ったんですが、特別難しい部分もなく。反面「こんなん無くてもmakefileでええやんけ!」という主張も非常にわかります、なんだかんだで全く苦労せずに出来たかというと概念の理解に時間取られたりもしましたし。
今回は直接Cloud Runへのデプロイでしたが、Github Actionsへの組み込みなども今後試していきます。