phpmyadmin / docker

Docker container for phpMyAdmin
https://hub.docker.com/_/phpmyadmin
GNU General Public License v3.0
666 stars 453 forks source link

Support request: How do you use the FPM version? #284

Open hkirsman opened 4 years ago

hkirsman commented 4 years ago

Not sure how it's supposed to work. Could you give some hints?

ibennetch commented 4 years ago

The fpm versions are built against the PHP FPM Docker images. You need to provide a reverse proxy to interface with the phpMyAdmin fpm container. Most often I see people using an nginx container for this.

https://www.linode.com/docs/web-servers/nginx/serve-php-php-fpm-and-nginx/ is one resource that isn't specific to Docker, but gives a good introduction to the concepts. https://stackoverflow.com/questions/29905953/how-to-correctly-link-php-fpm-and-nginx-docker-containers and https://www.pascallandau.com/blog/php-php-fpm-and-nginx-on-docker-in-windows-10/ have some content that is more specific to Docker.

Is there a specific part you're having particular trouble with?

However, if you aren't comfortable setting that up, I really recommend using the Apache image instead which contains everything you need in one image. phpmyadmin/phpmyadmin:latest is the tag I'd recommend.

lordslair commented 4 years ago

Hello,

I stumbled on this question while trying to achieve this, inside a Kubernetes environment.

The question, docker-style is opened here https://github.com/phpmyadmin/docker/issues/253 I read it, tried almost everything, but it's not 100% applicable. Works with pure docker though.

With k8s, the $document_root can't be mounted inside the nginx container, as it is strictly inside phpmyadmin container (the /var/www/html). So nginx fails to serve the static parts.

PHP code is well served by the FPM, no problem with that, I receive a 200 OK GET /index.php HTTP/1.1" 200 3600 But every other resources end up with a 404 as they are not served by the FPM (not his job), nor by nginx (it doesn't have them locally).

Is there somewhere in the documentation a relevant best practice ? I can't be the only one trying to achieve this: Using the fpm build inside a Kubernetes environment, behind a nginx

Thanks,

ibennetch commented 4 years ago

@lordslair this is a good question. To be honest, I have never tried to run the phpMyAdmin container from a k8s environment, so I don't have an immediate answer for you.

lordslair commented 4 years ago

Thank you for the answer!

For now I'll probably use the "traditional" Apache version then. Just pulled it, and it works flawlessly with nginx using a proxy_pass

If you ever have other feedbacks or try a deploy on k8s, I'll be gladly interested by a follow-up Thanks again,

ibennetch commented 4 years ago

Thanks! I'm glad you found a working solution for your situation and sorry again that I didn't have a good answer right away.

This is something I'd love to be able to improve or offer better documentation for, so I may take you up on that. If you make any more progress on this, please let us know here as well.

Cheers!

rpasing commented 4 years ago

Hey, this was possible before and stopped working after #285

The way I did it before: Just define /var/www/html as external volume, and mount that volume also in the nginx container.

This of course now is not working anymore, as the /var/www/html directory is filled with the files inside of the container, and hence when mounting it from outside, we are overriding the directory from inside the container, and then the directory is empty.

I currently don't see another solution than to write a custom entrypoint script and therein copy the contents from /var/www/html directory to a custom directory (e.g. /opt/phpmyadmin), and mount to use that custom directory as a shared volume mount for the nginx container too.

Other suggestions are very welcome. It's a bit sad to see that #285 is breaking existing setups :(

williamdes commented 4 years ago

@rpasing I have an idea, what about having an ENV flag to create symlink to a specific folder at start time ?

ibennetch commented 4 years ago

Sorry I'm not quite getting what's wrong here @rpasing. What is it you're trying to do here that isn't working? The Kubernetes environment or anything with fpm?

ibennetch commented 4 years ago

If we have a good reason to revert #285, we certainly can do that because the only reason we do it is from the suggestion at https://github.com/docker-library/official-images/pull/7288. It seems to be an improvement, but if I missed some cases like these that it breaks then we can find a better solution.

rpasing commented 4 years ago

hm?

