21

I have Wordpress running inside Docker, for local development, and it's super slow. My docker-compose.yml looks like this:

version: '3.3'

services:
  db:
    image: mysql:5.7
    volumes:
      - ./db_data:/var/lib/mysql
      - ./dbconfig.cnf:/etc/mysql/conf.d/custom.cnf
    restart: always
    ports:
      - "3308:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: wp_database
      MYSQL_USER: db_user
      MYSQL_PASSWORD: some_secure_password

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "80:80"
      - "443:443"
    restart: always
    volumes:
      - ./wp-content:/var/www/html/wp-content
      - ./.htaccess:/var/www/html/.htaccess
      - ./wp-config.php:/var/www/html/wp-config.php
      - ./logs/debug.log:/var/www/html/wp-content/debug.log
volumes:
  db_data: {}
  wp_content: {}

As far as I read online, it might be the reason I am mounting the wp-content volume, which causes super slow page loading (takes like half a second to load each file, e.g. a jquery file, and it has to load a ton of files for one page).

Is there a solution for this? I read about NFS, but it didn't work for me to configure NFS with docker-compose, somehow I keep getting "permission errors". On the other hand, the Docker interface of macOS already shows me a "Shared folder" tab but I don't know whether I am using those shared folders at the moment or just mounting them again.

Any help is appreciated.

Erik van de Ven
  • 4,747
  • 6
  • 38
  • 80

6 Answers6

11

TL;DR Mount to temporary folder on container, sync that folder with Bindfs to public server folder. Serving WP site with direct mount is slow because container has to access Host files one by one, which is a heavy process. Serving from public folder while files being part directly of container is much faster.

I've encountered exactly the same problem with local WordPress on Docker Compose development. It doesn't matter how fast your computer might be, it'll still be slow when mounting the folders in the containers.

I also tried solutions like NFS and other recommendations like properly excluding the project in the antivirus, adding .dockerignore, etc. which at best improve just slightly the performance.

While browsing for a similar speed improvement I came across this Dockerfile at the WordPress Starter repository https://github.com/visiblevc/wordpress-starter/blob/cd7a3c4dc1dacdfb247fa6a86001cf6909734c87/Dockerfile. If you look at this file you'll see that the way they intialize and mount the project in the container is by mounting it not to, let's say, /var/www/html/ directly, but a temporary folder instead. Then they sync this temporary folder to /var/www/html/ through bindfs. This way every time you load a WordPress page in the browser it'll be lightning fast because it won't have to access and read the Host files on every request. The WordPress files are part of the Linux container. When you make changes to your code those changes will reflect on the container temporary folder and bindfs will instantly sync those changes over to the public container folder, and same the other way around. All changes made on the public folder will be synced over to the temp folder, and from there to your Host project files.

Francesco Meli
  • 2,484
  • 2
  • 21
  • 52
Arman Shahinyan
  • 149
  • 4
  • 8
  • I can't see where this is done in the Dockerfile you suggest. – Pablo Ezequiel Leone Oct 17 '19 at 09:30
  • The part I talk about is in the last block of the dockerfile. You can see that it adds and admin user, adjusts permissions on the /app folder where your WordPress host files will be mounted, and finally it adds a symlink from /app to /var/www/html with the magic of bindfs. – Arman Shahinyan Oct 17 '19 at 20:49
  • 13
    That would be a 404 – Mac Jan 24 '20 at 03:45
  • 3
    You just need to go back in time to find the repo around the posting date to find the dockerfile @ArmanShahinyan is suggesting: https://github.com/visiblevc/wordpress-starter/blob/cd7a3c4dc1dacdfb247fa6a86001cf6909734c87/Dockerfile – Mike Averto Feb 23 '20 at 13:46
  • 1
    Thanks for the hind in the right direction. But I didn't use bindfs as it's not that popular and I try to avoid too many dependencies from unknown sources. But I've found a program with a similar functionality with a very simple syntax: `lsyncd --rsync /source/path /target/path`. Though it's not bidirectional. https://github.com/axkibe/lsyncd – FullStack Alex Jun 22 '20 at 14:48
  • 1
    Normally TL;DR would be at the top of your post, not the bottom. It's not too helpful if someone reads through your entire post then encounters the TL;DR part at the end. At that point they have already read it all and no longer are in need of TL;DR part. – Adam Sep 03 '20 at 07:10
  • downvoted for linking to 404 and not providing code examples. Furthermore the link provided in comments by Mike Averto has provided dosen't address how to apply in a docker-compose.yml using offical images. – kevzettler Dec 10 '22 at 20:35
10

In Mac and Windows there are some volumes performance issues that we should consider.

I made change in my docker-compose.yml

Note as I changed the short syntax to long syntax.

This notation permits add consistency option.

I added wp-content and php-conf (to get php.ini) because they are files directory most frequently called every time when a Wordpress page is loaded in browser.

