์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ Go์–ธ์–ด ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ์™„์ „์ •๋ณต

๐Ÿš€ Go์–ธ์–ด ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ์™„์ „์ •๋ณต

ํ•œ ๋ฒˆ์˜ ๋นŒ๋“œ๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์„ ์ •๋ณตํ•˜๋Š” ๋งˆ๋ฒ• ๊ฐ™์€ ์ด์•ผ๊ธฐ

์•ˆ๋…•! ์˜ค๋Š˜์€ Go์–ธ์–ด์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๋ฌด๊ธฐ ์ค‘ ํ•˜๋‚˜์ธ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณด๋ ค๊ณ  ํ•ด. ๐ŸŽฏ
ํ˜น์‹œ ํ”„๋กœ๊ทธ๋žจ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ์œˆ๋„์šฐ, ๋งฅ, ๋ฆฌ๋ˆ…์Šค์— ๋‹ค ๋ฐฐํฌํ•˜๋ ค๋ฉด ๊ฐ๊ฐ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ์—์„œ ๋นŒ๋“œํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋˜ ์  ์žˆ์–ด? ๊ทธ๋Ÿฐ๋ฐ Go๋Š” ๊ทธ๋Ÿฐ ๊ณ ๋ฏผ์„ ์™„์ „ํžˆ ๋‚ ๋ ค๋ฒ„๋ ธ์–ด!

๋งฅ๋ถ์—์„œ ์ž‘์—…ํ•˜๋ฉด์„œ ์œˆ๋„์šฐ์šฉ ์‹คํ–‰ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ , ๋ฆฌ๋ˆ…์Šค ์„œ๋ฒ„์šฉ ๋ฐ”์ด๋„ˆ๋ฆฌ๋„ ๋š๋”ฑ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋‹ˆ... ๋งˆ์น˜ ๋งˆ๋ฒ• ๊ฐ™์ง€ ์•Š์•„? โœจ
์ด๊ฒŒ ๋ฐ”๋กœ Go์˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๋Šฅ๋ ฅ์ด์•ผ. ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋“ค๋„ ์ด ๊ธฐ๋Šฅ์„ ์ •๋ง ๋งŽ์ด ํ™œ์šฉํ•˜๊ณ  ์žˆ์–ด.

Go ์†Œ์Šค์ฝ”๋“œ main.go ๐ŸชŸ Windows ๐ŸŽ macOS ๐Ÿง Linux ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

๐ŸŽช ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ๋ญ๊ธธ๋ž˜?

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ(Cross Compile)์ด๋ผ๋Š” ์šฉ์–ด๊ฐ€ ์ข€ ์–ด๋ ต๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์‚ฌ์‹ค ๊ฐœ๋…์€ ์ •๋ง ๋‹จ์ˆœํ•ด.
๋‚ด๊ฐ€ ์ง€๊ธˆ ์‚ฌ์šฉํ•˜๋Š” ์ปดํ“จํ„ฐ์™€ ๋‹ค๋ฅธ ์šด์˜์ฒด์ œ๋‚˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์œ„ํ•œ ์‹คํ–‰ ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๋งํ•ด. ๐ŸŽฏ

๐Ÿ’ก ์‰ฌ์šด ์˜ˆ์‹œ๋กœ ์ดํ•ดํ•˜๊ธฐ

๋งฅ๋ถ(macOS)์—์„œ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์œˆ๋„์šฐ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ .exe ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋ฉด?
์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์œˆ๋„์šฐ ์ปดํ“จํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ฒ ์ง€. ํ•˜์ง€๋งŒ Go๋Š” ๋งฅ๋ถ์—์„œ ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ์œˆ๋„์šฐ์šฉ ์‹คํ–‰ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด!

์ „ํ†ต์ ์ธ ์–ธ์–ด๋“ค(C, C++ ๋“ฑ)์—์„œ๋Š” ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ์ •๋ง ๋ณต์žกํ–ˆ์–ด. ๊ฐ ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ , ๋ณต์žกํ•œ ์„ค์ •์„ ํ•ด์•ผ ํ–ˆ๊ฑฐ๋“ .
ํ•˜์ง€๋งŒ Go๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ง ๊ฐ„๋‹จํ•ด! ๐Ÿ˜Š

๐Ÿ” ์™œ Go๋Š” ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ์‰ฌ์šธ๊นŒ?

Go ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ˆœ์ˆ˜ Go ์–ธ์–ด๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๊ณ , ๋ชจ๋“  ํ”Œ๋žซํผ์˜ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ Go ์„ค์น˜ ์‹œ ํ•จ๊ป˜ ํฌํ•จ๋˜์–ด ์žˆ์–ด.
๊ทธ๋ž˜์„œ ๋ณ„๋„์˜ ํˆด์ฒด์ธ์„ ์„ค์น˜ํ•  ํ•„์š” ์—†์ด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋‘ ๊ฐœ๋งŒ ์„ค์ •ํ•˜๋ฉด ๋์ด์•ผ!

๐Ÿ› ๏ธ ๊ธฐ๋ณธ์ ์ธ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๋ฐฉ๋ฒ•

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ํฌ๋กœ์Šค ์ปดํŒŒ์ผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ๊นŒ? ์ •๋ง ๊ฐ„๋‹จํ•˜๋‹ˆ๊นŒ ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ! ๐Ÿ˜„

๐Ÿ“ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

Go์—์„œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ํ•˜๋ ค๋ฉด ๋‘ ๊ฐ€์ง€ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ด:

๐ŸŽฏ ํ•ต์‹ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜

GOOS: ํƒ€๊ฒŸ ์šด์˜์ฒด์ œ (์˜ˆ: windows, linux, darwin)
GOARCH: ํƒ€๊ฒŸ ์•„ํ‚คํ…์ฒ˜ (์˜ˆ: amd64, arm64, 386)

์ด ๋‘ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋นŒ๋“œ ๋ช…๋ น์–ด ์•ž์— ๋ถ™์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ผ. ์ •๋ง ๊ฐ„๋‹จํ•˜์ง€?

๐Ÿ’ป ์‹ค์ „ ์˜ˆ์ œ

๊ฐ„๋‹จํ•œ Hello World ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด์„œ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์šฉ์œผ๋กœ ๋นŒ๋“œํ•ด๋ณด์ž!

// main.go
package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Printf("Hello from Go!\n")
    fmt.Printf("OS: %s\n", runtime.GOOS)
    fmt.Printf("Architecture: %s\n", runtime.GOARCH)
}

์ด์ œ ์ด ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ์šฉ์œผ๋กœ ์ปดํŒŒ์ผํ•ด๋ณด์ž! ๐Ÿš€

๐ŸชŸ Windows์šฉ ๋นŒ๋“œ (64๋น„ํŠธ)

