개발자의 오르막

golang과 Docker로 환경변수 제어하기 본문

GoLang

golang과 Docker로 환경변수 제어하기

계단 2022. 8. 23. 18:19

 

환경변수란?


https://acaroom.net/ko/blog/youngdeok/%EC%97%B0%EC%9E%AC-%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%B3%80%EC%88%98%EC%99%80-%EC%9E%90%EB%A3%8C%ED%98%95

 

 

환경변수는 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임이다.

 

우리가 흔히 Java 와 golang 을 처음 설치할 때 설정해주는 JAVA_HOME, GO_PATH 처럼 서버에서 특정 값을 담아, 해당 변수만 호출하여 다른 프로세스도 그 값을 참조하게끔 사용하는 변수이다.

그렇다면 위의 환경변수는 우리가 개발할 때 어떤 용도로 많이 쓰일 수 있을까?

  • 하나의 서버에서 여러 프로세스가 공통적으로 사용하는 정보
    • ex) DB 접속 정보, 언어 환경변수, 주키퍼와 같은 접속서버
  • 하나의 프로세스가 여러 서버에 배포되는 경우
    • DEV, STAGE, PROD 등 같은 프로세스이지만 다른 서버에 배포될 때

우리는 제일 보편적으로 config 파일에서 사용하는 정보를 환경변수로 전달할 수 있으며, 이를 Docker나 쿠버네티스를 통해 각 서버마다 다른 환경변수로 손 쉽게 정보를 전달할 수 있다.

이렇게 사용하면 접속 정보가 변경된다 하더라도, 우리는 일일이 config 파일을 업데이트 하여 올리지 않을 수 있다.

 

 

그럼 먼저 어플리케이션에서 환경변수를 어떻게 로직으로 담을 수 있는지 알아보자.

 

 

Golang 의 Envconfig


  • envconfig 는 환경 변수에서 구성을 분석하고 임의의 구조체를 채울 수 있는 라이브러리
  • 지원 유형
    • time.Duration 은 기본 지원
    • slices 및 arrays
    • struct
    • Unmarshaler 인터페이스를 통한 사용자 정의 유형
  • config.cfg 파일을 파싱해서 변수로 사용하는 것보다 환경변수를 활용하여 변수로 활용하게 되면 Docker 나 Kube 에서 환경변수로 지정한 값으로 자유롭게 활용 가능하다. (config.cfg 파일 변경 소요가 없어짐)

 

 

Basic Code

package main

import (
    "fmt"
    "log"

    "github.com/kelseyhightower/envconfig"
)

type Config struct {
    Foo string `default:"bar"`
}

func main() {
    var cfg Config
    if err := envconfig.Process("app", &cfg); err != nil {
        log.Fatalln(err)
    }
    fmt.Println(cfg.Foo)
}
  • Config 구조체에 입력한 필드에 대한 default 값은 envconfig.Process("app", &cfg) 를 통해 값이 주입된다.
  • 이 때 주의할 점은 구조체의 필드는 대문자로 해야 사용할 수 있다.
  • golang 에서는 환경변수를 담을 수 있는 구조체를 선언하고, 해당 환경변수의 값이 존재하면 그 값을 주입하며, 없을 때는 default 에 명시된 값을 주입한다.

 

위처럼 어플리케이션에서 환경변수가 존재하는 경우 그 값을 구조체에 담아 사용하는 것을 알 수 있었다. 그럼 이러한 환경변수는 어디서 설정하여 어떻게 전달하는 걸까?

 

 

물론 실제 서버에 들어가서 export {환경변수명}={환경변수값} 의 cmd 로 직접 지정하는 방법도 있다. 하지만 우리 개발자가 일일이 모든 서버에 들어가서 환경변수 값을 수정할 것은 아니기 때문에 다른 방법이 있어야 한다.

 

 

 

Docker 로 환경변수 값 전달하기


 

도커는 서비스를 컨테이너화 시켜 하나의 서버 안에서 독립적인 환경을 만들어주는 서비스이다. 기본적으로는 각 컨테이너끼리 다른 컨테이너의 정보를 모르기 때문에, Docker 를 구동하는 호스트에서 해당 정보를 알려줘야 한다. 이 때 우리는 환경변수를 사용한다.

 

 

