0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoのGinでUnix Domain Socketを使う方法(Nginx経由)

0
Posted at

GinでUnix Domain Socket

GinでUnix Domain Socketを使うには、net.Listen("unix", "/tmp/demo.sock")を使用します。

main.go
package main

import (
	"fmt"
	"net"
	"net/http"
	"runtime"

	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()

	router.GET("/ram", func(c *gin.Context) {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)

		// Convert bytes to megabytes
		mb := m.Alloc / 1024 / 1024

		c.String(http.StatusOK, fmt.Sprintf("Current RAM usage: %v MB", mb))
	})

	listener, err := net.Listen("unix", "/tmp/demo.sock")
	if err != nil {
		panic(err)
	}

	http.Serve(listener, router)
}

Nginxの設定ファイル

$ brew install nginx

設定ファイルは、/opt/homebrew/etc/nginx/にあると思います。

demo.conf
upstream demo {
    server unix:/tmp/demo.sock;
}

# the nginx server instance
server {
    listen 8081;
    server_name localhost;

    location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_http_version 1.1; # for keep-alive
      proxy_pass http://demo/;
      proxy_redirect off;
    }
}

Graceful Shutdown版

GinでUnix Domain Socketを使用してGraceful Shutdownをするコードを示します。サーバー起動時の.sockファイルの削除(サーバークラッシュをケア)とサーバー停止時の.sockファイルの削除処理を追加しています。

router.SetTrustedProxies([]string{"127.0.0.1"})も大事なのでお忘れなく。

main.go
package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
)

var socketPath = "/tmp/demo.sock"

func main() {
	// 1. Remove existing socket file if it exists from a previous crash
	if _, err := os.Stat(socketPath); err == nil {
		_ = os.Remove(socketPath)
	}

	router := gin.Default()

	// Trust NGINX proxy headers (highly recommended)
	router.SetTrustedProxies([]string{"127.0.0.1"})

	router.GET("/ram", func(c *gin.Context) {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)

		// Convert bytes to megabytes
		mb := m.Alloc / 1024 / 1024

		c.String(http.StatusOK, fmt.Sprintf("Current RAM usage: %v MB", mb))
	})

	listener, err := net.Listen("unix", socketPath)
	if err != nil {
		panic(err)
	}

	server := &http.Server{
		Handler: router,
	}

	// 2. Run the server in a goroutine
	go func() {
		log.Printf("Starting Gin server on UNIX socket: %s", socketPath)

		if err := server.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Fatalf("Failed to run server: %v", err)
		}
	}()

	// 3. Fix permissions so NGINX can access the socket file
	// Give the socket file read/write permissions (adjust as needed for security)
	time.Sleep(100 * time.Millisecond) // Wait a brief moment for the file to be created
	if err := os.Chmod(socketPath, 0666); err != nil {
		log.Fatalf("Failed to set socket permissions: %v", err)
	}

	// 4. Graceful Shutdown handling to clean up the socket file
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("Shutting down server...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := server.Shutdown(ctx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}

	// Always delete the socket file on exit
	_ = os.Remove(socketPath)
	log.Println("Server exiting, socket file removed.")
}

動作確認

Nginx側

demo.confnginx-conf-directory/servers/demo.confに配置して、nginxを起動。

$ pbpaste > nginx-conf-directory/servers/demo.conf # macOSの場合
$ brew services reload nginx

Server側

$ mkdir workspace
$ cd workspace
$ go mod init example
$ go get github.com/gin-gonic/gin
$ pbpaste > main.go # macOSの場合
$ go run main.go

Client側

$ curl http://localhost:8081/ram 
Current RAM usage: 0 MB

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?