# Linux๋‚˜ macOS์—์„œ ์‹คํ–‰
GOOS=windows GOARCH=amd64 go build -o myapp.exe main.go

# Windows PowerShell์—์„œ ์‹คํ–‰
$env:GOOS="windows"; $env:GOARCH="amd64"; go build -o myapp.exe main.go

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด myapp.exe ํŒŒ์ผ์ด ์ƒ์„ฑ๋ผ. ์ด ํŒŒ์ผ์„ ์œˆ๋„์šฐ ์ปดํ“จํ„ฐ๋กœ ๊ฐ€์ ธ๊ฐ€๋ฉด ๋ฐ”๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด!

๐ŸŽ macOS์šฉ ๋นŒ๋“œ

# Intel Mac์šฉ (amd64)
GOOS=darwin GOARCH=amd64 go build -o myapp-mac-intel main.go

# Apple Silicon (M1/M2) Mac์šฉ (arm64)
GOOS=darwin GOARCH=arm64 go build -o myapp-mac-arm main.go

๐Ÿ’ก Pro Tip

macOS๋Š” ์ฝ”๋“œ๋ช…์ด darwin์ด์•ผ. ์ฒ˜์Œ์—๋Š” ์ข€ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๊ฑด macOS์˜ ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ์šด์˜์ฒด์ œ ์ด๋ฆ„์—์„œ ๋”ฐ์˜จ ๊ฑฐ์•ผ.
๊ทธ๋ฆฌ๊ณ  ์ตœ์‹  ๋งฅ๋ถ์€ Apple Silicon(M1, M2 ๋“ฑ)์„ ์‚ฌ์šฉํ•˜๋‹ˆ๊นŒ arm64๋กœ ๋นŒ๋“œํ•ด์•ผ ํ•ด!

๐Ÿง Linux์šฉ ๋นŒ๋“œ

# Linux 64๋น„ํŠธ์šฉ
GOOS=linux GOARCH=amd64 go build -o myapp-linux main.go

# Linux ARM 64๋น„ํŠธ์šฉ (๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ๋“ฑ)
GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm main.go

# Linux 32๋น„ํŠธ์šฉ
GOOS=linux GOARCH=386 go build -o myapp-linux-32 main.go

๋ฆฌ๋ˆ…์Šค๋Š” ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋‹ˆ๊นŒ, ํŠนํžˆ ์ค‘์š”ํ•ด. ํด๋ผ์šฐ๋“œ ์„œ๋ฒ„์— ๋ฐฐํฌํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•˜์ง€! โ˜๏ธ

๐ŸŒ ์ง€์›ํ•˜๋Š” ํ”Œ๋žซํผ ์ „์ฒด ๋ชฉ๋ก

Go๊ฐ€ ์ง€์›ํ•˜๋Š” ํ”Œ๋žซํผ์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€์ง€ ๊ถ๊ธˆํ•˜์ง€? ์ •๋ง ๋†€๋ผ์šธ ์ •๋„๋กœ ๋‹ค์–‘ํ•ด! ๐Ÿ˜ฒ

๋‹ค์Œ ๋ช…๋ น์–ด๋กœ ์ง€์›ํ•˜๋Š” ๋ชจ๋“  ํ”Œ๋žซํผ ์กฐํ•ฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด:

go tool dist list

์ด ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 50๊ฐœ๊ฐ€ ๋„˜๋Š” ํ”Œ๋žซํผ ์กฐํ•ฉ์ด ๋‚˜์™€. ์ฃผ์š” ํ”Œ๋žซํผ๋“ค์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ!

๐ŸชŸ Windows

โ€ข windows/amd64 (64๋น„ํŠธ)
โ€ข windows/386 (32๋น„ํŠธ)
โ€ข windows/arm64 (ARM 64๋น„ํŠธ)

๐ŸŽ macOS (Darwin)

โ€ข darwin/amd64 (Intel Mac)
โ€ข darwin/arm64 (Apple Silicon)

๐Ÿง Linux

โ€ข linux/amd64 (64๋น„ํŠธ)
โ€ข linux/386 (32๋น„ํŠธ)
โ€ข linux/arm (32๋น„ํŠธ ARM)
โ€ข linux/arm64 (64๋น„ํŠธ ARM)

๐ŸŒ ๊ธฐํƒ€ ํ”Œ๋žซํผ

โ€ข freebsd, openbsd, netbsd
โ€ข android, ios
โ€ข plan9, solaris
โ€ข dragonfly, illumos

๐ŸŽฎ ํŠน๋ณ„ํ•œ ํ”Œ๋žซํผ๋“ค

Go๋Š” ์‹ฌ์ง€์–ด WebAssembly(js/wasm)๋„ ์ง€์›ํ•ด! ์ด๊ฑด Go ์ฝ”๋“œ๋ฅผ ์›น๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด์•ผ.
๋˜ํ•œ ๋ชจ๋ฐ”์ผ ํ”Œ๋žซํผ์ธ Android์™€ iOS๋„ ์ง€์›ํ•˜๋‹ˆ๊นŒ, ์ •๋ง ๋‹ค์–‘ํ•œ ๊ณณ์—์„œ Go๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ“ฑ

โš™๏ธ ๊ณ ๊ธ‰ ๋นŒ๋“œ ์˜ต์…˜๋“ค

๊ธฐ๋ณธ์ ์ธ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ๋„˜์–ด์„œ, ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์–ด. ์ด์ œ ๊ณ ๊ธ‰ ์˜ต์…˜๋“ค์„ ์•Œ์•„๋ณด์ž! ๐ŸŽ“

๐Ÿ”ง ๋นŒ๋“œ ํƒœ๊ทธ ํ™œ์šฉํ•˜๊ธฐ

๋นŒ๋“œ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ํ”Œ๋žซํผ์—์„œ๋งŒ ์ปดํŒŒ์ผ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด.
์ด๊ฑด ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ๊ตฌํ˜„์ด ํ•„์š”ํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•ด!

// file_windows.go
//go:build windows

package main

import "fmt"

func platformSpecific() {
    fmt.Println("์ด ์ฝ”๋“œ๋Š” Windows์—์„œ๋งŒ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค!")
}
// file_linux.go
//go:build linux

package main

import "fmt"

