[linux] 타임존 바꿨는데 DB·도커 시간이 그대로일 때
timedatectl 로 OS 타임존을 바꿔도 DB와 컨테이너는 옛 시간을 씁니다. 같은 클러스터 안에서 NOW() 가 9시간 차이 나던 사례와, 재시작 없이는 반영되지 않는 이유입니다.

서버 약 60대의 타임존을 점검했더니 21대가 UTC였습니다. 로그 시각이 서버마다 9시간씩 달라 장애를 추적할 때마다 머릿속으로 시차를 더하고 있었습니다.
timedatectl set-timezone Asia/Seoul 을 돌렸습니다. date 를 찍어보니 전부 한국 시간이 나왔습니다. 여기서 끝난 줄 알았습니다.
같은 클러스터인데 NOW() 가 9시간 달랐습니다
며칠 뒤 DB 쪽을 확인하다 이상한 것을 봤습니다. 3노드 클러스터인데 노드마다 NOW() 결과가 달랐습니다.
노드 A NOW() 18:44:xx system_time_zone = KST
노드 B NOW() 09:44:xx system_time_zone = UTC
노드 C NOW() 09:44:xx system_time_zone = UTC
OS 타임존은 세 대 모두 Asia/Seoul 이었습니다. 그런데 DB만 옛 시간을 쓰고 있었습니다.
MariaDB는 기동할 때 OS의 타임존을 읽어 system_time_zone 에 캐싱합니다. 그 뒤로는 OS 설정이 바뀌어도 다시 읽지 않습니다. 노드 A만 KST였던 것은 그 노드의 DB가 타임존 변경 이후에 한 번 재시작됐기 때문이었습니다.
같은 문제가 컨테이너에도 있습니다. Docker 컨테이너는 호스트의 /etc/localtime 을 따라가지 않고 이미지 안의 설정을 씁니다. 대부분의 베이스 이미지는 UTC입니다. 호스트를 아무리 바꿔도 컨테이너 안은 그대로입니다.
정리하면 타임존은 세 개의 층에 따로 존재합니다.