Previously I had something like this in my docker-compose.yml under a container using the phpmyadmin/phpmyadmin:fpm-alpine image:

volumes:
  - /var/www/phpmyadmin/:/var/www/html/

Before #285 that would result in the PMA files being available on the host in the directory /var/www/phpmyadmin, because the entrypoint-script of the PMA container copied the files into the /var/www/html container after the container started, so after the directory has been mounted.

And then I could have in my nginx docker-compose something like:

volumes:
  - /var/www/phpmyadmin/:/var/www/phpmyadmin/:ro

And in the nginx server definitions I could hence reach the static files of PMA from inside the nginx container.

Now, with the changes from #285, the files inside the PMA container in directory /var/www/html are being placed there at container-buildtime (and not after container-startup), so when I mount a directory there after the container started, it will be empty (because the host-directory is empty, and it is beign mounted inside of the container).

Is it clearer now?

ibennetch commented 4 years ago

Ah, yes, thank you. That does make sense now. Sorry it's just my inexperience with docker-compose that makes more difficult some things that should be obvious :-) I appreciate your explanation.

Seems to me like you have a great reason for us to revert #285. I can't think of any other workaround that would be suitable.

rpasing commented 4 years ago

Actually, I think we should think about a better solution than to just revert #285. I think so because also with the previous approach there were some problems.

For example were PMA-updates not easily doable, because the host always held a non-empty version of the PMA files, and the entrypoint-script then never actually replaced the files with a newer version. My workaround for that was to clear that directory before each container-startup, so that the directory is empty then and the entrypoint-script placed the new files there...

rpasing commented 4 years ago

As far as I know other PHP-projects just do the extraction of the soure-files in the entrypoint-script, and not in the Dockerfile. So instead of downloading to /usr/src/phpmyadmin in the Dockerfile and copying to /var/www/html in the entrypoint, what about downloading+extracting to /var/www/html in the entrypoint, and don't do it in the Dockerfile?

ibennetch commented 4 years ago

Hm, that's an interesting case I hadn't considered. I'll have to look further at some of the options here. I appreciate your suggestions.

ibennetch commented 4 years ago

As far as I can think through, there would never be a scenario where config.inc.php is placed in /var/www/html/ — it always belongs in /etc/phpmyadmin or as environment variables passed to Docker. Does anyone disagree?

williamdes commented 4 years ago

As far as I can think through, there would never be a scenario where config.inc.php is placed in /var/www/html/ — it always belongs in /etc/phpmyadmin or as environment variables passed to Docker. Does anyone disagree?

Hmm, I think you are pointing out the case where the config would not be written in he root that the user choose to be right

ibennetch commented 4 years ago

Sorry, I think my question just came from nowhere and I should have explained better.

I'm working through the logic of resolving this, and want to correctly handle any situations with the mounted volume. I think that if there's a new phpMyAdmin version, we should just overwrite what's in /var/www/html/, but had a nagging concern that there could be a scenario where a user puts their config.inc.php there. But I think that's not possible.

williamdes commented 4 years ago

Sorry, I think my question just came from nowhere and I should have explained better.

I'm working through the logic of resolving this, and want to correctly handle any situations with the mounted volume. I think that if there's a new phpMyAdmin version, we should just overwrite what's in /var/www/html/, but had a nagging concern that there could be a scenario where a user puts their config.inc.php there. But I think that's not possible.

My idea is:

J0WI commented 4 years ago

If you revert #285 you may also want to revert parts of https://github.com/phpmyadmin/docker/pull/286/files#diff-80edf79b0f382a3c6e871ac209ffd6ab to restore the custom user feature. Currently www-data is hardcoded.

ibennetch commented 4 years ago

If you revert #285 you may also want to revert parts of https://github.com/phpmyadmin/docker/pull/286/files#diff-80edf79b0f382a3c6e871ac209ffd6ab to restore the custom user feature. Currently www-data is hardcoded.

Yes, thanks, that's a good suggestion.

ibennetch commented 4 years ago
  • use default folder
  • add an env variable to change the root location
  • add an env variable to fill the root directory with our stored data
  • use the same or add one more to manage the configurations filling process ?