func platformSpecific() {
    fmt.Println("์ด ์ฝ”๋“œ๋Š” Linux์—์„œ๋งŒ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค!")
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ํ”Œ๋žซํผ์— ๋งž๋Š” ์ฝ”๋“œ๋งŒ ์ปดํŒŒ์ผ๋˜๋‹ˆ๊นŒ, ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๊ฐ€ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ํฌํ•จ๋˜์ง€ ์•Š์•„! ๐Ÿ‘

๐Ÿ“ฆ ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๊ธฐ ์ค„์ด๊ธฐ

Go ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋ชจ๋“  ์˜์กด์„ฑ์„ ํฌํ•จํ•˜๋Š” ์ •์  ๋งํฌ ๋ฐฉ์‹์ด๋ผ ํฌ๊ธฐ๊ฐ€ ์ข€ ํฐ ํŽธ์ด์•ผ.
ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ์˜ต์…˜์œผ๋กœ ํฌ๊ธฐ๋ฅผ ๋งŽ์ด ์ค„์ผ ์ˆ˜ ์žˆ์–ด!

# ๋””๋ฒ„๊ทธ ์ •๋ณด ์ œ๊ฑฐ ๋ฐ ์ตœ์ ํ™”
go build -ldflags="-s -w" -o myapp main.go

# ๋” ๊ณต๊ฒฉ์ ์ธ ์ตœ์ ํ™”
go build -ldflags="-s -w" -trimpath -o myapp main.go

๐ŸŽฏ ldflags ์˜ต์…˜ ์„ค๋ช…

-s: ์‹ฌ๋ณผ ํ…Œ์ด๋ธ” ์ œ๊ฑฐ
-w: DWARF ๋””๋ฒ„๊น… ์ •๋ณด ์ œ๊ฑฐ
-trimpath: ํŒŒ์ผ ๊ฒฝ๋กœ ์ •๋ณด ์ œ๊ฑฐ

์ด ์˜ต์…˜๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๊ธฐ๊ฐ€ 30~40% ์ •๋„ ์ค„์–ด๋“ค ์ˆ˜ ์žˆ์–ด! ํ•˜์ง€๋งŒ ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ง€๋‹ˆ๊นŒ, ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์•„.

๐Ÿท๏ธ ๋ฒ„์ „ ์ •๋ณด ํฌํ•จํ•˜๊ธฐ

๋ฐฐํฌํ•  ๋•Œ ๋ฒ„์ „ ์ •๋ณด๋ฅผ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ํฌํ•จ์‹œํ‚ค๋ฉด ์ •๋ง ์œ ์šฉํ•ด. ๋‚˜์ค‘์— ์–ด๋–ค ๋ฒ„์ „์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์‰ฝ๊ฑฐ๋“ !

// main.go
package main

import "fmt"

var (
    version = "dev"
    commit  = "none"
    date    = "unknown"
)

func main() {
    fmt.Printf("Version: %s\n", version)
    fmt.Printf("Commit: %s\n", commit)
    fmt.Printf("Build Date: %s\n", date)
}
# ๋นŒ๋“œ ์‹œ ๋ฒ„์ „ ์ •๋ณด ์ฃผ์ž…
go build -ldflags="-X main.version=1.0.0 -X main.commit=$(git rev-parse HEAD) -X main.date=$(date +%Y-%m-%d)" -o myapp

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์‹คํ–‰ ํŒŒ์ผ์— ๋ฒ„์ „ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด์„œ, ๋‚˜์ค‘์— ์–ด๋–ค ๋ฒ„์ „์ธ์ง€ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ“‹

๐Ÿ”’ CGO ๋น„ํ™œ์„ฑํ™”ํ•˜๊ธฐ

CGO๋Š” Go์—์„œ C ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ธ๋ฐ, ํฌ๋กœ์Šค ์ปดํŒŒ์ผํ•  ๋•Œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์–ด.
์ˆœ์ˆ˜ Go ์ฝ”๋“œ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด CGO๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒŒ ์ข‹์•„!

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o myapp main.go

๐Ÿ’ก CGO_ENABLED=0์˜ ์žฅ์ 

โ€ข ์™„์ „ํ•œ ์ •์  ๋งํฌ ๋ฐ”์ด๋„ˆ๋ฆฌ ์ƒ์„ฑ
โ€ข ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ ์ œ๊ฑฐ
โ€ข ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ๋” ์•ˆ์ •์ 
โ€ข ๋ฐฐํฌ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด์ง

ํŠนํžˆ Docker ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐํฌํ•  ๋•Œ CGO_ENABLED=0์œผ๋กœ ๋นŒ๋“œํ•˜๋ฉด, scratch ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ปจํ…Œ์ด๋„ˆ ํฌ๊ธฐ๊ฐ€ ์—„์ฒญ ์ž‘์•„์ ธ! ๐Ÿณ

๐Ÿค– ์ž๋™ํ™” ์Šคํฌ๋ฆฝํŠธ ๋งŒ๋“ค๊ธฐ

๋งค๋ฒˆ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์šฉ์œผ๋กœ ๋นŒ๋“œํ•˜๋Š” ๊ฒŒ ๊ท€์ฐฎ๋‹ค๋ฉด? ์Šคํฌ๋ฆฝํŠธ๋กœ ์ž๋™ํ™”ํ•˜๋ฉด ๋ผ! ๐ŸŽ‰
์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณต์œ ํ•  ๋•Œ๋„ ์ด๋Ÿฐ ์ž๋™ํ™” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•ด.

๐Ÿ“œ Bash ์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ

#!/bin/bash
# build.sh

APP_NAME="myapp"
VERSION="1.0.0"
BUILD_DIR="./build"

# ๋นŒ๋“œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
mkdir -p $BUILD_DIR

# ํ”Œ๋žซํผ ๋ชฉ๋ก
platforms=(
    "windows/amd64"
    "windows/386"
    "darwin/amd64"
    "darwin/arm64"
    "linux/amd64"
    "linux/386"
    "linux/arm"
    "linux/arm64"
)

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}
    
    output_name=$APP_NAME'-'$VERSION'-'$GOOS'-'$GOARCH
    
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi
    
    echo "Building for $GOOS/$GOARCH..."
    
    env GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0 go build \
        -ldflags="-s -w -X main.version=$VERSION" \
        -o $BUILD_DIR/$output_name \
        main.go
    
    if [ $? -ne 0 ]; then
        echo "Failed to build for $GOOS/$GOARCH"
        exit 1
    fi
done

echo "Build completed successfully!"

์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ชจ๋“  ํ”Œ๋žซํผ์šฉ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ build ํด๋”์— ์ƒ์„ฑ๋ผ! ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ˜Š

๐ŸŽฏ Makefile ํ™œ์šฉํ•˜๊ธฐ

Makefile์„ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์ฒด๊ณ„์ ์œผ๋กœ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.

# Makefile

APP_NAME := myapp
VERSION := 1.0.0
BUILD_DIR := ./build

.PHONY: all clean windows linux darwin

all: clean windows linux darwin

clean:
	rm -rf $(BUILD_DIR)
	mkdir -p $(BUILD_DIR)

windows:
	GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-windows-amd64.exe
	GOOS=windows GOARCH=386 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-windows-386.exe

linux:
	GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-linux-amd64
	GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-linux-arm64