세 층을 각각 확인하는 명령은 이렇습니다.
timedatectl # OS
mysql -e "SELECT @@system_time_zone" # DB 프로세스
docker exec <name> date # 컨테이너
date 하나만 보고 넘어가면 아래 두 층은 영영 확인하지 않게 됩니다.
무중단으로 갈지, 재시작할지
여기서 선택지가 갈립니다.
OS만 바꿔두고 다음 정기 재시작 때 자연히 반영되게 두는 것도 방법입니다. 무중단이고, 어차피 재부팅은 언젠가 합니다. 다만 그때까지 DB 로그와 애플리케이션 로그의 시각이 어긋난 채로 남습니다.
이번에는 DB만 순차 재시작하기로 했습니다. 클러스터라 한 대씩 내려도 서비스가 유지되기 때문입니다.
재시작 전에 클러스터 상태부터 확인했습니다.
3노드 전부 Synced / Primary
동일한 cluster_state_uuid
last_committed 값 일치
세 대의 커밋 지점이 같다는 것은 복제가 밀리지 않았다는 뜻입니다. 이 상태가 아니라면 한 대를 내리는 순간 나머지가 흔들릴 수 있습니다.
그다음 한 대씩 재시작했습니다. 동시 재시작은 절대 하지 않습니다. 쿼럼을 잃으면 클러스터가 통째로 멈춥니다.
1. 노드 B 재시작 -> 10초 만에 Synced 복귀, cluster_size=3
2. 다른 노드에서 교차 확인 (3노드 전부 목록에 있는지, Primary 유지되는지)
3. 노드 C 재시작 -> 동일하게 10초
데이터량이 적어 전체 동기화 없이 증분으로 따라잡았습니다. 재시작 후 system_time_zone 이 세 대 모두 KST가 됐고 NOW() 도 1초 이내로 일치했습니다.
시간대가 아니라 시각 자체가 틀린 서버도 있었습니다
점검하는 김에 시각 오차도 쟀는데 6대가 어긋나 있었습니다. 가장 심한 것은 105초였습니다.
원인은 대부분 같았습니다. 인터넷 아웃바운드가 없는 서버들이었습니다. 기본 NTP 서버가 ntp.ubuntu.com 같은 외부 주소로 잡혀 있는데, 그 서버는 밖으로 나가지 못하니 영원히 동기화에 실패합니다. 그리고 그 실패는 아무 소리도 내지 않습니다.
내부 NTP 서버를 지정해 해결했습니다.
# chrony 쓰는 노드
server <내부NTP> iburst prefer # chrony.conf 최상단
chronyc makestep # 즉시 보정
# systemd-timesyncd 쓰는 노드
# /etc/systemd/timesyncd.conf.d/10-internal-ntp.conf
[Time]
NTP=<내부NTP>
6대 모두 오차가 0~1초로 들어왔습니다. NTP 서버를 내부에 두는 것은 폐쇄망뿐 아니라 아웃바운드가 제한된 서버가 하나라도 있으면 필요합니다.
점검 항목으로 만들었습니다
한 번 맞춰두면 끝나는 일이 아닙니다. 새로 만든 서버는 기본값이 UTC일 수 있고, DB는 재시작할 때마다 그 시점의 OS 설정을 다시 읽습니다.
그래서 매일 도는 점검에 넣었습니다.
| 점검 항목 | 등급 |
|---|---|
타임존이 Asia/Seoul 이 아님 |
CRITICAL |
| 시각 오차 10초 초과 | WARNING |
| 시각 오차 60초 초과 | CRITICAL |
| 클러스터 노드 간 DB 타임존 불일치 | CRITICAL |
| OS는 KST인데 DB만 아님 | WARNING (재시작 필요 신호) |
마지막 두 줄이 이번에 겪은 문제를 그대로 잡아내는 항목입니다. OS와 DB를 따로 보지 않으면 이 상태를 발견할 수 없습니다.
조사에서 두 번 놓칠 뻔했습니다
전수 점검을 병렬로 돌리다 보면 몇 대는 응답이 늦어 타임아웃이 납니다. 그걸 “접속 실패”로 묶어두고 넘어갔는데, 나중에 개별로 다시 붙어보니 멀쩡한 서버였고 타임존도 UTC였습니다. 하마터면 대상에서 빠질 뻔했습니다.
조사 실패는 “해당 없음”이 아닙니다. 실패한 항목은 반드시 개별 재시도해야 합니다.
다른 하나는 더 조용했습니다. SSH 설정 파일에 등록되지 않은 서버가 한 대 있었는데, 조사 스크립트가 그 파일을 기준으로 목록을 만들다 보니 애초에 점검 대상에 들어오지도 않았습니다. 결과 보고서에는 실패로도 안 나옵니다. 그냥 없는 서버가 됩니다.
인벤토리와 조사 대상 목록을 교차 검증하지 않으면 이런 누락은 드러나지 않습니다.
정리
timedatectl로 바꾼 것은 OS뿐입니다. DB와 컨테이너는 각자의 시점에 각자 읽습니다- DB는 재시작해야 반영됩니다. 클러스터라면 상태를 확인하고 한 대씩 순차로 합니다
- 컨테이너는 재생성하거나
TZ환경변수를 주입해야 합니다 - 아웃바운드가 없는 서버는 공용 NTP에 영원히 실패합니다. 조용히 실패하므로 오차를 직접 재봐야 합니다
시간이 어긋난 서버는 평소에는 아무 문제를 일으키지 않습니다. 장애가 났을 때 여러 서버의 로그를 나란히 놓고 순서를 따질 때 비로소 문제가 됩니다. 그때는 이미 늦습니다.