I have a Dockerfile
which builds a Rust application and puts it in a scratch
image.
# build application
FROM ubuntu:latest as system-deps
RUN apt-get update && apt-get install -y tzdata
FROM scratch
COPY --from=system-deps /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=app-builder --chown=myuser:myuser /app/ryot /app
ENTRYPOINT ["/app"]
However, regardless of what timezone I specify using the --env TZ="<a valid timezone>"
docker flag, I always get the current UTC.
How can I make it respect the timezone?
Here is an article I found pertaining to Go projects: Using local time in a Golang Docker container built from Scratch | by Chris Binder | Medium
Entire dockerfile: https://github.com/IgnisDa/ryot/blob/ec3194eee6840f4eed902d7fa1a78a6824d8f878/Dockerfile#L45
This question is not specific to Rust. Add a /etc/localtime
symlink via the Dockerfile. See localtime(5) - Linux manual page
But that makes me have to hardcore the value at docker build time. I want the users to be able to set the TZ
environment variable.
Ok, do it the hard way.
You aren’t really supposed to change the environment in Rust, but you can if you isolate it. It just ends up being code that is completely unnecessary.
As I said in my original post, I am already settings the environment variable.
My question is why is Rust not respecting it?
Hyeonu
July 14, 2023, 1:18am
10
Wht does it mean by Rust not respecting it? Are you using crates like time
or chrono
?
The chrono
crate uses types like Local
and Utc
to set the timezone, where Local
comes from the system (i.e. /etc/localtime
). For example, chrono::DateTime<Utc>
will give you UTC times.
If you want it dynamically configured via a $TZ
environment variable then create your own TimeZone
implementation that does what you want. To the best of my knowledge, there is no built-in thing that uses a $TZ
environment variable for setting the timezone, so it's not surprising that --env TZ=...
does nothing.
mpol
July 14, 2023, 8:59pm
13
But doesn't chrono use TZ
?
#[cfg(not(target_os = "android"))]
let bytes = fs::read(format!("{}/{}", TZDB_LOCATION, tz_name)).ok()?;
#[cfg(target_os = "android")]
let bytes = android_tzdata::find_tz_data(&tz_name).ok()?;
TimeZone::from_tz_data(&bytes).ok()
}
impl Default for Cache {
fn default() -> Cache {
// default to UTC if no local timezone can be found
let env_tz = env::var("TZ").ok();
let env_ref = env_tz.as_deref();
Cache {
last_checked: SystemTime::now(),
source: Source::new(env_ref),
zone: current_zone(env_ref),
}
}
}
fn current_zone(var: Option<&str>) -> TimeZone {
1 Like
bjorn3
July 15, 2023, 8:17am
14
I think the issue is that the scratch layer doesn't contain the timezone database, so it fails to load the timezone file for the TZ
you specified causing a fallback to UTC. https://github.com/chronotope/chrono/blob/38b19bbe4e21c402f81edfa2932a43831e679a35/src/offset/local/tz_info/timezone.rs#L614 Chrono looks in /usr/share/zoneinfo
, /share/zoneinfo
, /etc/zoneinfo
and /usr/share/lib/zoneinfo
in that order. Try copying the timezone database from your host system or download it from Time Zone Database
3 Likes
riking
July 18, 2023, 7:38pm
15
Build FROM gcr.io/distroless/base
instead of FROM scratch
. That will include the time zone database and libc.
# Documentation for `gcr.io/distroless/base` and `gcr.io/distroless/static`
## Image Contents
This image contains a minimal Linux, glibc-based system. It is intended for use directly by "mostly-statically compiled" languages like Go, Rust or D.
Statically compiled applications (Go) that do not require libc can use the `gcr.io/distroless/static` image, which contains:
* ca-certificates
* A /etc/passwd entry for a root user
* A /tmp directory
* tzdata
Most other applications (and Go apps that require libc/cgo) should start with `gcr.io/distroless/base`, which contains all
of the packages in `gcr.io/distroless/static`, and
* glibc
* libssl
* openssl
This file has been truncated. show original