darwin:
	GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-darwin-amd64
	GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o $(BUILD_DIR)/$(APP_NAME)-$(VERSION)-darwin-arm64

์ด์ œ make all ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์šฉ ๋นŒ๋“œ๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿš€

๐Ÿ”„ GoReleaser ์‚ฌ์šฉํ•˜๊ธฐ

๋” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ฅผ ์›ํ•œ๋‹ค๋ฉด GoReleaser๋ฅผ ์ถ”์ฒœํ•ด! ์ด๊ฑด Go ํ”„๋กœ์ ํŠธ์˜ ๋ฆด๋ฆฌ์Šค๋ฅผ ์ž๋™ํ™”ํ•ด์ฃผ๋Š” ๋„๊ตฌ์•ผ.

# .goreleaser.yaml

before:
  hooks:
    - go mod tidy

builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X main.version={{.Version}}
      - -X main.commit={{.Commit}}
      - -X main.date={{.Date}}

archives:
  - format: tar.gz
    name_template: >-
      {{ .ProjectName }}_
      {{- .Version }}_
      {{- .Os }}_
      {{- .Arch }}
    format_overrides:
      - goos: windows
        format: zip

checksum:
  name_template: 'checksums.txt'

changelog:
  sort: asc

GoReleaser๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด GitHub Release์— ์ž๋™์œผ๋กœ ์—…๋กœ๋“œํ•˜๊ณ , ์ฒดํฌ์„ฌ๋„ ์ƒ์„ฑํ•˜๊ณ , ๋ณ€๊ฒฝ ๋กœ๊ทธ๋„ ๋งŒ๋“ค์–ด์ค˜! ์ •๋ง ํŽธ๋ฆฌํ•ด! ๐ŸŽ

๐Ÿณ Docker์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

์š”์ฆ˜์€ Docker๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ž–์•„? Go์˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ Docker๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•ด! ๐Ÿ’ช

๐Ÿ—๏ธ ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ

Go ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ Docker๋กœ ๋ฐฐํฌํ•  ๋•Œ๋Š” ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค์•ผ.

# Dockerfile

# ๋นŒ๋“œ ์Šคํ…Œ์ด์ง€
FROM golang:1.21-alpine AS builder

WORKDIR /app

# ์˜์กด์„ฑ ๋‹ค์šด๋กœ๋“œ
COPY go.mod go.sum ./
RUN go mod download

# ์†Œ์Šค ์ฝ”๋“œ ๋ณต์‚ฌ ๋ฐ ๋นŒ๋“œ
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
    -ldflags="-s -w" \
    -o myapp \
    main.go

# ์‹คํ–‰ ์Šคํ…Œ์ด์ง€
FROM scratch

# ๋นŒ๋“œ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋งŒ ๋ณต์‚ฌ
COPY --from=builder /app/myapp /myapp

# SSL ์ธ์ฆ์„œ ๋ณต์‚ฌ (HTTPS ํ†ต์‹ ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

ENTRYPOINT ["/myapp"]

โœจ ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ์˜ ์žฅ์ 

โ€ข ์ตœ์ข… ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ ์—„์ฒญ ์ž‘์•„์ ธ (์ˆ˜ MB ์ˆ˜์ค€!)
โ€ข ๋นŒ๋“œ ๋„๊ตฌ๊ฐ€ ์ตœ์ข… ์ด๋ฏธ์ง€์— ํฌํ•จ๋˜์ง€ ์•Š์•„
โ€ข ๋ณด์•ˆ์ด ํ–ฅ์ƒ๋ผ
โ€ข ๋ฐฐํฌ ์†๋„๊ฐ€ ๋นจ๋ผ์ ธ

scratch ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ์ตœ์†Œํ•œ์˜ ํฌ๊ธฐ๋กœ Docker ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. 5MB ์ดํ•˜๋„ ๊ฐ€๋Šฅํ•ด! ๐ŸŽฏ

๐ŸŒ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ Docker ์ด๋ฏธ์ง€

Docker Buildx๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ์•„ํ‚คํ…์ฒ˜์šฉ ์ด๋ฏธ์ง€๋ฅผ ํ•œ ๋ฒˆ์— ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์–ด!

# ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ์ด๋ฏธ์ง€ ๋นŒ๋“œ
docker buildx build \
    --platform linux/amd64,linux/arm64,linux/arm/v7 \
    -t myapp:latest \
    --push \
    .

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Intel ์„œ๋ฒ„, ARM ์„œ๋ฒ„, ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ๋“ฑ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ ๊ฐ™์€ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŒ

๐ŸŽฏ ์‹ค์ „ ๋ฐฐํฌ ์ „๋žต

์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋ฐฐํฌํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž! ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ ํƒํ•˜๋ฉด ๋ผ. ๐Ÿ“ฆ

๐Ÿ“ค GitHub Releases ํ™œ์šฉ

์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋ผ๋ฉด GitHub Releases๊ฐ€ ์ •๋ง ์ข‹์•„. ์‚ฌ์šฉ์ž๋“ค์ด ์‰ฝ๊ฒŒ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ !

๐Ÿ”„ GitHub Actions ์›Œํฌํ”Œ๋กœ์šฐ ์˜ˆ์ œ

# .github/workflows/release.yml

name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Build
        run: |
          mkdir -p dist
          
          # Windows
          GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o dist/myapp-windows-amd64.exe
          
          # macOS
          GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o dist/myapp-darwin-amd64
          GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o dist/myapp-darwin-arm64
          
          # Linux
          GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o dist/myapp-linux-amd64
          GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o dist/myapp-linux-arm64
      
      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          files: dist/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ํƒœ๊ทธ๋ฅผ ํ‘ธ์‹œํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์šฉ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ๋นŒ๋“œ๋˜๊ณ  ๋ฆด๋ฆฌ์Šค๊ฐ€ ์ƒ์„ฑ๋ผ! ์™„์ „ ์ž๋™ํ™”! ๐Ÿค–

โ˜๏ธ ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ

ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค์— ๋ฐฐํฌํ•  ๋•Œ๋„ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ์œ ์šฉํ•ด. ๋กœ์ปฌ์—์„œ ๋นŒ๋“œํ•ด์„œ ์—…๋กœ๋“œํ•˜๋ฉด ๋˜๊ฑฐ๋“ !

๐ŸŒฉ๏ธ AWS Lambda

Lambda๋Š” Linux ํ™˜๊ฒฝ์ด๋‹ˆ๊นŒ:
GOOS=linux GOARCH=amd64
๋กœ ๋นŒ๋“œํ•˜๊ณ  ZIP์œผ๋กœ ์••์ถ•ํ•ด์„œ ์—…๋กœ๋“œ!

โ˜๏ธ Google Cloud Functions

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Linux ํ™˜๊ฒฝ:
GOOS=linux GOARCH=amd64
๋นŒ๋“œ ํ›„ ๋ฐฐํฌ ๋ช…๋ น์–ด ์‹คํ–‰!

