Почему Centos minimal не minimal
Как и обещал, начинаю серию статей про серверную оптимизацию. Для начала подготовим систему для тестов: установим ОС, MySQL-сервер, Nginx, Apache. Далее произведем базовую настройку, после чего будем проводить итерации: тестирование/оптимизация.
Приступим к подготовке ОС и сегодня будем урезать базовый дистрибутив Centos 7 устанавливаемый на instance servers.ru.
Содержание:
Intro
Первым делом осмотримся в системе и посмотрим что нам предлагают servers.ru в образе Centos 7:
# yum list installed | wc -l
357
# free -h
total used free shared buff/cache available
Mem: 992M 79M 551M 12M 361M 742M
Swap: 0B 0B 0B
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 29G 1.3G 26G 5% /
devtmpfs 477M 0 477M 0% /dev
tmpfs 497M 0 497M 0% /dev/shm
tmpfs 497M 13M 484M 3% /run
tmpfs 497M 0 497M 0% /sys/fs/cgroup
tmpfs 100M 0 100M 0% /run/user/1000
Итого имеем: 357 пакетов, 1.3Gb занято на диске, доступно 742Mb RAM. Ради эксперимента установил Centos 7 minimal на виртуальную машину и получил 305 пакетов. Взглянем на kickstart файл, который использовался для установки:
%packages
@core
chrony
cloud-init
cloud-utils-growpart
dracut-config-generic
dracut-norescue
firewalld
grub2
kernel
nfs-utils
rsync
tar
yum-utils
-NetworkManager
-aic94xx-firmware
-alsa-firmware
-alsa-lib
-alsa-tools-firmware
-biosdevname
-iprutils
-ivtv-firmware
-iwl100-firmware
-iwl1000-firmware
-iwl105-firmware
-iwl135-firmware
-iwl2000-firmware
-iwl2030-firmware
-iwl3160-firmware
-iwl3945-firmware
-iwl4965-firmware
-iwl5000-firmware
-iwl5150-firmware
-iwl6000-firmware
-iwl6000g2a-firmware
-iwl6000g2b-firmware
-iwl6050-firmware
-iwl7260-firmware
-libertas-sd8686-firmware
-libertas-sd8787-firmware
-libertas-usb8388-firmware
-plymouth
Видимо образ уже оптимизировали, но в итоге получилось еще больше пакетов чем в минимальной установке. Попробуем немного облегчить систему. Можно было бы просто удалить ненужные пакеты, но это слишком легко, пойдем длинным путем - подготовим свой образ для загрузки в OpenStack.
Готовим свой образ для загрузки в OpenStack
Первое что нам понадобится - это образ NetInstall Centos 7 (скачиваем с официального сайта). Далее устанавливаем для своей системы пакеты: qemu, libvirtd, virt-install, virt-manager и virt-sysprep.
Подготавливаем файл kickstart на основе позаимствованного у servers.ru:
# System authorization information
auth --enableshadow --passalgo=sha512
# Reboot after installation
reboot
# Use network installation
url --url="http://mirror.yandex.ru/centos/7/os/x86_64/"
# Firewall configuration
firewall --enabled --service=ssh
firstboot --disable
ignoredisk --only-use=vda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
repo --name "os" --baseurl="http://mirror.yandex.ru/centos/7/os/x86_64/" --cost=100
repo --name "updates" --baseurl="http://mirror.yandex.ru/centos/7/updates/x86_64/" --cost=100
repo --name "extras" --baseurl="http://mirror.yandex.ru/centos/7/extras/x86_64/" --cost=100
# Network information
network --bootproto=dhcp
network --hostname=localhost.localdomain
# Root password
rootpw --iscrypted notpasswd
selinux --enforcing
services --disabled="kdump" --enabled="network,sshd,rsyslog"
timezone UTC --isUtc
# Disk
bootloader --append="console=tty0" --location=mbr --timeout=1 --boot-drive=vda
# Clear the Master Boot Record
zerombr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
part / --fstype="xfs" --ondisk=vda --size=8191
%post --erroronfail
# workaround anaconda requirements
passwd -d root
passwd -l root
echo -n "Creating grub.conf for pvgrub"
rootuuid=$( awk '$2=="/" { print $1 };' /etc/fstab )
mkdir /boot/grub
echo -e 'default=0\ntimeout=0\n\n' > /boot/grub/grub.conf
for kv in $( ls -1v /boot/vmlinuz* |grep -v rescue |sed s/.*vmlinuz-// ); do
echo "title CentOS Linux 7 ($kv)" >> /boot/grub/grub.conf
echo -e "\troot (hd0)" >> /boot/grub/grub.conf
echo -e "\tkernel /boot/vmlinuz-$kv ro root=$rootuuid console=hvc0 LANG=en_US.UTF-8" >> /boot/grub/grub.conf
echo -e "\tinitrd /boot/initramfs-$kv.img" >> /boot/grub/grub.conf
echo
done
#link grub.conf to menu.lst to work
echo -n "Linking menu.lst to old-style grub.conf for pv-grub"
ln -sf grub.conf /boot/grub/menu.lst
ln -sf /boot/grub/grub.conf /etc/grub.conf
# setup systemd to boot to the right runlevel
echo -n "Setting default runlevel to multiuser text mode"
rm -f /etc/systemd/system/default.target
ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
echo .
# this is installed by default but we don't need it in virt
echo "Removing linux-firmware package."
yum -C -y remove linux-firmware
# Remove firewalld; it is required to be present for install/image building.
echo "Removing firewalld."
yum -C -y remove firewalld --setopt="clean_requirements_on_remove=1"
# remove avahi and networkmanager
echo "Removing avahi/zeroconf and NetworkManager"
yum -C -y remove avahi\* Network\*
echo -n "Getty fixes"
# although we want console output going to the serial console, we don't
# actually have the opportunity to login there. FIX.
# we don't really need to auto-spawn _any_ gettys.
sed -i '/^#NAutoVTs=.*/ a\
NAutoVTs=0' /etc/systemd/logind.conf
echo -n "Network fixes"
# initscripts don't like this file to be missing.
cat > /etc/sysconfig/network << EOF
NETWORKING=yes
NOZEROCONF=yes
EOF
# For cloud images, 'eth0' _is_ the predictable device name, since
# we don't want to be tied to specific virtual (!) hardware
rm -f /etc/udev/rules.d/70*
ln -s /dev/null /etc/udev/rules.d/80-net-name-slot.rules
# simple eth0 config, again not hard-coded to the build hardware
cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
DEVICE="eth0"
BOOTPROTO="dhcp"
ONBOOT="yes"
TYPE="Ethernet"
USERCTL="yes"
PEERDNS="yes"
IPV6INIT="no"
PERSISTENT_DHCLIENT="1"
EOF
# simple eth1 config, again not hard-coded to the build hardware
cat > /etc/sysconfig/network-scripts/ifcfg-eth1 << EOF
DEVICE="eth1"
BOOTPROTO="dhcp"
ONBOOT="yes"
TYPE="Ethernet"
USERCTL="yes"
PEERDNS="yes"
IPV6INIT="no"
PERSISTENT_DHCLIENT="1"
EOF
# set virtual-guest as default profile for tuned
echo "virtual-guest" > /etc/tuned/active_profile
# generic localhost names
cat > /etc/hosts << EOF
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
EOF
echo .
# Because memory is scarce resource in most cloud/virt environments,
# and because this impedes forensics, we are differing from the Fedora
# default of having /tmp on tmpfs.
echo "Disabling tmpfs for /tmp."
systemctl mask tmp.mount
cat <<EOL > /etc/sysconfig/kernel
# UPDATEDEFAULT specifies if new-kernel-pkg should make
# new kernels the default
UPDATEDEFAULT=yes
# DEFAULTKERNEL specifies the default kernel package type
DEFAULTKERNEL=kernel
EOL
# make sure firstboot doesn't start
echo "RUN_FIRSTBOOT=NO" > /etc/sysconfig/firstboot
echo "Cleaning old yum repodata."
yum clean all
echo "set instance type markers"
echo 'genclo' > /etc/yum/vars/infra
# chance dhcp client retry/timeouts
cat >> /etc/dhcp/dhclient.conf << EOF
timeout 300;
retry 60;
EOF
# clean up installation logs"
rm -rf /var/log/yum.log
rm -rf /var/lib/yum/*
rm -rf /root/install.log
rm -rf /root/install.log.syslog
rm -rf /root/anaconda-ks.cfg
rm -rf /var/log/anaconda*
rm -rf /root/anac*
echo "Fixing SELinux contexts."
touch /var/log/cron
touch /var/log/boot.log
mkdir -p /var/cache/yum
/usr/sbin/fixfiles -R -a restore
# reorder console entries
sed -i 's/console=tty0/console=tty0 console=ttyS0,115200n8/' /boot/grub2/grub.cfg
#Servers.ru settings
sed -i 's/centos/cloud-user/' /etc/cloud/cloud.cfg
sed -i 's/lock_passwd: true/lock_passwd: false/' /etc/cloud/cloud.cfg
%end
%packages --excludedocs --nobase --instLangs=en
@core --nodefaults
cloud-init
cloud-utils-growpart
dracut-config-generic
dracut-norescue
firewalld
grub2
kernel
nfs-utils
rsync
tar
sudo
-NetworkManager
-aic94xx-firmware
-alsa-*
-biosdevname
-btrfs-progs*
-iprutils
-ivtv-firmware
-iwl*firmware
-libertas-sd8686-firmware
-libertas-sd8787-firmware
-libertas-usb8388-firmware
-plymouth
-kexec-tools
%end
Так как в облачных серверах servers.ru используются два сетевых интерфейса, нам нужно создать еще одну виртуальную сеть. Создаем файл dummynet.xml:
<network>
<name>dummynet</name>
<bridge name="virbr100" />
<forward mode="route" />
<ip address="10.10.120.1" netmask="255.255.255.0" />
</network>
Подключаем сеть:
# virsh net-create dummynet.xml
Для того чтобы сделать файл kickstart доступным по сети запустим Web-сервер в директории с этим файлом (очень часто использую этот метод в работе - удобно стягивать с серверов конфигурационные файлы):
# python -m SimpleHTTPServer 80
Запускаем создание образа:
# qemu-img create -f qcow2 /tmp/centos.qcow2 10G
# virt-install --virt-type kvm \
--name centos \
--ram 2048 \
--disk /tmp/centos.qcow2,format=qcow2 \
--network network=default \
--network network=dummynet \
--os-type=linux --os-variant=centos7.0 \
--location=/tmp/CentOS-7-x86_64-NetInstall-1611.iso \
--nographics \
--extra-args="ip=dhcp ks=http://192.168.122.1/centos7_min.cfg console=tty0 console=ttyS0,115200n8"
В примере:
- 192.168.122.1 - наш ip в виртуальной сети
- centos7_min.cfg - имя kickstart файла
Подготавливаем образ для загрузки:
# virt-sysprep -d centos
# virsh undefine centos
Готовый образ /tmp/centos.qcow2 загружаем через портал servers.ru и создаем новый instance с новым образом.
Итоговый результат
В итоге получаем:
# yum list installed | wc -l
300
# free -h
total used free shared buff/cache available
Mem: 992M 89M 725M 6.5M 177M 742M
Swap: 0B 0B 0B
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 30G 643M 30G 3% /
devtmpfs 484M 0 484M 0% /dev
tmpfs 497M 0 497M 0% /dev/shm
tmpfs 497M 6.6M 490M 2% /run
tmpfs 497M 0 497M 0% /sys/fs/cgroup
tmpfs 100M 0 100M 0% /run/user/1000
tmpfs 100M 0 100M 0% /run/user/0
Результат:
- количество пакетов сократилось с 357 до 300;
- потребление RAM осталось на том же уровне;
- занятое место на диске уменьшилось с 1.3Gb до 643Mb.
P.S. Это только первая итерация в подготовке своего образа, возможно в процессе дальнейших исследований я вернусь к этой статье и переделаю некоторые моменты.
Если у вас есть замечания/предложения - пишите в комментариях, буду признателен.