【问题标题】:Kubernetes: how to correctly set php-fpm and nginx shared volume permissionKubernetes:如何正确设置php-fpm和nginx共享卷权限
【发布时间】:2021-05-18 23:38:29
【问题描述】:

我是 Kubernetes 新手,

目前我正在尝试在 kuberetes 上部署 laravel 应用程序。我已经设置了 1 个部署 yaml,其中包含 2 个容器(nginx 和 php-fpm)和一个共享卷。

这是完整的 yaml:


apiVersion: v1
kind: Service
metadata:
  name: operation-service
  labels:
    app: operation-service
spec:
  type: NodePort
  selector:
    app: operation
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    targetPort: 443
    protocol: TCP
    name: https
  - port: 9000
    targetPort: 9000
    protocol: TCP
    name: fastcgi

---
# Create a pod containing the PHP-FPM application (my-php-app)
# and nginx, each mounting the `shared-files` volume to their
# respective /var/www/ directories.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: operation
spec:
  selector:
    matchLabels:
      app: operation
  replicas: 1
  template:
    metadata:
      labels:
        app: operation
    spec:
      volumes:
        # Create the shared files volume to be used in both pods
        - name: shared-files
          emptyDir: {}

        # Secret containing
        - name: secret-volume
          secret:
            secretName: nginxsecret

        # Add the ConfigMap we declared for the conf.d in nginx
        - name: configmap-volume
          configMap:
            name: nginxconfigmap

      containers:
        # Our PHP-FPM application
        - image: asia.gcr.io/operations
          name: app
          volumeMounts:
            - name: shared-files
              mountPath: /var/www
          ports:
            - containerPort: 9000
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh", "-c", "cp -r /app/. /var/www"]

        - image: nginx:latest
          name: nginx
          ports:
            - containerPort: 443
            - containerPort: 80
          volumeMounts:
            - name: shared-files
              mountPath: /var/www
            - mountPath: /etc/nginx/ssl
              name: secret-volume
            - mountPath: /etc/nginx/conf.d
              name: configmap-volume

---

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
spec:
  rules:
  - host: testing.com
    http:
      paths:
      - path: /
        backend:
          serviceName: operation-service
          servicePort: 443

这是我的工作nginxconf

server {
    listen 80;
    listen [::]:80;

    # For https
    listen 443 ssl;
    listen [::]:443 ssl ipv6only=on;
    ssl_certificate /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;

    server_name testing.com;
    root /var/www/public;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }


    error_log /var/log/nginx/laravel_error.log;
    access_log /var/log/nginx/laravel_access.log;
}

部署后,我的应用无法加载到网络上。原来 nginx 日志正在返回:

[error] 19#19: *64 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught ErrorException: file_put_contents(/app/storage/framework/views/ba2564046cc89e436fb993df6f661f314e4d2efb.php): failed to open stream: Permission denied in /var/www/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:185

我知道如何在本地 docker 中正确设置卷,如何在 kubernetes 中正确设置共享卷权限?