๐Ÿ”ท Azure Functions

Windows๋‚˜ Linux ์„ ํƒ ๊ฐ€๋Šฅ:
GOOS=linux ๋˜๋Š”
GOOS=windows

๐Ÿš€ ์ผ๋ฐ˜ ์„œ๋ฒ„

์„œ๋ฒ„ OS์— ๋งž์ถฐ ๋นŒ๋“œ:
Ubuntu โ†’ GOOS=linux
CentOS โ†’ GOOS=linux

๐Ÿ“ฑ ๋ชจ๋ฐ”์ผ ์•ฑ ๋ฐฐํฌ

Go๋กœ ๋ชจ๋ฐ”์ผ ์•ฑ๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! gomobile ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ.

# gomobile ์„ค์น˜
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init

# Android์šฉ ๋นŒ๋“œ
gomobile bind -target=android -o myapp.aar

# iOS์šฉ ๋นŒ๋“œ
gomobile bind -target=ios -o MyApp.framework

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Android์™€ iOS์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋ผ! ๐Ÿ“ฑ

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ๊ณผ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ํ•ญ์ƒ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฑด ์•„๋‹ˆ์•ผ. ๋ช‡ ๊ฐ€์ง€ ์ฃผ์˜ํ•  ์ ๋“ค์ด ์žˆ์–ด! ๐Ÿ”

๐Ÿšซ CGO ์‚ฌ์šฉ ์‹œ ๋ฌธ์ œ

โš ๏ธ CGO ๊ด€๋ จ ์ฃผ์˜์‚ฌํ•ญ

CGO๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€(์˜ˆ: SQLite ๋“œ๋ผ์ด๋ฒ„)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ๋ณต์žกํ•ด์ ธ.
๊ฐ ํ”Œ๋žซํผ๋ณ„๋กœ C ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ•„์š”ํ•˜๊ฑฐ๋“ .

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:
โ€ข ์ˆœ์ˆ˜ Go ๊ตฌํ˜„ ํŒจํ‚ค์ง€ ์‚ฌ์šฉ (์˜ˆ: modernc.org/sqlite)
โ€ข Docker๋ฅผ ์‚ฌ์šฉํ•œ ๋นŒ๋“œ ํ™˜๊ฒฝ ๊ตฌ์ถ•
โ€ข ๊ฐ ํ”Œ๋žซํผ์—์„œ ์ง์ ‘ ๋นŒ๋“œ

๐Ÿ” ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฌธ์ œ

Windows์™€ Unix ๊ณ„์—ด OS๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ ๊ตฌ๋ถ„์ž๊ฐ€ ๋‹ฌ๋ผ. Windows๋Š” ๋ฐฑ์Šฌ๋ž˜์‹œ(\), Unix๋Š” ์Šฌ๋ž˜์‹œ(/)๋ฅผ ์‚ฌ์šฉํ•ด.

// ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•
path := "config\\app.json"  // Windows์—์„œ๋งŒ ์ž‘๋™

// ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
import "path/filepath"

path := filepath.Join("config", "app.json")  // ๋ชจ๋“  OS์—์„œ ์ž‘๋™

filepath ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด OS์— ๋งž๋Š” ๊ฒฝ๋กœ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค˜! ๐Ÿ‘

๐ŸŽญ ํ”Œ๋žซํผ๋ณ„ ๋™์ž‘ ์ฐจ์ด

์ผ๋ถ€ ๊ธฐ๋Šฅ์€ ํ”Œ๋žซํผ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ์‹œ์Šคํ…œ ์ฝœ์ด๋‚˜ ๋„คํŠธ์›Œํฌ ๊ด€๋ จ ๊ธฐ๋Šฅ๋“ค์ด ๊ทธ๋ž˜.

package main

import (
    "fmt"
    "runtime"
)

func main() {
    switch runtime.GOOS {
    case "windows":
        // Windows ์ „์šฉ ๋กœ์ง
        fmt.Println("Running on Windows")
    case "darwin":
        // macOS ์ „์šฉ ๋กœ์ง
        fmt.Println("Running on macOS")
    case "linux":
        // Linux ์ „์šฉ ๋กœ์ง
        fmt.Println("Running on Linux")
    default:
        fmt.Println("Unknown OS")
    }
}

runtime.GOOS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹คํ–‰ ์ค‘์ธ OS๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด!

๐Ÿงช ํ…Œ์ŠคํŠธ์˜ ์ค‘์š”์„ฑ

๐ŸŽฏ ๋ฐ˜๋“œ์‹œ ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ!

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋กœ ๋งŒ๋“  ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ๋กœ์ปฌ์—์„œ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ํ•ด์„œ ํƒ€๊ฒŸ ํ”Œ๋žซํผ์—์„œ๋„ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋Š” ๋ณด์žฅ์€ ์—†์–ด.
ํŠนํžˆ ๋‹ค์Œ ์‚ฌํ•ญ๋“ค์„ ๊ผญ ํ™•์ธํ•ด์•ผ ํ•ด:

โ€ข ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ถŒํ•œ
โ€ข ๋„คํŠธ์›Œํฌ ์„ค์ •
โ€ข ํ™˜๊ฒฝ ๋ณ€์ˆ˜
โ€ข ์™ธ๋ถ€ ์˜์กด์„ฑ
โ€ข ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค

๐Ÿ” ๋””๋ฒ„๊น… ํŒ

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์–ด๋ ค์šธ ๋•Œ๋Š” ์ด๋ ‡๊ฒŒ ํ•ด๋ด:

// ์ƒ์„ธํ•œ ๋กœ๊น… ์ถ”๊ฐ€
import "log"

log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Printf("OS: %s, Arch: %s", runtime.GOOS, runtime.GOARCH)

// ํŒจ๋‹‰ ๋ณต๊ตฌ
defer func() {
    if r := recover(); r != nil {
        log.Printf("Panic recovered: %v", r)
    }
}()

๐ŸŽจ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์˜ˆ์ œ

์ด๋ก ๋งŒ ๋ฐฐ์šฐ๋ฉด ์žฌ๋ฏธ์—†์ž–์•„? ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ๐Ÿ› ๏ธ

๐Ÿ“Š ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ

์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ.

// main.go
package main

import (
    "fmt"
    "runtime"
    "time"
)

type SystemInfo struct {
    OS           string
    Architecture string
    NumCPU       int
    GoVersion    string
}

func getSystemInfo() SystemInfo {
    return SystemInfo{
        OS:           runtime.GOOS,
        Architecture: runtime.GOARCH,
        NumCPU:       runtime.NumCPU(),
        GoVersion:    runtime.Version(),
    }
}

func getMemoryStats() runtime.MemStats {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    return m
}

