东八区时区解决的补充(抄来的)

文章目录
一、场景描述
二、问题分析
三、解决方案
一、场景描述
  在采用容器化部署应用程序的过程中,发现写日志的时间是正确的东八区时间,但是容器内部采用 date 获取的时间比实际东八区的时间慢了八个小时(这里一直比较纠结这个八小时用什么动词来修饰,网上很多人用 晚 、 早,但是站在东八区来理解这两个动词,似乎都有点奇怪。纠结很久,还是以东八区的时间为参照物,来定义默认时间比东八区时间慢了八个小时吧)。

宿主机的时间

[root@~ /]# date
2020年 12月 22日 星期二 18:39:24 CST
1
2
写入日志的时间

2020-12-22 18:40:23.233  INFO [,c19fc6564922e71f,54009447514b80af,true] 1 --- [http-nio-9013-exec-10] c.m.report.common.aspect.LogAspect       :

容器中的时间

[root@~ /]# docker exec -it app /bin/bash
bash-4.4# date
Tue Dec 22 10:39:54 UTC 2020

此容器的Dockerfile定义

# From 基础镜像
FROM openjdk:8-jre-alpine3.9

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

# 自定义环境变量
ENV TZ=Asia/Shanghai

# 设置本地系统时间和时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]


CST     China Standard Time
UTC     Coordinated Universal Time

/etc/localtime  对应 date 指令本地时间
/etc/timezone   对应 java 所获取的时区

二、问题分析
通过以上 Dockerfile 可以了解到,本次实验采用的是 openjdk:8-jre-alpine3.9 最精简的版本,镜像大小 84.9M

Dockerfile 中设置本地时间和时区并写入到时间配置文件中

问题分析和研究结论:

由于 openjdk 采用的 Linux 环境的镜像是 alpine 的,其镜像特别小,集成 openjdk 也能很好的控制在 100M 左右,因此应用非常广泛,在 Docker Hub 中有大量基于 Linux alpine 版本的 JRE 镜像

# 如何验证容器采用的 Linux 内核
# 进入容器内部
docker exec -it 容器ID sh

# 查看 Linux 内核
cat /etc/issue

alpine 的镜像使用的是默认时区,并且也不存在 /usr/share/zoneinfo 路径和相关文件

为什么 Docker 容器中的日志时间却是对的呢?原因是由于以下命令将 Asia/Shanghai 配置指向了容器中的 /etc/timezone 时间,而日志输出和 JAVA 程序获取时间都是通过 /etc/timezone 这个时间配置获取的

ENV TZ=Asia/Shanghai
# 如果是基于 Alpine 的 Linux 镜像, && 前面的部分是不起作用的(因为 Alpine Linux 中都没有这个路径),所以进入容器后采用 date 查看时区还是 UTC 的时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone

通过以上的操作,只是将程序读取的时间设置成了东八区的时间,但是容器中的时区还是 UTC时区,如果涉及到别的程序,比如写 MySQL 的时候,就有可能存在时间不对的问题

所以,建议在构建镜像时设置了时间配置文件的同时,也需要将 Linux 时区也设置为东八区

三、解决方案
欢迎使用此镜像

FROM ramboyang/openjdk-alpine:jre-8u212-timezone-ttf
1
解决方案一

编写基于 openjdk:8-jre-alpine3.9 镜像制作包含时间组件镜像的 Dockerfile

# 基础镜像
FROM openjdk:8-jre-alpine3.9

# 设置东八区时间
ENV TZ=Asia/Shanghai

# 安装时间组件 + 安装 ttf-dejavu 解决生成验证码空指针异常问题
# 1.1 版本
# RUN apk update && apk upgrade && apk add ca-certificates && update-ca-certificates && apk add --update tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && apk add --update curl bash ttf-dejavu && rm -rf /var/cache/apk/*

# 1.2 版本
# RUN apk update && apk upgrade && apk add --update tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && apk add --update curl bash ttf-dejavu && rm -rf /var/cache/apk/*