services:
    wordpress:

        ...

        volumes:
            - ./data:/data
            - ./scripts:/docker-entrypoint-initwp.d
            #- ./wp-content:/app/wp-content
            - type: bind
              source: ./wp-content
              target: /app/wp-content
              consistency: cached
            #- ./php-conf:/usr/local/etc/php
            - type: bind
              source: ./php-conf
              target: /usr/local/etc/php
              consistency: cached

enter image description here

molavec
  • 8,848
  • 1
  • 27
  • 22
3

I have been experiencing the same issue but might have found a solution.

In the docker Desktop app (up top with the time, looks like a whale)

Open Settings Select Resources\File Sharing

Add the relevant folders. I had MySQL and the Wordpress folders in the same parent folder so added that.

Click Apply and Restart.

My website sped up massively.

I hope this helps.

  • Did not help at all :( Exactly same bad load time as before in my case. Could you maybe share some screenshots or code snippets of your docker-compose.yml and/or Dockerfile? – FullStack Alex Jun 22 '20 at 15:03
3

What could be the fix for slowness?

As per Docker best practices, Performance is much higher when files are bind-mounted from the Linux filesystem, rather than remoted from the Windows host. Linux containers only receive file change events, “inotify events”, if the original files are stored in the Linux filesystem and this helps in reloading when files have changed instead of scanning all the files.

Reference docker-compse.yml file used: https://www.hostinger.in/tutorials/run-docker-wordpress [Change the versions as required and apply the below fix in the volumes section of wordpress container]

1. For Docker on Windows, simply use below code in docker-compose.yml:

volumes:
  ["~/{replace_with_a_wsl_dir/}:/var/www/html"]

2. Create a Linux directory in windows to be used as a host directory for volume in the above code:

We need to have the WSL1 or WSL2 for running Docker from Windows 10 or 11. The Windows Subsystem for Linux lets developers run a GNU/Linux environment.

Open Windows Command Prompt (windows > cmd) and enter below commands to create a dir in Windows' Linux

wsl
cd ~
mkdir wsl_dir
sudo chmod 777 ~/wsl_dir

We need run docker compose from wsl itself and don't worry if the yml file is in windows file system as we can access it from wsl itself. The windows file system will be mounted by default at /mnt and you can check by using 'ls /mnt'

cd /mnt/{windows_path_to_the_docker_compose_file}
docker compose up -d

Kudos, you are done!

Mr.Quant
  • 31
  • 2
  • Thanks! My notes: We're literally adding the files into the user folder in WSL Linux: /home/yourname/website-folder The whole point is avoiding the /mnt/c/... path, that's what's making it slow. We're running the whole she-bang from inside WSL. you can still access these files in Windows Explorer, just go to: \\wsl.localhost\Ubuntu-22.04\home\yourname\website-folder (I'm using ubuntu, you may need to change the path to suit your distro) And you can open this folder in Visual Studio Code, however it will ask you if you want to use a special WSL mode, so say yes to that. – Purple Tentacle Jul 08 '23 at 14:26
1

I realized that if you narrow the directories that Docker has to look through to run your site, it'll run much faster. For example, in Docker Desktop Settings, /Users is default in Settings > Resources > File Sharing. If you delete that resource and just narrow it down to the directory your site(s) are in, that'll get rid of a lot of overhead for Docker.

enter image description here

Josh Coast
  • 602
  • 6
  • 7
0

Notes: I am on OS X. I've tried added increasing my RAM and CPU allotted to Docker and also include folders as resources and still things were slow.

I looked into improving docker as much as I could and the biggest things I did that help were:

  1. I had to make sure I wasn't loading any extra files into the container. In my project, for some reason, someone wanted to load the current $PWD into the container. Removing that helped a lot

  2. I added a :delegated flag to the mysql volume. Why use this instead of :cached well I was developing locally so I didn't want the files to be cached which would have led to me reloading the page to try to get the latest changes.

Then, after those improvement I was at about 1-3minute load times for a page. A couples weeks went by and I got the idea to turn off all the wordpress features that involved reading or writing to the database that weren't necessary, such things as autosaving when editing, wp-cron; which are nice features for production but while developing I suspected they were doing too much and causing the long page loads. here is what I went with in my wp-config.php file that I only use while developing locally:

define( 'AUTOSAVE_INTERVAL', 60*60*60*24*365 ); // Set autosave interval to 1x per year
define( 'EMPTY_TRASH_DAYS',  0 ); // Empty trash now: Zero days
define( 'WP_POST_REVISIONS', false );
define( 'DISABLE_WP_CRON', true ); // sends an XHR request with timestamp to server on every page load which queries db for posts that may need to be published and does so; :gross:

I hope this helps someone. IMHO I shouldn't have to do this since I can run a MAMP/LAMP stack with wordpress just fine. I do NOT have an answer as to why docker and wordpress perform so poorly on my operating system and with Docker Desktop

Sgnl
  • 1,808
  • 22
  • 30