func main() {
    info := getSystemInfo()
    
    fmt.Println("=== System Information ===")
    fmt.Printf("OS: %s\n", info.OS)
    fmt.Printf("Architecture: %s\n", info.Architecture)
    fmt.Printf("CPU Cores: %d\n", info.NumCPU)
    fmt.Printf("Go Version: %s\n", info.GoVersion)
    
    fmt.Println("\n=== Memory Statistics ===")
    
    for {
        mem := getMemoryStats()
        
        fmt.Printf("\rAlloc: %d MB | TotalAlloc: %d MB | Sys: %d MB | NumGC: %d",
            mem.Alloc/1024/1024,
            mem.TotalAlloc/1024/1024,
            mem.Sys/1024/1024,
            mem.NumGC)
        
        time.Sleep(1 * time.Second)
    }
}

์ด ํ”„๋กœ๊ทธ๋žจ์„ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์šฉ์œผ๋กœ ๋นŒ๋“œํ•ด๋ณด์ž!

#!/bin/bash
# build-monitor.sh

APP="sysmonitor"
VERSION="1.0.0"

# Windows
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o ${APP}-windows.exe

# macOS
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o ${APP}-mac-intel
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o ${APP}-mac-arm

# Linux
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ${APP}-linux

echo "Build completed!"

๐ŸŒ ๊ฐ„๋‹จํ•œ ์›น ์„œ๋ฒ„

ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์›น ์„œ๋ฒ„๋„ ๋งŒ๋“ค์–ด๋ณด์ž!

// server.go
package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    info := fmt.Sprintf(`
        <h1>Hello from Go Server!</h1>
        <p>OS: %s</p>
        <p>Architecture: %s</p>
        <p>Go Version: %s</p>
        <p>Request from: %s</p>
    `, runtime.GOOS, runtime.GOARCH, runtime.Version(), r.RemoteAddr)
    
    fmt.Fprintf(w, info)
}

func main() {
    http.HandleFunc("/", handler)
    
    port := ":8080"
    fmt.Printf("Server starting on http://localhost%s\n", port)
    fmt.Printf("OS: %s, Arch: %s\n", runtime.GOOS, runtime.GOARCH)
    
    if err := http.ListenAndServe(port, nil); err != nil {
        log.Fatal(err)
    }
}

์ด ์„œ๋ฒ„๋ฅผ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ์— ๋ฐฐํฌํ•˜๋ฉด, ๊ฐ ํ™˜๊ฒฝ์—์„œ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ด! ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿš€

๐Ÿ”ฎ ๊ณ ๊ธ‰ ํ™œ์šฉ ์‚ฌ๋ก€

์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋“ค์„ ์•Œ์•„๋ณด์ž! ์‹ค๋ฌด์—์„œ ์ •๋ง ์œ ์šฉํ•œ ํŒ๋“ค์ด์•ผ. ๐Ÿ’Ž

๐ŸŽญ ์กฐ๊ฑด๋ถ€ ์ปดํŒŒ์ผ ๊ณ ๊ธ‰ ํ™œ์šฉ

๋นŒ๋“œ ํƒœ๊ทธ๋ฅผ ์กฐํ•ฉํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด!

// config_dev.go
//go:build dev

package main

const (
    APIEndpoint = "http://localhost:8080"
    Debug       = true
)

// config_prod.go
//go:build prod

package main

const (
    APIEndpoint = "https://api.production.com"
    Debug       = false
)
# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋นŒ๋“œ
go build -tags dev -o myapp-dev

# ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋นŒ๋“œ
go build -tags prod -o myapp-prod

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ”Œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ

Go์˜ plugin ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ ์œผ๋กœ ๋กœ๋“œ๋˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
ํ•˜์ง€๋งŒ ์ฃผ์˜ํ•  ์ ์ด ์žˆ์–ด - ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ๋งŒ ์ž‘๋™ํ•ด!

// plugin.go
package main

import "fmt"

func Hello() {
    fmt.Println("Hello from plugin!")
}

// ํ”Œ๋Ÿฌ๊ทธ์ธ ๋นŒ๋“œ (Linux/macOS๋งŒ ์ง€์›)
go build -buildmode=plugin -o plugin.so plugin.go

๐Ÿ’ก ํ”Œ๋Ÿฌ๊ทธ์ธ ๋Œ€์•ˆ

Windows์—์„œ๋Š” plugin ํŒจํ‚ค์ง€๊ฐ€ ์ง€์›๋˜์ง€ ์•Š์•„. ๋Œ€์‹  ๋‹ค์Œ ๋ฐฉ๋ฒ•๋“ค์„ ๊ณ ๋ คํ•ด๋ด:
โ€ข gRPC๋ฅผ ์‚ฌ์šฉํ•œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค
โ€ข WebAssembly ๋ชจ๋“ˆ
โ€ข ๋ณ„๋„ ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰

๐ŸŒ ๊ตญ์ œํ™”(i18n) ์ง€์›

์—ฌ๋Ÿฌ ๋‚˜๋ผ์— ๋ฐฐํฌํ•  ๋•Œ๋Š” ๊ตญ์ œํ™”๊ฐ€ ์ค‘์š”ํ•ด!

package main

import (
    "fmt"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
)

