π‘ κ°μ
컨ν μ΄λ νκ²½μμ μ ν리μΌμ΄μ μ μ΄μν λ, μ νν νμμ‘΄(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-nameKubernetes νκ²½
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- μ₯μ : 컨ν μ΄λ λ΄λΆμμ μ§μ μμ€ν νμμ‘΄μ μ€μ νλ κ²κ³Ό μ μ¬ν ν¨κ³Όλ₯Ό λΌ μ μλ€.
- λ¨μ : λλΆλΆμ κ²½λ 컨ν
μ΄λ μ΄λ―Έμ§μλ
systemdλtimedatectlμ΄ ν¬ν¨λμ΄ μμ§ μμ μ¬μ©νκΈ° μ΄λ ΅λ€. 컨ν μ΄λ μ¬μμ μ μ€μ μ΄ μ μ§λμ§ μμ μ μλ€.
β νμΈ
컨ν μ΄λ λ΄λΆμμ νμμ‘΄μ΄ μ¬λ°λ₯΄κ² μ€μ λμλμ§ νμΈνλ λ°©λ²μ΄λ€.
# 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 μ€μΉ νμ, μ€μΉλμ§ μμ κ²½μ° κΈ°λ³Έ UTC | tzdataκ° ν¬ν¨λ κ²½λ μ΄λ―Έμ§ μ¬μ© μ, κ°λ¨ν μ€μ |
timedatectl | 컨ν μ΄λ λ΄λΆμμ μ§μ μ€μ κ°λ₯ | λλΆλΆμ κ²½λ μ΄λ―Έμ§μμ μ¬μ© λΆκ°, 컨ν μ΄λ μ¬μμ μ μ€μ μ μ§ μλ¨, λλ²κΉ λͺ©μ μΈ λΉκΆμ₯ | λλ²κΉ λͺ©μ , νΉμ λ² μ΄μ€ μ΄λ―Έμ§ μ¬μ© μ |
π μ°Έκ³
- https://dev.to/0xbf/set-timezone-in-your-docker-image-d22
- Docker 곡μ λ¬Έμ: Configure timezone (ENV λͺ λ Ήμ΄ κ΄λ ¨)
- Kubernetes 곡μ λ¬Έμ: Volumes - hostPath (hostPath κ΄λ ¨)
- Linux man page: tzset(3) (TZ νκ²½ λ³μ κ΄λ ¨)