Sidecar-based log rotation for ACS applications

更新时间:
复制 MD 格式

Container Compute Service (ACS) clusters use a serverless architecture to manage cluster resources, which prevents you from deploying a DaemonSet to manage log rotation. If not rotated, log files can grow to exhaust all available disk space. ACS provides a sidecar-based solution: a cron job triggers logrotate inside a sidecar container to rotate application log files automatically.

How it works

Important

This log rotation solution is not recommended in the following scenarios:

  • Applications that write to a single output file. Use stdout instead of file-based logging. Containers natively rotate stdout, and this approach also simplifies log monitoring for container anomalies.

  • Applications built with languages like Java or Python that have built-in log rotation. Use the logging library's native rotation features instead.

image

Configure a logrotate sidecar for an application

The following example deploys the logrotate container as a native sidecar: an init container configured with restartPolicy: Always. For ACS clusters running Kubernetes 1.28 or earlier, you can use the ACS-enhanced environment variable __IS_SIDECAR=true to mark a regular container as a sidecar, allowing you to manage its lifecycle the same way. For more information, see Configure Sidecar container startup and shutdown sequence.

Important

The logrotate container must share a volume with the application container. Mount the /var/lib directory to the logrotate container to persist rotation state data. This prevents state loss on container restart and avoids incorrect rotation actions. Ensure that the application's log files are stored in the shared volume.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-logrotate
  labels:
    app: test
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      initContainers:
        - name: logrotate
          env:
            - name: CRON_EXPR
              value: "5 * * * *"
            - name: LOGROTATE_LOGFILES
              value: "/var/log/*/*.log"
            - name: LOGROTATE_FILENUM
              value: "5"
            - name: LOGROTATE_FILESIZE
              value: "10M"
            - name: __IGNORE_RESOURCE__
              value: "true"
            - name: __IGNORE_READY__
              value: "true"
          command: [ "sh", "/start.sh" ]
          image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/logrotate:v1.1
          volumeMounts:
            - mountPath: /var/log
              name: shared-log
            - mountPath: /var/lib
              name: logrotate-state
          restartPolicy: Always
          resources:
            limits:
               cpu: 0.25
               memory: 0.5Gi
      containers:
        - name: busybox
          image: mirrors-ssl.aliyuncs.com/busybox:latest
          command: [ "sh", "-c" ]
          args:
            - |
              mkdir /var/log/busybox
              while true; do
                TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
                LOG_LEVEL=$(shuf -n1 -e INFO WARNING ERROR)
                APP_NAME="busybox"
                HOSTNAME=$(hostname)
                MESSAGE=$(shuf -n1 -e "Success" "Timeout" "Database error")
                echo "$TIMESTAMP $HOSTNAME [$LOG_LEVEL] $APP_NAME: $MESSAGE" >> /var/log/busybox/busybox.log
                sleep 1
              done
          volumeMounts:
            - mountPath: /var/log
              name: shared-log
      volumes:
        ## Collect stdout logs.
        - emptyDir:
          name: shared-log
        - emptyDir:
          name: logrotate-state

The following table describes the key environment variables.

Environment variable name

Description

Example

CRON_EXPR

Cron expression for the logrotate schedule.

5 * * * * specifies that log rotation runs at the fifth minute of every hour. We recommend that you avoid running log rotation at the top of the hour to prevent conflicts with other scheduled tasks.

LOGROTATE_LOGFILES

Path to the log files to rotate.