【问题讨论】:

    标签: php laravel nginx kubernetes


    【解决方案1】:

    对于任何正在寻找答案的人,我设法使用 php-fpm 和 nginx 为我们的生产服务器设置 kubernetes。

    需要2张图片,1张包含php-fpm和我们的代码,另一张是nginx图片,里面有我们的conf。

    我们还必须在这两个图像之间设置一个共享卷才能访问。我缺少的是 postStart 命令来执行 chmodphp artisan optimize 以确保我清除了缓存

    为了将来参考,请使用kubectl logs <pods-name>kubectl describe pods <pods-name> 轻松调试并查看每个 pod 中发生的情况

    这是最终的工作配置,希望它对未来的人有所帮助

    
    apiVersion: v1
    kind: Service
    metadata:
      name: operation-service
      labels:
        app: operation-service
    spec:
      type: NodePort
      selector:
        app: operation
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
        name: http
    ---
    # Create a pod containing the PHP-FPM application (my-php-app)
    # and nginx, each mounting the `shared-files` volume to their
    # respective /var/www/ directories.
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: operation
    spec:
      selector:
        matchLabels:
          app: operation
      replicas: {{ .Values.replicaCount }}
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 50%
        type: RollingUpdate
      template:
        metadata:
          labels:
            app: operation
        spec:
          volumes:
            # Create the shared files volume to be used in both pods
            - name: shared-files
              emptyDir: {}
          securityContext:
            fsGroup: 82
          containers:
            # Our PHP-FPM application
            - image: asia.gcr.io/3/operations:{{ .Values.version }}
              name: app
              envFrom:
              - configMapRef:
                  name: prod
              - secretRef:
                  name: prod
              volumeMounts:
                - name: shared-files
                  mountPath: /var/www
              # Important! After this container has started, the PHP files
              # in our Docker image aren't in the shared volume. We need to
              # get them into the shared volume. If we tried to write directly
              # to this volume from our Docker image the files wouldn't appear
              # in the nginx container.
              #
              # So, after the container has started, copy the PHP files from this
              # container's local filesystem (/app -- added via the Docker image)
              # to the shared volume, which is mounted at /var/www.
              ports:
                - containerPort: 9000
                  name: fastcgi
              lifecycle:
                postStart:
                  exec:
                    command:
                      - "/bin/sh"
                      - "-c"
                      - >
                        cp -r /app/. /var/www &&
                        cd /var/www &&
                        php artisan optimize &&
                        php artisan migrate --force &&
                        chgrp -R www-data /var/www/* &&
                        chmod -R 775 /var/www/*
    
            # Our nginx container, which uses the configuration declared above,
            # along with the files shared with the PHP-FPM app.
            - image: asia.gcr.io/3/nginx:1.0
              name: nginx
              ports:
                - containerPort: 80
              volumeMounts:
                - name: shared-files
                  mountPath: /var/www
    
    
    # We don't need this anymore as we're not using fastcgi straightaway
    # ---
    
    # apiVersion: v1
    # kind: ConfigMap
    # metadata:
    #   name: ingress-cm
    # data:
    #   SCRIPT_FILENAME: "/var/www/public/index.php$is_args$args"
    
    ---
    
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: operation-ingress
      labels:
        app: operation-ingress
      annotations:
        kubernetes.io/ingress.class: "nginx"
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
        nginx.ingress.kubernetes.io/proxy-body-size: "0"
        cert-manager.io/cluster-issuer: letsencrypt-prod
    
    spec:
      tls:
        - hosts:
            - myservice.com.au
          secretName: kubernetes-tls
      rules:
      - host: myservice.com.au
        http:
          paths:
          - backend:
              serviceName: operation-service
              servicePort: 80
    

    【讨论】:

      【解决方案2】:

      您可以使用init container 描述here 来更改挂载目录的权限,也可以设置fsGroup 来更改拥有卷的组ID,描述here

      在您的情况下,我认为通过修改“复制”命令来设置权限会更容易:

      command: ["/bin/sh", "-c", "cp -r /app/. /var/www"]
      

      添加带有适当参数的chmod 命令,例如:

      command: ["/bin/sh", "-c", "cp -r /app/. /var/www && chmod -R a+r /var/www"]
      

      【讨论】:

        【解决方案3】:

        您可以阅读日志并明确提及权限被拒绝,这意味着 Nginx 无权访问该文件,您可能需要更改目录或文件的权限,以便 Nginx 可以访问它。

        您可以在 docker build 期间更改权限,或者运行 prehook 或设置在部署更新时将与映像一起运行的命令。

        类似:

        sudo chmod -R 775 /var/www/vendor
        

        sudo chmod -R 755 /var/www/
        

        我试图以与 php-fpm 相同的方式设置 WordPress,并将 Nginx 容器与 php-fpm 一起使用,但遇到了同样的问题。

        您可以找到所有示例文件:https://github.com/harsh4870/Kubernetes-wordpress-php-fpm-nginx

        【讨论】:

          猜你喜欢
          • 2014-01-25
          • 1970-01-01
          • 2015-04-08
          • 2019-01-16
          • 1970-01-01
          • 2020-07-19
          • 2016-03-26
          • 1970-01-01
          • 2018-07-17
          相关资源
          最近更新 更多