💡 개요

컨테이너 환경에서 애플리케이션을 운영할 때, 정확한 타임존(Timezone) 설정은 매우 중요하다. 로그 기록, 데이터베이스 시간 동기화, 스케줄링된 작업 등 다양한 영역에서 시간 정보가 일관되지 않으면 예상치 못한 문제나 오류가 발생할 수 있다. 이 문서에서는 Docker 컨테이너의 타임존을 설정하는 다양한 방법과 각 방법의 특징을 살펴보았다.

💬 이슈

쿠버네티스(Kubernetes) 상에 동작 중인 파드(Pod)마다 서로 다른 timezone을 가지고 있었고, 이를 GMT+9 (Asia/Seoul)로 일괄 변환하는 방법이 필요했다.

🧗 해결

컨테이너의 타임존을 설정하는 주요 방법은 다음과 같다.

1. Dockerfile을 통한 설정 (Build-time)

컨테이너 이미지를 빌드하는 시점에 Dockerfile 내에서 타임존을 설정하는 방법이다. 이 방법은 컨테이너가 시작될 때마다 별도의 설정 없이 일관된 타임존을 보장하여 가장 권장되는 방식 중 하나이다.

  • 원리: 대부분의 Linux 시스템은 /etc/timezone 파일에 타임존 정보를 저장하거나, /etc/localtime 파일이 실제 타임존 데이터 파일(예: /usr/share/zoneinfo/Asia/Seoul)을 가리키는 심볼릭 링크로 구성된다. tzdata 패키지는 이러한 타임존 데이터 파일을 제공한다. ENV TZ 명령어는 컨테이너 내부의 환경 변수를 설정하여 시스템이 해당 타임존을 사용하도록 지시한다.
# 예시: Ubuntu/Debian 기반 이미지
FROM ubuntu:latest
 
