Golang 專案實戰與部署 ── 雲端部署(AWS、GCP、Azure)
簡介
在完成 Go 程式的開發之後,最終的目標往往是把服務 上線,讓使用者可以隨時存取。雲端平台(Amazon Web Services、Google Cloud Platform、Microsoft Azure)提供了彈性、可擴展且成本可控的運算資源,是當前最主流的部署選擇。
本篇文章將帶領 初學者到中級開發者,一步步了解在三大公有雲上部署 Go 應用的核心概念、實作範例、常見陷阱與最佳實踐,並說明每種平台適合的使用情境。
核心概念
1. 為什麼要先產出 靜態編譯 的二進位檔?
Go 語言天生支援交叉編譯,透過 GOOS、GOARCH 兩個環境變數即可產出適用於 Linux、Windows、macOS 等不同作業系統的執行檔。
在雲端環境(尤其是容器或 EC2、Compute Engine、App Service)大多使用 Linux,因此建議先產出 Linux x86_64 的靜態二進位檔,減少容器層的相依性。
// build.sh
#!/usr/bin/env bash
# 設定交叉編譯目標為 Linux amd64
export GOOS=linux
export GOARCH=amd64
# -ldflags="-s -w" 會去除符號表與除錯資訊,減小檔案大小
go build -ldflags="-s -w" -o bin/app .
echo "✅ Build 完成,產生 bin/app"
小技巧:若專案使用
go.mod,請確保在 CI/CD 環境中已安裝相同版本的 Go,避免因版本差異導致編譯失敗。
2. Docker 化:最通用的部署方式
容器化是跨平台部署的事實標準。以下提供一個 最小化 的 Dockerfile,僅包含 Go 靜態二進位檔與必要的執行環境(scratch)。
# Dockerfile
# ---------- Build Stage ----------
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go mod tidy && \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /app .
# ---------- Runtime Stage ----------
FROM scratch
COPY --from=builder /app /app
EXPOSE 8080
ENTRYPOINT ["/app"]
說明
CGO_ENABLED=0讓編譯結果不依賴 glibc,才能在scratch中執行。EXPOSE僅是文件化的宣告,實際端口仍由雲端服務(如 ALB、Load Balancer)控制。
建置與推送映像檔:
docker build -t myrepo/go-hello:latest .
docker push myrepo/go-hello:latest
3. 基礎 IaC(Infrastructure as Code):Terraform 範例
使用 Terraform 可以一次性在 AWS、GCP、Azure 上建立 VPC、子網路、容器服務,且程式碼可版本管理。以下示範在 AWS ECS Fargate 上部署剛才的容器映像。
# main.tf (AWS)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = ">= 1.5"
}
provider "aws" {
region = "ap-northeast-1"
}
# 建立 ECS Cluster
resource "aws_ecs_cluster" "go_cluster" {
name = "go-ecs-cluster"
}
# 建立 Fargate 任務定義
resource "aws_ecs_task_definition" "go_task" {
family = "go-task"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([{
name = "go-app"
image = "myrepo/go-hello:latest"
essential = true
portMappings = [{
containerPort = 8080
protocol = "tcp"
}]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = "/ecs/go-app"
"awslogs-region" = "ap-northeast-1"
"awslogs-stream-prefix" = "ecs"
}
}
}])
}
# 建立 Fargate Service
resource "aws_ecs_service" "go_service" {
name = "go-service"
cluster = aws_ecs_cluster.go_cluster.id
task_definition = aws_ecs_task_definition.go_task.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = ["subnet-xxxxxx", "subnet-yyyyyy"]
security_groups = ["sg-zzzzzz"]
assign_public_ip = true
}
}
重點:在 GCP 與 Azure 中,概念相同,只是資源名稱與提供者不同(
google_cloud_run_service、azurerm_container_group),可依需求自行替換。
4. CI/CD 流程:GitHub Actions + Cloud Build
以下示範 GitHub Actions,在 push 至 main 分支時自動建置 Docker 映像、推送至 AWS ECR,最後使用 Terraform 執行 apply。
# .github/workflows/deploy.yml
name: Deploy Go App to AWS
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. Checkout 原始碼
- uses: actions/checkout@v4
# 2. 設定 Go
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
# 3. 登入 AWS ECR
- name: Login to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v2
with:
region: ap-northeast-1
# 4. Build Docker image
- name: Build & Push Docker image
env:
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/go-hello:$IMAGE_TAG .
docker push $ECR_REGISTRY/go-hello:$IMAGE_TAG
# 5. Terraform Init & Apply
- name: Terraform Apply
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
TF_VAR_image_tag: ${{ github.sha }}
run: |
cd infra
terraform init -backend-config="bucket=my-terraform-state"
terraform apply -auto-approve
備註:若是 GCP Cloud Build 或 Azure Pipelines,只要把
aws-actions/amazon-ecr-login換成相應的登入步驟,其他流程幾乎相同。
5. 觀測與日誌:CloudWatch、Stackdriver、Azure Monitor
部署完成後,觀測 是不可或缺的。以下示範在 Go 程式內使用 logrus 輸出結構化日誌,並在容器啟動時將日誌傳送至雲端日誌服務。
// logger.go
package main
import (
"os"
"github.com/sirupsen/logrus"
)
var log = logrus.New()
func init() {
// 輸出 JSON 格式,方便 CloudWatch / Stackdriver 解析
log.SetFormatter(&logrus.JSONFormatter{})
// 直接寫入 stdout,容器平台會自動收集
log.SetOutput(os.Stdout)
// 設定最低等級為 Info
log.SetLevel(logrus.InfoLevel)
}
func main() {
log.WithFields(logrus.Fields{
"service": "go-hello",
"port": 8080,
}).Info("服務啟動")
// 你的 HTTP 伺服器程式碼...
}
在 AWS 中,可透過 awslogs driver 把 stdout 直接送到 CloudWatch;在 GCP,Cloud Run 會自動收集 stdout 送至 Stackdriver Logging;在 Azure,App Service 亦同理。
常見陷阱與最佳實踐
| 陷阱 | 可能的影響 | 解決方案 / 最佳實踐 |
|---|---|---|
| 容器映像過大(包含完整的 Go SDK) | 部署時間長、成本提升 | 使用 scratch 或 distroless 基底,並關閉 CGO (CGO_ENABLED=0) |
| 硬編碼環境變數(如 DB 密碼) | 安全漏洞、難以在多環境切換 | 使用雲端的 Secret Manager(AWS Secrets Manager、GCP Secret Manager、Azure Key Vault) |
| 忽略健康檢查 | 負載均衡器無法自動剔除失效容器 | 在 Dockerfile 或 Cloud Run 中加入 /healthz 端點,並在 Terraform 設定 health_check |
| 未設定資源限制(CPU/Memory) | 容器因資源爭用被 OOM kill | 在 Terraform/ECS/Fargate、Cloud Run、Azure Container Apps 中明確設定 cpu、memory |
| 日誌未結構化 | 難以在雲端觀測平台搜尋 | 使用 logrus、zap 等支援 JSON 輸出的 logger |
| CI/CD 沒有回滾機制 | 部署失敗時無法快速恢復 | 在 Terraform 中使用 -target 或 terraform state rollback,或在容器平台使用 Blue/Green 部署策略 |
實際應用場景
| 場景 | 推薦平台 | 為什麼適合 |
|---|---|---|
| 小型 API 服務(單一容器) | AWS Lambda + API Gateway 或 GCP Cloud Run | 零伺服器模式,按請求付費,管理負擔最低 |
| 高併發微服務(多容器) | AWS ECS Fargate、Azure Container Apps、GCP GKE Autopilot | 完全托管的容器執行環境,支援自動水平擴展 |
| 需要持久磁碟或資料庫的後端 | Azure App Service (Linux) + Azure Database for PostgreSQL | 整合式平台,內建磁碟與資料庫連線設定 |
| 跨區域容災 | Multi‑Region Cloud Run 或 AWS Global Accelerator + ECS | 透過 DNS 及負載均衡自動切換,降低單點失效風險 |
| 企業內部私有雲 | GCP Anthos 或 Azure Arc | 可在本地或多雲環境統一管理容器與 Kubernetes |
總結
- 先產出 Linux 靜態二進位檔,再以最小化的 Docker 映像部署,能顯著降低映像大小與安全風險。
- IaC(Terraform) 為跨雲部署的關鍵,讓基礎建設可程式化、版本化、可回溯。
- CI/CD(GitHub Actions、Cloud Build、Azure Pipelines)自動化建置、測試與部署,確保每一次推送都能安全上線。
- 觀測、日誌與資源限制 必不可少,避免服務在高負載或異常時失控。
- 根據 業務需求(API、微服務、容災)選擇最適合的雲平台與服務類型,才能發揮 Go 語言的高效能與低資源佔用優勢。
透過本文的概念與範例,你已具備在 AWS、GCP、Azure 三大雲端環境中,從 程式碼 → Docker → IaC → CI/CD → 觀測 的完整部署流程。接下來,只要依照自己的專案需求微調設定,即可把 Go 應用快速、穩定地交付給使用者。祝開發順利,部署無憂!