GoアプリケーションをKubernetesへデプロイする:クラウドネイティブ開発の実践的な流れ

GoアプリケーションをKubernetesへデプロイする

現代のソフトウェア開発は、スピード、スケーラビリティ、可観測性が求められる時代へと突入しています。これを支えるのがクラウドネイティブなアプローチであり、その中核を担うのがGoKubernetesの組み合わせです。

この投稿では、Goで開発したWeb APIアプリケーションを、Dockerを使ってコンテナ化し、Kubernetes上にデプロイするまでの流れを、実践的な手順で詳しく解説していきます。

さらに、Helmによるデプロイの自動化、PrometheusとGrafanaを活用した可観測性の確保、そして最終的にはGKE・EKS・AKSといったパブリッククラウドへの展開までを網羅します。

開発者、SRE、DevOpsエンジニアの皆さんにとって、クラウドネイティブ時代の基盤を築く一助となれば幸いです。


📑 目次


1. なぜGoとKubernetesなのか?クラウドネイティブ時代の選択

モノリシックなアーキテクチャでは、拡張性や柔軟性に限界があります。そうした背景から、マイクロサービス化とクラウドネイティブな設計へのシフトが進んでいます。

Goはシンプルで高速、コンパイル後は単一バイナリで実行できるため、コンテナとの相性が非常に良い言語です。一方、Kubernetesは、複数のコンテナを自動的に管理・スケーリング・監視できるコンテナオーケストレーションプラットフォームです。

この強力な組み合わせは、Google、Dropbox、Uberといった大規模サービスの基盤でも採用されており、今後のインフラのスタンダードになるといっても過言ではありません。

このシリーズでは、Goアプリケーションをコンテナ化し、Kubernetesにデプロイし、クラウド環境にまでスケールさせていく実践的なアプローチを段階的に解説します。

Goアプリケーションの準備

2. Goアプリケーションの準備

Goは、静的型付け・コンパイル型の言語であり、依存関係を含んだ自己完結型の単一バイナリを生成できるため、Dockerコンテナとの親和性が非常に高いという特徴を持っています。

Kubernetes上での運用を前提としたアプリケーション開発では、コードの構造をモジュール化し、設定を外部化することが重要です。ここでは、簡単なRESTful API(/pingエンドポイント)を題材に、Goアプリの構成を解説します。

📁 推奨ディレクトリ構成

以下は、マイクロサービスとしてGoアプリケーションを構築する際の一例となるプロジェクト構成です:

go-k8s-app/
├── go.mod
├── go.sum
├── main.go
├── handler/
│   └── ping.go
├── config/
│   └── config.go
└── Dockerfile

go.modはGoモジュールの依存関係を管理するファイルであり、handlerディレクトリには各エンドポイントの処理ロジックをまとめることで、コードの可読性と保守性が向上します。

📌 REST APIの最小サンプル

以下は、/pingへのGETリクエストに対して”pong”と応答する最小構成のAPIサーバーコードです:

package main

import (
	"log"
	"net/http"
	"yourapp/handler"
)

