Skillversitas

MySQL on a MicroVM

Run a MySQL server in a MicroVM for lightweight database workloads. Since MicroVM is minimalist, MySQL needs to be configured to conserve resources.

Preparing the Image

Make sure the MicroVM image already has MySQL installed:

# Mount the image
sudo mount -o loop rootfs.img /mnt/microvm

# Debian/Ubuntu
sudo chroot /mnt/microvm bash -c '
  apt update && apt install -y mysql-server mysql-client
  mysql_install_db --user=mysql --datadir=/var/lib/mysql
'

# Alpine
sudo chroot /mnt/microvm bash -c '
  apk add mysql mysql-client
  mysql_install_db --user=mysql --datadir=/var/lib/mysql
'

sudo umount /mnt/microvm

Configuring MySQL

Create an optimized configuration file for MicroVM:

# Mount the image again
sudo mount -o loop rootfs.img /mnt/microvm

sudo tee /mnt/microvm/etc/mysql/conf.d/microvm.cnf << 'EOF'
[mysqld]
# Resource optimization for MicroVM
bind-address = 0.0.0.0
port = 3306

# Memory tuning
innodb_buffer_pool_size = 64M
innodb_log_file_size = 16M
innodb_log_buffer_size = 4M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Connection
max_connections = 50
thread_cache_size = 8

# Query cache
query_cache_type = 0

# Table cache
table_open_cache = 256

# Temp tables
tmp_table_size = 8M
max_heap_table_size = 8M

# Logging
slow_query_log = 0
general_log = 0

# Disable expensive features
skip-name-resolve
symbolic-links = 0
EOF

sudo umount /mnt/microvm

Running the MicroVM with MySQL

qemu-system-x86_64 \
  -M microvm -enable-kvm -cpu host -m 512m -smp 2 \
  -kernel vmlinuz \
  -append "console=ttyS0 root=/dev/vda rw" \
  -drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=none,aio=linux \
  -device virtio-blk-device,drive=rootfs \
  -netdev user,id=net0,hostfwd=tcp::3306-:3306 \
  -device virtio-net-device,netdev=net0 \
  -nographic -serial stdio

Setting Up Inside the Guest

# Init MySQL
mysql_install_db --user=mysql --datadir=/var/lib/mysql

# Start MySQL
mysqld_safe --user=mysql &

# Wait a few seconds, then secure the installation
mysql_secure_installation

# Create a database and a user
mysql -u root -p << 'SQL'
CREATE DATABASE app_db;
CREATE USER 'app_user'@'%' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;
SQL

Auto Start MySQL

Using an init script (Alpine)

sudo mount -o loop rootfs.img /mnt/microvm

sudo tee /mnt/microvm/etc/init.d/mysqld << 'INITEOF'
#!/sbin/openrc-run

MYSQLD=/usr/sbin/mysqld
PIDFILE=/run/mysqld/mysqld.pid
LOGFILE=/var/log/mysql/mysqld.log

depend() {
    need net
    after firewall
    keyword timeout 300
}

start() {
    ebegin "Starting MySQL"
    mkdir -p /run/mysqld
    chown mysql:mysql /run/mysqld
    start-stop-daemon --start --background \
        --make-pidfile --pidfile $PIDFILE \
        --exec $MYSQLD -- --user=mysql
    eend $?
}

stop() {
    ebegin "Stopping MySQL"
    start-stop-daemon --stop --pidfile $PIDFILE
    eend $?
}
INITEOF

sudo chmod +x /mnt/microvm/etc/init.d/mysqld
sudo chroot /mnt/microvm rc-update add mysqld default

sudo umount /mnt/microvm

Using systemd (Debian/Ubuntu)

sudo chroot /mnt/microvm systemctl enable mysql

Port Forwarding

Access MySQL from the host via port forwarding:

# QEMU command with port forwarding
-netdev user,id=net0,hostfwd=tcp::3306-:3306

# From the host, connect to MySQL
mysql -h 127.0.0.1 -P 3306 -u app_user -p

Backup Database

# Inside the guest
mysqldump -u root -p --all-databases > /data/backup.sql

# or with a file copy
cp /var/lib/mysql/app_db/*.ibd /data/mysql-backup/

# From the host via SSH
ssh -p 2222 root@localhost "mysqldump -u root -p app_db" > local_backup.sql

Monitoring

# Status MySQL
mysqladmin -u root -p status

# Check the connections
mysql -u root -p -e "SHOW PROCESSLIST;"

# Check the database size
mysql -u root -p -e "
  SELECT table_schema AS 'Database',
    ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
  FROM information_schema.tables
  GROUP BY table_schema;
"

Troubleshooting

MySQL will not start

# Check the log
cat /var/log/mysql/mysqld.log

# Check whether the data directory has been initialized
ls /var/lib/mysql/

# Re-initialize if needed
mysql_install_db --user=mysql --datadir=/var/lib/mysql

Out of memory

# Reduce the buffer pool
innodb_buffer_pool_size = 32M

# Reduce max connections
max_connections = 20

# Disable performance_schema
performance_schema = 0

Slow query

# Enable the slow query log for debugging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1