Փաթեթներ, log-եր, cron և սկավառակներ
Սերվերը պահիր թարմացված, իմացիր, թե որտեղ են log-երը, պլանավորիր job-եր և երբեք մի մնա առանց սկավառակի տեղի։
30 վայրկյանում
Սերվերի սպասարկման մեծ մասը հանգում է չորս բանի՝ package manager-ով ծրագրերի տեղադրում և թարմացում, log-երի ընթերցում և rotation, կրկնվող job-երի պլանավորում և սկավառակի ու հիշողության հսկում։ Միայն լցված սկավառակը կարող է միանգամից շարքից հանել տվյալների բազան, վեբ սերվերը և deploy-ը։ Այս դասը տալիս է հրամաններն ու սովորությունները, որոնք սերվերը առողջ են պահում։
Ինչու եմ օգտագործում
- unattended-upgrades-ը յուրաքանչյուր սերվերի իմ baseline-ի մասն է, որովհետև չթարմացված փաթեթները ներս մտնելու ամենահեշտ ճանապարհներից են։
- Մեկ production սերվերի սկավառակի զբաղվածությունը 91%-ից իջեցրի 66%-ի՝ գտնելով հին log-երը, հին build-երը և չափազանց մեծ node_modules-ները։
- Սկավառակի, load-ի և uptime-ի monitoring-ը իմ ստանդարտ ցուցակում է, որովհետև լցված սկավառակը լուռ ձախողում է, մինչև ամեն ինչ միանգամից կոտրվի։
Ինչպես է աշխատում
01apt՝ ծրագրերի տեղադրում և թարմացում
Debian-ում և Ubuntu-ում apt-ը ծրագրեր է տեղադրում վստահելի repository-ներից, լուծում է dependency-ները և ստուգում է փաթեթների ստորագրությունները։ apt update-ը թարմացնում է հասանելի տարբերակների ցուցակը․ այն ոչինչ չի տեղադրում։ apt upgrade-ը տեղադրում է արդեն եղածի նոր տարբերակները, իսկ apt full-upgrade-ը կարող է նաև փաթեթներ ավելացնել կամ հեռացնել, երբ dependency-ները փոխվում են, ինչը պետք է kernel-ի թարմացումների համար։ RHEL ընտանիքի համակարգերում նույն աշխատանքներն արվում են dnf-ով (dnf check-update, dnf upgrade)։ Նախընտրիր դիստրիբուտիվի repository-ների փաթեթները․ third-party repository-ներ ավելացրու միայն վստահելի vendor-ներից՝ օգտագործելով նրանց signed-by keyring-ները։ Kernel-ի կամ core գրադարանի թարմացումից հետո ստուգիր՝ արդյոք reboot է պահանջվում։
sudo apt update # refresh package lists
apt list --upgradable # what would change
sudo apt upgrade # install updates
sudo apt full-upgrade # also handle changed dependencies
sudo apt install nginx htop # install packages
sudo apt remove --purge apache2 # remove, including config
sudo apt autoremove # remove unused dependencies
apt show nginx; apt policy nginx # details and versions
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required
02Անվտանգության ավտոմատ թարմացումներ
unattended-upgrades-ը ամեն օր ավտոմատ տեղադրում է անվտանգության թարմացումները, այնպես որ հայտնի անցքերը փակվում են, նույնիսկ երբ ոչ ոք մուտք չի գործում։ Այն լռելյայն տեղադրված է Ubuntu Server-ում․ կարող ես ստուգել և միացնել այն dpkg-reconfigure-ով։ Լռելյայն այն կիրառում է միայն security pocket-ի թարմացումները, ինչը խելամիտ հավասարակշռություն է անվտանգության և կայունության միջև։ Կարող ես կարգավորել այն ավտոմատ reboot անելու հանգիստ ժամին, երբ kernel-ի թարմացումը դա պահանջում է, և հին kernel-ները մաքրելու։ RHEL-ում համարժեքը dnf-automatic-ն է։ Դրա log-ը՝ /var/log/unattended-upgrades/-ում, ցույց է տալիս, թե ինչ և երբ է տեղադրվել։ Ավտոմատ թարմացումները չեն փոխարինում major տարբերակների միջև պլանավորված upgrade-ներին, որոնք պետք է նախ փորձարկես։
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades # enable
cat /etc/apt/apt.conf.d/20auto-upgrades
# In /etc/apt/apt.conf.d/50unattended-upgrades you can set:
# Unattended-Upgrade::Automatic-Reboot "true";
# Unattended-Upgrade::Automatic-Reboot-Time "04:00";
# Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
sudo unattended-upgrade --dry-run --debug # test it
03Log-եր՝ /var/log, journald և logrotate
Ժամանակակից սերվերի վրա log-երի երկու համակարգ կա։ systemd-ի journal-ը հավաքում է ծառայությունների և kernel-ի output-ը․ այն կարդում ես journalctl-ով։ /var/log-ի դասական տեքստային ֆայլերը գալիս են rsyslog-ից և nginx-ի նման հավելվածներից։ Ubuntu-ում օգտակար ֆայլերն են /var/log/syslog-ը՝ ընդհանուր հաղորդագրությունների համար, /var/log/auth.log-ը՝ login-ների և sudo-ի համար, և /var/log/nginx/-ը՝ վեբ traffic-ի և սխալների համար (RHEL-ն օգտագործում է /var/log/messages և /var/log/secure)։ Log-երը անվերջ աճում են, եթե ինչ-որ բան դրանք չկրճատի։ logrotate-ը դա անում է տեքստային ֆայլերի համար․ այն վերանվանում է ընթացիկ ֆայլը, սեղմում է հները և պահում միայն որոշակի քանակ։ Journal-ի համար սահմանիր չափի սահմանափակում journald-ի config-ում կամ մաքրիր այն vacuum-ով։
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
# Test without changing anything: sudo logrotate -d /etc/logrotate.d/myapp
# Journal size: journalctl --disk-usage
# sudo journalctl --vacuum-size=500M
# Permanent cap: SystemMaxUse=500M in /etc/systemd/journald.conf
04Պլանավորում cron-ով
cron-ը հրամաններ է գործարկում ժամանակացույցով։ Յուրաքանչյուր օգտատեր ունի crontab (խմբագրիր այն crontab -e-ով), իսկ համակարգային job-երը գտնվում են /etc/crontab-ում և /etc/cron.d-ում։ Տողն ունի հինգ ժամանակային դաշտ՝ րոպե, ժամ, ամսվա օր, ամիս և շաբաթվա օր, որոնց հաջորդում է հրամանը։ Աստղանիշը նշանակում է «ամեն», */5-ը՝ «ամեն հինգը», իսկ 1-5-ի նման միջակայքերը՝ երկուշաբթիից ուրբաթ։ Cron-ն աշխատում է նվազագույն environment-ով․ PATH-ը կարճ է, և shell profile-դ չի բեռնվում, ուստի օգտագործիր բացարձակ ճանապարհներ և output-ը վերաուղղորդիր log, այլապես սխալներն անհետանում են։ Cron-ն օգտագործում է սերվերի ժամային գոտին, որը cloud սերվերներում հաճախ UTC է։ crontab.guru-ի նման կայքը օգնում է ստուգել արտահայտությունը։
# m h dom mon dow command
*/5 * * * * /usr/local/bin/healthcheck.sh >> /var/log/healthcheck.log 2>&1
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
30 2 * * 1 /usr/local/bin/weekly-report.sh
# Laravel scheduler: run every minute as the app user
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
# Prevent overlapping runs with flock
0 * * * * flock -n /tmp/sync.lock /usr/local/bin/sync.sh
05Սկավառակներ՝ df, du, lsblk և mount
df-ը ցույց է տալիս, թե որքան է լցված յուրաքանչյուր mount արված ֆայլային համակարգ, du-ն՝ որքան տեղ են զբաղեցնում ֆայլերն ու դիրեկտորիաները։ lsblk-ը ցուցակում է block սարքերը, այնպես որ կարող ես տեսնել սկավառակներն ու partition-ները, ներառյալ նոր միացրած volume-ը։ Նոր volume օգտագործելու համար մեկ անգամ ստեղծիր ֆայլային համակարգ դրա վրա (ext4-ը անվտանգ լռելյայն է), mount արա այն և ավելացրու /etc/fstab-ում ըստ UUID-ի, որպեսզի reboot-ից հետո վերադառնա։ fstab-ը ստուգիր mount -a-ով մինչև reboot անելը, որովհետև կոտրված գրառումը կարող է խանգարել սերվերի boot-ին։ Հետևիր նաև inode-ներին df -i-ով․ սկավառակը կարող է «լցված» լինել ազատ տեղով, եթե միլիոնավոր փոքր ֆայլեր (session-ներ, cache) սպառել են բոլոր inode-ները։
df -h # space per filesystem
df -i # inodes per filesystem
lsblk -f # disks, partitions, filesystems, UUIDs
sudo mkfs.ext4 /dev/sdb # format a NEW empty volume (destroys data!)
sudo mkdir -p /mnt/data
sudo mount /dev/sdb /mnt/data
# /etc/fstab line (use the UUID from lsblk -f):
# UUID=your-uuid /mnt/data ext4 defaults,nofail 0 2
sudo mount -a # test fstab before rebooting
06Ինչն է լցնում սկավառակը
Երբ df-ը ցույց է տալիս սկավառակ 90% կամ ավելի, աշխատիր վերևից ներքև։ du-ն խորության սահմանափակմամբ ցույց է տալիս ամենամեծ դիրեկտորիաները․ կրկնիր ամենամեծի ներսում։ ncdu-ն ինտերակտիվ տարբերակ է, որը սա արագ է դարձնում։ Սովորական կասկածյալներն են հին log-երը և rotate արված արխիվները, systemd journal-ը, Docker image-ները և build cache-ը, deploy-ների հին release թղթապանակները, node_modules և vendor դիրեկտորիաները, home դիրեկտորիաներում մոռացված տվյալների բազայի dump-երը և apt-ի փաթեթների cache-ը։ Մեկ թակարդ՝ եթե ջնջում ես log ֆայլ, որը պրոցեսը դեռ բաց է պահում, տեղը չի ազատվում, մինչև այդ պրոցեսը restart չանի կամ ֆայլը նորից չբացի։ lsof +L1-ը ցուցակում է այդ ջնջված, բայց բաց ֆայլերը։ Կենդանի log-ը truncate անելն ավելի անվտանգ է, քան ջնջելը։
sudo du -xh --max-depth=1 / | sort -h | tail
sudo du -xh --max-depth=1 /var | sort -h | tail
sudo ncdu -x / # interactive (apt install ncdu)
sudo find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null
journalctl --disk-usage
docker system df # images, containers, cache
sudo apt clean # apt package cache
sudo lsof +L1 # deleted files still held open
sudo truncate -s 0 /var/log/myapp/huge.log # empty a live log safely
07Հիշողություն և swap
free -h-ը ցույց է տալիս հիշողությունը։ Մի խուճապի մատնվիր փոքր «free» թվից․ Linux-ը ազատ հիշողությունն օգտագործում է որպես disk cache և վերադարձնում է այն, երբ հավելվածներին պետք է։ Կարդալու սյունը available-ն է։ Երբ available հիշողությունը սպառվում է, kernel-ի OOM (out of memory) killer-ը ավարտում է պրոցեսներից մեկը, հաճախ ամենամեծը, որը հաճախ քո տվյալների բազան է։ Swap-ը սկավառակի տեղ է, որն օգտագործվում է որպես լրացուցիչ հիշողություն։ Այն շատ ավելի դանդաղ է, քան RAM-ը, բայց փոքր VPS-ի վրա համեստ swap ֆայլը (1-ից 2 GB) հանկարծակի crash-ը վերածում է դանդաղման, որը կարող ես նկատել և շտկել։ Եթե սերվերը անընդհատ swap է անում, քեզ պետք է ավելի շատ RAM կամ քիչ ագահ հավելված, ոչ թե ավելի շատ swap։
free -h # read the "available" column
sudo journalctl -k | grep -i "out of memory" # OOM kills
# Create a 2 GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab
swapon --show
Օգտագործեք, երբ
- Քո յուրաքանչյուր սերվեր․ թարմացումները, log rotation-ը և սկավառակի monitoring-ը հիմնական հիգիենա են։
- Լցված սկավառակի incident-ներ, ձախողվող deploy-ներ կամ գրելը մերժող տվյալների բազաներ։
- Կրկնվող առաջադրանքներ, ինչպես backup-ներ, հաշվետվություններ, մաքրումներ և framework-ների scheduler-ներ։
- Փոքր VPS instance-ներ, որտեղ swap ֆայլը և journal-ի սահմանափակումները կանխում են խուսափելի crash-երը։
Մի՛ օգտագործեք, երբ
- Production-ում մի գործարկիր apt full-upgrade կամ major release upgrade առանց snapshot-ի և maintenance window-ի։
- Ծանրաբեռնված տվյալների բազայի սերվերի վրա swap-ը մի օգտագործիր որպես բավարար RAM-ի փոխարինող։
- Միայն տեղ ազատելու համար մի ջնջիր ֆայլեր, որոնք չես հասկանում․ նախ ստուգիր, թե ինչն է դրանք գրում։
Այլընտրանքներ
- dnf / dnf-automatic
apt-ի և unattended-upgrades-ի համարժեքները RHEL-ում, Rocky-ում և Alma-ում։
- systemd timer-ներ
cron-ի ավելի դիտարկելի այլընտրանք՝ journal-ի log-երով և բաց թողածի լրացմամբ։
- Կենտրոնացված logging (Loki, ELK, hosted)
Log-երը տեղափոխիր սերվերից դուրս, որպեսզի կարողանաս որոնել բոլոր մեքենաներում և պահել դրանք սկավառակի մահից հետո էլ։
- Object storage
Օգտատերերի upload-ները և backup-ները տեղափոխիր S3-համատեղելի storage, որպեսզի սերվերի սկավառակը մնա փոքր և փոխարինելի։
Լավագույն պրակտիկաներ
- Միացրու unattended-upgrades-ը անվտանգության թարմացումների համար և ստուգիր պահանջվող reboot-ները։
- Մեծ upgrade-ներից առաջ snapshot արա և նախ upgrade արա staging-ը։
- Հավելվածի յուրաքանչյուր log-ի համար logrotate կանոն տուր և սահմանափակիր journal-ի չափը։
- Alert սահմանիր սկավառակի զբաղվածության վրա շատ ավելի վաղ, քան այն կլցվի, օրինակ՝ 80%-ում։
- Cron-ում օգտագործիր բացարձակ ճանապարհներ, output-ը վերաուղղորդիր log և flock-ով կանխիր իրար վրա ընկնելը։
- Լրացուցիչ volume-ները mount արա ըստ UUID-ի nofail տարբերակով և fstab-ը ստուգիր mount -a-ով։
- Release-ները, Docker image-ները և build cache-երը մաքրիր որպես deploy գործընթացի մաս։
Տարածված սխալներ
- apt upgrade գործարկել առանց նախապես apt update-ի, ուստի ոչ մի նոր բան չի տեղադրվում։
- Կենդանի log-ը ջնջել rm-ով և տեսնել, որ տեղ չի ազատվել, որովհետև պրոցեսը դեռ բաց է պահում այն։
- Cron job-եր, որոնք աշխատում են տերմինալում, բայց աննկատ ձախողվում են PATH-ի կամ բացակայող վերաուղղորդման պատճառով։
- Տառասխալ /etc/fstab-ում, որը խանգարում է սերվերի boot-ին։
- Կարդալ «free» հիշողությունը «available»-ի փոխարեն և ավելացնել RAM, որը պետք չէր։
Խորը վերլուծություն
08apt-ի տակ․ dpkg, source-եր, pinning և phased updates
apt-ը պլանավորողն է, տեղադրումն անում է dpkg-ն։ dpkg-ն բացում է .deb արխիվները, գործարկում է դրանց maintainer script-երը և վիճակը գրանցում /var/lib/dpkg-ում։ Եթե upgrade-ն ընդհատվում է, փաթեթները մնում են կիսակարգավորված, մինչև գործարկես dpkg --configure -a։ Ubuntu 24.04-ից repository-ները նկարագրվում են deb822 ֆորմատով, այնպիսի ֆայլերում, ինչպես /etc/apt/sources.list.d/ubuntu.sources-ն է, իսկ երրորդ կողմի repository-ները պետք է իրենց key-ը նշեն Signed-By-ով, որպեսզի այդ key-ը չկարողանա երաշխավորել այլ repository-ներ։ Pinning-ը /etc/apt/preferences.d-ում սահմանում է repository-ների միջև առաջնահերթություններ, իսկ apt-mark hold-ը սառեցնում է փաթեթի տարբերակը, երբ upgrade անելուց առաջ պետք է սպասել։ Ubuntu-ն օգտագործում է նաև phased updates․ ոչ անվտանգային թարմացումները մի քանի օրվա ընթացքում տարածվում են մեքենաների աճող տոկոսի վրա, ուստի apt-ը կարող է որոշ upgrade-ներ ցույց տալ որպես «deferred due to phasing»։ Դա սպասելի է, ոչ թե կոտրված mirror։
# /etc/apt/sources.list.d/vendor.sources (deb822 format)
Types: deb
URIs: https://packages.example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/vendor.gpg
# Useful commands:
# sudo dpkg --configure -a # finish interrupted installs
# sudo apt-mark hold nginx # freeze a version (unhold to undo)
# apt-cache policy nginx # which repo and priority wins
# dpkg -S /usr/sbin/nginx # which package owns a file
# zgrep ' install ' /var/log/dpkg.log* # install history
09Ֆայլային համակարգեր․ reserved block-եր, volume-ների մեծացում և LVM
ext4-ը լռելյայն պահում է բլոկների 5%-ը root-ի համար, որպեսզի root-ով աշխատող ծառայությունները շարունակեն աշխատել, երբ օգտատերերը լցնում են սկավառակը։ 500 GB data volume-ի վրա դա 25 GB է․ tune2fs -m 1-ը նվազեցնում է այն, բայց root ֆայլային համակարգի վրա պահիր լռելյայնը։ ext4-ը կարելի է մեծացնել online և փոքրացնել միայն offline, իսկ XFS-ը՝ RHEL-ի լռելյայնը, կարելի է մեծացնել online, բայց երբեք չի փոքրացվում։ Երբ provider-ի մոտ մեծացնում ես սկավառակը, ֆայլային համակարգն ինքնուրույն չի մեծանում․ եթե սկավառակն ունի partition-ներ, նախ մեծացրու partition-ը growpart-ով, հետո ֆայլային համակարգը resize2fs-ով (ext4) կամ xfs_growfs-ով (XFS)։ Շատ cloud image-ներ դա ավտոմատ անում են root սկավառակի համար boot-ի ժամանակ cloud-init-ի միջոցով, բայց միացված volume-ները սովորաբար ձեռքով են պահանջում։ LVM-ն ավելացնում է շերտ, որը թույլ է տալիս միավորել սկավառակներ, մեծացնել logical volume-ներ և snapshot-ներ անել՝ ավելի շատ շարժվող մասերի գնով։
lsblk # disk vs partition sizes
sudo growpart /dev/vda 1 # grow partition 1 to fill the disk
sudo resize2fs /dev/vda1 # grow ext4 online
sudo xfs_growfs / # grow XFS (by mount point)
sudo resize2fs /dev/sdb # unpartitioned volume: grow directly
sudo tune2fs -l /dev/sdb | grep -i 'reserved block count'
sudo tune2fs -m 1 /dev/sdb # 1% reserved on a data volume
sudo lvextend -r -l +100%FREE /dev/vg0/data # LVM: grow LV and filesystem
10I/O-ի և հիշողության ճնշման ախտորոշում
Երբ սերվերը դանդաղ է, բայց CPU-ն պարապ է, չափիր սկավառակը։ vmstat 1-ը ամեն վայրկյան ցույց է տալիս I/O-ի վրա արգելափակված պրոցեսները (b), swap-in-ը և swap-out-ը (si, so) և I/O-ի սպասման CPU ժամանակը (wa)։ iostat -x 1-ը (sysstat փաթեթ) ցույց է տալիս ըստ սարքի latency-ն r_await-ում և w_await-ում և utilization-ը․ SSD-ների և ցանցային volume-ների վրա latency-ն և provider-ի IOPS սահմանն ավելի կարևոր են, քան %util-ը։ iotop-ը կամ pidstat -d 1-ը ցույց են տալիս, թե որ պրոցեսն է I/O անում։ Գրառումները նախ գնում են page cache, իսկ ավելի ուշ flush են արվում, ուստի մեծ գրառումը կարող է արագ թվալ, իսկ հետո writeback-ի ժամանակ ամեն ինչ կանգնեցնել։ /proc/pressure/io-ում և /proc/pressure/memory-ում Pressure Stall Information-ը ցույց է տալիս, թե ժամանակի որ մասն են task-երը կանգնած եղել, ինչը շատ ավելի լավ ազդանշան է, քան ազատ հիշողությունը։ vm.swappiness-ը կառավարում է, թե որքան պատրաստակամ է kernel-ը swap անում․ լռելյայն 60-ը նորմալ է սերվերների մեծ մասի համար։
vmstat 1 5 # b, si/so, wa columns
iostat -x 1 3 # r_await, w_await, %util per device
sudo iotop -oPa # processes doing I/O (accumulated)
pidstat -d 1 5 # per-process disk reads/writes
cat /proc/pressure/io # some/full stall percentages
grep -E 'Dirty|Writeback' /proc/meminfo
sysctl vm.swappiness
11Log pipeline-ի նախագծում
Մեկ սերվերի վրա journald-ը logrotate-ի հետ բավարար է, եթե չափերը սահմանափակես։ journald-ը log-երը պահում է /var/log/journal-ում, երբ այդ դիրեկտորիան գոյություն ունի կամ դրված է Storage=persistent, հակառակ դեպքում՝ միայն հիշողության մեջ /run-ի տակ, և դրանք անհետանում են reboot-ի ժամանակ։ Այն նաև rate limit է կիրառում աղմկոտ ծառայությունների վրա (RateLimitIntervalSec և RateLimitBurst), ուստի ցիկլով կրկնվող սխալը կարող է թաքցնել իր կրկնությունները․ journal-ը գրանցում է, թե քանի հաղորդագրություն է ճնշվել։ Մեկ սերվերից այն կողմ log-երը պետք է լքեն մեքենան․ agent-ը, ինչպես Grafana Alloy-ն (Promtail-ի հաջորդը), Vector-ը կամ Fluent Bit-ը, կարդում է journal-ը և ֆայլերը և ուղարկում Loki, Elasticsearch կամ hosted ծառայություն։ Նախընտրիր կառուցվածքային JSON log-եր համաձայնեցված դաշտերով, ինչպես level-ը, request ID-ն և user ID-ն, որպեսզի կարողանաս ֆիլտրել grep-ի փոխարեն։ Retention-ը որոշիր ըստ տիպի՝ debug log-երը օրերով, access log-երը շաբաթներով, audit log-երը այնքան, որքան պահանջում է policy-ն։
# /etc/systemd/journald.conf.d/size.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=2G
MaxRetentionSec=30day
RateLimitIntervalSec=30s
RateLimitBurst=10000
# Apply: sudo systemctl restart systemd-journald
# Check: journalctl --disk-usage; journalctl --verify
Իրական իրավիճակներ
apt-ը կողպված է կամ կիսատ է մնացել
Խնդիր
apt install-ը ձախողվում է «Could not get lock /var/lib/dpkg/lock-frontend» սխալով, իսկ upgrade-ի ժամանակ SSH session-ի կտրվելուց հետո apt-ը բողոքում է, որ dpkg-ն ընդհատվել է։
Ինչպես լուծել
Նախ ստուգիր՝ արդյոք մեկ այլ apt իսկապես աշխատում է․ ps aux | grep -E 'apt|dpkg|unattended' և systemctl status unattended-upgrades apt-daily-upgrade.service։ Նոր սերվերներում unattended-upgrades-ը հաճախ աշխատում է boot-ից անմիջապես հետո, ուստի սպասիր դրան՝ lock ֆայլերը ջնջելու փոխարեն, ինչը կարող է վնասել dpkg-ի բազան։ Եթե ոչինչ չի աշխատում, և նախորդ upgrade-ն ընդհատվել է, գործարկիր sudo dpkg --configure -a, հետո sudo apt -f install՝ կոտրված կախվածությունները շտկելու համար, հետո նորից apt update և upgrade։ Կարդա /var/log/apt/term.log-ը՝ ձախողվող maintainer script-ը գտնելու համար։ Հետագայում երկար upgrade-ները գործարկիր tmux-ի ներսում, որպեսզի կտրված connection-ը դրանք չսպանի։
Provider-ի սկավառակը մեծացվել է, բայց df-ը ցույց է տալիս հին չափը
Խնդիր
Provider-ի panel-ում միացված volume-ը մեծացրիր 100 GB-ից 200 GB։ lsblk-ը ցույց է տալիս 200 GB, բայց df -h-ը դեռ 100 GB է հաղորդում, և սկավառակը դեռ գրեթե լիքն է։
Ինչպես լուծել
Block device-ը մեծացել է, բայց partition-ը և ֆայլային համակարգը՝ ոչ։ Գործարկիր lsblk -f՝ դասավորությունը և ֆայլային համակարգի տիպը տեսնելու համար։ Եթե ֆայլային համակարգն անմիջապես սարքի վրա է (առանց partition-ի, ինչը տարածված է volume-ների համար), մեծացրու այն online՝ sudo resize2fs /dev/sdb ext4-ի համար կամ sudo xfs_growfs /mnt/data XFS-ի համար։ Եթե կա partition, նախ sudo growpart /dev/sdb 1, հետո resize արա partition-ի ֆայլային համակարգը։ LVM-ի դեպքում օգտագործիր pvresize, հետո lvextend -r։ Սկսելուց առաջ snapshot արա։ Հետո շտկիր նաև աճի արմատական պատճառը, քանի որ ավելի մեծ սկավառակը միայն ժամանակ է շահում, եթե log-երը կամ upload-ները անսահմանափակ են աճում։
«No space left on device»՝ գիգաբայթներով ազատ տեղով
Խնդիր
Upload-ները և PHP session-ները ձախողվում են «No space left on device» սխալով, բայց df -h-ը ցույց է տալիս սկավառակը 60%-ով։ Ծառայությունների restart-ը չի օգնում։
Ինչպես լուծել
Ստուգիր inode-ները df -i-ով․ եթե IUse%-ը 100% է, ֆայլային համակարգին վերջացել են ֆայլերի գրառումները, սովորաբար միլիոնավոր փոքրիկ ֆայլերի պատճառով։ Ամենաշատ ֆայլերով դիրեկտորիան գտիր sudo find / -xdev -type f | cut -d/ -f2-4 | sort | uniq -c | sort -rn | head-ով։ Տիպիկ մեղավորներն են PHP session ֆայլերն առանց garbage collection-ի, cache դիրեկտորիաները կամ mail queue-երը։ Հիները ջնջիր find -mtime +2 -delete-ով ճիշտ դիրեկտորիայում։ Հետո շտկիր պատճառը․ միացրու session-ների garbage collection-ը կամ session-ները տեղափոխիր Redis, ավելացրու մաքրման timer և alert դիր inode-ների օգտագործման վրա՝ տեղի հետ մեկտեղ։ Նոր ֆայլային համակարգերի համար, որոնք պահելու են հսկայական քանակությամբ փոքր ֆայլեր, inode ratio-ն ընտրիր mkfs-ի ժամանակ։
Արագ ուղեցույց
- Ավարտել ընդհատված փաթեթի տեղադրումը
sudo dpkg --configure -a && sudo apt -f install- Որ փաթեթին է պատկանում ֆայլը
dpkg -S /usr/bin/curl- Սառեցնել / ապասառեցնել փաթեթի տարբերակը
sudo apt-mark hold nginx / sudo apt-mark unhold nginx- Մեծացնել partition-ը և ext4 ֆայլային համակարգը
sudo growpart /dev/vda 1 && sudo resize2fs /dev/vda1- Ամենաշատ ֆայլերով դիրեկտորիաները (inode-ներ)
sudo du --inodes -x -d 2 / | sort -n | tail- Սկավառակի latency ըստ սարքի
iostat -x 1 3- I/O անող պրոցեսները
sudo iotop -oPa- Նախորդ boot-ի log-երը
journalctl -b -1 -p warning- Հիմա փոքրացնել journal-ը
sudo journalctl --vacuum-time=14d- Ստիպողաբար գործարկել logrotate-ը կանոնը փորձարկելու համար
sudo logrotate -vf /etc/logrotate.d/myapp
Իմ իրական նախագծերում
- Մեկ սերվերի սկավառակի զբաղվածությունը 91%-ից իջեցրի 66%-ի՝ մաքրելով հին log-երը, հին build-երը և չափազանց մեծ node_modules-ները, և դրանից հետո ստուգեցի դրա backup-ները։
- unattended-upgrades-ը և սկավառակի, load-ի ու uptime-ի monitoring-ը այն baseline-ի մեջ են, որը կիրառում եմ բոլոր սերվերների վրա։
- Սերվերներիս վրա cron-ով եմ գործարկում Laravel-ի scheduler-ը։
- POS SaaS սերվերի վրա log-երը կենտրոնացված հավաքվում են Loki-ով և վիզուալացվում Grafana-ում՝ Prometheus-ի մետրիկաների կողքին։
Հարցեր և պատասխաններ
Q1Ո՞րն է տարբերությունը apt update-ի և apt upgrade-ի միջև։
apt update-ը միայն ներբեռնում է փաթեթների թարմ ցուցակները կարգավորված repository-ներից, որպեսզի apt-ն իմանա, թե որ տարբերակներն են գոյություն ունեն։ Այն ոչ մի ծրագիր չի փոխում։ apt upgrade-ը հետո տեղադրում է արդեն տեղադրված փաթեթների նոր տարբերակները՝ ոչինչ չհեռացնելով։ apt full-upgrade-ը գնում է ավելի հեռու և կարող է տեղադրել նոր dependency-ներ կամ հեռացնել փաթեթներ upgrade-ն ավարտելու համար, ինչը պետք է kernel-ի և որոշ գրադարանների թարմացումներին։ Այնպես որ նորմալ հաջորդականությունն է՝ update, հետո upgrade։ Production-ում նախ դիտում եմ apt list --upgradable-ը, մեծ փոփոխություններից առաջ snapshot եմ անում և թողնում եմ, որ unattended-upgrades-ը ամեն օր մշակի սովորական անվտանգության շտկումները։ Ubuntu-ի թողարկումների միջև անցումը առանձին, պլանավորված do-release-upgrade է։
Q2Production սերվերի սկավառակը լցված է։ Ի՞նչ կանես։
Նախ կայունացնում եմ․ df -h՝ տեսնելու, թե որ ֆայլային համակարգն է լցված, և df -i՝ inode-ների սպառումը բացառելու համար։ Հետո պատճառը գտնում եմ du -xh --max-depth=1-ով՝ դասավորված ըստ չափի, խորանալով ամենամեծ դիրեկտորիաների մեջ, կամ ncdu-ով։ Սովորական մեղավորներն են առանց rotation-ի log-երը, journal-ը, Docker image-ները և build cache-ը, հին release դիրեկտորիաները և մոռացված տվյալների բազայի dump-երը։ Տեղն ազատում եմ անվտանգ․ կենդանի log-երը truncate եմ անում ջնջելու փոխարեն, vacuum եմ անում journal-ը, prune եմ անում Docker-ը, հեռացնում եմ հին release-ները։ Եթե տեղը չի վերադառնում, lsof +L1-ը ցույց է տալիս ջնջված ֆայլերը, որոնք պրոցեսը դեռ բաց է պահում։ Դրանից հետո շտկում եմ արմատական պատճառը logrotate կանոններով, journal-ի սահմանափակումներով և սկավառակի alert-ով։
Q3Ինչո՞ւ է իմ cron job-ը աշխատում տերմինալում, բայց ոչ cron-ից։
Cron-ը հրամանները գործարկում է նվազագույն environment-ով։ PATH-ը պարունակում է միայն մի քանի համակարգային դիրեկտորիա, քո .bashrc-ն կամ .profile-ը չի բեռնվում, աշխատանքային դիրեկտորիան օգտատիրոջ home-ն է, և այն օգտագործում է /bin/sh, ոչ թե bash, եթե այլ բան չնշես։ Այդ պատճառով այլ տեղերում տեղադրված node-ի կամ php-ի նման հրամանները չեն գտնվում, հարաբերական ճանապարհները կոտրվում են, և environment փոփոխականները բացակայում են։ Շտկիր բինար ֆայլերի և ֆայլերի բացարձակ ճանապարհներով, cd արա ճիշտ դիրեկտորիա, անհրաժեշտ փոփոխականները սահմանիր crontab-ում կամ wrapper script-ում և output-ը միշտ վերաուղղորդիր log >> file 2>&1-ով, որպեսզի տեսնես սխալները։ Ստուգիր նաև ժամային գոտին։
Q4Ինչպե՞ս կանխել, որ log-երը լցնեն սկավառակը։
Տեքստային log ֆայլերի համար յուրաքանչյուր հավելվածի համար ավելացնում եմ logrotate կանոն՝ rotation ամեն օր կամ ամեն շաբաթ, ֆայլերի ֆիքսված քանակ, հների սեղմում, և copytruncate կամ postrotate signal, որպեսզի հավելվածը շարունակի գրել նոր ֆայլում։ systemd journal-ի համար journald.conf-ում սահմանում եմ SystemMaxUse, որպեսզի այն մնա չափի սահմանի տակ։ Հավելվածները production-ում պետք է խուսափեն debug մակարդակի logging-ից։ Երկարաժամկետ կարևոր ամեն ինչի համար log-երը պետք է ուղարկվեն կենտրոնական համակարգ, ինչպես Loki-ն կամ hosted ծառայություն, որպեսզի սերվերը լոկալ պահի միայն կարճ պատուհան։ Իսկ սկավառակի զբաղվածության alert-ը բռնում է այն, ինչ կանոնները բաց են թողնում։
Q5free-ը ցույց է տալիս գրեթե զրո ազատ հիշողություն։ Սերվերը խնդրի մե՞ջ է։
Սովորաբար՝ ոչ։ Linux-ը այլապես պարապ RAM-ն օգտագործում է որպես ֆայլերի page cache, ինչը արագացնում է սկավառակից կարդալը, և անմիջապես ազատում է այն, երբ հավելվածներին հիշողություն է պետք։ Այդ cache-ը երևում է որպես used, ուստի առողջ մեքենայի վրա free սյունը փոքր է թվում։ Հետևելու թիվը available-ն է, որը գնահատում է, թե որքան հիշողություն կարելի է տալ նոր աշխատանքին առանց swap-ի։ Իրական խնդիրը նման է ցածր available հիշողության, կայուն swap ակտիվության, բարձր I/O wait-ով աճող load-ի կամ OOM killer-ի հաղորդագրությունների journalctl -k-ում։ Այդ դեպքում փնտրում եմ աճած պրոցեսը, օրինակ՝ leak կամ չկարգավորված տվյալների բազա, մինչև պարզապես ավելի շատ RAM գնելը։
Q6Սերվերը պե՞տք է swap ունենա։
Փոքր և միջին VPS instance-ների մեծ մասում՝ այո, համեստ քանակով, սովորաբար մոտ 1-ից 2 GB։ Այն գործում է որպես անվտանգության buffer․ հիշողության կարճ պոռթկումը սերվերը դանդաղեցնում է OOM killer-ին trigger անելու փոխարեն, որը կարող էր սպանել տվյալների բազան։ Այն նաև թույլ է տալիս kernel-ին հազվադեպ օգտագործվող էջերը RAM-ից դուրս տեղափոխել։ Բայց swap-ը լրացուցիչ հիշողություն չէ․ սկավառակը շատ ավելի դանդաղ է, քան RAM-ը։ Եթե սերվերը անընդհատ swap է անում, այն թույլ է կամ հավելվածը leak ունի, և լուծումն ավելի շատ RAM-ն է կամ կարգավորումը։ Որոշ setup-ներ, ինչպես Kubernetes node-երը կամ latency-ի նկատմամբ կրիտիկական տվյալների բազաները, միտումնավոր աշխատում են առանց swap-ի կամ շատ ցածր swappiness-ով։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս ես հավասարակշռում ավտոմատ թարմացումները և կայունությունը production սերվերներում։
Ես առանձնացնում եմ ռիսկի մակարդակները։ Դիստրիբուտիվի security pocket-ի անվտանգային թարմացումները կիրառվում են ավտոմատ ամեն օր unattended-upgrades-ով, քանի որ բաց թողնված հայտնի խոցելիությունն ավելի մեծ ռիսկ է, քան լավ փորձարկված security patch-ը։ Feature և point թարմացումները, երրորդ կողմի repository-ները, ինչպես database-ները կամ runtime-ները, և այն ամենը, ինչ պահանջում է կրիտիկական ծառայության restart, անցնում են պլանավորված պատուհանով՝ նախ staging, snapshot, հետո production։ Փաթեթները, որոնք պետք է շարժվեն հավելվածի հետ համաքայլ, օրինակ՝ database-ի major տարբերակը, pin կամ hold են արվում։ Kernel-ի թարմացումների համար ես կամ թույլ եմ տալիս ավտոմատ reboot հանգիստ ժամին, եթե հավելվածը հանդուրժում է կարճ restart, կամ հետևում եմ /var/run/reboot-required-ին և reboot անում գիտակցաբար։ Ամբողջ fleet-ի մակարդակով թարմացումները սերվերների միջև աստիճանաբար եմ անում, որպեսզի վատ թարմացումը երբեք միանգամից ամեն ինչին չհարվածի։
S2Database սերվերը դանդաղ է, և iowait-ը բարձր է։ Ինչպե՞ս ես պարզում՝ արդյոք storage-ն է bottleneck-ը։
Ես հաստատում եմ դա թվերով՝ մինչև որևէ բան tune անելը։ vmstat-ը ցույց է տալիս արգելափակված պրոցեսները և wa-ն, iostat -x-ը՝ ըստ սարքի կարդալու և գրելու latency-ն և հերթի չափը։ Ցանցով միացված cloud volume-ների վրա համեմատիր դիտարկված IOPS-ը և throughput-ը plan-ի փաստաթղթավորված սահմանների հետ, քանի որ provider-ի cap-ին հասնելը ճիշտ դանդաղ սկավառակի տեսք ունի։ pidstat -d-ն կամ iotop-ը հաստատում են, որ I/O անողը database-ն է, իսկ /proc/pressure/io-ն ցույց է տալիս, թե որքան ժամանակ են task-երը կանգնած։ Հետո ստուգում եմ պատճառը database-ի կողմից․ բացակայող index-ներ, որոնք full scan են առաջացնում, working set-ի համար չափազանց փոքր buffer pool, ուստի կարդալը գնում է սկավառակ, կամ checkpoint կամ backup job, որը հագեցնում է գրառումները։ Լուծումները տատանվում են query-ների և հիշողության tuning-ից մինչև տեղական NVMe կամ ավելի բարձր IOPS tier։
S3Ի՞նչ կպահես սերվերի սկավառակի վրա, և ի՞նչ կտեղափոխես դրանից դուրս։
Սերվերի սկավառակը համարում եմ փոխարինելի։ Այն պահում է օպերացիոն համակարգը, հավելվածի release-ը, կարճաժամկետ cache-երը, տեղական log-երի կարճ պատուհանը և database-ի ֆայլերը, եթե database-ը self-hosted է։ Այն ամենը, ինչի կորուստը ցավոտ կլինի, գնում է այլ տեղ՝ օգտատերերի upload-ները S3-համատեղելի object storage, database-ի backup-ները object storage այլ provider-ի կամ տարածաշրջանի մոտ, իսկ log-երը ուղարկվում են կենտրոնական համակարգ։ Դա սկավառակը դարձնում է փոքր և կանխատեսելի, ուստի այն հազվադեպ է լցվում, և սերվերի վերակառուցումը դառնում է provisioning-ի և տվյալների վերականգնման հարց, ոչ թե «ընտանի կենդանու» մեքենան փրկելու։ Գինը object storage-ի լրացուցիչ latency-ն և egress-ն է, ավելի շատ շարժվող մասերը և այդ ծառայությունների credential-ները անվտանգ կառավարելու անհրաժեշտությունը։
Բառարան
- dpkg
- Debian-ի ցածր մակարդակի փաթեթային գործիքը, որը տեղադրում է .deb ֆայլերը և հետևում դրանց վիճակին։ apt-ը կանչում է այն։
- deb822 sources
- apt repository ֆայլերի (.sources) կառուցվածքային key-value ֆորմատը, Ubuntu-ում լռելյայն՝ 24.04-ից։
- Pinning
- apt preference-ներ, որոնք առաջնահերթություններ են տալիս repository-ներին կամ տարբերակներին՝ կառավարելով, թե որ տարբերակն է տեղադրվում։
- Phased updates
- Ubuntu-ի ոչ անվտանգային թարմացումների աստիճանական տարածումը մեքենաների աճող մասի վրա՝ regression-ները շուտ բռնելու համար։
- Reserved blocks
- ext4-ի տեղ, լռելյայն 5%, որը միայն root-ը կարող է օգտագործել՝ համակարգը օգտագործելի պահելով, երբ սկավառակը լցվում է։
- Inode exhaustion
- Ֆայլային համակարգում ֆայլերի գրառումների վերջանալը, մինչդեռ ազատ տեղ դեռ կա, սովորաբար միլիոնավոր փոքրիկ ֆայլերի պատճառով։
- LVM
- Logical Volume Manager․ շերտ, որը սկավառակները միավորում է volume-ների մեջ, որոնք կարելի է resize անել, տարածել և snapshot անել։
- Page cache
- RAM, որը kernel-ն օգտագործում է ֆայլերի տվյալները cache անելու և գրառումները բուֆերացնելու համար․ ազատվում է, երբ հավելվածներին հիշողություն է պետք։
- I/O wait
- CPU-ի պարապ ժամանակ, մինչ պրոցեսները սպասում են սկավառակին։ Բարձր արժեքները ցույց են տալիս, որ bottleneck-ը storage-ն է, ոչ թե CPU-ն։
- Log shipping
- Log-երի ուղարկումը սերվերներից կենտրոնական պահոց agent-ի միջոցով, որպեսզի դրանք որոնելի լինեն և դիմանան սերվերի կորստին։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։