我們經常會發現docker和宿主機的時間是不同步的,這幾乎是個坑,特別是數據庫系統,時間錯誤簡直要命。這時間一般是相差8小時,因我們的時間是東八區時間,而docker用的是標準時間:
CST是指(China Shanghai Time,東八區時間)
UTC是指(Coordinated Universal Time,標準時間)
這2個時間相差8個小時,一般沒有設置過的容器,跟宿主機時間相差8h,通過date命令就能看出來。雖然這個問題很簡單,但沒人提醒的話,一頓找別的原因,也足以讓很多人抓狂(我在部署docker版的skywalking時就犯了這個錯,怎麼修改配置都看不到監控數據,因爲當前收集的數據全變成8小時前的歷史數據了)。
遇到docker時區不一致,我們只需要對其進行同步處理就可以了,但由於docker運行的基礎操作系統不同,或者系統裏沒裝時區工具或是沒有zoneinfo信息,那麼我們的處理方式就略有不同:
1. Docker常用的運行環境
docker常用的操作系統包括busybox、alpine、debian、ubuntu、centos,它們的大小都不一樣,適用的範圍也會有區別,一般由docker中部署的項目特性來決定,鏡像大小肯定也是優先考慮的因素:
基本上除了busybox,大部分的linux系統都可以通過命令 cat /etc/issue 來獲知其系統版本:
# 進入容器命令行
docker exec -it [container_name | container_id] /bin/sh
##########################################
/ # cat /etc/issue
Welcome to Alpine Linux 3.12
Kernel \r on an \m (\l)
##########################################
root@9f1fc6293ff9:/# cat /etc/issue
Debian GNU/Linux 10 \n \l
#########################################
[root@qa ~]# cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m
對於CentOS / Redhat 可以通過 cat /etc/redhat-release 來看具體版本:
[root@localhost ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
busybox和alpine系統在bin目錄下,可以找到busybox文件:
/ # find /bin |grep busybox
/bin/busybox
對於docker環境,除了進入容器用以上的命令查看方式來判斷操作系統版本,有時候可以通過鏡像文件dockerfile的images標識或是RUN命令來判斷(其實不好判斷,一般apk命令是針對alpine,apt-get是針對debian或ubuntu,yum命令是針對centos):
2. busybox下同步時區
busybox是極度輕量版的操作系統,很多時候沒法安裝時區數據文件,我們可以採用簡單粗暴方式,直接從宿主機拷。
# 查看是否有Shanghai時區文件
ls /usr/share/zoneinfo/Asia/Shanghai
# 如果沒有就需要獲取時區文件,先進入busybox,如container_id=be318f78137f
docker exec -ti be318f78137f /bin/sh
mkdir -p /usr/share
exit
# 拷貝宿主機的時區文件到docker中
docker cp /usr/share/zoneinfo be318f78137f:/usr/share/zoneinfo
# 進入busybox,同步時區
docker exec -ti be318f78137f /bin/sh
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
同步完時間後,通過date命令就可以看到時間已和宿主機同步。
另外也可以在dockerfile中完成這個工作:
# 需將/usr/share/zoneinfo先拷到dockerfile的目錄下
COPY zoneinfo /usr/share/zoneinfo/
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
3. alpine下同步時區
alpine默認也是沒有時區文件,也需要安裝:
# 進入容器命令行
docker exec -it [container_name | container_id] /bin/sh
# 安裝 timezone 數據包,爲了防止添加失敗,加上-U參數,更新倉儲緩存。
apk add -U tzdata
# 列出安裝的時區文件,驗證是否下載成功。
ls /usr/share/zoneinfo
# 拷貝需要的時區文件到localtime,國內需要的是Asia/Shanghai:
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 驗證時區,CST 即爲中國標準時間。
date
# Tue Jun 30 11:53:46 CST 2020
# 移除時區文件:
apk del tzdata
另外也可以在dockerfile中添加以下內容,完成時區的構建:
# Install root filesystem
ADD ./rootfs /
# Install base packages
RUN apk update && apk add curl bash tree tzdata \
&& cp -r -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo -ne "timezone Asia/Shanghai. (`uname -rsv`)\n" >> /root/.built
4. debian / ubuntu下同步時區
# 進入容器命令行
docker exec -it [container_name | container_id] /bin/bash
# 列出安裝的時區文件,驗證是否存在tzdata。
ls /usr/share/zoneinfo
# 一般是已經安裝了 timezone 數據包,如未安裝則執行
apt-get install tzdata
# 軟鏈接時區文件到localtime
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
另外也可以在dockerfile中添加以下內容,完成時區的構建:
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
5. centos下同步時區
# 進入容器命令行
docker exec -it [container_name | container_id] /bin/bash
# 一般都已經安裝了 timezone 數據包,如遇到未安裝則執行
yum install -y tzdata
# 軟鏈接時區文件到localtime
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
在dockerfile中可以添加:
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' >/etc/timezone
如果你獲取的docker鏡像沒有root權限,你又着急馬上進入容器修改時區,那就簡單暴力一點,直接從宿主機拷入時區文件到docker中,來實現時區的修改:
docker cp /usr/share/zoneinfo/Asia/Shanghai 容器ID:/etc/localtime
echo 'Asia/Shanghai' >/etc/timezone && docker cp /etc/timezone 容器ID:/etc/timezone