mirror of
https://github.com/offen/docker-volume-backup.git
synced 2026-04-28 11:15:36 +02:00
Support reading timezone info from env (#748)
* add tzdata package * updated timezone documentation * add missing bind-mount from updated docs * Add timezone deprecation warnings and related logging to backup commands * fix lint CI job error * Address PR comments: refactor timezone deprecation warning handling, update docs
This commit is contained in:
committed by
GitHub
parent
0955d6fe80
commit
6a83ce4034
@@ -14,7 +14,7 @@ FROM alpine:3.23
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
RUN apk add --no-cache ca-certificates && \
|
||||
RUN apk add --no-cache ca-certificates tzdata && \
|
||||
chmod a+rw /var/lock
|
||||
|
||||
COPY --from=builder /app/cmd/backup/backup /usr/bin/backup
|
||||
|
||||
@@ -36,6 +36,13 @@ func (c *command) runAsCommand() error {
|
||||
}
|
||||
|
||||
for _, config := range configurations {
|
||||
warnings, warnErr := config.timezoneDeprecationWarnings()
|
||||
if warnErr != nil {
|
||||
return errwrap.Wrap(warnErr, "error collecting startup warnings")
|
||||
}
|
||||
for _, w := range warnings {
|
||||
c.logger.Warn(w)
|
||||
}
|
||||
if err := runScript(config); err != nil {
|
||||
return errwrap.Wrap(err, "error running script")
|
||||
}
|
||||
@@ -102,6 +109,14 @@ func (c *command) schedule(strategy configStrategy) error {
|
||||
|
||||
for _, cfg := range configurations {
|
||||
config := cfg
|
||||
warnings, warnErr := config.timezoneDeprecationWarnings()
|
||||
if warnErr != nil {
|
||||
return errwrap.Wrap(warnErr, "error collecting startup warnings")
|
||||
}
|
||||
for _, w := range warnings {
|
||||
c.logger.Warn(w)
|
||||
}
|
||||
|
||||
id, err := c.cr.AddFunc(config.BackupCronExpression, func() {
|
||||
c.logger.Info(
|
||||
fmt.Sprintf(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
@@ -97,6 +98,7 @@ type Config struct {
|
||||
GoogleDriveImpersonateSubject string `split_words:"true"`
|
||||
GoogleDriveEndpoint string `split_words:"true"`
|
||||
GoogleDriveTokenURL string `split_words:"true"`
|
||||
Timezone string `envconfig:"TZ"`
|
||||
source string
|
||||
additionalEnvVars map[string]string
|
||||
}
|
||||
@@ -322,3 +324,81 @@ func (c *Config) resolve() (reset func() error, warnings []string, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mountedPaths(path string) (map[string]struct{}, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
mounts := make(map[string]struct{})
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.SplitN(line, " - ", 2)
|
||||
fields := strings.Fields(parts[0])
|
||||
if len(fields) < 5 {
|
||||
continue
|
||||
}
|
||||
mounts[fields[4]] = struct{}{}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (c *Config) timezoneDeprecationWarnings() ([]string, error) {
|
||||
mounts, err := mountedPaths("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error reading mount info")
|
||||
}
|
||||
|
||||
deprecatedMounts := []string{
|
||||
"/etc/timezone",
|
||||
"/etc/localtime",
|
||||
"/usr/share/zoneinfo",
|
||||
}
|
||||
|
||||
var found []string
|
||||
for _, mnt := range deprecatedMounts {
|
||||
if _, ok := mounts[mnt]; ok {
|
||||
found = append(found, mnt)
|
||||
}
|
||||
}
|
||||
|
||||
if len(found) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
// Primary deprecation message (compressed)
|
||||
warnings = append(warnings,
|
||||
fmt.Sprintf(
|
||||
"Deprecated timezone bind mounts detected: %s. Support for these will be removed in a future version.",
|
||||
strings.Join(found, ", "),
|
||||
),
|
||||
)
|
||||
|
||||
// Guidance based on TZ usage
|
||||
if c.Timezone == "" {
|
||||
warnings = append(warnings,
|
||||
"Set the container timezone using the `TZ` environment variable instead.",
|
||||
"Refer to the documentation for migration details.",
|
||||
)
|
||||
} else {
|
||||
warnings = append(warnings,
|
||||
fmt.Sprintf(
|
||||
"`TZ=%s` is set, but deprecated timezone bind mounts are still present. Remove the bind mounts after confirming timezone handling works as expected.",
|
||||
c.Timezone,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,13 @@ func runPrintConfig() error {
|
||||
for _, warning := range warnings {
|
||||
fmt.Printf("warning:%s\n", warning)
|
||||
}
|
||||
timezoneWarnings, warnErr := config.timezoneDeprecationWarnings()
|
||||
if warnErr != nil {
|
||||
return errwrap.Wrap(warnErr, "error collecting timezone deprecation warnings")
|
||||
}
|
||||
for _, warning := range timezoneWarnings {
|
||||
fmt.Printf("warning:%s\n", warning)
|
||||
}
|
||||
// insert line breaks before each field name, assuming field names start with uppercase letters
|
||||
formatted := formatter.ReplaceAllString(fmt.Sprintf("%+v", *config), "\n$1")
|
||||
fmt.Printf("%s\n", formatted)
|
||||
|
||||
@@ -1,26 +1,55 @@
|
||||
---
|
||||
title: Set the timezone the container runs in
|
||||
title: Setting the Time Zone
|
||||
layout: default
|
||||
parent: How Tos
|
||||
nav_order: 8
|
||||
---
|
||||
|
||||
# Set the timezone the container runs in
|
||||
# Setting the Time Zone
|
||||
|
||||
By default a container based on this image will run in the UTC timezone.
|
||||
As the image is designed to be as small as possible, additional timezone data is not included.
|
||||
In case you want to run your cron rules in your local timezone (respecting DST and similar), you can mount your Docker host's `/etc/timezone`, `/etc/localtime`, and `/usr/share/zoneinfo` in read-only mode:
|
||||
## Use Environment Variable `TZ`
|
||||
|
||||
A container started using this image will default to UTC. To modify the time zone, set the `TZ` environment variable to a valid [tz database time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones):
|
||||
|
||||
```yml
|
||||
services:
|
||||
backup:
|
||||
image: offen/docker-volume-backup:v2
|
||||
image: offen/docker-volume-backup:latest
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- data:/backup/my-app-backup:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /usr/share/zoneinfo:/usr/share/zoneinfo:ro
|
||||
|
||||
volumes:
|
||||
data:
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This approach is preferred because it:
|
||||
|
||||
- avoids dependency on host configuration
|
||||
- works consistently across environments
|
||||
|
||||
### Compatibility
|
||||
|
||||
- Bind-mounting timezone files will continue to work if `TZ` is not set.
|
||||
- If `TZ` is set, it takes precedence over any bind-mounted timezone configuration.
|
||||
- An invalid `TZ` value will cause the container to default to UTC.
|
||||
|
||||
:warning: **Deprecation Warning**
|
||||
The method described below (bind-mounting files from the host) is **deprecated**. Please use the new method described above (`TZ`)
|
||||
|
||||
> ```yml
|
||||
> services:
|
||||
> backup:
|
||||
> image: offen/docker-volume-backup:latest
|
||||
> volumes:
|
||||
> - data:/backup/my-app-backup:ro
|
||||
> - /etc/timezone:/etc/timezone:ro
|
||||
> - /etc/localtime:/etc/localtime:ro
|
||||
> - /usr/share/zoneinfo:/usr/share/zoneinfo:ro
|
||||
>
|
||||
> volumes:
|
||||
> data:
|
||||
> ```
|
||||
Reference in New Issue
Block a user