This feels quite complex to me, is such a system worthwhile?

williamdes commented 4 years ago
  • use default folder
  • add an env variable to change the root location
  • add an env variable to fill the root directory with our stored data
  • use the same or add one more to manage the configurations filling process ?

This feels quite complex to me, is such a system worthwhile?

Maybe reverting the diff would be easier. Anyway it did not cause us trouble as far as I know

tianon commented 4 years ago

The problem with the shared volume is that it's essentially a deployment crutch, and it's inherently fragile.

What I'd suggest instead of a shared volume (which is going to ultimately limit scalability) is a short Dockerfile copying the relevant static files from the phpmyadmin image into a new nginx-based image, which can then be scaled separately within the cluster without having a corresponding phpmyadmin container running on every host; something like:

FROM nginx:1.17
COPY --from=phpmyadmin/phpmyadmin:5.0 /var/lib/www /usr/share/nginx/html

You could even go further by pre-baking the NGINX configuration into this image (thus making deployment even simpler).

If you don't need the scalability/performance of NGINX + FPM, that's the use case of the Apache-based default image (which should also work fine behind NGINX, if multiple applications need to run behind the same external port).

J0WI commented 4 years ago

@tianon thanks for sharing your thoughts!

We actually have the same discussion in https://github.com/nextcloud/docker/pull/968. I have some concerns with this variant that the two images may get out of sync.

Would you accept this nginx stub image in the library or how can we distribute it?

Another use case for NGINX + FPM is if you use a shared webserver/proxy and multiple FPM applications. But then prebuild nginx stubs are pretty useless.

tianon commented 4 years ago