func main() {
    // ํ•œ๊ตญ์–ด
    p := message.NewPrinter(language.Korean)
    p.Printf("์•ˆ๋…•ํ•˜์„ธ์š”! ์ˆซ์ž: %d\n", 1234567)
    
    // ์˜์–ด
    p = message.NewPrinter(language.English)
    p.Printf("Hello! Number: %d\n", 1234567)
    
    // ์ผ๋ณธ์–ด
    p = message.NewPrinter(language.Japanese)
    p.Printf("ใ“ใ‚“ใซใกใฏ! ๆ•ฐๅญ—: %d\n", 1234567)
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ์ง€์—ญ์— ๋งž๋Š” ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŒ

๐Ÿ“ˆ ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ์ตœ๋Œ€ํ•œ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์•Œ์•„๋ณด์ž! โšก

๐ŸŽฏ ์ปดํŒŒ์ผ๋Ÿฌ ์ตœ์ ํ™” ์˜ต์…˜

# ๊ธฐ๋ณธ ์ตœ์ ํ™”
go build -ldflags="-s -w" -o myapp

# ๋” ๊ณต๊ฒฉ์ ์ธ ์ตœ์ ํ™”
go build -ldflags="-s -w" -gcflags="all=-l -B" -o myapp

# ์ธ๋ผ์ด๋‹ ๋น„ํ™œ์„ฑํ™” (๋””๋ฒ„๊น…์šฉ)
go build -gcflags="all=-N -l" -o myapp-debug

๐ŸŽฏ gcflags ์˜ต์…˜ ์„ค๋ช…

-l: ์ธ๋ผ์ด๋‹ ๋น„ํ™œ์„ฑํ™”
-N: ์ตœ์ ํ™” ๋น„ํ™œ์„ฑํ™”
-B: ๋ฐ”์šด๋“œ ์ฒดํฌ ๋น„ํ™œ์„ฑํ™” (์œ„ํ—˜ํ•  ์ˆ˜ ์žˆ์Œ!)

ํ”„๋กœ๋•์…˜์—์„œ๋Š” -s -w๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•ด. ๋‹ค๋ฅธ ์˜ต์…˜๋“ค์€ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด!

๐Ÿ“ฆ ๋ฐ”์ด๋„ˆ๋ฆฌ ์••์ถ•

๋นŒ๋“œ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ UPX๋กœ ์••์ถ•ํ•˜๋ฉด ํฌ๊ธฐ๋ฅผ ๋” ์ค„์ผ ์ˆ˜ ์žˆ์–ด!

# UPX ์„ค์น˜ (macOS)
brew install upx

# UPX ์„ค์น˜ (Linux)
apt-get install upx

# ๋ฐ”์ด๋„ˆ๋ฆฌ ์••์ถ•
upx --best --lzma myapp

# ์••์ถ• ์ „ํ›„ ๋น„๊ต
ls -lh myapp*

โš ๏ธ UPX ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

โ€ข ์ผ๋ถ€ ์•ˆํ‹ฐ๋ฐ”์ด๋Ÿฌ์Šค๊ฐ€ ์˜คํƒํ•  ์ˆ˜ ์žˆ์–ด
โ€ข ์‹คํ–‰ ์‹œ ์••์ถ• ํ•ด์ œ ์‹œ๊ฐ„์ด ์ถ”๊ฐ€๋ผ
โ€ข ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ ธ
โ€ข ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด

๐Ÿš€ ๋ณ‘๋ ฌ ๋นŒ๋“œ

์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์„ ๋™์‹œ์— ๋นŒ๋“œํ•˜๋ฉด ์‹œ๊ฐ„์„ ๋งŽ์ด ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์–ด!

#!/bin/bash
# parallel-build.sh

build_platform() {
    local GOOS=$1
    local GOARCH=$2
    local output="myapp-${GOOS}-${GOARCH}"
    
    if [ "$GOOS" = "windows" ]; then
        output="${output}.exe"
    fi
    
    echo "Building for $GOOS/$GOARCH..."
    GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-s -w" -o "dist/$output" main.go
    echo "โœ“ Completed $GOOS/$GOARCH"
}

# ๋ณ‘๋ ฌ ์‹คํ–‰
build_platform "windows" "amd64" &
build_platform "darwin" "amd64" &
build_platform "darwin" "arm64" &
build_platform "linux" "amd64" &

# ๋ชจ๋“  ๋นŒ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
wait

echo "All builds completed!"

๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์‹คํ–‰ํ•˜๋ฉด ๋นŒ๋“œ ์‹œ๊ฐ„์ด ํฌ๊ฒŒ ๋‹จ์ถ•๋ผ! โฑ๏ธ

๐Ÿ›ก๏ธ ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

๋ฐฐํฌํ•  ๋•Œ๋Š” ๋ณด์•ˆ๋„ ์ •๋ง ์ค‘์š”ํ•ด! ๋ช‡ ๊ฐ€์ง€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์•Œ์•„๋ณด์ž. ๐Ÿ”’

๐Ÿ” ๋ฏผ๊ฐํ•œ ์ •๋ณด ์ œ๊ฑฐ

// ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• โŒ
const APIKey = "sk-1234567890abcdef"

// ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• โœ…
import "os"

apiKey := os.Getenv("API_KEY")
if apiKey == "" {
    log.Fatal("API_KEY environment variable is required")
}

์ ˆ๋Œ€๋กœ API ํ‚ค๋‚˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฝ”๋“œ์— ํ•˜๋“œ์ฝ”๋”ฉํ•˜๋ฉด ์•ˆ ๋ผ! ํ™˜๊ฒฝ๋ณ€์ˆ˜๋‚˜ ์„ค์ • ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด.

๐ŸŽญ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋‚œ๋…ํ™”

Go ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋ฆฌ๋ฒ„์Šค ์—”์ง€๋‹ˆ์–ด๋ง์ด ๋น„๊ต์  ์‰ฌ์šด ํŽธ์ด์•ผ. ์ค‘์š”ํ•œ ๋กœ์ง์ด ์žˆ๋‹ค๋ฉด ๋‚œ๋…ํ™”๋ฅผ ๊ณ ๋ คํ•ด๋ด.

# garble์„ ์‚ฌ์šฉํ•œ ๋‚œ๋…ํ™”
go install mvdan.cc/garble@latest

garble -literals -tiny build -o myapp-obfuscated main.go

๐Ÿ” garble ์˜ต์…˜

-literals: ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด ๋‚œ๋…ํ™”
-tiny: ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๊ธฐ ์ตœ์†Œํ™”
-seed: ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋นŒ๋“œ๋ฅผ ์œ„ํ•œ ์‹œ๋“œ

โœ… ์ฒดํฌ์„ฌ ์ƒ์„ฑ

๋ฐฐํฌํ•œ ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฒดํฌ์„ฌ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒŒ ์ข‹์•„!

#!/bin/bash
# generate-checksums.sh

cd dist

# SHA256 ์ฒดํฌ์„ฌ ์ƒ์„ฑ
for file in *; do
    if [ -f "$file" ]; then
        sha256sum "$file" >> checksums.txt
    fi
done

echo "Checksums generated in checksums.txt"

์‚ฌ์šฉ์ž๋“ค์€ ์ด ์ฒดํฌ์„ฌ์œผ๋กœ ๋‹ค์šด๋กœ๋“œํ•œ ํŒŒ์ผ์ด ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ›ก๏ธ

๐ŸŽ“ ์‹ค๋ฌด ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ข…ํ•ฉํ•ด์„œ, ์‹ค๋ฌด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ! ๐Ÿ“š

๐Ÿ“‹ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

myproject/
โ”œโ”€โ”€ cmd/
โ”‚   โ””โ”€โ”€ myapp/
โ”‚       โ””โ”€โ”€ main.go
โ”œโ”€โ”€ internal/
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ handler/
โ”‚   โ””โ”€โ”€ service/
โ”œโ”€โ”€ pkg/
โ”‚   โ””โ”€โ”€ utils/
โ”œโ”€โ”€ build/
โ”‚   โ”œโ”€โ”€ build.sh
โ”‚   โ””โ”€โ”€ Dockerfile
โ”œโ”€โ”€ dist/
โ”œโ”€โ”€ .goreleaser.yaml
โ”œโ”€โ”€ Makefile
โ”œโ”€โ”€ go.mod
โ””โ”€โ”€ go.sum

์ด๋Ÿฐ ๊ตฌ์กฐ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด ๊ด€๋ฆฌํ•˜๊ธฐ ์ •๋ง ํŽธํ•ด! ๐Ÿ—‚๏ธ

๐Ÿ”„ CI/CD ํŒŒ์ดํ”„๋ผ์ธ

์™„์ „ํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ.

# .github/workflows/ci-cd.yml

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Run tests
        run: go test -v -race -coverprofile=coverage.txt ./...
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage.txt

  build:
    needs: test
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v4
        with:
          version: latest
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  docker:
    needs: test
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            myapp:latest
            myapp:${{ github.ref_name }}

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ํ‘ธ์‹œํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ณ , ํƒœ๊ทธ๋ฅผ ๋‹ฌ๋ฉด ์ž๋™์œผ๋กœ ๋นŒ๋“œํ•˜๊ณ  ๋ฐฐํฌํ•ด! ์™„์ „ ์ž๋™ํ™”! ๐Ÿค–

๐Ÿ“ ๋ฌธ์„œํ™”

README์— ํ”Œ๋žซํผ๋ณ„ ์„ค์น˜ ๋ฐฉ๋ฒ•์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด!

# MyApp

## Installation

### Windows
```powershell
# Download the latest release
curl -LO https://github.com/user/myapp/releases/latest/download/myapp-windows-amd64.exe

# Run
.\myapp-windows-amd64.exe
```

### macOS
```bash
# Intel Mac
curl -LO https://github.com/user/myapp/releases/latest/download/myapp-darwin-amd64
chmod +x myapp-darwin-amd64
./myapp-darwin-amd64

# Apple Silicon (M1/M2)
curl -LO https://github.com/user/myapp/releases/latest/download/myapp-darwin-arm64
chmod +x myapp-darwin-arm64
./myapp-darwin-arm64
```

### Linux
```bash
curl -LO https://github.com/user/myapp/releases/latest/download/myapp-linux-amd64
chmod +x myapp-linux-amd64
./myapp-linux-amd64
```

## Docker
```bash
docker run -it myapp:latest
```

์‚ฌ์šฉ์ž๋“ค์ด ์‰ฝ๊ฒŒ ๋”ฐ๋ผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช…ํ™•ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด! ๐Ÿ“–

๐ŸŽ‰ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€! ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์–ด. Go์˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์— ๋Œ€ํ•ด ์ •๋ง ๋งŽ์€ ๊ฑธ ๋ฐฐ์› ์ง€? ๐ŸŽŠ

โœจ ํ•ต์‹ฌ ์š”์•ฝ

1. ๊ฐ„๋‹จํ•œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ
GOOS์™€ GOARCH ํ™˜๊ฒฝ๋ณ€์ˆ˜๋งŒ ์„ค์ •ํ•˜๋ฉด ๋!

2. ์ž๋™ํ™”๊ฐ€ ํ•ต์‹ฌ
์Šคํฌ๋ฆฝํŠธ, Makefile, GoReleaser๋กœ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž๋™ํ™”ํ•˜์ž.

3. Docker์™€์˜ ์กฐํ•ฉ
๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ๋กœ ์ตœ์†Œ ํฌ๊ธฐ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

4. CI/CD ํ†ตํ•ฉ
GitHub Actions ๋“ฑ์œผ๋กœ ์™„์ „ ์ž๋™ํ™”๋œ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜์ž.

5. ๋ณด์•ˆ๊ณผ ํ…Œ์ŠคํŠธ
ํ•ญ์ƒ ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ณ , ๋ณด์•ˆ์„ ๊ณ ๋ คํ•˜์ž.

Go์˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๊ธฐ๋Šฅ์€ ์ •๋ง ๊ฐ•๋ ฅํ•ด. ํ•œ ๋ฒˆ์˜ ๋นŒ๋“œ๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑด ์—„์ฒญ๋‚œ ์žฅ์ ์ด์•ผ! ๐Ÿš€
ํŠนํžˆ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋‚˜ CLI ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค ๋•Œ ์ด ๊ธฐ๋Šฅ์ด ๋น›์„ ๋ฐœํ•ด.

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„, ์ด๋Ÿฐ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜๋ฉด ๋” ๋งŽ์€ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์–ด.
Windows ์‚ฌ์šฉ์ž๋“ , Mac ์‚ฌ์šฉ์ž๋“ , Linux ์‚ฌ์šฉ์ž๋“  ๋ชจ๋‘๊ฐ€ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐Ÿ’ช

๐ŸŽฏ ๋‹ค์Œ ๋‹จ๊ณ„

์ด์ œ ์ง์ ‘ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ์‹ค์Šตํ•ด๋ณด๋Š” ๊ฒŒ ์ค‘์š”ํ•ด!
๊ฐ„๋‹จํ•œ CLI ๋„๊ตฌ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ, ์ ์  ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๋ฐœ์ „์‹œ์ผœ๋ณด์ž.

โ€ข ๊ฐ„๋‹จํ•œ ํŒŒ์ผ ๋ณ€ํ™˜ ๋„๊ตฌ
โ€ข ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง ์œ ํ‹ธ๋ฆฌํ‹ฐ
โ€ข ์›น ์„œ๋ฒ„๋‚˜ API ์„œ๋ฒ„
โ€ข ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ

๋ญ๋“  ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ๋ฐฐ์šฐ๋Š” ๊ฒŒ ์ตœ๊ณ ์•ผ! ๐ŸŽจ

Go์˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์€ ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•œ๋ฒˆ ์ต์ˆ™ํ•ด์ง€๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•ด.
๋” ์ด์ƒ ์—ฌ๋Ÿฌ ์ปดํ“จํ„ฐ๋ฅผ ์˜ค๊ฐ€๋ฉฐ ๋นŒ๋“œํ•  ํ•„์š”๊ฐ€ ์—†์–ด. ๋‚ด ๋งฅ๋ถ์—์„œ ๋ชจ๋“  ํ”Œ๋žซํผ์šฉ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ! โœจ

์ด ๊ธ€์ด Go ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์–ด.
๊ถ๊ธˆํ•œ ์ ์ด ์žˆ๊ฑฐ๋‚˜ ๋” ์•Œ๊ณ  ์‹ถ์€ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด, Go ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ฐธ์—ฌํ•ด์„œ ๋ฌผ์–ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ! ๐Ÿค

์ž, ์ด์ œ ๋‹น์‹ ์˜ Go ํ”„๋กœ์ ํŠธ๋ฅผ ์ „ ์„ธ๊ณ„ ๋ชจ๋“  ํ”Œ๋žซํผ์— ๋ฐฐํฌํ•ด๋ณด์ž! ๐ŸŒ
Happy coding! ๐ŸŽ‰

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.