با توجه فراگیر شدن systemd در توزیع های مختلف لینوکس، نیاز است تا با نحوه ایجاد و مدیریت سرویس در این محیط آشنا باشیم به همین منظور، در این متن قصد داریم مختصرا به این موضوع بپردازیم و در نهایت، سرویسی را برای استارت خودکار دیتابیس اوراکل تعریف کنیم.
برای ایجاد سرویس با systemd، باید فایلی را در یکی از مسیرهای زیر ایجاد کرد:
/usr/lib/systemd/system
/usr/lib/systemd/user
/etc/systemd/system
/etc/systemd/user
برای نمونه، تعدادی از فایلهایی که در مسیر etc/systemd/system/ قرار دارند را در قسمت زیر مشاهده می کنید:
[root@ol7 system]# ls -l
drwxr-xr-x. 2 root root 31 Jul 23 2018 basic.target.wants
drwxr-xr-x. 2 root root 31 Jul 24 2018 bluetooth.target.wants
drwxr-xr-x. 2 root root 87 Jul 23 2018 default.target.wants
drwxr-xr-x. 2 root root 32 Jul 23 2018 getty.target.wants
drwxr-xr-x. 2 root root 4096 Aug 1 2018 graphical.target.wants
drwxr-xr-x. 2 root root 4096 Feb 4 04:56 multi-user.target.wants
-rw-r–r– 1 root root 586 Aug 1 2018 oracle-ohasd.service
برای ایجاد فایل در هر کدام از این مسیرها، بدیهی است که باید با ساختار این نوع از فایلها آشنا باشیم. فایلهای که در این مسیر تعریف می شوند، می توانند شامل سه قسمت Unit، Service و Install باشند که به عنوان مثال، فایل مربوط به سرویس oracleasm.service، چنین ساختاری دارد:
[root@ol7 system]# less oracleasm.service
[Unit]
Description=Load oracleasm Modules
[Service]
ExecStart=/usr/sbin/service oracleasm start_sysctl
ExecStop=/usr/sbin/service oracleasm stop_sysctl
ExecReload=/usr/sbin/service oracleasm restart_sysctl
[Install]
WantedBy=multi-user.target
در ادامه متن، با بعضی از پارامترهای مهم هر کدام از این قسمتها(Unit – Service – Install)، آشنا خواهیم شد.
[Unit]
پارامتر Description: از طریق این پارامتر، توضیحاتی را در مورد سرویس مورد نظر تعیین می کنیم.
مثال:
Description=Start Oracle Database
Before: در زمان boot شدن سیستم و تا قبل از اجرای سرویس جاری، چه سرویسهایی امکان اجرا ندارند؟
مثال:
Before =auditd.service systemd-user-sessions.service time-sync.target
After: سرویس مورد نظر؛ بعد از اجرای چه سرویسی می تواند استارت شود؟
مثال:
After=auditd.service systemd-user-sessions.service time-sync.target
Conflicts: این پارامتر، لیست سرویسهایی که امکان اجرای همزمان را با سرویس جاری ندارند، مشخص خواهد کرد.
نکته: لیست سرویسها را می توان با دستور زیر مشاهده کرد:
[root@ol7 system]# systemctl list-units|less
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target loaded active active Network
nfs-client.target loaded active active NFS client services
smb.service loaded active running Samba SMB Daemon
sshd.service loaded active running OpenSSH server daemon
sysstat.service loaded active exited Resets System Activity Logs
[Service]
در این قسمت تعیین می کنیم که با start، stop و restart شدن سرویس، درعمل چه اتفاقی باید رخ دهد به بیانی بهتر، چه اسکریپت و یا دستوری باید اجرا شود؟ در ادامه، تعدادی از پارامترهای این [Service] را مورد بررسی قرار داده ایم:
ExecStart: با استارت شدن سرویس، چه دستور و یا اسکریپتی اجرا شود؟
مثالهای زیر را ببینید:
ExecStart=/usr/sbin/service oracleasm start_sysctl
ExecStart=/usr/sbin/firewalld –nofork –nopid $FIREWALLD_ARGS
ExecStart=/sbin/multipathd
ExecStart=/usr/bin/touch /root/mynewwwwwwfile
ExecStop: سرویسی که توسط پارامتر ExecStart استارت شده، با چه دستور و یا اسکریپتی متوقف خواهد شد؟
مثال:
ExecStop=/usr/sbin/service oracleasm stop_sysctl
ExecReload: با restart شدن سرویس، چه دستور و یا اسکریپتی اجرا می شود؟
مثال:
ExecReload=/usr/sbin/service oracleasm restart_sysctl
[Install]
زمانی که از دستور systemctl enable و systemctl disable استفاده می کنیم، به قسمت [Install] رجوع خواهد شد. پارامتر مهمی که در این بخش تعریف می شود، WantedBy می باشد.
WantedBy: با boot شدن مجدد سرور/ماشین، سرویس در چه runlevelای اجرا شود؟
توجه! برای استارت خودکار سرویس بعد از boot شدن سرور، علاوه بر پارامتر WantedBy، باید دستور systemctl enable را هم اجرا کرده باشیم.
نکته: لیست runlevelها را در قسمت زیر می بینید:
[root@ol7 ~]# cd /usr/lib/systemd/system/
[root@ol7 system]# ls -l runlevel*.target
lrwxrwxrwx. 1 root root 15 Jul 23 2018 runlevel0.target -> poweroff.target
lrwxrwxrwx. 1 root root 13 Jul 23 2018 runlevel1.target -> rescue.target
lrwxrwxrwx. 1 root root 17 Jul 23 2018 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Jul 23 2018 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Jul 23 2018 runlevel4.target -> multi-user.target
lrwxrwxrwx. 1 root root 16 Jul 23 2018 runlevel5.target -> graphical.target
lrwxrwxrwx. 1 root root 13 Jul 23 2018 runlevel6.target -> reboot.target
در ادامه با دو مثال، شیوه ایجاد سرویس را مورد بررسی قرار خواهیم داد.
مثال 1: در قسمت زیر، سرویسی تعریف شده است که استارت کردن آن سبب ایجاد فایلی در مسیر home/oracle/ خواهد شد:
[root@ol7 ~]# vi /root/myscript.sh
/usr/bin/touch /home/oracle/m_`date +%y%m%d_%H%M%S`
[root@ol7 ~]# chmod +x /root/myscript.sh
[root@ol7 ~]# vi /etc/systemd/system/test1.service
[Service]
ExecStart=/bin/bash /root/myscript.sh
[root@ol7 ~]# systemctl daemon-reload
نکته: با هر بار تغییر در متن یک سرویس، باید دستور systemctl daemon-reload را هم اجرا کرد.
بعد از تعریف سرویس test1.service، این سرویس را استارت می کنیم:
[root@ol7 ~]#systemctl start test1.service
با اجرای این دستور، فایلی در مسیر home/oracle/ ایجاد خواهد شد:
[root@ol7 ~]# ls -l /home/oracle/m_*
-rw-r–r– 1 root root 0 Feb 4 09:05 /home/oracle/m_190204_090501
مثال 2: در این مثال می خواهیم با هر بار reboot شدن سرور، سرویس test1.service هم به صورت خودکار اجرا شود.
برای این کار می توانیم متن سرویس test1.service را به شکل زیر اصلاح کنیم:
[root@ol7 ~]# vi /etc/system/system/test1.service
[Service]
ExecStart=/bin/bash /root/myscript.sh
[Install]
WantedBy=multi-user.target
بعد از تغییر فایل test1.service، کافیست تا دستور systemctl enable را برای این سرویس اجرا کنیم:
[root@ol7 ~]# systemctl enable test1.service
Created symlink from /etc/systemd/system/multi-user.target.wants/test1.service to /etc/systemd/system/test1.service.
برای تست درستی تعریف سرویس، ماشین را reboot می کنیم:
[root@ol7 ~]# date
Mon Feb 4 09:06:38 EST 2019
[root@ol7 ~]# reboot
PolicyKit daemon disconnected from the bus.
We are no longer a registered authentication agent.
با استارت مجدد ماشین، خواهیم دید که فایل دیگری هم در مسیرhome/oracle/ ایجاد شده است:
[root@ol7 ~]# ls -l /home/oracle/m_*
-rw-r–r– 1 root root 0 Feb 4 09:05 /home/oracle/m_190204_090501
-rw-r–r– 1 root root 0 Feb 4 09:07 /home/oracle/m_190204_090701
تعریف سرویس برای استارت خودکار دیتابیس
در ادامه قصد داریم با کمک سه اسکریپت ساده زیر، سرویسی را برای stop، start و restart کردن دیتابیس تعریف کنیم:
[root@hkm2 ~]$ vi start_database
#!/bin/sh
su – oracle <<EOF
sqlplus “/as sysdba”
startup ;
EOF
[root@ol7 ~]$ vi restart_database
#!/bin/sh
su – oracle <<EOF
sqlplus “/as sysdba”
startup force;
EOF
[root@ol7 ~]$ vi stop_database
#!/bin/sh
su – oracle <<EOF
sqlplus “/as sysdba”
shut abort
EOF
با دستور زیر، سرویسی با نام oracledb.service ایجاد خواهد شد که از سه اسکریپت بالا برای مدیریت(stop-start-restart) دیتابیس اوراکل استفاده خواهد کرد:
[root@ol7 ~]# vi /etc/systemd/system/oracledb.service
[Unit]
Description=Start Oracle Database
After=network.target
[Service]
RemainAfterExit=yes
ExecStart=/home/oracle/start_database
ExecStop=/home/oracle/stop_database
ExecReload=/home/oracle/restart_database
[Install]
WantedBy=multi-user.target
برای استارت خودکار سرویس oracledb.service، کافیست دستور زیر را اجرا کنیم:
[root@ol7 ~]# systemctl enable oracledb.service
Created symlink from /etc/systemd/system/multi-user.target.wants/oracledb.service to /etc/systemd/system/oracledb.service.
سرویس systemd در زمان استارت کردن سرویس oracledb.service، از تنظیمات فایل limit.conf صرف نظر خواهد کرد، به این جهت، برای اعمال تنظیماتی چون nproc،nofile و stack باید پارامترهای زیر را به متن سرویس oracledb.service اضافه کرد:
LimitMEMLOCK=infinity
LimitNOFILE=65535
LimitSTACK=10240
همچنین در صورت تنظیم Huge Page در سرور/ماشین، باید پارامتر معادل memlock را هم به این اسکریپت اضافه کرد:
LimitMEMLOCK=infinity
با این تغییرات، متن نهایی سرویس oracledb.service، به شکل زیر تغییر خواهد کرد:
[root@ol7 ~]# vi /etc/systemd/system/oracledb.service
[Unit]
Description=Start Oracle Database
After=network.target
[Service]
LimitMEMLOCK=infinity
LimitNOFILE=65535
LimitNPROC=1638400
LimitSTACK=10240
RemainAfterExit=yes
ExecStart=/home/oracle/start_database
ExecStop=/home/oracle/stop_database
ExecReload=/home/oracle/restart_database
[Install]
WantedBy=multi-user.target
با تنظیم این سرویس، با دستورات زیر هم می توان دیتابیس را stop و start کرد:
[root@ol7 ~]# systemctl stop oracledb.service
[root@ol7 ~]# systemctl start oracledb.service
[root@ol7 ~]# systemctl restart oracledb.service