# tzdata 패키지 설치 (타임존 데이터 제공)
# noninteractive 모드로 설치하여 사용자 입력 없이 진행
RUN apt-get update && apt-get install -y tzdata && rm -rf /var/lib/apt/lists/*
 
# 환경 변수 TZ를 Asia/Seoul로 설정
ENV TZ=Asia/Seoul
 
# 애플리케이션 실행 명령어 (예시)
CMD ["/bin/bash"]
  • 장점:
    • 이미지 자체에 타임존 정보가 포함되어 있어 이식성이 높다.
    • 컨테이너 실행 시 별도의 설정이 필요 없어 관리가 용이하다.
    • 빌드 시점에 타임존이 고정되므로 예측 가능하다.
  • 단점:
    • 타임존 변경 시 이미지를 다시 빌드해야 한다.
    • tzdata 패키지 설치로 인해 이미지 크기가 약간 증가할 수 있다.

2. Volume Mount를 통한 설정 (Run-time)

호스트 시스템의 타임존 정보를 컨테이너 내부로 마운트하여 사용하는 방법이다. 이 방법은 컨테이너 이미지를 수정하지 않고 런타임에 타임존을 유연하게 설정할 수 있다.

  • 원리: 호스트 시스템의 /etc/localtime 파일 또는 /usr/share/zoneinfo 디렉토리를 컨테이너 내부의 /etc/localtime 경로로 마운트한다. 컨테이너는 마운트된 호스트의 타임존 정보를 사용하게 된다.

Docker CLI

$ docker run -d \
  -v /etc/localtime:/etc/localtime:ro \
  -v /usr/share/zoneinfo/Asia/Seoul:/etc/localtime:ro # 특정 타임존 파일 마운트 (더 명시적)
  your-image-name
  • /etc/localtime:/etc/localtime:ro: 호스트의 현재 타임존 설정을 컨테이너로 읽기 전용(read-only)으로 마운트한다.
  • /usr/share/zoneinfo/Asia/Seoul:/etc/localtime:ro: 호스트의 특정 타임존 데이터 파일(Asia/Seoul)을 컨테이너의 /etc/localtime로 마운트한다. 이 방법은 호스트의 현재 타임존 설정과 무관하게 컨테이너에 특정 타임존을 강제할 때 유용하다.

Kubernetes 환경

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: your-image-name
        volumeMounts:
        - name: tz-config
          mountPath: /etc/localtime # /etc/localtime 파일을 마운트
          readOnly: true
      volumes:
      - name: tz-config
        hostPath:
          path: /usr/share/zoneinfo/Asia/Seoul # 호스트의 Asia/Seoul 타임존 파일을 사용
          type: File # 파일임을 명시
  • 장점:
    • 이미지 재빌드 없이 런타임에 타임존을 변경할 수 있다.
    • 호스트의 타임존과 동기화하거나, 호스트에 존재하는 특정 타임존 파일을 선택하여 사용할 수 있다.
  • 단점:
    • 컨테이너가 호스트 시스템에 의존하게 된다. 호스트의 타임존 설정이 변경되면 컨테이너에도 영향을 미친다.
    • hostPath 사용 시 노드 간 이식성이 저하될 수 있다 (모든 노드에 동일한 타임존 파일이 존재해야 한다).
    • 보안상의 이유로 hostPath 사용을 제한하는 환경도 있다.

3. 환경 변수 TZ만 설정 (Run-time)

컨테이너 이미지에 이미 tzdata 패키지가 설치되어 있는 경우, TZ 환경 변수만 설정하여 타임존을 변경할 수 있다.

  • 원리: TZ 환경 변수는 C 라이브러리(glibc)에서 시간을 처리할 때 참조하는 타임존을 지정한다. tzdata 패키지가 설치되어 있다면, /usr/share/zoneinfo 경로에 다양한 타임존 데이터 파일이 존재하며, TZ 변수는 이 중 어떤 파일을 사용할지 알려주는 역할을 한다.

Docker CLI

$ docker run -d \
  -e TZ=Asia/Seoul \
  your-image-name

Kubernetes 환경

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: your-image-name
        env:
        - name: TZ
          value: Asia/Seoul
  • 장점:
    • 가장 간단하고 유연한 방법이다.
    • 이미지 재빌드 없이 런타임에 타임존을 변경할 수 있다.
  • 단점:
    • 컨테이너 이미지 내부에 tzdata 패키지가 미리 설치되어 있어야 한다. 그렇지 않으면 TZ 환경 변수가 제대로 작동하지 않거나 기본 UTC로 동작할 수 있다.

4. timedatectl 명령어 사용 (컨테이너 내부)

일부 컨테이너 이미지에는 systemd가 포함되어 있지 않아 timedatectl 명령어를 직접 사용할 수 없는 경우가 많다. 하지만 디버깅 목적이나 특정 베이스 이미지에서는 유용할 수 있다.

# 컨테이너 내부에서 실행 (예시)
$ docker exec -it <container_id> /bin/bash
# 컨테이너 쉘 내부에서
$ timedatectl set-timezone Asia/Seoul
  • 장점: 컨테이너 내부에서 직접 시스템 타임존을 설정하는 것과 유사한 효과를 낼 수 있다.
  • 단점: 대부분의 경량 컨테이너 이미지에는 systemdtimedatectl이 포함되어 있지 않아 사용하기 어렵다. 컨테이너 재시작 시 설정이 유지되지 않을 수 있다.

✅ 확인

컨테이너 내부에서 타임존이 올바르게 설정되었는지 확인하는 방법이다.

# date 명령어 사용
$ date
Tue Nov 22 07:44:20 KST 2022 # 예시 출력: KST (한국 표준시)로 표시되었다.
 
# timedatectl 명령어 사용 (timedatectl이 설치된 경우)
$ timedatectl
               Local time: 2022-11-22 07:44:20 KST
           Universal time: 2022-11-21 22:44:20 UTC
                 RTC time: 2022-11-21 22:44:20
                Time zone: Asia/Seoul (KST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

🚀 요약

방법장점단점권장 시나리오
Dockerfile이미지에 타임존 내장, 이식성 높음, 일관된 설정 보장이미지 재빌드 필요, 이미지 크기 약간 증가대부분의 프로덕션 환경, 일관된 타임존이 필요한 경우
Volume Mount이미지 재빌드 불필요, 런타임 유연성, 호스트와 동기화 가능호스트 의존성, 노드 간 이식성 저하, hostPath 보안 문제런타임에 타임존 변경이 잦거나 호스트와 동기화가 필요한 경우
환경 변수 TZ가장 간단, 이미지 재빌드 불필요, 런타임 유연성tzdata 설치 필수, 설치되지 않은 경우 기본 UTCtzdata가 포함된 경량 이미지 사용 시, 간단한 설정
timedatectl컨테이너 내부에서 직접 설정 가능대부분의 경량 이미지에서 사용 불가, 컨테이너 재시작 시 설정 유지 안됨, 디버깅 목적 외 비권장디버깅 목적, 특정 베이스 이미지 사용 시

🔗 참고