为什么我从 Nginx 收到只读文件系统错误?

问题描述 投票:0回答:3

当我部署应用程序 Pod 时,我从 Nginx 收到此错误消息。我的应用程序 Angular 6 应用程序托管在 Nginx 服务器内,该服务器部署为 EKS 内的 Docker 容器。

我将应用程序配置为“只读容器文件系统”,但我将“emptyDir”类型的“临时安装”卷与只读文件系统结合使用。

所以我不确定以下错误的原因:

2019/04/02 14:11:29 [紧急] 1#1: mkdir() “/var/cache/nginx/client_temp”失败(30:只读文件系统) nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" 失败 (30: 只读文件系统)

我的

deployment.yaml
是:

...
 spec:
      volumes:
        - name: tmp-volume
          emptyDir: {}
        # Pod Security Context
      securityContext:
        fsGroup: 2000
      containers:
      - name: {{ .Chart.Name }}
        volumeMounts:
        - mountPath: /tmp
          name: tmp-volume
        image: "{{ .Values.image.name }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        securityContext:
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
        securityContext:
          readOnlyRootFilesystem: true
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
...

nginx.conf 是:

...
http {

include           /etc/nginx/mime.types;
  default_type      application/octet-stream;

  # Turn off the bloody buffering to temp files
  proxy_buffering off;

  sendfile          off;
  keepalive_timeout 120;
  
  server_names_hash_bucket_size 128;
  
  # These two should be the same or nginx will start writing 
  #  large request bodies to temp files
  client_body_buffer_size 10m;
  client_max_body_size    10m;
...
nginx deployment kubernetes kubernetes-helm security-context
3个回答
0
投票

似乎您的

nginx
没有以 root 用户身份运行。

自发布

1.12.1-r2
以来,nginx 守护进程以用户
1001
身份运行。

1.12.1-r2

nginx 容器已迁移到非根容器方法。以前,容器以 root 用户身份运行,nginx 守护进程以 nginx 用户身份启动。从现在开始,容器和 nginx 守护进程都以用户 1001 的身份运行。因此,运行 nginx 进程的用户可以写入配置文件。

这就是为什么你无法绑定端口

80
,必须使用> 1000的端口。

您应该使用:

  ports:
   - '80:8080'
   - '443:8443'

并编辑 nginx.conf,使其侦听端口 8080:

server {
        listen 0.0.0.0:8080;
        ...

或者以 root 身份运行 nginx:

command: [ "/bin/bash", "-c", "sudo nginx -g 'daemon off;'" ]


0
投票

正如 Crou 所说,nginx 镜像维护者切换到非 root 用户方法。

这有两个含义:

  1. 您的 nginx 进程可能无法绑定所有网络套接字。
  2. 您的 nginx 进程可能无法读取所有文件系统位置。

您可以尝试按照Crou(nginx.conf和deployment.yaml)所述更改端口。即使容器中添加了 NET_BIND_SERVICE 能力,这并不一定意味着 nginx 进程获得了此能力。您可以尝试使用

添加该功能
$ sudo setcap 'cap_net_bind+p' $(which nginx)

作为 Dockerfile 中的 RUN 指令。 然而,更改监听端口通常更简单。

对于文件系统,请注意,

/var/cache/nginx/
未挂载为卷,因此属于以只读方式挂载的 RootFS。解决此问题的最简单方法是在
/var/cache/nginx/
部分中为
volumes
添加第二个临时空目录。请确保 nginx 用户具有读写此目录的文件系统权限。只要您保留默认位置,docker 镜像维护人员通常已经处理好这一问题。

我建议您不要切换回以 root 身份运行 nginx,因为这可能会让您面临安全漏洞。


0
投票

对于任何面临此问题的人。在 terraform 中处理此问题时,对我有帮助的是设置此值:

# to allow nginx to write to the filesystem
readonly_root_filesystem = false

这是完整的地形代码

module "ecs_service_ui" {
  source  = "terraform-aws-modules/ecs/aws//modules/service"
  version = "~> 5.11.4"

  name        = "${local.project_name}-ui-service"
  cluster_arn = module.ecs_cluster.arn

  desired_count = 1

  requires_compatibilities = ["FARGATE"]
  cpu                      = 256
  memory                   = 512
  network_mode             = "awsvpc"

  container_definitions = {
    main = {
      name      = "${local.project_name}-ui-container"
      image     = "${module.ecr_ui.repository_url}:${var.ui_image_tag}"
      essential = true

      # Container-level resource limits
      memory_reservation = 256

      # Ensure container can write to /tmp
      readonly_root_filesystem = false

      port_mappings = [
        {
          name          = "${local.project_name}-ui-port"
          containerPort = 8080
          hostPort      = 8080
          protocol      = "tcp"
        }
      ]

      environment = [
        {
          name  = "ENVIRONMENT"
          value = var.environment
        }
      ]

      log_configuration = {
        logDriver = "awslogs"
        options = {
          awslogs-group         = aws_cloudwatch_log_group.ecs_logs.name
          awslogs-region        = local.aws_region
          awslogs-stream-prefix = "app-ui"
        }
      }
    }
  }

  load_balancer = {
    service = {
      target_group_arn = module.alb_public.target_groups["ui-tg"].arn
      container_name   = "${local.project_name}-ui-container"
      container_port   = 8080
    }
  }

  subnet_ids = data.aws_subnets.private.ids
  security_group_rules = {
    ingress_from_alb = {
      type                     = "ingress"
      from_port                = 8080
      to_port                  = 8080
      protocol                 = "tcp"
      description              = "Ingress from ALB"
      source_security_group_id = module.alb_public.security_group_id
    }
    egress_all = {
      type        = "egress"
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }

  create_iam_role       = true
  create_tasks_iam_role = true

  task_exec_iam_role_name        = "${local.project_name_short}-ui-task-exec-role"
  task_exec_iam_role_description = "Task execution role for ${local.project_name} UI"
  task_exec_iam_role_policies = {
    AmazonECSTaskExecutionRolePolicy = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
  }

  tasks_iam_role_name        = "${local.project_name_short}-ui-task-role"
  tasks_iam_role_description = "Tasks role for ${local.project_name} UI"
  tasks_iam_role_policies = {
    AmazonECS_FullAccess = "arn:aws:iam::aws:policy/AmazonECS_FullAccess"
  }

  tags = local.common_tags
  depends_on = [
    module.alb_public,
    module.ecs_cluster
  ]
}

这是 Dockerfile:

# Build stage
FROM node:20-alpine AS build-stage

# Set working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm ci

# Copy project files and folders to the current working directory (i.e. 'app' folder)
COPY . .

# Build app for production with minification
RUN npm run build

# Production stage
FROM nginx:stable-alpine AS production-stage

# Remove default Nginx config
RUN rm -rf /etc/nginx/conf.d

# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf

# Copy built assets from build-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html

# Set up nginx directories and permissions
RUN chown -R nginx:nginx /usr/share/nginx/html && \
    chmod -R 755 /usr/share/nginx/html && \
    mkdir -p /tmp/nginx/{client_temp,proxy_temp,fastcgi_temp,uwsgi_temp,scgi_temp} && \
    chown -R nginx:nginx /tmp/nginx && \
    chmod -R 755 /tmp/nginx

# Expose port 8080
EXPOSE 8080

# Use nginx user
USER nginx

# Start Nginx and keep it running in the foreground
CMD ["nginx", "-g", "daemon off;"]

这是 nginx.conf 文件:

worker_processes auto;

error_log /dev/stderr warn;
pid       /tmp/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # Set temp paths to /tmp which is writable
    client_body_temp_path /tmp/nginx/client_temp;
    proxy_temp_path       /tmp/nginx/proxy_temp;
    fastcgi_temp_path    /tmp/nginx/fastcgi_temp;
    uwsgi_temp_path      /tmp/nginx/uwsgi_temp;
    scgi_temp_path       /tmp/nginx/scgi_temp;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /dev/stdout main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    server {
        listen 8080;
        server_name localhost;

        root /usr/share/nginx/html;
        index index.html;

        location / {
            try_files $uri $uri/ /index.html;
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/html;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.