I think if you've got multiple FPM applications, the easiest way is to leverage Docker's "copy up" functionality (https://docs.docker.com/engine/reference/commandline/service_create/#options-for-named-volumes, default enabled for -v but default disabled for --mount) and --volumes-from on your NGINX instance (which also then creates the appropriate "dependency" relationship), but I think that's significantly more complex to accomplish on something like Kubernetes, and is still very fragile.

The reality here is that FPM is difficult to deploy and use in Docker (it wasn't really designed for Docker, after all -- they expect to run on the same host as whatever consumes their FastCGI socket, which is reasonable from the perspective of when it was written). Adding another variant that pre-bakes the NGINX configuration is a band-aid to this problem, although it's a slightly less fragile one (IMO) than sharing volumes with container image source code in them? Given the number of users we've seen over the years complaining about how to use the Wordpress FPM variants, I imagine you'll probably see a lot of users who used the NGINX variant and are wondering why it doesn't "seem to work" (because it won't execute any PHP scripts by itself).

I guess I'm really coming back to whether there's something wrong with just using Apache and letting one container be your "source of truth" for the phpMyAdmin application? :smile:

(Maybe NGINX could be convinced to make a new official image variant for NGINX Unit? :smile:)

rpasing commented 4 years ago

Sorry, I didn't really follow this discussion here anymore. What are the results of your thoughts?

What I read so far ("just use the apache-based phpmyadmin image") is not really satisfying: Of course I can proxy that apache httpd through my "external webserver" (which in this case is nginx), but why should I let a full-blown instance of Apache be running just to serve some small static files, which could get served from the nginx directly if it had access to the files? That sounds very unefficient.

A stupid workaround for me for the time being would to create a "stub container" based on Alpine which just copies the files from the phpmyadmin image (like shown above, but now based on Alpine and not nginx) and write an entrypoint script which copies the copied files into a shared volume mount and exits directly afterwards. As I said, stupid workaround.

From my point of view the phpmyadmin php-fpm image should be able to handle a volume mount as storage for its sourcefiles. And that's my problem, it currently doesn't. All "solutions" to this are just workarounds till now.

hbielenia commented 4 years ago

I found this discussion while looking for information on using fpm images, since instructions from here no longer work. Just wanted to state it clearly because it may not be evident from this thread: as far as I can tell, the change made in #285 makes fpm images completely unusable. Those images require a separate web server to handle static files and without shared directory, paths can't be handled correctly. The change you've made means they're no longer able to work with external server, and of course those images don't provide one on their own (since that's the entire point of having them).

For the time being, people can just resort to use "main" (Apache-based) image, but in my opinion reverting #285 should take priority, as it turned out to be a very breaking change. Discussing better solution can take place afterwards.

pzystorm commented 4 years ago

Ah, yes, please revert it. I've just hit exact this problem and commented it already here: https://github.com/phpmyadmin/docker/issues/253#issuecomment-685153896

Apache is no alternative. For the time being I would say I dont use this screwed up phpmyadmin fpm docker image and use my own nginx/fpm docker image and install phpmyadmin from source by my own.

qeepcologne commented 2 years ago

i came to the same conclusion when i tried to use it with haproxy (#327), fpm is not usable.

huancz commented 2 years ago

I stumbled here after painful experience of trying to make alpine version work. I was just trying to have "quick" solution for one of our contractor's request to have access to phpmyadmin on already dockerized wordpress installation. The discussion here steered in a direction that I can't really follow, but I think this post fits at least OP question.

My problem was mainly that my background is c#/dotnet + usual linux devops, last I touched php was some 15 or 20 years ago. I had no idea what fpm is and how it differs from normal php hosted via apache module, in my head I just assumed it's some nickname for phpmyadmin version itself, like those ubuntu release names. Certainly nothing to worry about. I was just trained from previous experience with docker that alpine version is that one to get, unless I have special needs, and fpm was the only alpine version available, so... why not?

Docker hub description doesn't hint at any pitfalls either - just use the image and it will listen on guest port 80, easy. Only the usual caveats of alpine distribution - different libc etc - something image builder should worry about, not user of that image. Even error messages I get from links or curl on host are very similar, unless I pay close attention ("connection timed out" vs. "connection reset by peer". Which is what pointed me at the right direction when I finally did notice it).

tl;dr: Few words on dockerhub that mention current state of alpine-fpm and that it cannot serve http traffic directly without external fastcgi proxy would have been very helpful.

Eagle3386 commented 2 years ago

Docker hub description doesn't hint at any pitfalls either - just use the image and it will listen on guest port 80, easy. Only the usual caveats of alpine distribution - different libc etc - something image builder should worry about, not user of that image. Even error messages I get from links or curl on host are very similar, unless I pay close attention ("connection timed out" vs. "connection reset by peer". Which is what pointed me at the right direction when I finally did notice it).

Thanks so much for this hint - Firefox only showed the 502 Bad Gateway error that my Synology NAS threw at me, the logs where pretty much empty & only using Curl revealed the real error (Connection reset by peer).

tl;dr: Few words on dockerhub that mention current state of alpine-fpm and that it cannot serve http traffic directly without external fastcgi proxy would have been very helpful.

Can you (or @ibennetch or maybe @williamdes) explain to me what needs to be changed in order to get this working on a Synology NAS using Docker & its built-in reverse proxy (Nginx)? Because Synology's own PMA is stuck with 4.x versions & I'd therefore really like to get PMA working (preferably as fpm-alpine flavor)?

PittyXu commented 9 months ago

My solution is overwrite the docker-entrypoint.sh .

docker-compose.yml:

nginx:
  image: nginx:alpine
  container_name: nginx
  ports:
    - "80:80"
  volumes:
    - ./conf:/etc/nginx/conf.d
    - ./html:/usr/share/nginx/html
php:
  image: phpmyadmin:fpm-alpine
  container_name: php
  entrypoint:
    - /var/www/docker-entrypoint.sh
  command: php-fpm
  volumes:
    - ./docker-entrypoint.sh:/var/www/docker-entrypoint.sh
    - ./html:/scripts
    - ./html/phpmyadmin:/var/www/phpmyadmin

/etc/nginx/conf.d/default.conf:

server {
    listen  80;
    root /usr/share/nginx/html;

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

    location ~ ^/.+\.php(/|$) {
        fastcgi_pass php:9000;
        include fastcgi_params;
        fastcgi_index  index.php;
        fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
        fastcgi_param   SCRIPT_FILENAME   /scripts$fastcgi_script_name;
        fastcgi_param   PATH_INFO         $fastcgi_path_info;
        fastcgi_param   PATH_TRANSLATED   /scripts$fastcgi_path_info;
    }
}

./docker-entrypoint.sh

#!/bin/bash

CONTAINER_ALREADY_STARTED="CONTAINER_ALREADY_STARTED_PLACEHOLDER"
if [ ! -e ../$CONTAINER_ALREADY_STARTED ]; then
    touch ../$CONTAINER_ALREADY_STARTED
    echo "-- First container startup --"
    /bin/cp -rfT /var/www/html/. /var/www/phpmyadmin/
else
    echo "-- Not first container startup --"
fi

/docker-entrypoint.sh "$@"
armada45-pixel commented 7 months ago

My solution.

docker
├── docker-compose.yml
├── nginx
│   ├── log
│   │   └── host.access.log
│   ├── config
│   └── nginx.conf
│
└── phpmyadmin
    ├── config.user.inc-v2.php
    └── theme
        ├── blueberry
        ├── boodark
        └── darkwolf

nginx.conf


worker_processes 1;

events {
    worker_connections 1024;
}

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

    log_format main '$remote_addr - $remote_user [$time_local] \t'
    '"$request_method" - "$request_uri" - "$server_protocol" \t'
    '$status $body_bytes_sent "$http_referer" \t'
    '"$http_user_agent" "$http_x_forwarded_for" \t'
    # '$request_time \t'
    ' req_body:"$request_body" \t'
    '$upstream_response_time ms';
    # 'resp_body:"$resp_body"';

    access_log /var/log/nginx/host.access.log main; # store access log on host

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    types_hash_max_size 2048;
    #keepalive_timeout  0;
    keepalive_timeout 65;

    client_max_body_size 50M;

    gzip on;

    server {
        server_name localhost;
        add_header X-Frame-Options "DENY";
        listen 80;
        listen [::]:80;

        root /var/www/html;  # path where phpmyadmin place
        index index.php;

        location ~ \.php$ {
            try_files $fastcgi_script_name =404;

            fastcgi_pass cs_phpmyadmin_FPM:9000;  # cs_phpmyadmin_FPM is name of container / Easier then using ip / or you can use ip instead of name like 172.0.16.1
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }

        ## Images and static content is treated different
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
            access_log off;
            expires 30d;
        }

        location ~ /\.ht {
            deny all;
        }

        location ~ /(libraries|setup/frames|setup/libs) {
            deny all;
            return 404;
        }
    }
}

