chown:更改“/var/lock/apache2.fm2cgWmnxk”的所有权:不允许操作

chown: changing ownership of '/var/lock/apache2.fm2cgWmnxk': Operation not permitted

我正在一个只读的 kubernetes 集群中部署我的应用程序,所以我正在为 apache 服务器的 tmp 文件夹使用卷和 volumeMounts。在只读 pod 中启动 apache 服务器时,出现此错误:

chown: changing ownership of '/var/lock/apache2.fm2cgWmnxk': Operation not permitted

我遇到了这个问题 并尝试使用 SecurityContext.fsGroup 但仍然遇到同样的问题。

这是我的deployment.yaml供参考:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: &DeploymentName abc
spec:
  replicas: 1
  selector:
    matchLabels: &appName
      app: *DeploymentName
  template:
    metadata:
      name: main
      labels:
        <<: *appName
    spec:
      securityContext:
        fsGroup: 2000
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 3000
        fsGroupChangePolicy: "OnRootMismatch"
      volumes:
        - name: var-lock
          emptyDir: {}
      containers:
        - name: *DeploymentName
          image: abc-image
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /var/lock
              name: var-lock
          readinessProbe:
              tcpSocket:
                port: 80
              initialDelaySeconds: 180
              periodSeconds: 60
          livenessProbe:
              tcpSocket:
                port: 80
              initialDelaySeconds: 300
              periodSeconds: 180
          imagePullPolicy: Always
          tty: true
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          envFrom:
            - configMapRef:
                name: *DeploymentName
          resources:
            limits:
              cpu: 1
              memory: 2Gi
            requests:
              cpu: 1
              memory: 2Gi

---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: &hpaName abc
spec:
  maxReplicas: 1
  minReplicas: 1
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: *hpaName
  targetCPUUtilizationPercentage: 60

感谢任何帮助。

字段:fsGroupChangePolicy 对 secret、configMap 和 emptydir 等临时卷类型没有影响。资料来源:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods

除此之外,我假设您只是复制了示例,但您需要在 yaml 中的必填字段中应用您自己的用户,正如您在评论中提到的那样,该字段为“1000”。在您设置之前,只需使用 id 命令验证来自 运行 容器的 ID。该文档应该对您有很大帮助:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod

您好,希望您开启 Kubernetes 之旅!

我想在本地集群(docker 中的 Kubernetes)集群上尝试这个。这就是我所做的:

