Notice
Recent Posts
250x250
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
관리 메뉴

일상 코딩

[윈도우 개발 환경 설정] 5편: Go & Gin 환경 구축 본문

Windows 개발환경 세팅

[윈도우 개발 환경 설정] 5편: Go & Gin 환경 구축

polarcompass 2026. 3. 31. 22:24
728x90

이제 모든 최신 정보를 확인했습니다. 5편을 작성합니다.


5편: Go & Gin 환경 구축

시리즈: 윈도우 네이티브 개발 환경 세팅부터 클라우드 배포까지 (5/14)

이전 편 전제: nvm-windows, Node.js LTS, Vite + React + TypeScript + Tailwind CSS + React Router 프로젝트 세팅 완료


들어가며

4편에서 프론트엔드(React SPA)를 세팅했다. 이제 첫 번째 백엔드를 만들 차례다. Go는 컴파일 언어답게 실행 파일 하나로 배포할 수 있고, 동시성 처리가 뛰어나 API 서버로 인기가 높다. 여기에 Gin 프레임워크를 얹으면 라우팅, 미들웨어, JSON 직렬화 등을 간결하게 처리할 수 있다.

이번 편에서는 winget으로 Go를 설치하고, 환경변수를 확인한 뒤, Go 모듈을 초기화하고, Gin으로 Hello World API 서버를 띄워 브라우저에서 응답을 확인하는 것까지 진행한다. 모든 작업은 PowerShell 7에서 진행하며, WSL은 사용하지 않는다.


1. winget으로 Go 설치

1-1. 설치

PowerShell 7에서 한 줄이면 된다.

winget install -e --id GoLang.Go

-e는 정확한 ID 매칭, --id는 패키지 식별자를 지정하는 플래그다. 설치가 완료되면 터미널을 종료했다가 다시 열어야 PATH 환경변수가 반영된다.

1-2. 설치 확인

go version
go version go1.26.1 windows/amd64

위와 비슷한 출력이 나오면 성공이다. 현재 Go 최신 안정 버전은 1.26 계열이다.


2. 환경변수 확인: GOROOT & GOPATH

Go를 처음 접하면 GOROOT와 GOPATH가 혼란스러울 수 있다. 결론부터 말하면, 대부분의 경우 직접 건드릴 필요가 없다. Go가 설치될 때 자동으로 설정되며, Go 모듈(go mod) 시스템 덕분에 프로젝트별로 의존성이 관리된다.

2-1. 현재 값 확인

go env GOROOT
go env GOPATH
C:\Program Files\Go
C:\Users\사용자이름\go

GOROOT는 Go SDK가 설치된 경로이고, GOPATH는 go install로 설치한 바이너리와 모듈 캐시가 저장되는 작업 공간이다.

2-2. 각 변수의 역할

GOROOT는 Go 컴파일러, 표준 라이브러리, 도구 체인이 설치된 디렉토리다. winget이나 공식 인스톨러로 Go를 설치하면 자동으로 설정되므로 직접 수정할 일이 없다.

GOPATH는 기본값이 %USERPROFILE%\go이다. 이 경로 아래에 bin/(설치된 실행 파일), pkg/(모듈 캐시) 디렉토리가 자동 생성된다. Go 모듈을 사용하는 현재는 프로젝트 코드를 GOPATH 안에 둘 필요가 없다. 어디서든 프로젝트를 만들면 된다.

2-3. GOPATH/bin을 PATH에 추가

go install로 설치하는 CLI 도구(linter, formatter 등)가 GOPATH/bin에 저장된다. 이 경로가 PATH에 없으면 설치한 도구를 바로 실행할 수 없다. 확인해 보자.

$env:Path -split ';' | Select-String 'go\\bin'

C:\Users\사용자이름\go\bin이 목록에 있으면 이미 설정된 것이다. 없다면 영구적으로 추가한다.

$gobin = "$(go env GOPATH)\bin"
[Environment]::SetEnvironmentVariable(
    "Path",
    [Environment]::GetEnvironmentVariable("Path", "User") + ";$gobin",
    "User"
)

터미널을 재시작한 뒤 반영을 확인한다.