/var/log/*/*.log scans for files that end with .log in all subdirectories of /var/log.

LOGROTATE_FILENUM

Number of rotated log files to retain per log file.

5.

LOGROTATE_FILESIZE

Maximum size of a log file. Files exceeding this size are rotated.

10M.

Note

LOGROTATE_FILESIZE * LOGROTATE_FILENUM determines the maximum disk space consumed by log files. Configure these values based on your instance's storage capacity.

__IGNORE_RESOURCE__

Excludes the logrotate container's resource declaration from scheduling to avoid extra resource costs. The logrotate container shares CPU and memory with the application container and remains constrained by the configured resource.limits. For more information, see Configure scheduling policies to ignore the resource requests of specific sidecar containers.

"true".

__IGNORE_READY__

Excludes the logrotate container from Pod readiness checks. This prevents a NotReady sidecar from affecting the overall Pod status. For more information, see Ignore the NotReady state of the sidecar container.

"true".

Verify the shared volume and log rotation

  • Verify the shared volume:

    Check the /var/log/busybox directory in both the busybox and logrotate containers.

    ❯ kubectl exec -it deploy/test-logrotate -c busybox -- sh
    / # ls -al var/log/busybox/
    total 36
    drwxr-xr-x    2 root     root          4096 May 30 03:10 .
    drwxrwxrwx    3 root     root          4096 May 30 03:10 ..
    -rw-r--r--    1 root     root         21426 May 30 03:15 busybox.log
    / # exit
    ❯ kubectl exec -it deploy/test-logrotate -c logrotate -- sh
    / # ls -al var/l
    lib/    local/  lock/   log/
    / # ls -al var/log/busybox/
    total 36
    drwxr-xr-x    2 root     root          4096 May 30 03:10 .
    drwxrwxrwx    3 root     root          4096 May 30 03:10 ..
    -rw-r--r--    1 root     root         23780 May 30 03:15 busybox.log
    / #

    The busybox.log file appears in the same directory within both containers, confirming that the shared volume is mounted correctly.

  • Check the log rotation result:

    Note

    To quickly demonstrate the rotation effect, we adjusted the CRON_EXPR and LOGROTATE_FILESIZE values to accelerate the rotation cycle, producing the following result.

    > kubectl exec -it deploy/test-logrotate -c logrotate -- sh
    / # ls var/log/busybox/
    busybox.log    busybox.log.1   busybox.log.2   busybox.log.3   busybox.log.4   busybox.log.5
    / #

Inject logrotate sidecars with a SidecarSet

Important

To create and use a SidecarSet in an ACS cluster, you must first install the ack-kruise component. For more information, see Manage components.

The OpenKruise SidecarSet manages sidecar containers with automatic injection and independent upgrades. The following SidecarSet injects the logrotate sidecar into all Pods labeled with kruise.io/inject-logrotate: "true". It also enables the shared volume policy shareVolumePolicy.type=enabled, which automatically mounts all Pod volumeMounts into the sidecar. If the injected Pods share a common volume name, you can also declare that name in the SidecarSet.

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: logrotate-sidecarset
spec:
  selector:
    matchLabels:
      kruise.io/inject-logrotate: "true"
  updateStrategy: 
    type: NotUpdate
  initContainers:
    - name: logrotate
      env:
        - name: CRON_EXPR
          value: "5 * * * *"
        - name: LOGROTATE_LOGFILES
          value: "/var/log/*/*.log"
        - name: LOGROTATE_FILENUM
          value: "5"
        - name: LOGROTATE_FILESIZE
          value: "10M"
        - name: __IGNORE_RESOURCE__
          value: "true"
      command: [ "sh", "/start.sh" ]
      image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/logrotate:v1.1
      shareVolumePolicy:
        type: enabled
      volumeMounts:
        - mountPath: /var/lib/
          name: logrotate-state
      restartPolicy: Always
      resources:
        limits:
           cpu: 0.25
           memory: 0.5Gi
  volumes:
    - name: logrotate-state
      emptyDir: {}

Related information

The following Dockerfile and script build the logrotate image. Modify them to meet your requirements.

  • Dockerfile:

    FROM registry-cn-hangzhou.ack.aliyuncs.com/dev/alpine:3.20-update
    RUN apk --update add bash logrotate
    ADD start.sh /start.sh
    CMD ["/start.sh"]
  • start.sh:

    #!/bin/sh
    LOGROTATE_LOGFILES="${LOGROTATE_LOGFILES:?Files for rotating must be given}"
    LOGROTATE_FILESIZE="${LOGROTATE_FILESIZE:-10M}"
    LOGROTATE_FILENUM="${LOGROTATE_FILENUM:-5}"
    cat > /etc/logrotate.conf << EOF
    ${LOGROTATE_LOGFILES}
    {
      size ${LOGROTATE_FILESIZE}
      missingok
      notifempty
      copytruncate
      rotate ${LOGROTATE_FILENUM}
    }
    EOF
    if [ -z "$CRON_EXPR" ]; then
      CRON_EXPR="0 6 * * *"
      echo "CRON_EXPR environment variable is not set. Set to default: $CRON_EXPR"
    else
      echo "CRON_EXPR environment variable set to $CRON_EXPR"
    fi
    echo "$CRON_EXPR	/usr/sbin/logrotate -v /etc/logrotate.conf" >> /etc/crontabs/root
    (crond -f) & CRONPID=$!
    trap "kill $CRONPID; wait $CRONPID" SIGINT SIGTERM
    wait $CRONPID