laravellaradockmysql-backuplaravel-backup

Laradock mysqldump not found when executing artisan backup:run (Spatie Laravel Backup)


I have deployed a Laravel application with Laradock.

I want to point out that the database connection works fine (users can register, login, ... etc.).

In order to back up the application, I have installed the Spatie's Laravel Backup package.

I set up all config variables accordingly as follows:

config/backup.php

<?php

return [

    'backup' => [

        /*
         * The name of this application. You can use this name to monitor
         * the backups.
         */
        'name' => env('APP_NAME', 'laravel-backup'),

        'source' => [

            /*......*/

            /*
             * The names of the connections to the databases that should be backed up
             * MySQL, PostgreSQL, SQLite and Mongo databases are supported.
             *
             * The content of the database dump may be customized for each connection
             * by adding a 'dump' key to the connection settings in config/database.php.
             * E.g.
             * 'mysql' => [
             *       ...
             *      'dump' => [
             *           'excludeTables' => [
             *                'table_to_exclude_from_backup',
             *                'another_table_to_exclude'
             *            ]
             *       ],
             * ],
             *
             * If you are using only InnoDB tables on a MySQL server, you can
             * also supply the useSingleTransaction option to avoid table locking.
             *
             * E.g.
             * 'mysql' => [
             *       ...
             *      'dump' => [
             *           'useSingleTransaction' => true,
             *       ],
             * ],
             *
             * For a complete list of available customization options, see https://github.com/spatie/db-dumper
             */
            'databases' => [
                'mysql',
            ],
        ],

        /*
         * The database dump can be compressed to decrease diskspace usage.
         *
         * Out of the box Laravel-backup supplies
         * Spatie\DbDumper\Compressors\GzipCompressor::class.
         *
         * You can also create custom compressor. More info on that here:
         * https://github.com/spatie/db-dumper#using-compression
         *
         * If you do not want any compressor at all, set it to null.
         */
        'database_dump_compressor' => null,

        /*....*/
        ],
    ],

];

In Laravel Homestead the backup works fine.

$ php artisan backup:run.

According to this package's docs, we need to specify the path to the mysqldump binaries as follows:

config/database.php

//config/database.php
'connections' => [
    'mysql' => [
        'driver'    => 'mysql'
        ...,
        'dump' => [
           'dump_binary_path' => '/path/to/the/binary', // only the path, so without `mysqldump` or `pg_dump`
           'use_single_transaction',
           'timeout' => 60 * 5, // 5 minute timeout
           'exclude_tables' => ['table1', 'table2'],
           'add_extra_option' => '--optionname=optionvalue',
        ]  
    ],

This is what I got by default in that same file:

            'mysql' => [
                'driver' => 'mysql',
                'url' => env('DATABASE_URL'),
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE', 'forge'),
                'username' => env('DB_USERNAME', 'forge'),
                'password' => env('DB_PASSWORD', ''),
                'unix_socket' => env('DB_SOCKET', ''),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'prefix_indexes' => true,
                'strict' => true,
                'engine' => null,
                'options' => extension_loaded('pdo_mysql') ? array_filter([
                    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                ]) : [],
                'dump'=>[
                   'dump_binary_path' => env('DB_DUMP_PATH'), // only the path, so without `mysqldump` or `pg_dump`
                   'use_single_transaction',
                   'timeout' => 60 * 5, // 5 minute timeout
                   //'exclude_tables' => ['table1', 'table2'],
                   //'add_extra_option' => '--optionname=optionvalue',
                   'add_extra_option'  => '--host='.env('DB_HOST'), 
                ]
            ],

In my .env file:

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DUMP_PATH='/usr/bin/'

If I execute the mysqldump inside the MySQL container, it does work:

Usage: mysqldump [OPTIONS] database [tables]
OR     mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
OR     mysqldump [OPTIONS] --all-databases [OPTIONS]
For more options, use mysqldump --help

However, If I run the backup command inside the workspace container,

artisan backup:run

I get the error:

Backup failed because: The dump process failed with exitcode 127 : Command not found : sh: 1: mysqldump: not found

Then how do I tell Laradock where the mysqldump binary path is located?

Is there a workaround? Maybe setting up a new container that connects the Workspace with the MySQL container?

Any alternative approach?

SOLVING with the help of Adrien Right at the .env file, I indeed found that the following variable is set to false:

### WORKSPACE #############################################
####
# ...
WORKSPACE_INSTALL_MYSQL_CLIENT=false
# ...

So i changed that to true:

### WORKSPACE #############################################
####
# ...
WORKSPACE_INSTALL_MYSQL_CLIENT=true
# ...

I saved and exited.

This also means that I don't have to make any more changes in the docker-compose.custom.yml file

To apply that change, I executed (without having to stop any container)

$ docker-compose build workspace

$ docker-compose -f docker-compose.custom.yml up -d workspace

Then I got inside the container

$ docker exec -it my_workspace bash

Once inside I looked for mysqldump:

# which mysqldump
/usr/bin/mysqldump

Finally I could execute the Spatie's Laravel Backup package:

# artisan backup:run
Starting backup...
Dumping database xyz...
Determining files to backup...
Zipping x files and directories...
Created zip containing x files and directories. Size is x.x MB
Copying zip to disk named backMeUp...
Successfully copied zip to disk named backMeUp.
Backup completed!

And that did the trick!

Further Issue

That exact same error

The dump process failed with exitcode 127 : Command not found : sh: /usr/bin/mysqldump: not found

shows up when trying to run

artisan backup:run

from a Laravel scheduled task. That means that the php-worker container does not have the mysql-client (therefore, the mysqldump) package installed.

Workaround I logged into the container as follows:

docker exec -it php-worker sh

Then I installed the mysql-client as follows:

/etc/supervisor/conf.d # apk add mysql-client
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/3) Installing mariadb-common (10.5.17-r0)
(2/3) Installing mariadb-client (10.5.17-r0)
(3/3) Installing mysql-client (10.5.17-r0)
Executing busybox-1.32.1-r3.trigger
OK: 358 MiB in 107 packages
/etc/supervisor/conf.d # which mysqldump
/usr/bin/mysqldump
/etc/supervisor/conf.d # exit

That seemed to do the trick?

If so, a new question arises: how to include the mysql-client right from the php-worker Dockerfile?

Answering myself Well, I forgot to set to true all the variables related to "_INSTALL_MYSQL_CLIENT" ...


Solution

  • As mentioned here, edit laradock .env file and set:

    WORKSPACE_INSTALL_MYSQL_CLIENT=true
    

    Then run:

    docker-compose build workspace && docker-composer up -d workspace
    

    That will update your workspace container and restart it.

    Connect to your container:

    docker-compose exec workspace bash
    

    You should have access to mysqldump:

    root@82d8b3b3c0a0:/var/www# which mysqldump
    /usr/bin/mysqldump