I’ve posted a recipe for chrooting MySQL on Debian sarge a while ago. These instructions no longer work out of the box for newer MySQL packages from Debian and Ubuntu. The main problem is that the startup script added a few extra checks and script invocations that don’t understand the chroot environment. So here’s an updated plan:
- Prepare the chroot directory. It’s recommended to use an extra partition/filesystem for it. I will use
/srv/mysql
(which is an LVM2 partition with an ext3 filesystem on my system) for the rest of the text. - Stop MySQL:
/etc/init.d/mysql stop
- Copy the databases to new location:
mkdir -p /srv/mysql/var/lib cp -a /var/lib/mysql /srv/mysql/var/lib
- Copy this script to
/etc/default/mysql-chroot
- Edit
/etc/init.d/mysql
:- Source the
mysql-chroot
script somewhere at the top:… test -x /usr/sbin/mysqld || exit 0 . /etc/default/mysql-chroot SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) …
- Fix the disk space check:
… # check for diskspace shortage datadir=`mysqld_get_param datadir` if LC_ALL=C BLOCKSIZE= df --portability $CHROOT_DIR$datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then log_failure_msg "$0: ERROR: The partition with $datadir is too full!" …
- Run
setup_chroot
right in the start section:… if mysqld_status check_alive nowarn; then echo "...already running." else setup_chroot /usr/bin/mysqld_safe > /dev/null 2>&1 & …
- Somehow
/var/run/mysqld/mysqld.pid
disappears after each start. We have to create it each time, otherwise thestop
command won’t work properly:… if mysqld_status check_alive warn; then log_end_msg 0 ln -sf $CHROOT_DIR/var/run/mysqld/mysqld.pid \ /var/run/mysqld # Now start mysqlcheck or whatever the admin wants. output=$(/etc/mysql/debian-start) …
- Source the
- In
/etc/mysql/debian.cnf
, change the twosocket
lines to:socket = /srv/mysql/var/run/mysqld/mysqld.sock
- In
/etc/mysql/my.cnf
:- Change the
socket
line in the[client]
section to:socket = /srv/mysql/var/run/mysqld/mysqld.sock
Don’t change the
socket
lines in the other sections! - Add
chroot = /srv/mysql
to the
[mysqld]
section.
- Change the
- Prepend
/srv/mysql
to the log files listed in/etc/logrotate.d/mysql-server
- Make
/usr/bin/mysql_upgrade_shell
use the chrooted socket. Note: Currently these changes must be made each time mysql gets upgraded because upgrades override this file!… --password=*) password=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --socket=*) socket=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --ldata=*|--data=*|--datadir=*) DATADIR=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; … fi $bindir/mysql_fix_privilege_tables --silent --user=$user --password=$password --socket=$socket $args exit 0 … check_args="--check-upgrade --all-databases --auto-repair --user=$user --password=$password --socket=$socket" … $bindir/mysql_fix_privilege_tables --silent --user=$user --password=$password --socket=$socket $args …
- Start MySQL:
/etc/init.d/mysql start
- Check
/var/log/syslog
for errors ;-)