当我部署应用程序 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
没有以 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;'" ]
正如 Crou 所说,nginx 镜像维护者切换到非 root 用户方法。
这有两个含义:
您可以尝试按照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,因为这可能会让您面临安全漏洞。
对于任何面临此问题的人。在 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;
}
}
}