Francesco Posa
Francesco Posa

Reputation: 21

Running NGINX and PHP-FPM as separated containers in Docker with a shared volume

I would like to start NGINX and PHP-FPM in two different containers sharing a volume to let NGINX serve the app. All solutions I've found include sharing the source directly as a volume in the docker-composer file.

volumes:
   - ./:/var/www

I don't want to implement this solution as I believe is just for the developing phase. I have a private Docker image that contains the source code and exposes php-fpm on port 9000. The solution I have in mind consists in adding the following parameter to both nginx and php-fpm containers.

volumes:
   - code:/var/www/html

code is a volume already specified in the docker-composer file. Thus, the final result should be something like:

version: "3.6"

networks:
  inside:
    external: false

volumes:
  code:
    driver: local

services:
  server:
    image: nginx:1.17-alpine
    ports:
      - "80:80"
    volumes:
      - code:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - inside
    restart: always

  app:
    image: PRIVATE_IMAGE
    volumes:
      - code:/var/www/html
    networks:
      - inside
    restart: always

The issue is about permissions: when I try to load the app since the cache folder inside the app is not writable, I receive Permission denied.

Do you know the clearest way to solve this issue?

Upvotes: 2

Views: 2064

Answers (1)

David Maze
David Maze

Reputation: 158647

Named volumes, on their own, are not a reliable way to publish files from one container to another. The easiest way to see this is to make some change in your html directory and run docker-compose build; docker-compose up -d. What you'll see in this case is that the old contents of the code volume are used in the Nginx container without updates, and in fact the old contents of the volume hide the updated code in your application container. For things that aren't Docker named volumes, including Docker bind-mounts and Kubernetes volumes, you'll just get an empty directory with nothing copied into it.

The absolute easiest way to address this is to let the application serve its own static assets. The mechanism to do this is framework-specific (and I'm not well-versed in PHP), but if you can do this then your Nginx configuration just has a proxy_pass or fastcgi_pass directive, and it doesn't have any files on its own to serve. That eliminates the need for this volume.

If that's not an option, then you can create a second image for the reverse proxy that includes the static assets.

FROM nginx:1.17-alpine
COPY ./html/ /usr/share/nginx/html/
# use the CMD from the base image, no need to repeat it

Now you're not "sharing files" per se, but the application and the reverse proxy both contain the same static files built from the same source tree. This means you don't need volumes: in the Compose setup, except maybe to do things like inject configuration. (It's likely reasonable to COPY this into the image as well.)

version: "3.8"
services:
  server:
    build:
      context: .
      dockerfile: Dockerfile.nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    restart: always

  app:
    build: .
    restart: always

Upvotes: 2

Related Questions