# 1.3 版本
RUN apk add --update tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && apk add --update ttf-dejavu && rm -rf /var/cache/apk/* 

# 1.4 版本
# RUN apk add --update tzdata && cp /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone && rm -rf /var/cache/apk/*

基于以上定制的 Dockerfile 构建基础镜像

# 1.1 版本
docker build -t ramboyang/openjdk-alpine:jre-8u212-cert-timezone-ttf .

# 1.2 版本
docker build -t ramboyang/openjdk-alpine:jre-8u212-timezone-ttf-bash .

# 1.3 版本
docker build -t ramboyang/openjdk-alpine:jre-8u212-timezone-ttf .

# 1.4 版本
docker build -t ramboyang/openjdk-alpine:jre-8u212-timezone .

将本地镜像推送至 Docker Hub 个人公有仓库

docker login

# 1.1 版本
docker push ramboyang/openjdk-alpine:jre-8u212-cert-timezone-ttf

# 1.2 版本
docker push ramboyang/openjdk-alpine:jre-8u212-timezone-ttf-bash

# 1.3 版本
docker push ramboyang/openjdk-alpine:jre-8u212-timezone-ttf

# 1.4 版本
docker push ramboyang/openjdk-alpine:jre-8u212-timezone

采用此镜像为基础镜像构建 JAVA 应用

# From 基础镜像(包含了东八区的设置、ttf-dejavu绘制验证码组件)
FROM ramboyang/openjdk-alpine:jre-8u212-timezone-ttf

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]

解决方案二

点击此处获取所需的非 alpine 内核的 openjdk

非 alpine 内核的 openjdk 一般都存在本地时间文件夹和时区文件,采用以下 Dockerfile 即可完成容器内本地时间和时区的设置

# From 基础镜像
FROM openjdk:8u275-jre-slim

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

# 自定义环境变量
ENV TZ=Asia/Shanghai

# 设置本地系统时间和时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]

解决方案三

Dockerfile 文件中设置 JAVA 应用读取的时间配置文件

# From 基础镜像
FROM openjdk:8-jre-alpine3.9

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

# 设置本地系统时间和时区
RUN Asia/Shanghai > /etc/timezone

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]

将镜像启动设置容器共享宿主机的时区

docker run --name spring-boot-sample -v /etc/localtime:/etc/localtime:ro -p 8888:8888 镜像ID
1
解决方案四

从一台有时间文件夹的 Linux 服务器复制出 zoneinfo 文件夹到 Dockerfile 所在构建文件夹

cp -r /usr/share/zoneinfo Dockerfile所在构建文件夹目录
1
Dockerfile 构建镜像时将本地 zoneinfo 文件夹复制到 Alpine Linux 系统中的固定目录

# From 基础镜像
FROM openjdk:8-jre-alpine3.9

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

# 复制时间文件夹到指定 Alpine 目录
COPY zoneinfo /usr/share/zoneinfo/

# 自定义环境变量
ENV TZ=Asia/Shanghai

# 设置本地系统时间和时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]

解决方案五(不推荐)

在构建镜像过程中安装时区组件(受网络的影响,会导致构建镜像变慢或者失败)

# From 基础镜像
FROM openjdk:8-jre-alpine3.9

# 定义镜像创建者
LABEL maintainer=Rambo@xx.com

#安装时区组件
RUN apk add -U tzdata

# 自定义环境变量
ENV TZ=Asia/Shanghai

# 设置本地系统时间和时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone

# 前端界面路径
# RUN mkdir -p /opt/java/front/sample-web

# 后端程序路径
WORKDIR /opt/java/spring-boot-sample

COPY ./*.jar ./spring-boot-sample.jar

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "./spring-boot-sample.jar"]

K8S容器时区问题解决

方法一

在制作容器镜像时候,将时区问题解决

RUN rm -f /etc/localtime && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone

方法二

采用hostpath方式将主机时区挂载至容器内部
          volumeMounts:
            - mountPath: /etc/localtime
              name: time_name
      volumes:
        - hostPath:
            path: /usr/share/zoneinfo/Asia/Shanghai
            type: ''
          name: time_name

nginx伪静态try_files和rewrite

location ^~ /location {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
}

完整的解释是:try_files 去尝试到网站目录读取用户访问的文件,如果第一个变量存在,就直接返回;不存在继续读取第二个变量,如果存在,直接返回;不存在直接跳转到第三个参数上。变量就是每个uri资源。并不改变请求路径。 $uri表示文件资源, $uri/表示目录资源。

location ^~ /location {
    root /usr/share/nginx/html;
    index index.html index.htm;
    rewrite http://www.baidu.com break;
}

请求location,跳转至百度,改变请求路径。break表示不再向下匹配。

hpa自动扩容缩

kubectl autoscale deployment 名称 --cpu-percent=80 --min=3 --max=6 -n 命名空间
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: gsvauth-v1
  namespace: istio-system
spec:
  maxReplicas: 6
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: gsvauth-v1
  targetCPUUtilizationPercentage: 80

secret模板

生成系统变量的模板

apiVersion: v1
kind: Secret
metadata:
  name: gitlogin
  namespace: template
type: Opaque
data:
  username: xxxxx ## 直接base64直接转码后挂进来 使用"echo 字符串 | base64加密,使用echo 字符串 | base64 -d解密"
  password: xxxxx ## 此处密码被挂载到git服务中,其中含有@字符,必须将“@”转义成“%40”,然后进行base64转换成密码
---
apiVersion: batch/v1
kind: Job
metadata:
  name: git
  namespace: template
spec:
  template:
    metadata:
      name: git
      labels:
        app: git
        version: v1
      spec:
        containers:
          - name: git
            image: bitnami/git:latest
            workingDir: /tmp
            command:
              - "sh"
              - "-c"
              - git clone -b dev https://${username}:${password}@xxx.git && echo "job done!"
              #- env
            env:
              - name: username
                valueFrom:
                  secretKeyRef:
                    name: gitlogin
                    key: username
              - name: password
                valueFrom:
                  secretKeyRef:
                    name: gitlogin
                    key: password
        restartPolicy: OnFailure