Closed14
Cloud Run × Gin × TiDBでREST APIを始める

まずは構成から。
- Cloud RunとTiDBで構成されたWeb APIを一定間隔でラズパイが叩く仕様
- GCPとTiDBの無料枠を活用
- 学校のネットワークでの仕様を想定しているので、クラウドからラズパイにメッセージを伝える方法はセキュリティ上困難なため、ラズパイ側からのポーリング処理で通信
- Web APIは基本的なRESTで実装

TiDBとまずはターミナルからやり取りしてみる
TiDBのコンソール画面から接続のコマンドを簡単にコピーできる
実行してみるとエラーが出た
ERROR 2059 (HY000): Authentication plugin 'mysql_native_password' cannot be loaded
どうやらネイティブパスワードを使用してのMySQLとの通信はデフォルトで無効になっているらしい

別の通信方法で試す
MySQLWorkbenchで接続することができた
テーブルは作っていないので存在しない
TiDBで起動したDBの中身も確認できるようになったので、APIのベースを作る

ginでサーバーを起動する
package main
import (
infrastructure "gcp_go_cloud_run/app/infrastructure/mysql"
"log"
"os"
"github.com/gin-gonic/gin"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
infrastructure.InitDB()
r := gin.Default()
if err := r.Run(":" + port); err != nil {
log.Fatalf("Failed to start the server: %v", err)
}
}

dbを初期化する関数はこんな感じ
db.go
package infrastructure
import (
"fmt"
"gcp_go_cloud_run/app/infrastructure/mysql/entity"
"log"
"os"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func InitDB() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
getEnv("DB_USER", "root"),
getEnv("DB_PASSWORD", ""),
getEnv("DB_HOST", "localhost"),
getEnv("DB_PORT", "4000"),
getEnv("DB_NAME", "your_db_name"),
)
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}
DB.AutoMigrate(&entity.Bell{}, &entity.Store{}, &entity.CallLog{})
}

しかし、これでは接続できなかった。
tidbはtls接続のみを許可するようになっている
[error] failed to initialize database, got error Error 1105 (HY000): Connections using insecure transport are prohibited. See https://docs.pingcap.com/tidbcloud/secure-connections-to-serverless-tier-clusters
ではどうやってtls接続をするのか
公式ドキュメントにGo言語を使った簡易的なREST APIの実装についてのチュートリアルがあり、そこでは以下のようにdsnを変更すると記述されている
mysql.RegisterTLSConfig("register-tidb-tls", &tls.Config {
MinVersion: tls.VersionTLS12,
ServerName: "xxx.tidbcloud.com",
})
dsn := "2aEp24QWEDLqRFs.root:123456@tcp(xxx.tidbcloud.com:4000)/test?charset=utf8mb4&tls=register-tidb-tls"

先ほどの記事をもとにtls接続の設定を追加した
package infrastructure
import (
"crypto/tls"
"fmt"
"gcp_go_cloud_run/app/infrastructure/mysql/entity"
"log"
"os"
gormsql "gorm.io/driver/mysql"
"gorm.io/gorm"
"github.com/go-sql-driver/mysql" //標準のmysqlドライバーをインポート
)
var DB *gorm.DB
func InitDB() {
//ここではgoの標準のmysqlドライバーを使用する。gormのドライバーにはRegisterTLSConfigメソッドが存在しないことに注意
err := mysql.RegisterTLSConfig("tidb", &tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: GetEnv("DB_HOST", "localhost"),
})
if err != nil {
log.Fatalf("failed to register TLS config: %v", err)
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&tls=tidb",
GetEnv("DB_USER", "root"),
GetEnv("DB_PASSWORD", ""),
GetEnv("DB_HOST", "localhost"),
GetEnv("DB_PORT", "4000"),
GetEnv("DB_NAME", "your_db_name"),
)
DB, err = gorm.Open(gormsql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}
DB.AutoMigrate(&entity.Bell{}, &entity.Store{}, &entity.CallLog{})
}

ローカルで実行してみると見事データベースにテーブルを追加できた

しかしCloud Runへのデプロイできない
→環境変数が読み込めていないため正しいdsnが構成できずにtidbとの接続に失敗している

なぜ環境変数が読み込めていないのか?
→デプロイ時ではなく、ビルド時に環境変数を読み込んでいた。
どう解決したか
→デプロイ時に環境変数を渡すように変更した
DB_USERはsecretManagerにて設定済み
args:
- run
- services
- update
<--中略-->
- '--set-secrets=DB_USER=DB_USER:latest'
id: Deploy
entrypoint: gcloud

無事デプロイできた!

叩いてみると??
無事動かすことができました
このスクラップは5ヶ月前にクローズされました