환경변수 지정 방법

  • Dockerfile 로 환경변수 지정
  • Docker run 명령어를 실행 시 환경변수 지정

 

 

Dockerfile 로 환경변수 지정

ENV LANG ko_KR.UTF-8
ENV LANGUAGE ko_KR.UTF-8
ENV LC_ALL ko_KR.UTF-8

환경변수를 ENV {환경변수 이름} {환경변수 값} 의 형태로 도커파일에서 지정하면 도커 이미지를 빌드할 때 위의 환경변수에 값이 주입되어 사용할 수 있게된다.

 

Docker run 명령어를 통한 환경변수 사용

도커 이미지를 이용해 컨테이너를 만들 때마다 환경변수를 변경하고 싶을 때가 있다. 그럴 때 사용하는 것이 docker run 수행시 환경변수를 지정하는 것이다.

sudo docker run -e HOME=/home/complusblog/workspace/helloword helloworld

위처럼 docker run -e {환경변수이름}={환경변수값} 의 형태로 사용하면 환경변수에 값이 주입된다.

 

 

 

Docker 환경변수 적용 여부에 대한 확인 방법

  • 환경변수가 잘 적용되었는지는 docker inspect {컨테이너ID} 명령어를 통해 알 수 있다.
  • 다른 방법으로 docker exec {컨테이너ID} env 를 통해서 알 수 있다.
  • docker exec -it {컨테이너ID} bin/bash 로 해당 컨테이너에 들어가 export 명령어를 선언하면 적용된 환경변수 목록을 알 수 있다.

 

 

그러나 우리는 환경변수가 너무 많아지면 아래와 같은 명령어를 사용해야 할 수도 있다.

sudo docker run -d -t -i -e REDIS_NAMESPACE='staging' \
-e POSTGRES_ENV_POSTGRES_PASSWORD='foo' \
-e POSTGRES_ENV_POSTGRES_USER='bar' \
-e POSTGRES_ENV_DB_NAME='mysite_staging' \
-e POSTGRES_PORT_5432_TCP_ADDR='docker-db-1.hidden.us-east-1.rds.amazonaws.com' \
-e SITE_URL='staging.mysite.com' \
-p 80:80 \
--link redis:redis \
--name container_name dockerhub_id/image_name

 

예를들면 DEV, STAGE, PROD 에는 각기 다른 환경변수를 전달해야 하는데, 그럼 각 서버별로 환경변수를 다르게 한 명령어를 사용해야 하는 단점이 생길 수 있다. 뿐만 아니라 이는 배포할 때 개발자가 명령어를 잘못치면 오류상황이 야기될 수도 있다.

 

 

 

Docker Compose 에서 각 서비스 컨테이너에 환경변수 전달


Docker Compose 란 복수 개의 컨테이너를 실행시키는 도커 어플리케이션이 정의를 하기 위한 툴입니다.

Compose 를 사용하면 YAML 파일을 사용하여 애플리케이션의 서비스를 구성할 수 있습니다.

docker Compose 를 이용하면 각 컨테이너 별 같은 환경변수에 서로 다른 값을 넣는 것을 정의할 수 있다.

 

 

  • docker-compose.yml
version: '3.1'

services:
	zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181
  • ZOO_MY_ID , ZOO_SERVERS 는 같은 환경변수임에 불구하고, docker-compose.yml 에서 서로 다른 값을 주입하여 활용될 수 있음을 보여준다.

 

 

version: '3.5'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile-dev

특히 docker compose 는 각 서비스 별 참조하는 도커파일을 지정할 수 있기 때문에 용도별, 서버별 Dockerfile 을 따로 생성하여 해당 컨테이너를 실행시킬 수 있습니다.

 

 

 

 

환경변수 값이 선택되는 우선순위


  • Compose 파일에 직접 입력한 값
  • 쉘 환경변수로 등록한 값
  • 환경변수 파일로 입력된 값 ( .env 등 )
  • Dockerfile 을 통해 삽입된 값

 

 

 

Reference


 

 

 

Comments