$env:Path -split ';' | Select-String 'go\\bin'

2-4. 전체 Go 환경 한눈에 보기

Go 관련 환경변수를 전부 보고 싶다면:

go env

주요 항목만 추려서 확인하고 싶다면:

go env GOROOT GOPATH GOBIN GOPROXY GOMODCACHE

3. Go 모듈 초기화

Go 1.11부터 도입된 Go 모듈 시스템은 프로젝트별 의존성 관리의 표준이다. go.mod 파일이 프로젝트 루트에 존재하면 그 디렉토리가 하나의 모듈이 된다.

3-1. 프로젝트 디렉토리 생성

mkdir my-go-api
cd my-go-api

3-2. 모듈 초기화

go mod init my-go-api
go: creating new go.mod: module my-go-api

go.mod 파일이 생성된다. 내용을 확인해 보자.

cat go.mod
module my-go-api

go 1.26

module 뒤의 이름은 이 모듈의 import path다. 나중에 GitHub에 올릴 계획이라면 github.com/사용자이름/my-go-api처럼 지정하는 것이 관례다. 로컬 개발 단계에서는 짧은 이름으로 충분하다.


4. Gin 프레임워크 설치

4-1. 패키지 추가

go get -u github.com/gin-gonic/gin

go get -u는 최신 버전을 가져오면서 go.mod에 의존성을 기록하고, go.sum에 체크섬을 기록한다. 현재 Gin 최신 버전은 v1.12.0이다.

설치 후 go.mod를 다시 확인하면 의존성이 추가되어 있다.

cat go.mod
module my-go-api

go 1.26

require github.com/gin-gonic/gin v1.12.0

require (
    // indirect dependencies...
)

require 블록에 Gin과 그 하위 의존성이 나열된다.


5. Hello World API 서버 작성

5-1. main.go 생성

프로젝트 루트에 main.go 파일을 만든다.

package main

import (
    "net/http"

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

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

    // GET /ping → {"message": "pong"}
    router.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })

    // GET /hello/:name → {"hello": "이름"}
    router.GET("/hello/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.JSON(http.StatusOK, gin.H{
            "hello": name,
        })
    })

    // 기본 포트 8080에서 서버 시작
    router.Run(":8080")
}

코드를 한 블록씩 짚어 보자.

gin.Default()는 Logger와 Recovery 미들웨어가 포함된 기본 라우터를 생성한다. Logger는 모든 요청을 터미널에 로깅하고, Recovery는 패닉이 발생해도 서버가 죽지 않도록 복구한다.

router.GET("/ping", handler)GET /ping 요청에 대한 핸들러를 등록한다. gin.Hmap[string]any의 축약형이고, c.JSON()이 이 맵을 JSON으로 직렬화해서 응답한다.

router.GET("/hello/:name", handler)에서 :name은 경로 파라미터다. /hello/world로 요청하면 c.Param("name")"world"를 반환한다.

router.Run(":8080")0.0.0.0:8080에서 서버를 시작한다. 포트만 지정하면 모든 네트워크 인터페이스에서 수신한다.

5-2. 현재 프로젝트 구조

my-go-api/
├── go.mod
├── go.sum
└── main.go

6. 서버 실행 & 확인

6-1. 서버 실행

go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)
[GIN-debug] GET    /hello/:name              --> main.main.func2 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8080

등록된 라우트 목록과 함께 서버가 :8080에서 대기 중이라는 메시지가 출력된다.

6-2. API 테스트

새 PowerShell 탭을 열어서 요청을 보낸다.

# /ping 테스트
curl http://localhost:8080/ping
{"message":"pong"}
# /hello/:name 테스트
curl http://localhost:8080/hello/gopher
{"hello":"gopher"}

브라우저에서 http://localhost:8080/ping을 직접 열어도 같은 JSON 응답을 확인할 수 있다.

6-3. 서버 종료

서버가 실행 중인 터미널에서 Ctrl+C를 누르면 종료된다.


7. 빌드 & 실행 파일 생성

go run은 컴파일과 실행을 동시에 하는 개발용 명령이다. 배포할 때는 실행 파일을 빌드해서 바이너리 하나만 서버에 올린다.

7-1. 빌드