首先,我使用此配置在本地设置了一个类集群(此处信息:https://kind.sigs.k8s.io/docs/user/quick-start/):

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: so-cluster-1
nodes:
- role: control-plane
  image: kindest/node:v1.23.5
- role: control-plane
  image: kindest/node:v1.23.5
- role: control-plane
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5

在此之后,我使用以下命令创建了我的集群:

kind create cluster --config=config.yaml

接下来,我创建了一个测试命名空间(通过以下方式获得的清单:kubectl create ns so-tests -o yaml --dry-run):

apiVersion: v1
kind: Namespace
metadata:
  name: so-tests

从那里开始,我设置了我的环境,所以我使用了你的部署配置并将 deploymentName、appName 和 hpaName 的出现替换为“so-71823613”(stack-overflow,你质疑 id),但是对于测试,我决定不使用hpa配置。

接下来,由于您没有提供用于apache 的图像,我使用了dockerhub 图像httpd:2.4.53 (https://hub.docker.com/layers/httpd/library/httpd/2.4.53/images/sha256-10ed1591781d9fdbaefaafee77067f12e833c699c84ed4e21706ccbd5229fd0a?context=explore)

同样,由于我没有您的 configmap 配置,我决定注释掉您从 configmap 获取环境变量的部分。

由于 httpd 映像中的默认用户是“www-data”,我首先部署了没有任何 securityContext 的 pod,只是为了获取该用户的 ID:

❯ k exec -it pod/so-71823613-555d8b454-z5ks5 -- id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)

一旦我知道 www-data 用户的 ID 是什么,我就修改了 securityContext。我保留了您配置的其余配置(探测器、卷等),现在是清单:

在配置文件中,运行AsUser 字段指定对于 Pod 中的任何容器,所有进程 运行 用户 ID 为 33(www-data)。 运行AsGroup 字段为 Pod 的任何容器内的所有进程指定主组 ID 33。如果省略此字段,则容器的主要组 ID 将为 root(0)。 当指定 运行AsGroup 时,创建的任何文件也将归用户 33 和组 33 所有。 由于指定了 fsGroup 字段,容器的所有进程也是补充组 ID 33 的一部分。卷“/var/lock”的所有者和在该卷中创建的任何文件都将是组 ID 33。 ... fsGroupChangePolicy - fsGroupChangePolicy 定义在 Pod 内公开之前更改卷的所有权和权限的行为。此字段仅适用于支持 fsGroup 控制的所有权和权限的卷类型。该字段有两个可能的值:

OnRootMismatch:如果根目录的权限和所有权与卷的预期权限不匹配,则仅更改权限和所有权。这有助于缩短更改卷的所有权和权限所需的时间。 始终:始终在安装卷时更改卷的权限和所有权。

(此处的描述:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

所以,一旦我使用以下方式部署我的配置:

kubectl apply -f deployment.yaml
deployment.apps/so-71823613 created

我收到这个错误:

 k logs -f pod/so-71823613-7c5b65df4d-6scg5
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.244.1.2. Set the 'ServerName' directive globally to suppress this message
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
AH00015: Unable to open logs

所以,首先要修复第一行错误,我重新连接到 pod 以获取 httpd.conf 文件:

k exec -it pod/so-71823613-555d8b454-fgjcs -- cat /usr/local/apache2/conf/httpd.conf > httpd.conf

获得 http.conf 文件后,我修改了它,添加了:

ServerName localhost:8080

(比照https://ixnfo.com/en/solution-ah00558-apache2-could-not-reliably-determine-the-servers-fully-qualified-domain-name.html)

然后我将新的 httpd.conf 文件放入名为“httpconf”的 configmap 中,并修改部署以将 configmap 挂载到正确的位置,以替换第一个(此处 -> “/usr/local/apache2/conf/httpd.conf") 与:

    ...
    volumeMounts:
    ...
      - name: "config"
        mountPath: "/usr/local/apache2/conf/httpd.conf"
        subPath: "httpd.conf"
  volumes:
  ...
    - name: "config"
      configMap:
        name: "httpconf"
  ...



❯ kubectl apply -f configmap.yaml -f deployment.yaml
configmap/httpconf created
deployment.apps/so-71823613 created

然后我得到了这个错误:

(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80

所以,为了修复它,我直接将apache的监听端口更改为configmap http.conf文件(根据这个:https://askubuntu.com/questions/338218/why-am-i-getting-permission-denied-make-sock-could-not-bind-to-address-when

Listen 8080
ServerName localhost:8080

由于我现在暴露了8080端口,因此我也修改了探针和端口:

...
ports:
  - containerPort: 8080
readinessProbe:
    tcpSocket:
      port: 8080
    initialDelaySeconds: 180
    periodSeconds: 60
livenessProbe:
    tcpSocket:
      port: 8080
...

重新应用我的配置后,我收到了这个新错误:

❯ k  logs -f pod/so-71823613-7dd7bdb66d-qtf9t
[Wed Apr 20 05:50:57.863971 2022] [core:error] [pid 1:tid 139771999915328] (13)Permission denied: AH00099: could not create /usr/local/apache2/logs/httpd.pid.KYUI5g
[Wed Apr 20 05:50:57.864061 2022] [core:error] [pid 1:tid 139771999915328] AH00100: httpd: could not log pid to file /usr/local/apache2/logs/httpd.pid

为了解决这个问题,我使用了你的 emptyDir 解决方法并添加了这个:

    volumeMounts:
    ...
      - mountPath: /usr/local/apache2/logs/
        name: apache2-logs
  volumes:
  ...
    - name: apache2-logs
      emptyDir: {}

这是清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: so-71823613
spec:
  replicas: 1
  selector:
    matchLabels:
      app: so-71823613
  template:
    metadata:
      name: main
      labels:
        app: so-71823613
    spec:
      securityContext:
        fsGroup: 33
        runAsNonRoot: true
        runAsUser: 33
        runAsGroup: 33
        fsGroupChangePolicy: "OnRootMismatch"
      containers:
      - name: so-71823613
        image: httpd:2.4.53
        ports:
          - containerPort: 8080
        readinessProbe:
            tcpSocket:
              port: 8080
            initialDelaySeconds: 180
            periodSeconds: 60
        livenessProbe:
            tcpSocket:
              port: 8080
            initialDelaySeconds: 300
            periodSeconds: 180
        imagePullPolicy: Always
        tty: true
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
        # envFrom:
        #   - configMapRef:
        #       name: so-71823613
        resources:
          limits:
            cpu: 1
            memory: 2Gi
          requests:
            cpu: 1
            memory: 2Gi
        volumeMounts:
          - mountPath: /var/lock
            name: var-lock
          - mountPath: /usr/local/apache2/logs/
            name: apache2-logs
          - name: "config"
            mountPath: "/usr/local/apache2/conf/httpd.conf"
            subPath: "httpd.conf"
      volumes:
        - name: var-lock
          emptyDir: {}
        - name: apache2-logs
          emptyDir: {}
        - name: "config"
          configMap:
            name: "httpconf"

---

apiVersion: v1
kind: ConfigMap
metadata:
  name: httpconf
data:
  httpd.conf: |
    ServerRoot "/usr/local/apache2"
    Listen 8080

    LoadModule mpm_event_module modules/mod_mpm_event.so
    LoadModule authn_file_module modules/mod_authn_file.so
    LoadModule authn_core_module modules/mod_authn_core.so
    LoadModule authz_host_module modules/mod_authz_host.so
    LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
    LoadModule authz_user_module modules/mod_authz_user.so
    LoadModule authz_core_module modules/mod_authz_core.so
    LoadModule access_compat_module modules/mod_access_compat.so
    LoadModule auth_basic_module modules/mod_auth_basic.so
    LoadModule reqtimeout_module modules/mod_reqtimeout.so
    LoadModule filter_module modules/mod_filter.so
    LoadModule mime_module modules/mod_mime.so
    LoadModule log_config_module modules/mod_log_config.so
    LoadModule env_module modules/mod_env.so
    LoadModule headers_module modules/mod_headers.so
    LoadModule setenvif_module modules/mod_setenvif.so
    LoadModule version_module modules/mod_version.so
    LoadModule unixd_module modules/mod_unixd.so
    LoadModule status_module modules/mod_status.so
    LoadModule autoindex_module modules/mod_autoindex.so

    <IfModule !mpm_prefork_module>
    </IfModule>
    <IfModule mpm_prefork_module>
    </IfModule>

    LoadModule dir_module modules/mod_dir.so
    LoadModule alias_module modules/mod_alias.so

    <IfModule unixd_module>

    User www-data
    Group www-data

    </IfModule>

    ServerAdmin you@example.com
    ServerName localhost:8080

    <Directory />
        AllowOverride none
        Require all denied
    </Directory>

    DocumentRoot "/usr/local/apache2/htdocs"
    <Directory "/usr/local/apache2/htdocs">
        Options Indexes FollowSymLinks

        AllowOverride None

        Require all granted
    </Directory>

    <IfModule dir_module>
        DirectoryIndex index.html
    </IfModule>

    <Files ".ht*">
        Require all denied
    </Files>

    ErrorLog /proc/self/fd/2

    LogLevel warn

    <IfModule log_config_module>
 
        LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
        LogFormat "%h %l %u %t \"%r\" %>s %b" common

        <IfModule logio_module>
          LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
        </IfModule>

        CustomLog /proc/self/fd/1 common

    </IfModule>

    <IfModule alias_module>


        ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"

    </IfModule>

    <IfModule cgid_module>
    </IfModule>

    <Directory "/usr/local/apache2/cgi-bin">
        AllowOverride None
        Options None
        Require all granted
    </Directory>

    <IfModule headers_module>

        RequestHeader unset Proxy early
    </IfModule>

    <IfModule mime_module>

        TypesConfig conf/mime.types

        AddType application/x-compress .Z
        AddType application/x-gzip .gz .tgz

    </IfModule>

    <IfModule proxy_html_module>
    Include conf/extra/proxy-html.conf
    </IfModule>

    <IfModule ssl_module>
    SSLRandomSeed startup builtin
    SSLRandomSeed connect builtin
    </IfModule>



# ---
# apiVersion: autoscaling/v1
# kind: HorizontalPodAutoscaler
# metadata:
#   name: so-71823613
# spec:
#   maxReplicas: 1
#   minReplicas: 1
#   scaleTargetRef:
#     apiVersion: extensions/v1beta1
#     kind: Deployment
#     name: so-71823613
#   targetCPUUtilizationPercentage: 60

在等待探测器的 initialDelaySeconds 之后,我终于启动了我的 pod 并且 运行正确地连接了:

Every 1.0s: kubectl get po,svc,cm -o wide                                                                                       DESKTOP-6PBJAOK: Wed Apr 20 03:15:02 2022

NAME                              READY   STATUS    RESTARTS   AGE     IP           NODE                   NOMINATED NODE   READINESS GATES
pod/so-71823613-897768549-mcmb4   1/1     Running   0          4m13s   10.244.4.4   so-cluster-1-worker3   <none>           <none>

NAME                         DATA   AGE
configmap/httpconf           1      4m14s

奖金:

然后我决定使用服务公开 http 部署,这是清单(从“k expose deployment so-71823613 --port 80 --target-port 8080 --dry-run =客户端-o yaml":

apiVersion: v1
kind: Service
metadata:
  name: so-71823613
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: so-71823613

如你所见,我port-forwarded服务中的8080 pod端口为80(你也可以使用ingress controller将服务暴露在集群外)

在我的机器上试过这个:

❯ k port-forward service/so-71823613 8080:80
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080

结果如下:

多田!

总而言之,我尝试使用您提供的信息尽我所能重现(这有点酷),所以如果这对您不起作用,则意味着我需要更多信息。 谢谢你的演讲。 bguess.