解决容器时区问题
# 背景
业务程序在使用时间的时候(比如打印日志),没有指定时区,使用的系统默认时区,而基础镜像一般默认使用 UTC 时间,程序输出时间戳的时候,就与国内的时间相差 8 小时,如何使用国内的时间呢?本文教你如何解决。
# 方案一:指定 TZ 环境变量
很多编程语言都支持 TZ 这个用于设置时区的环境变量,可以在部署工作负载的时候,为容器指定该环境变量,示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: app
env:
- name: TZ
value: Asia/Shanghai
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 方案二:Dockerfile 里设置时区
下面给出在一些常见的基础镜像里设置时区的示例:
#ubuntu
FROM ubuntu:latest
RUN apt update -y && \
DEBIAN_FRONTEND="noninteractive" apt -y install tzdata
RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata
#alpine
FROM alpine:latest
# 安装 tzdata,复制里面的时区文件后删除 tzdata,保持精简
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
apk del tzdata && \
echo "Asia/Shanghai" > /etc/timezone
#centos
FROM centos:latest
RUN rm -f /etc/localtime \
&& ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 方案三:挂载主机时区配置到容器(不推荐)
最后一种思路是将 Pod 所在节点的时区文件挂载到容器内 /etc/localtime,这种方式对 Pod 有一定侵入性,而且依赖主机内时区配置,在不得已的情况下不推荐使用。
下面是 YAML 示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: app
volumeMounts:
- name: tz
mountPath: /etc/localtime
volumes:
- name: tz
hostPath:
path: /etc/localtime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 方法四:手动强制注入配置并重启
既然 Helm 没能把配置传递到 Pod,我们现在直接操作 Kubernetes 对象来达到目的。
# 1. 手动注入环境变量(最保底方案,100%生效)
这是解决此类问题最直接、最可靠的方法。我们直接修改运行中的 StatefulSet 或 Deployment,把 TZ=Asia/Shanghai 这个环境变量写进去。
请按顺序执行以下命令:
第一步:查看有哪些资源需要修改
集群版 VictoriaLogs 通常包含 vlstorage (StatefulSet)、vlinsert 和 vlselect (Deployment) 等组件。先用命令确认一下:
bash
kubectl get statefulset,deployment -n $NAMESPACE | grep vlc
第二步:为每个资源注入环境变量
你需要对列出的每个资源(如 vlc-vlstorage, vlc-vlinsert, vlc-vlselect)执行类似的操作。
如果资源是 StatefulSet(如 vlstorage):
bash
kubectl set env statefulset/vlc-vlstorage -n $NAMESPACE TZ=Asia/Shanghai1如果资源是 Deployment(如 vlinsert/vlselect):
bash
kubectl set env deployment/vlc-vlinsert -n $NAMESPACE TZ=Asia/Shanghai kubectl set env deployment/vlc-vlselect -n $NAMESPACE TZ=Asia/Shanghai1
2
为什么这个操作会重启? 当你使用
kubectl set env修改环境变量时,这直接改变了 Pod 的模板定义。Kubernetes 检测到这个变化后,会立即触发这些 Pod 的滚动更新。
# 2. 手动触发 Pod 重启(兜底操作)
如果上面 set env 命令执行后,Pod 还是没有反应(极少数情况),我们可以通过强制删除来重启。
执行滚动重启(推荐,无中断):
bash
# 根据你实际的资源类型选择
kubectl rollout restart statefulset/vlc-vlstorage -n $NAMESPACE
kubectl rollout restart deployment/vlc-vlinsert -n $NAMESPACE
kubectl rollout restart deployment/vlc-vlselect -n $NAMESPACE
2
3
4
或者,直接删除 Pod(有短暂中断,但最彻底):
bash
# 删除后,Kubernetes 会立即自动重建新的 Pod
kubectl delete pod --all -n $NAMESPACE
2
# helm安装操作
# 使用 values.yaml 文件(推荐生产环境)
创建一个 values.yaml 文件,包含所有配置:
# values.yaml
vlstorage:
persistentVolume:
storageClassName: nfs-csi
size: "100Gi"
retentionPeriod: "30d"
replicaCount: 3
# 时区配置 - 方法一
env:
TZ: "Asia/Shanghai"
# 时区配置 - 方法二(备用)
extraVolumes:
- name: localtime
hostPath:
path: /etc/localtime
extraVolumeMounts:
- name: localtime
mountPath: /etc/localtime
readOnly: true
vlinsert:
image:
registry: docker.1ms.run
env:
TZ: "Asia/Shanghai"
extraVolumes:
- name: localtime
hostPath:
path: /etc/localtime
extraVolumeMounts:
- name: localtime
mountPath: /etc/localtime
readOnly: true
vlselect:
image:
registry: docker.1ms.run
env:
TZ: "Asia/Shanghai"
extraVolumes:
- name: localtime
hostPath:
path: /etc/localtime
extraVolumeMounts:
- name: localtime
mountPath: /etc/localtime
readOnly: true
vmauth:
enabled: true
global:
image:
registry: docker.1ms.run
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
然后使用以下命令安装:
helm install vlc ./victoria-logs-cluster-0.0.20.tgz \
--namespace $NAMESPACE \
--timeout 15m \
--values values.yaml
2
3
4
|