go build -o my-go-api.exe main.go

-o 플래그로 출력 파일명을 지정한다. 윈도우에서는 .exe 확장자를 붙인다.

7-2. 실행

.\my-go-api.exe

go run과 동일하게 서버가 시작된다. 차이점은 이미 컴파일된 바이너리를 실행하는 것이므로 Go SDK 없이도 동작한다는 점이다.

7-3. 리눅스용 크로스 컴파일

나중에 클라우드 리눅스 서버에 배포할 때는 윈도우에서 리눅스용 바이너리를 바로 빌드할 수 있다. Go의 크로스 컴파일은 환경변수 두 개만 지정하면 된다.

$env:GOOS = "linux"
$env:GOARCH = "amd64"
go build -o my-go-api main.go

확장자 없는 my-go-api 파일이 생성된다. 이 파일을 리눅스 서버에 올리고 실행 권한을 주면 바로 동작한다. 빌드 후에는 환경변수를 원래대로 돌려놓는다.

Remove-Item Env:GOOS
Remove-Item Env:GOARCH

참고: 14편(통합 Docker Compose)에서는 Docker 멀티스테이지 빌드로 이 과정을 자동화한다. 지금은 "Go는 크로스 컴파일이 된다"는 것만 알아 두면 충분하다.


8. 유용한 Go 도구 설치 (선택)

Go 개발에 자주 쓰이는 도구를 미리 설치해 두면 편하다. go install로 설치하면 GOPATH/bin에 바이너리가 저장된다.

8-1. gopls (Go Language Server)

Google Antigravity(VS Code 포크)에서 Go 확장 프로그램이 사용하는 언어 서버다. 자동 완성, 정의 이동, 리팩토링 등 거의 모든 에디터 기능이 이 서버를 통해 동작한다.

go install golang.org/x/tools/gopls@latest

8-2. staticcheck (린터)

Go 코드의 버그, 스타일 문제, 성능 이슈를 잡아주는 정적 분석 도구다.

go install honnef.co/go/tools/cmd/staticcheck@latest

8-3. dlv (Delve 디버거)

Go 전용 디버거다. Google Antigravity에서 브레이크포인트를 걸고 디버깅할 때 필요하다.

go install github.com/go-delve/delve/cmd/dlv@latest

8-4. 설치 확인

gopls version
staticcheck -version
dlv version

세 명령 모두 버전 정보가 출력되면 정상이다.


9. Google Antigravity에서 Go 개발 환경 설정

Google Antigravity는 VS Code 포크이므로 Go 확장 프로그램을 그대로 사용할 수 있다.

9-1. Go 확장 프로그램 설치

확장 프로그램 탭(Ctrl+Shift+X)에서 Go(golang.go)를 검색하여 설치한다.

9-2. 도구 자동 설치

Go 확장 프로그램이 설치되면 에디터 하단에 "Analysis Tools Missing" 알림이 뜰 수 있다. Install All을 클릭하면 gopls, dlv, staticcheck 등을 자동으로 설치한다. 8장에서 이미 수동 설치했다면 이 단계는 건너뛰어도 된다.

9-3. 프로젝트 열기

cd my-go-api
code .

code 명령이 Google Antigravity를 실행하도록 3편에서 PATH 설정을 완료한 상태를 전제한다. Google Antigravity의 CLI 명령이 antigravity로 등록되어 있다면 antigravity .로 실행한다.

main.go를 열어 보면 구문 하이라이팅, 자동 완성, 에러 표시 등이 동작하는 것을 확인할 수 있다. Ctrl+S로 저장하면 gofmt가 자동으로 코드를 포맷팅한다.


10. 최종 확인 체크리스트

# 1. Go 설치 확인
go version
# → go version go1.26.x windows/amd64

# 2. 환경변수 확인
go env GOROOT GOPATH
# → GOROOT: C:\Program Files\Go
# → GOPATH: C:\Users\사용자이름\go

# 3. GOPATH/bin이 PATH에 포함되어 있는지
gopls version
# → 버전 정보 출력

# 4. 프로젝트 이동 후 서버 실행
cd my-go-api
go run main.go
# → Listening and serving HTTP on :8080

