文章目录
感慨&概述
问题一:minio容器和本地容器时间不一致
问题二:minio修改时间和本地查询结果不一致 具体问题 原因探究 解决办法 时间转化工具类 调用测试和验证 上传文件说明
感慨&概述
在使用minio(容器部署方式)的过程中,由于使用容器时间和本地时间不同,然后寻求解决方法,花费了很多时间,然后才有以下的收获和整理。整个过程耗费不少时间。 本文章对于bitnami/minio:latest
和minio/minio
在问题二:minio修改时间和本地查询结果不一致 上均适用。在问题一:minio容器和本地容器时间不一致 上bitnami/minio:latest
在部署时,使用TZ=Asia/Shanghai
即可解决问题。
补充:MINIO_REGION和容器时间的关系
region描述的是服务器的物理位置,默认是us-east-1(美国东区1),也是亚马逊S3的默认区域。可以通过MINIO_REGION
环境变量进行修改 修改MINIO_REGION
并不能解决,容器时间和本地时间问题,也不能解决文件最后修改时间在web控制台和java查询时间不一致的问题。这个可能是为了minio容器部署时,划分机器用的(如果错误,请大佬指导) 当然,注意如果设置了MINIO_REGION
请在java代码中配置同样的时区设置,否则导致代码运行失败,因为时区相差太大无法正常连接到minio 当启动MinIO Docker容器时,可以通过设置环境变量MINIO_REGION
来指定区域(如无需要,建议不要配置 )
docker run -p 9000 :9000 --name minio1 \
-e "MINIO_ROOT_USER=minioadmin" \
-e "MINIO_ROOT_PASSWORD=minioadmin" \
-e "MINIO_REGION=cn-north-1" \
-e "TZ=Asia/Shanghai" \
minio/minio server /data
@Configuration
public class Config {
@Bean
public MinioClient minioClient ( ) {
return MinioClient . builder ( )
. region ( "cn-north-1" )
. endpoint ( "http://192.168.1.18:9000" )
. credentials ( "minioadmin" , "minioadmin" )
. build ( ) ;
}
}
问题一:minio容器和本地容器时间不一致
问题说明
原因探究
这里不再详述探究的过程,简略地给出研究思路、方法。 研究思路:查看容器中使用的时区,将其修改为东八区。 研究过程和结果:在该版本容器内查看没有常见的linux时区设置的目录和文件,不过通过复制本地的文件到,minio容器中重新设置时区,可以成功解决容器时区和本地时区不一致的问题。
解决方法
查看容器信息
docker ps
例如:运行中的MInio容器ID为 826ab07a0a42 ,名称为 minio [root@yang ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
826ab07a0a42 minio/minio:RELEASE. 2024-04-06T05-26-02Z "/usr/bin/docker-ent…" 14 minutes ago Up 14 minutes 0. 0. 0. 0:9001->9000/tcp, :::9001->9000/tcp, 0. 0. 0. 0:9000->9001/tcp, :::9000->9001/tcp minio
进入容器创建时区文件目录
docker exec - it docker_Minio_name bash
docker exec - it docker_Minio_ID bash
mkdir - p / usr/share/zoneinfo/Asia/
exit
复制本地时区文件到容器
[root@localhost ~]
[root@yang ~]
Successfully copied 2. 56kB to minio:/ usr/share/zoneinfo/Asia/
再次进入容器内部,修改本地时间
docker exec - it docker_Minio_name bash
docker exec - it docker_Minio_ID bash
ln - s / usr/share/zoneinfo/Asia/Shanghai / etc/localtime
bash-5. 1
结果验证
使用命令查看容器和本机时间是否一致
bash-5. 1
Sat May 4 23:58:36 CST 2024
bash-5. 1
exit
[root@yang ~]
2024年 05月 04日 星期六 23:58:43 CST
Minio上传文件测试时间是否生效 在观察页面显示正常,但是遗憾的是,如果使用java minio客户端查询还是显示相差八小时。(这是第二个问题)
问题二:minio修改时间和本地查询结果不一致
具体问题
minio在web管理显示的文件最后修改时间和本地一致,然后使用java代码查询出来的时间和本地时间差八个小时 查询代码和结果
@Test
void testObjectExists ( ) throws ServerException , InsufficientDataException , ErrorResponseException , IOException , NoSuchAlgorithmException , InvalidKeyException , InvalidResponseException , XmlParserException , InternalException {
StatObjectResponse response = minioClient. statObject (
StatObjectArgs . builder ( )
. bucket ( "test02" )
. object ( "image.jpg" )
. build ( )
) ;
System . out. println ( response) ;
}
ObjectStat { bucket= test02, object= image. jpg, last- modified= 2024 - 05 - 04 T06 : 53 : 55 Z, size= 563102 }
原因探究
MinIO存储文件的元数据时,通常会使用UTC(协调世界时间)来记录时间戳。这意味着无论实际的物理服务器位置如何,时间都会按照UTC来记录。但在Web管理界面中,MinIO会根据浏览器的时区设置自动调整显示时间,使其看起来与本地时间一致。 当使用Java代码通过MinIO的API查询文件的最后修改时间时,如果没有正确处理时区,Java可能会默认将UTC时间作为本地时间(即不进行时区转换)来处理。导致看到的时间比实际的本地时间少8小时(中国大陆时间为UTC+8)。
解决办法
Java代码在处理时间时将UTC时间转换为本地时间(虽然麻烦,但只能这么解决问题)
时间转化工具类
import java. lang. annotation. Retention ;
import java. time. Instant ;
import java. time. ZoneId ;
import java. time. ZonedDateTime ;
import java. time. format. DateTimeFormatter ;
import java. time. format. DateTimeFormatterBuilder ;
public class TimeConverter {
private static final DateTimeFormatter isoFormatter = new DateTimeFormatterBuilder ( )
. append ( DateTimeFormatter . ISO_LOCAL_DATE )
. appendLiteral ( 'T' )
. append ( DateTimeFormatter . ISO_LOCAL_TIME )
. optionalStart ( )
. appendOffsetId ( )
. optionalEnd ( )
. toFormatter ( ) ;
private static final DateTimeFormatter customFormatter = new DateTimeFormatterBuilder ( )
. append ( DateTimeFormatter . ISO_LOCAL_DATE )
. appendLiteral ( 'T' )
. append ( DateTimeFormatter . ISO_LOCAL_TIME )
. appendLiteral ( 'Z' )
. toFormatter ( ) ;
public static String convertUtcToLocal ( String utcTimeString) {
String zoneIdString= "Asia/Shanghai" ;
return convertUtcToLocal ( utcTimeString, zoneIdString) ;
}
public static String convertUtcToLocal ( String utcTimeString, String zoneIdString) {
Instant utcTime = Instant . parse ( utcTimeString) ;
ZonedDateTime localTime = utcTime. atZone ( ZoneId . of ( zoneIdString) ) ;
DateTimeFormatter formatter = customFormatter. withZone ( ZoneId . of ( zoneIdString) ) ;
return formatter. format ( localTime) ;
}
public static String convertLocalToUtc ( String localTimeString) {
String zoneIdString= "Asia/Shanghai" ;
return convertLocalToUtc ( localTimeString, zoneIdString) ;
}
public static String convertLocalToUtc ( String localTimeString, String zoneIdString) {
ZonedDateTime localTime = ZonedDateTime . parse ( localTimeString, customFormatter. withZone ( ZoneId . of ( zoneIdString) ) ) ;
Instant utcTime = localTime. toInstant ( ) ;
return isoFormatter. format ( utcTime. atZone ( ZoneId . of ( "UTC" ) ) ) ;
}
public static void main ( String [ ] args) {
String utcTime = "2024-05-07T04:20:00Z" ;
System . out. println ( "原UTC时间: " + utcTime) ;
System . out. println ( "转换为北京时间: " + convertUtcToLocal ( utcTime) ) ;
String shanghaiTime = "2024-05-20T20:20:00Z" ;
System . out. println ( "从北京时间转换回UTC时间: " + convertLocalToUtc ( shanghaiTime) ) ;
}
}
调用测试和验证
测试类代码@SpringBootTest
class MinioApplicationTests {
@Resource
private MinioClient minioClient;
@Test
void testObjectExists ( ) throws Exception {
StatObjectResponse response = minioClient. statObject (
StatObjectArgs . builder ( )
. bucket ( "test02" )
. object ( "image.jpg" )
. build ( )
) ;
System . out. println ( "修改前文件信息:" + response) ;
String localLastModifiedTime = TimeConverter . convertUtcToLocal ( response. lastModified ( ) . toString ( ) ) ;
ZonedDateTime localLastModified = ZonedDateTime . parse ( localLastModifiedTime) ;
try {
Field lastModifiedField = response. getClass ( ) . getDeclaredField ( "lastModified" ) ;
lastModifiedField. setAccessible ( true ) ;
lastModifiedField. set ( response, localLastModified) ;
} catch ( NoSuchFieldException | IllegalAccessException e) {
e. printStackTrace ( ) ;
}
System . out. println ( "修改后文件信息:" + response) ;
}
}
测试结果修改前文件信息:ObjectStat{ bucket= test02, object = image.jpg, last-modified= 2024 -05-04T06:53:55Z, size = 563102 }
修改后文件信息:ObjectStat{ bucket= test02, object = image.jpg, last-modified= 2024 -05-04T14:53:55Z, size = 563102 }
上传文件说明
在查询文件信息时,需要将文件修改时间进行本地化转化,但是在上传文件的时候,我没找到直接设置文件修改时间的配置。所以,上传文件的时候,正常上传就行。
@Test
void testObjectUpload ( ) throws Exception {
ObjectWriteResponse response = minioClient. uploadObject (
UploadObjectArgs . builder ( )
. bucket ( "test02" )
. object ( "image3.jpg" )
. filename ( "src/main/resources/picture/image.jpg" )
. build ( )
) ;
System . out. println ( response) ;
}
上传成功后,在web控制台正常显示本地时间。查询时,使用工具类就可以了!