Зачем и как использовать read-only файловую систему в контейнерах?
Read-only файловая система контейнера – это режим, при котором корневая файловая система монтируется только для чтения, запрещая любую запись в неё во время выполнения. Это защищает от внедрения вредоносного кода, модификации конфигурации, записи бэкдоров и изменения бинарных файлов приложения.
Аналогия: read-only ФС – как стеклянная витрина в музее. Экспонаты (файлы приложения) можно смотреть, но нельзя трогать. Если атакующий проникнет в контейнер, он не сможет ничего изменить или подложить.
В Docker
Пример
# Запуск с read-only ФС
docker run --read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--tmpfs /var/cache:rw,noexec,nosuid \
my-java-app
Флаги tmpfs:
| Флаг | Назначение |
|---|---|
rw |
Разрешить запись (только в tmpfs) |
noexec |
Запретить выполнение файлов из этой директории |
nosuid |
Игнорировать setuid-бит |
size=100m |
Ограничение размера |
В Kubernetes
Полный манифест с read-only ФС и необходимыми volume
apiVersion: v1
kind: Pod
metadata:
name: banking-service
spec:
containers:
- name: app
image: registry.bank.local/banking-service:1.0.0
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
# Java нуждается в /tmp для временных файлов
- name: tmp-volume
mountPath: /tmp
# Логи приложения
- name: logs-volume
mountPath: /app/logs
# Spring Boot может создавать temporary файлы
- name: spring-tmp
mountPath: /app/BOOT-INF/tmp
volumes:
- name: tmp-volume
emptyDir:
medium: Memory # Хранить в RAM (как tmpfs)
sizeLimit: 100Mi
- name: logs-volume
emptyDir:
sizeLimit: 500Mi
- name: spring-tmp
emptyDir:
medium: Memory
sizeLimit: 50Mi
Типичные директории, требующие записи для Java-приложений
| Директория | Зачем нужна | Рекомендация |
|---|---|---|
/tmp |
Временные файлы JVM, Tomcat | emptyDir с medium: Memory |
/app/logs |
Логи приложения | emptyDir или PVC |
/var/cache |
Кэш HTTP-клиентов | emptyDir |
/home/appuser/.java |
Preferences API | emptyDir |
Dockerfile с учётом read-only ФС
Пример
FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app && adduser -S app -G app && \
mkdir -p /app /tmp && \
chown -R app:app /app /tmp
WORKDIR /app
COPY --chown=app:app target/service.jar /app/app.jar
USER app
# Указать Java использовать /tmp для временных файлов
ENTRYPOINT ["java", "-Djava.io.tmpdir=/tmp", "-jar", "/app/app.jar"]
Вывод
Read-only файловая система – простая, но мощная мера защиты. Она гарантирует иммутабельность контейнера: то, что было собрано на этапе build, нельзя изменить в runtime. Для Java-приложений необходимо явно монтировать writable-директории (/tmp, /app/logs) через emptyDir или tmpfs.
На собеседовании: упомяните
readOnlyRootFilesystem: trueи объясните, что Java-приложению нужен writable/tmp(для JVM и Tomcat). Покажите знание флаговnoexecиnosuidдля tmpfs – это демонстрирует глубокое понимание.