# 5. 새 터미널에서 API 테스트
curl http://localhost:8080/ping
# → {"message":"pong"}

curl http://localhost:8080/hello/gopher
# → {"hello":"gopher"}

# 6. 빌드 확인
go build -o my-go-api.exe main.go
.\my-go-api.exe
# → 서버 정상 시작
확인 항목 기대 결과
go version go version go1.26.x windows/amd64
go env GOROOT Go SDK 설치 경로
go env GOPATH %USERPROFILE%\go
gopls version 버전 정보 출력
go run main.go :8080에서 서버 시작
GET /ping {"message":"pong"}
GET /hello/gopher {"hello":"gopher"}
go build .exe 파일 생성

11. 원클릭 자동화 스크립트

아래 PowerShell 스크립트 하나로 Go 설치부터 Gin 프로젝트 생성, 빌드 확인까지 자동화할 수 있다.

11-1. 스크립트 파일 생성

아래 내용을 setup-go-gin.ps1로 저장한다.

<#
  setup-go-gin.ps1
  5편 자동화 스크립트: Go + Gin API 서버 환경 구축
  실행: PowerShell 7에서 .\setup-go-gin.ps1
  인자: -ProjectName <이름>  (기본값: my-go-api)
#>

param(
    [string]$ProjectName = "my-go-api"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function Write-Step {
    param([string]$Message)
    Write-Host "`n========================================" -ForegroundColor Cyan
    Write-Host " $Message" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
}

# ─────────────────────────────────────────────
# 1. Go 설치 확인
# ─────────────────────────────────────────────
Write-Step "1/7 Go 설치 확인"

if (-not (Get-Command go -ErrorAction SilentlyContinue)) {
    Write-Host "Go가 설치되어 있지 않습니다. winget으로 설치합니다..." -ForegroundColor Yellow
    winget install -e --id GoLang.Go --accept-package-agreements --accept-source-agreements
    # PATH 새로고침
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
    if (-not (Get-Command go -ErrorAction SilentlyContinue)) {
        Write-Host "Go 설치 후 터미널을 재시작해야 합니다. 스크립트를 종료합니다." -ForegroundColor Red
        exit 1
    }
}
Write-Host "$(go version)" -ForegroundColor Green

# ─────────────────────────────────────────────
# 2. GOPATH/bin PATH 추가
# ─────────────────────────────────────────────
Write-Step "2/7 GOPATH/bin PATH 확인"

$gobin = "$(go env GOPATH)\bin"
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")

if ($userPath -notlike "*$gobin*") {
    Write-Host "GOPATH\bin을 PATH에 추가합니다: $gobin" -ForegroundColor Yellow
    [Environment]::SetEnvironmentVariable("Path", "$userPath;$gobin", "User")
    $env:Path = "$env:Path;$gobin"
} else {
    Write-Host "GOPATH\bin이 이미 PATH에 포함되어 있습니다." -ForegroundColor Green
}

# ─────────────────────────────────────────────
# 3. Go 개발 도구 설치
# ─────────────────────────────────────────────
Write-Step "3/7 Go 개발 도구 설치 (gopls, staticcheck, dlv)"

$tools = @(
    "golang.org/x/tools/gopls@latest",
    "honnef.co/go/tools/cmd/staticcheck@latest",
    "github.com/go-delve/delve/cmd/dlv@latest"
)

foreach ($tool in $tools) {
    $toolName = ($tool -split '/')[-1] -replace '@.*', ''
    Write-Host "  설치 중: $toolName ..." -ForegroundColor Gray
    go install $tool 2>&1 | Out-Null
}

Write-Host "gopls:       $(gopls version 2>&1 | Select-Object -First 1)" -ForegroundColor Green
Write-Host "staticcheck: $(staticcheck -version 2>&1)" -ForegroundColor Green
Write-Host "dlv:         $(dlv version 2>&1 | Select-Object -First 1)" -ForegroundColor Green

# ─────────────────────────────────────────────
# 4. 프로젝트 디렉토리 생성 & Go 모듈 초기화
# ─────────────────────────────────────────────
Write-Step "4/7 프로젝트 생성: $ProjectName"

if (Test-Path $ProjectName) {
    Write-Host "'$ProjectName' 폴더가 이미 존재합니다. 건너뜁니다." -ForegroundColor Yellow
} else {
    New-Item -ItemType Directory -Path $ProjectName | Out-Null
}

Set-Location $ProjectName

if (-not (Test-Path "go.mod")) {
    go mod init $ProjectName
    Write-Host "go.mod 생성 완료" -ForegroundColor Green
} else {
    Write-Host "go.mod가 이미 존재합니다." -ForegroundColor Yellow
}

# ─────────────────────────────────────────────
# 5. Gin 설치
# ─────────────────────────────────────────────
Write-Step "5/7 Gin 프레임워크 설치"

go get -u github.com/gin-gonic/gin
Write-Host "Gin 설치 완료" -ForegroundColor Green

# ─────────────────────────────────────────────
# 6. main.go 생성
# ─────────────────────────────────────────────
Write-Step "6/7 main.go 생성"

$mainGo = @'
package main

import (
    "net/http"

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

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

    // GET /ping → {"message": "pong"}
    router.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })

    // GET /hello/:name → {"hello": "이름"}
    router.GET("/hello/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.JSON(http.StatusOK, gin.H{
            "hello": name,
        })
    })

    // 기본 포트 8080에서 서버 시작
    router.Run(":8080")
}
'@