func main() {
	http.HandleFunc("/ping", handler.Ping)
	log.Println("Listening on port 8080...")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

次に、実際のハンドラ関数は以下のようになります(handler/ping.go):

package handler

import (
	"encoding/json"
	"net/http"
)

func Ping(w http.ResponseWriter, r *http.Request) {
	response := map[string]string{"message": "pong"}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

このようなヘルスチェック用のエンドポイントは、後述するKubernetesのlivenessProbereadinessProbeにも活用されます。

🛠️ 依存関係のインストールと起動

Goモジュールとアプリケーションを起動するためのコマンドは以下の通りです:

go mod tidy
go run main.go

ローカルホストで起動したアプリにアクセスするには、http://localhost:8080/pingにブラウザまたはcurlでリクエストを送ってください。

{
  "message": "pong"
}

これで、Kubernetes環境で動作させるためのGoアプリケーションの準備が整いました。次はこのアプリをDockerコンテナに変換するステップに進みましょう。


3. DockerによるGoアプリのコンテナ化

Goアプリケーションのローカル実行が確認できたら、次は本番環境を見据えてDockerコンテナとしてパッケージングしましょう。コンテナ化することで、どの環境でも同一の実行環境を再現でき、Kubernetesへのデプロイも可能になります。

Goの大きな特徴のひとつは、コンパイル後に単一のバイナリファイルを生成できることです。これにより、非常に軽量なコンテナイメージを構築することができます。ここでは、マルチステージビルドを活用したDockerfileを紹介します。

🧱 マルチステージDockerfileの例

以下は、Goアプリケーションの最適化されたDockerfileの例です。

# ビルドステージ
FROM golang:1.20-alpine AS builder
WORKDIR /app

COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY . ./
RUN go build -o app .

# 実行ステージ
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/app .

EXPOSE 8080
CMD ["./app"]

ポイント:

  • 最初のステージではAlpineベースのGoイメージを使用してバイナリをビルドします。
  • 最終ステージでは、ビルドしたバイナリのみを含むAlpineイメージを使用し、10MB未満の軽量なイメージを実現します。
  • マルチステージにより、セキュリティリスクのある不要な依存パッケージを含めずに済みます。

🐳 Dockerビルドと実行

以下のコマンドでDockerイメージをビルドし、コンテナを起動できます。

docker build -t go-k8s-app .
docker run -p 8080:8080 go-k8s-app

コンテナが起動したら、http://localhost:8080/ping にアクセスして応答を確認できます。

{
  "message": "pong"
}

🔎 なぜマルチステージビルドが重要か

シンプルなDockerfileでも動作しますが、開発環境と本番環境のビルドアーティファクトを分離することで、次のようなメリットがあります:

  • 最小限の依存性によるセキュリティ向上
  • ビルドキャッシュの活用による高速化
  • より軽量なデプロイ起動の高速化

このように、コンテナ化はKubernetesへのステップとしてだけでなく、運用・保守の観点からも重要な意味を持ちます。

次は、このコンテナ化したアプリケーションをKubernetes上にデプロイするためのYAMLファイルについて解説していきます。


4. KubernetesのYAMLマニフェストを理解する

GoアプリケーションをDockerでコンテナ化したら、いよいよKubernetes上にデプロイする準備に入ります。Kubernetesでは、リソースの状態を「宣言的」に定義するために、YAMLマニフェストを使用します。

ここでは、基本的な構成要素である DeploymentServiceConfigMap を例に、どのようにYAMLで定義するかを見ていきましょう。

KubernetesのYAMLマニフェストを理解する

📦 主なKubernetesリソース

リソース 概要
Deployment Podのレプリカ数、更新戦略などを管理
Service Podへのアクセスを提供(クラスタ内外から)
ConfigMap アプリ設定などの環境変数を外部化

📄 Deploymentの例

以下は、2つのレプリカでGoアプリを稼働させるDeploymentの例です:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-k8s-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: go-k8s-app
  template:
    metadata:
      labels:
        app: go-k8s-app
    spec:
      containers:
        - name: go-app
          image: go-k8s-app:latest
          ports:
            - containerPort: 8080
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"
            requests:
              memory: "64Mi"
              cpu: "250m"
          livenessProbe:
            httpGet:
              path: /ping
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

補足:

  • replicasでPodの数(=冗長性)を設定
  • resourcesでCPU・メモリのリソース制限を定義
  • livenessProbeでヘルスチェックを自動化

🔌 Serviceの例

次に、外部からアクセスできるようにするService定義です:

apiVersion: v1
kind: Service
metadata:
  name: go-k8s-service
spec:
  selector:
    app: go-k8s-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: NodePort

NodePortタイプを使用すると、クラスタ外からも指定されたポートでアクセス可能になります。クラウド環境ではLoadBalancerを使うことが多いです。

🧾 ConfigMapの例

アプリの設定情報をConfigMapで外部化する例です:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_MODE: "production"
  LOG_LEVEL: "info"

このConfigMapはDeploymentのenvセクションで参照することで、設定のコード分離が可能になります。

これらのYAMLファイルを使って、次章ではMinikubeやKindを使ったローカルクラスタへのデプロイを行います。


5. MinikubeまたはKindでのローカルデプロイ

KubernetesのYAMLマニフェストが準備できたら、まずはローカル環境でのデプロイを試してみましょう。これにより、本番クラスタに反映する前に動作確認が可能になります。

ローカル環境でよく使われるKubernetesツールには、MinikubeKind(Kubernetes IN Docker)があります。ここではMinikubeを使った流れを中心に説明しますが、Kindでもほぼ同じ手順で対応可能です。

🔧 Minikubeのインストールと起動

macOS環境の場合、以下のコマンドでMinikubeをインストールして起動できます:

brew install minikube
minikube start --driver=docker

起動が完了すると、ローカル上にKubernetesクラスタが構築され、kubectlコマンドで制御できるようになります。

📂 YAMLファイルの適用

準備したYAMLファイルを以下のように適用します:

kubectl apply -f configmap.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

すべてのリソースが正しく作成されたかどうかは、次のコマンドで確認できます:

kubectl get all

🌐 サービスへのアクセス

NodePortタイプのサービスは、以下のコマンドで自動的にアクセスURLを取得できます:

minikube service go-k8s-service --url

出力されたURL(例:http://127.0.0.1:30080)にアクセスし、/pingエンドポイントが動作しているか確認してみましょう。

📋 Podの状態確認とログ出力

実行中のPodのログをリアルタイムで確認するには:

kubectl logs -f deployment/go-k8s-app

複数のPodがある場合は、以下のコマンドで名前を確認した上で個別にログを見ることもできます:

kubectl get pods

📁 複数YAMLの一括適用

YAMLファイルを一つのフォルダにまとめておけば、次のように一括で適用できます:

kubectl apply -f ./k8s/

これで、GoアプリケーションがローカルのKubernetesクラスタで正常に稼働している状態が確認できました。

次章では、Helmを使ってこのデプロイ作業をさらに効率的に自動化する方法を学びましょう。


6. Helmを使ったデプロイの自動化

KubernetesではYAMLファイルでリソースを定義できますが、サービスが複雑になるにつれて管理が煩雑になります。Helmを使えば、テンプレート化とパラメータ管理を行うことで、再利用可能でメンテナンスしやすいデプロイメントが可能になります。

Helmを使ったデプロイの自動化

Helmは「Kubernetesのパッケージマネージャー」とも呼ばれ、Helm Chartを使ってアプリケーションを定義・管理・バージョン管理できます。

📦 Helm Chartとは?

Helm Chartは、複数のKubernetesリソース(Deployment, Service, ConfigMapなど)を一つの単位にまとめたテンプレートパッケージです。一般的な構成は以下の通りです:

go-k8s-chart/
├── Chart.yaml         # チャートのメタデータ
├── values.yaml        # 設定値(環境別に差し替え可能)
├── templates/         # YAMLテンプレート(Goテンプレート構文)
│   ├── deployment.yaml
│   ├── service.yaml
│   └── _helpers.tpl

🛠️ Helmのインストールとチャート作成

macOSではHomebrewを使ってインストールできます:

brew install helm
helm create go-k8s-chart

helm createを実行すると、サンプルテンプレートが含まれたチャートが自動生成されます。

📄 values.yamlの設定例

以下は、Goアプリケーション用の基本的な設定例です:

replicaCount: 2

image:
  repository: go-k8s-app
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: NodePort
  port: 80

resources:
  limits:
    cpu: 500m
    memory: 128Mi
  requests:
    cpu: 250m
    memory: 64Mi

これらの値はテンプレート内で{{ .Values.image.repository }}のように動的に参照され、環境ごとに柔軟な構成が可能です。

🚀 Helmによるデプロイとアップグレード

以下のコマンドでアプリケーションをデプロイします:

helm install go-app ./go-k8s-chart

values.yamlを変更後に設定を反映させるには、次のようにアップグレードします:

helm upgrade go-app ./go-k8s-chart

不要になった場合はアンインストールも可能です:

helm uninstall go-app

🌍 Helm活用のメリット

  • 再利用性: テンプレート化により複数環境での再利用が容易
  • 管理性: バージョン管理やロールバックが可能
  • GitOps対応: ArgoCDやFluxなどのCI/CDツールと統合しやすい

Helmを使うことで、手動のYAML管理から解放され、スピードと品質を両立した運用が実現できます。

次章では、クラスタ内でのアプリの動作を継続的に監視するための「可観測性」について詳しく解説します。


7. 可観測性の確保:Prometheus・Grafana・Loki

本番環境で安定した運用を行うには、「可観測性(Observability)」が不可欠です。これは、システムがどのように動いているのかを外部から理解し、問題を迅速に発見・対応するための仕組みです。

Kubernetesでは、プローブによるヘルスチェック機能に加え、PrometheusGrafanaによるメトリクス監視、Lokiによるログ収集が代表的な可観測性スタックとして広く使われています。

🩺 Liveness / Readiness プローブ

プローブはPodの状態を監視し、必要に応じて再起動やトラフィック制御を行うための設定です:

  • Liveness Probe: アプリが「生きているか」を確認し、失敗時には自動再起動
  • Readiness Probe: アプリが「リクエストを受け付けられる状態か」を確認

以下はReadiness Probeの追加例です(Deployment内):

readinessProbe:
  httpGet:
    path: /ping
    port: 8080
  initialDelaySeconds: 2
  periodSeconds: 5

📊 PrometheusとGrafanaによるメトリクス監視

PrometheusはKubernetesクラスタの状態やリソース使用量を収集・蓄積するツールで、Grafanaはそのデータを視覚化するダッシュボードツールです。

Helmを使ってPrometheusとGrafanaを一括導入するには:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install k8s-monitor prometheus-community/kube-prometheus-stack

GrafanaのUIにアクセスするにはポートフォワードを利用します:

kubectl port-forward svc/k8s-monitor-grafana 3000:80

ブラウザでhttp://localhost:3000にアクセス(初期ユーザー名・パスワードはadmin/admin)すると、ダッシュボードでリソース状況を確認できます。

📝 Lokiを使ったログ収集

LokiはGrafanaと統合できるログ集約システムで、Podごとのログを一元管理し、構造化クエリで検索できます。

Lokiのインストール手順は以下の通りです:

helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki-stack

Grafanaの「データソース」からLokiを追加すれば、{app="go-k8s-app"}のようなラベルでログ検索が可能になります。

📈 可観測性の構築がもたらす効果

  • CPUやメモリの使用量を時系列で把握
  • Pod単位でのレスポンスタイムやエラー率の追跡
  • アラートの設定による障害の即時検知
  • ログとメトリクスの相関分析による根本原因の特定

可観測性は、単なる「モニタリング」ではなく、運用の意思決定を支える情報基盤です。

次章では、これまで構築したアプリケーションをGKE・EKS・AKSといったクラウド環境へとスケールさせる方法を見ていきましょう。


8. GKE・EKS・AKSへのクラウド展開

ローカルでの動作確認が完了したら、いよいよ本番環境への展開です。Google Cloud, AWS, Azureが提供するマネージドKubernetesサービスである GKEEKSAKS を使うことで、高可用性・スケーラビリティ・セキュリティを確保しながら運用することが可能になります。

☁️ なぜマネージドKubernetesなのか?

各クラウドプラットフォームは、以下のような恩恵を提供します:

  • コントロールプレーンの自動管理とアップグレード
  • オートスケーリングと負荷分散の統合
  • クラウドネイティブなモニタリング/セキュリティ

🌐 GKE(Google Kubernetes Engine)

Google Cloud CLIを使ってGKEクラスタを作成する例:

gcloud container clusters create go-app-cluster \
  --zone=asia-northeast1-a \
  --num-nodes=3 \
  --enable-ip-alias

Workload Identityを使えば、KubernetesサービスアカウントとGoogle IAMの連携が可能になります。LoadBalancerタイプのServiceを使用すれば、外部IPが自動的に付与されます。

🛡️ EKS(Elastic Kubernetes Service / AWS)

eksctlコマンドを使って簡単にEKSクラスタを立ち上げることができます:

eksctl create cluster \
  --name go-app-cluster \
  --region ap-northeast-1 \
  --nodes 3

EKSでは、aws-auth ConfigMapによってIAMユーザー/ロールとRBACのマッピングが必要です。ALB Ingress ControllerやExternal DNSの設定もよく使われます。

📘 AKS(Azure Kubernetes Service)

Azure CLIを使用したAKSの作成例:

az aks create \
  --resource-group myResourceGroup \
  --name go-app-cluster \
  --node-count 3 \
  --enable-addons monitoring \
  --generate-ssh-keys

AKSはAzure ADと連携したRBACが可能で、Azure MonitorLog Analyticsと自動統合されます。

📌 クラウド展開時の主な注意点

項目 考慮点
認証・認可 IAMやRBAC、OIDC連携などクラウドごとのセキュリティ設定
ノード構成 オートスケーリング、スポットインスタンスの活用
ネットワーク VPC設計、ロードバランサー、Ingress Controller
モニタリング プラットフォーム統合の可観測性ツールとの連携

クラウド環境でKubernetesを使う際には、単なるYAMLの適用にとどまらず、インフラ設計・セキュリティ・運用戦略を包括的に考える必要があります。

次章では、本シリーズのまとめとして、拡張性と持続可能性を備えたクラウドネイティブアーキテクチャの考え方を整理していきます。


9. 持続可能なクラウドネイティブアーキテクチャとは

クラウドネイティブの実践は、単にKubernetesを導入し、Goでマイクロサービスを書くことにとどまりません。それは、変化に強く、スケーラブルで、メンテナンスしやすいシステムを設計・運用するという思想に根ざしています。

本シリーズでは、以下のステップに沿って、Goアプリケーションをクラウドネイティブな形で構築してきました:

  • GoによるREST APIの開発
  • Dockerを使ったコンテナ化
  • KubernetesへのデプロイとHelmによる自動化
  • Prometheus・Grafana・Lokiによる可観測性の構築
  • GKE・EKS・AKSなどクラウド環境への拡張

🧭 技術を超えた学び

  • 小さく始めて、着実にスケールする: 単純なユースケースから始めて、段階的にサービスを分離・拡張していく
  • Infrastructure as Code(IaC): 手動作業を減らし、すべてをコード化することで品質と再現性を高める
  • 見える化=信頼: メトリクス・ログ・アラートは運用の信頼性を支える柱
  • 疎結合: コンフィグ・サービス・リソースを疎結合に保ち、環境変更に強い設計を目指す

これらの原則は、どのような技術スタックでも通用する持続可能なアーキテクチャの本質です。

道具は進化し続けます。Goの後継言語が出てくるかもしれませんし、Kubernetesの上に新しい抽象化レイヤーが加わるかもしれません。しかし、「スピードと信頼性の両立」という目標は変わりません。

今、あなたのアプリケーションは、ただの機能提供を超えて、「運用文化」の一部となる準備ができています。

댓글 남기기

Table of Contents

Table of Contents