docker-compose.yml

 version: "3.8"

services:
  cs_phpmyadmin_FPM:
    image: phpmyadmin:fpm-alpine
    ports:
      - "9000:9000/tcp" # or "9123:9000/tcp" and Don't forget to change in nginx.conf "fastcgi_pass"
    volumes:
      - "./phpmyadmin/theme/blueberry:/var/www/html/themes/blueberry"
      - "./phpmyadmin/theme/boodark:/var/www/html/themes/boodark"
      - "./phpmyadmin/theme/darkwolf:/var/www/html/themes/darkwolf"
      - "./phpmyadmin/config.user.inc-v2.php:/etc/phpmyadmin/config.user.inc.php"
      - phpmyadmin-file:/var/www
    secrets:
      - phpmyadmin-config

  cs_nginx:
    image: nginx:alpine
    ports:
      - "8090:80/tcp" # nginx expose port 80 for development i change to 8090
    volumes:
      - "./nginx/config/nginx.conf:/etc/nginx/nginx.conf"
      - "./phpmyadmin/theme/blueberry:/var/www/html/themes/blueberry" # for some resaon need to volume theme again
      - "./phpmyadmin/theme/boodark:/var/www/html/themes/boodark"
      - "./phpmyadmin/theme/darkwolf:/var/www/html/themes/darkwolf"
      - phpmyadmin-file:/var/www

secrets:
  phpmyadmin-config:
    file: ./phpmyadmin/config.user.inc-v2.php

volumes:
  phpmyadmin-file: # use top-level volumes for link file content from phpmyadmin to nginx