🌈

Go言語で学ぶWebアプリケーション開発3:[Docker + gRPCを組み込む]

2025/03/03に公開

はじめに

前回の記事では、バックエンドにGo + Ginを使用、フロントエンドにはReact + Viteを使用して作成したWebアプリケーションにデータベース連携(GORM + SQLite)とJWT認証機能を追加しました。
今回は、さらにDockerを使ってアプリケーションをコンテナ化し、gRPCを組み込むことで、より高度なWebアプリケーションへと発展させます。
自分でもこのあたりは初めてやった時には複雑だったので、知識の整理も兼ねて解説します。

対象読者

  • GoでWebアプリを作成し、Dockerを活用して環境構築を行いたい方
  • REST APIだけでなく、gRPCを導入してさらにパフォーマンスの向上を図りたい方
  • Webアプリケーションをより実用的な形でデプロイしたい方

目次

  1. Dockerを使った環境構築
    • そもそものDockerの基本概念
    • Dockerfileの作成
    • Docker Composeを使ったサービス管理
  2. gRPCの組み込み
    • gRPCの基本概念
    • Protocol Buffers(.proto)の定義
    • gRPCサーバーの実装
    • gRPCクライアントの実装
  3. フロントエンドとの統合
    • ReactからREST API & gRPCを呼び出す方法
    • フロントエンドでのgRPCの利用方法

1. Docker を使った環境構築

1.1 Docker の基本概念

Dockerは、アプリケーションを コンテナ という単位で管理・実行するツールです。
コンテナを使うことで、環境の差異をなくし、どこでも同じように動作するアプリケーションを作ることができます。

1.2 Dockerfileの作成

まず、アプリケーションをDockerで動かせるようにするための Dockerfile を作成します。

Dockerfile

# ベースイメージ
FROM golang:1.19

# 作業ディレクトリを作成
WORKDIR /app

# 必要なファイルをコピー
COPY go.mod .
COPY go.sum .
RUN go mod download

# ソースコードをコピー
COPY . .

# アプリケーションをビルド
RUN go build -o main .

# ポート 8080 を開放
EXPOSE 8080

# アプリケーションを実行
CMD ["./main"]

1.3 Docker Composeを使ったサービス管理

docker-compose.ymlを作成し、バックエンド、データベース、フロントエンドをまとめて管理できるようにします。

docker-compose.yml

version: '3.8'
services:
  backend:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - database
  database:
    image: sqlite
  frontend:
    build: ./frontend
    ports:
      - "5173:5173"
    depends_on:
      - backend

docker-compose upを実行すれば、すべてのサービスがコンテナとして起動します。

docker-compose up --build

2. gRPCの組み込み

2.1 gRPC の基本概念

gRPCは、Googleが開発した高性能なRPC(Remote Procedure Call)フレームワーク です。

  • 軽量 & 高速:バイナリ形式のProtocol Buffers(protobuf)を使用するため、REST APIよりも効率的。
  • 双方向ストリーミング:クライアントとサーバーの双方向通信が可能。
  • マイクロサービスに最適:マルチ言語対応で、拡張性が高い。

2.2 Protocol Buffers (.proto) の定義

まず、gRPCの通信を定義する.protoファイルを作成します。

proto/todo.proto

syntax = "proto3";
package todo;

service TodoService {
    rpc GetTodos (Empty) returns (TodoList);
}

message Empty {}

message Todo {
    int32 id = 1;
    string task = 2;
    bool status = 3;
}

message TodoList {
    repeated Todo todos = 1;
}

2.3 gRPC サーバーの実装

server.go

package main

import (
    "context"
    "net"
    "log"

    "google.golang.org/grpc"
    pb "todo/proto"
)

type server struct {
    pb.UnimplementedTodoServiceServer
}

func (s *server) GetTodos(ctx context.Context, req *pb.Empty) (*pb.TodoList, error) {
    todos := []*pb.Todo{
        {Id: 1, Task: "Learn Go", Status: false},
        {Id: 2, Task: "Build a Web App", Status: true},
    }
    return &pb.TodoList{Todos: todos}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterTodoServiceServer(s, &server{})
    log.Println("gRPC server is running on port 50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

3. フロントエンドとの統合

3.1 ReactからREST API & gRPCを呼び出す方法

  • REST API: Axiosを使用
axios.get("http://localhost:8080/api/todos")
    .then(response => console.log(response.data));
  • gRPC: gRPC-Webを使用
import { TodoServiceClient } from "./proto/TodoServiceClientPb";
const client = new TodoServiceClient("http://localhost:50051");
client.getTodos({}, (err, response) => console.log(response));

まとめ

項目 説明
Docker アプリをコンテナ化し、どこでも同じ環境で動作させる
gRPC 高速なバイナリ通信が可能なRPCフレームワーク
REST API & gRPC の統合 フロントエンドで両方の通信方式を活用

本記事では、Dockerを使ってアプリをコンテナ化し、gRPCを導入する方法を解説しました。
少し難しめの概念ですが、とても効率的なアプリケーション開発が可能になるため、この辺りもマスターしていきましょう!

Discussion