Set-Content -Path "main.go" -Value $mainGo -Encoding UTF8
Write-Host "main.go 작성 완료" -ForegroundColor Green

# ─────────────────────────────────────────────
# 7. 빌드 테스트
# ─────────────────────────────────────────────
Write-Step "7/7 빌드 테스트"

go build -o "$ProjectName.exe" main.go

if (Test-Path "$ProjectName.exe") {
    $fileSize = [math]::Round((Get-Item "$ProjectName.exe").Length / 1MB, 1)
    Write-Host "빌드 성공: $ProjectName.exe ($fileSize MB)" -ForegroundColor Green
} else {
    Write-Host "빌드 실패. 에러 로그를 확인하세요." -ForegroundColor Red
    exit 1
}

# ─────────────────────────────────────────────
# 완료 메시지
# ─────────────────────────────────────────────
Write-Host "`n" -NoNewline
Write-Host "============================================" -ForegroundColor Green
Write-Host " Go + Gin API 프로젝트 세팅 완료!" -ForegroundColor Green
Write-Host "============================================" -ForegroundColor Green
Write-Host ""
Write-Host "  프로젝트 경로:     $(Get-Location)" -ForegroundColor White
Write-Host "  개발 서버 실행:    go run main.go" -ForegroundColor White
Write-Host "  빌드:              go build -o $ProjectName.exe main.go" -ForegroundColor White
Write-Host "  테스트 요청:       curl http://localhost:8080/ping" -ForegroundColor White
Write-Host ""
Write-Host "  현재 프로젝트 구조:" -ForegroundColor White
Write-Host "  $ProjectName/" -ForegroundColor Gray
Write-Host "  ├── go.mod" -ForegroundColor Gray
Write-Host "  ├── go.sum" -ForegroundColor Gray
Write-Host "  ├── main.go" -ForegroundColor Gray
Write-Host "  └── $ProjectName.exe" -ForegroundColor Gray
Write-Host ""

11-2. 스크립트 실행

# 기본 프로젝트 이름(my-go-api)으로 생성
.\setup-go-gin.ps1

# 커스텀 프로젝트 이름으로 생성
.\setup-go-gin.ps1 -ProjectName "my-awesome-api"

스크립트가 완료되면 7단계 모두 녹색 메시지로 결과가 출력되며, 실행 파일까지 빌드된 상태로 마무리된다. 이후 go run main.go로 개발 서버를 바로 시작할 수 있다.


다음 편 예고

6편: Python & FastAPI 환경 구축에서는 pyenv-win으로 Python 버전을 관리하고, 가상환경을 만든 뒤, FastAPI + Uvicorn으로 두 번째 백엔드 API 서버를 실행한다. Go 서버와 Python 서버, 두 개의 백엔드가 나란히 동작하는 구조의 기반을 완성하게 된다.

728x90