빠른 흐름
port, ok := os.LookupEnv("PORT")
if !ok {
port = "8080"
}
debug, err := strconv.ParseBool(os.Getenv("DEBUG"))
if err != nil {
debug = false
}Go 설정 코드는 환경 변수는 문자열이고, 누락과 빈 값을 구분해야 한다는 점에서 시작합니다.
기본 흐름
값만 필요하면 Getenv를 쓴다
dsn := os.Getenv("DATABASE_URL")Getenv는 값이 없으면 빈 문자열을 돌려줍니다. 빈 문자열도 유효한 값인지, 누락으로 봐야 하는지는 호출부에서 판단해야 합니다.
누락 여부가 중요하면 LookupEnv를 쓴다
value, ok := os.LookupEnv("DATABASE_URL")
if !ok {
return errors.New("DATABASE_URL is required")
}LookupEnv는 환경 변수가 존재했는지 알려 줍니다. 필수 설정이나 빈 값 허용 여부가 중요한 설정은 LookupEnv가 더 명확합니다.
숫자와 bool은 직접 파싱한다
raw := os.Getenv("PORT")
port, err := strconv.Atoi(raw)
if err != nil {
return Config{}, fmt.Errorf("invalid PORT: %w", err)
}환경 변수는 항상 문자열입니다. port, timeout, feature flag처럼 타입이 있는 값은 시작 시점에 파싱하고 실패를 빨리 드러내는 편이 좋습니다.
설정 구조
설정은 struct로 모은다
type Config struct {
Port int
DatabaseURL string
Debug bool
}환경 변수를 필요한 곳마다 직접 읽으면 테스트와 검증이 어려워집니다. 시작 시점에 한 번 읽어 Config로 모으면 필수 값 검증, 기본값, 타입 변환을 한 곳에서 관리할 수 있습니다.
func LoadConfig() (Config, error) {
port, err := strconv.Atoi(getenvDefault("PORT", "8080"))
if err != nil {
return Config{}, err
}
return Config{
Port: port,
Debug: os.Getenv("DEBUG") == "true",
}, nil
}선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 값만 읽음 | os.Getenv |
| 누락과 빈 값 구분 | os.LookupEnv |
| 필수 설정 | 시작 시점 검증 |
| 숫자 설정 | strconv.Atoi |
| bool 설정 | strconv.ParseBool |
| 여러 설정 관리 | Config struct |
주의할 점
환경 변수는 편하지만 타입 검증과 필수 값 검증을 자동으로 해 주지 않습니다. 서버가 요청을 받은 뒤 설정 오류를 처음 발견하는 구조보다, 프로세스 시작 시점에 설정을 읽고 실패를 명확히 내는 구조가 운영에 더 안전합니다. 비밀 값은 로그에 남기지 않습니다.
참고 링크
2 sources