書き込みが必要なDockerコンテナをReadOnlyで動かせるようにする
コンテナを触っている人であれば当たり前っちゃ当たり前のテクニックな感じだと思いますが、最近k8s環境でDockerコンテナを読み取り専用で動かすことができたので、メモしておきます。
Dockerコンテナを安全に運用するための手段の一つとして、コンテナを読み取り専用(ReadOnly)にすることがあります。 しかし、ログやキャッシュディレクトリなどアプリケーションの仕組み上、どうしても書き込みが必要な場合があり、そのままでは読み取り専用で動作させることはできません。
例えば、nginxの公式イメージだと起動時にこうなります。
docker run --rm --read-only nginx:1.18.0 /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: error: can not modify /etc/nginx/conf.d/default.conf (read-only file system?) /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2020/11/23 XX:XX:XX [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system) nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)
※ --read-only
をつけると読み取り専用で動作させることができます。
これを解決するために、書き込み可能なボリュームをマウントしてあげることで回避することができました。
以下、設定例です。
- dockerコマンドの場合
docker run --rm \ -v /var/cache/nginx \ -v /var/run \ -v /etc/nginx/conf.d \ --read-only \ -p 80:80 \ nginx:1.18.0
- docker-composeの場合
設定箇所のみピックアップして載せています
services: nginx: image: nginx:1.18.0 read_only: true volumes: - /var/cache/nginx - /var/run - /etc/nginx/conf.d
- Kubernetes(Deployment)の場合
設定箇所のみピックアップして載せています
template: spec: containers: - name: nginx image: nginx:1.18.0 securityContext: readOnlyRootFilesystem: true volumeMounts: - name: nginx-cache mountPath: /var/cache/nginx - name: pid-dir mountPath: /var/run - name: nginx-conf mountPath: /etc/nginx/conf.d volumes: - name: nginx-cache emptyDir: {} - name: pid-dir emptyDir: {} - name: nginx-conf emptyDir: {}
今回の例では匿名ボリューム、emptyDirを設定しましたが必要に応じて、適切なボリュームを設定してあげてください。
もっと良い方法があれば教えてください。