작은 백업 스크립트(btrfs 스냅샷 + USB로 전송) 시스템이 종료될 때.
다음 서비스는 종료 시 완벽하게 작동하지만 다시 시작하면 예상대로 작동하지 않습니다.
[Unit]
Description=Backup on poweroff to external encrypted USB disk.
DefaultDependencies=no
Before=shutdown.target
[Service]
Type=oneshot
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
RemainAfterExit=yes
[Install]
WantedBy=poweroff.target
서비스가 예상대로 작동하면 /usr/bin/sleep 30
실제 백업 스크립트로 대체됩니다.
하지만 백업 스크립트가 작동하려면 부팅하기 전에 cryptsetup을 사용하여 외부 USB 디스크의 암호를 해독해야 합니다. 이 모든 작업은 /etc/crypttab
systemd( )와 systemd() noauto
의 조합을 통해 백그라운드에서 처리 됩니다. 이는 위의 유닛에서 참조할 수 있는 systemd-cryptsetup-generator
systemd 유닛 파일을 자동으로 생성합니다 .systemd-cryptsetup@<name>.service
하지만 일단 [unit] 섹션에 다음 요구 사항을 추가하면:
[email protected]
[email protected]
시스템 종료/정전 중에는 서비스가 더 이상 시작되지 않습니다.
서비스를 수동으로 시작해도 문제가 없으니 systemctl start poweroff-backup.service
서비스 파일 자체에는 문제가 없습니다... :-/
나생각하다문제는 poweroff.target
via가 모든 장치(cryptsetup' 포함)를 차례로 제거 systemd-poweroff.service
해야 한다는 것입니다.umount.target
산')를 결합하여갈등 =그리고이후 =systemd 마운트 및 cryptsetup 장치에 대한 설명입니다. 그러나 다른 요구 사항을 추가해도 umount.target
다음과 같은 내용은 변경되지 않습니다.
Before=umount.target
umount.target
추가적인 요구 사항이 없어도 서비스는 항상 도달하자마자 시작된다는 것을 확실히 알 수 있습니다 .
답변1
글쎄요, 저는 여전히 systemd 워크플로를 따르는 올바르게 작동하는 솔루션을 구축할 수 있는 이 질문을 찾았습니다.대부분의 경우에).
질문
다음 서비스는 언뜻 보기에는 정확하지만 실행되지 않습니다.
# poweroff-backup.service
[Unit]
Description=Backup on poweroff to external encrypted USB disk.
DefaultDependencies=no
Before=shutdown.target
# This causes the service to be discarded/skipped due to
# a dependency cycle conflict. See below...
[email protected]
[email protected]
Before=umount.target
[Service]
Type=oneshot
# Note: The script executed here needs access to '/', '/tmp'
# (or Systemd's PrivateTemp) and '/dev/mapper/ext' which is the
# decrypted USB partition managed by /etc/crypttab and
# systemd-cryptsetup-generator (as [email protected])
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
# Note: This does not make any difference
RemainAfterExit=yes
[Install]
WantedBy=poweroff.target
서비스가 시작되지 않는 이유는 종료(전원 끄기/다시 시작) 및 전원 끄기-백업 전에 암호화된 모든 디스크가 분리되도록 하기 위해 shutdown.target과 cryptsetup.target 사이에 종속성 루프 문제/충돌이 있기 때문입니다. poweroff.target을 통해.poweroff.target -[require]-> shutdown.target -[conflicts]-> cryptsetup.target <-[require]- [email protected] <-[require]- poweroff-backup.service <-[wants]- poweroff.target
해결책
이것을 알면, 명백한 문제는 systemd가 poweroff-backup.service가 "일회성 파업"poweroff-backup.service가 활성화되고 비활성/완료로 전환되면 시스템은 정상적인 종료 전환을 계속하면서 먼저 서비스를 해결할 수 있습니다.
다음은 ExecStart= 대신 ExecStop=을 사용하는 서비스입니다. 이를 통해 종속성 주기를 피할 수 있지만 몇 가지 사소한 주의 사항이 있습니다.
# poweroff-backup.service
[Unit]
Description=Backup external encrypted USB disk on poweroff.
[email protected]
After=multi-user.target
[email protected]
[Service]
Type=oneshot
ExecStart=/usr/bin/echo "Waiting for poweroff..."
# Note: We need this, since there is no other way to detect poweroff vs reboot now.
ExecStop=/usr/bin/systemctl list-jobs | /usr/bin/egrep -q 'poweroff.target.*start'
# Note: This should be replaced with your script
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
이는 다음과 같은 이유로 작동합니다.
- shutdown.target, cryptsetup.target 및 poweroff-backup.service로 인한 종속성 주기 문제 방지
- systemd는 종료 순서가 시작 순서와 반대임을 보장하기 때문에 올바른 작업 순서는 계속 유지됩니다(After= 및 Before=에서 제공됨).
이 솔루션에 대해 두 가지 사소한 불만 사항이 있습니다.
서비스는 로그인 시 시작되므로 로그인 시 외부 USB 디스크의 암호도 해독됩니다. 나는 일반적인 시스템의 After= 및 Require= 순서 지정 및 종속성 메커니즘을 계속 사용하면서 실제 백업 스크립트가 실행될 때만 이런 일이 발생하기를 원합니다. 이는 다음을 추가하여 처리할 수 있지만 이는 USB 디스크를 해독/분리하기 위해 cryptsetup 서비스를 사용하지 않음을 의미합니다.
ExecStop=/usr/lib/systemd/systemd-cryptsetup attach ext [...] ExecStop=/usr/lib/systemd/systemd-cryptsetup detach ext
shutdown.target을 참조하여 종료 시에만 ExecStop=을 조건부로 실행할 수 있는 방법이 없으며 사용되는 일부 도우미 명령에 의존해야 합니다
systemctl list-jobs
.
질문:이러한 점을 개선하는 방법을 아는 사람이 있습니까?
완전한 서비스 문서
이것은 현재 서비스 파일입니다. USB 디스크를 마운트한 후에만 multi-user.target 대신 USB 장치(UUID를 통해)에 연결(WantedBy=)하여 서비스를 시작합니다.
# poweroff-backup.service
[Unit]
Description=Backup external encrypted USB disk on poweroff.
[email protected]
Requires=-.mount
Requires=tmp.mount
After=dev-disk-by\<uuid here>.device
[email protected]
After=-.mount
After=tmp.mount
[Service]
Type=oneshot
ExecStart=/usr/bin/echo "Waiting for poweroff to trigger snapshot and archive transfer..."
ExecStop=/usr/bin/systemctl list-jobs | /usr/bin/egrep -q 'poweroff.target.*start'
ExecStop=-/usr/local/bin/btrfs-snapshots.sh --device='UUID=<uuid>' @ @boot @home
ExecStop=/usr/local/bin/btrfs-archive.sh --source='UUID=<uuid>' --target=/dev/mapper/ext
TimeoutSec=infinity
RemainAfterExit=true
[Install]
WantedBy=dev-disk-by\<uuid here>.device
답변2
내 사용 사례는 약간 다릅니다. 다른 모든 서비스가 중지되었는지 확인하고 다시 시작하는 동안 Rsync를 사용하여 백업을 수행하고 싶습니다. 다음은 Ubuntu 22.04에서 저에게 효과적이었습니다. 나중에 종료 시 스크립트를 실행하려는 사람들을 위해 이 답변을 여기에 남겨 둡니다.
서비스 파일은 다음과 같습니다.
[Unit]
Description=Run my custom task at shutdown
DefaultDependencies=no
Before=systemd-reboot.service
After=final.target
[Service]
Type=oneshot
ExecStart=/usr/local/scripts/custom_script.sh
TimeoutStartSec=0
[Install]
WantedBy=systemd-reboot.service
나는 어떻게 custom_script.sh
생겼나요?
#!/bin/sh
ps aux > /usr/local/scripts/processes.txt
df -Th > /usr/local/scripts/df.txt
mount > /usr/local/scripts/mount.txt
sleep 180
sudo chmod 777 -R /usr/local/scripts/
이것은 단지 테스트용이므로 권한 문제가 있을 경우를 대비하여 실행하고 있습니다 .
제가 테스트한 단계는 다음과 같습니다.
- 종료하고 다시 시작할 때 스크립트가 실행되도록 하기 위해
sleep 180
다음을 수행합니다custom_script.sh
. 그런 다음 운영 체제를 종료합니다. 단 3분 후에 운영 체제가 완전히 종료됩니다. 스크립트가 실행되는 동안(대기 중) Ubuntu 로딩 로고가 표시됩니다. 시스템을 부팅하고 다시 시작했습니다. 동일한 Ubuntu 로딩 로고가 표시되고 3분 후에 시스템이 재부팅됩니다. 이는 종료/다시 시작 시 스크립트가 실행되고 있음을 증명합니다. custom_script.sh
다른 모든 서비스가 중지되었는지 확인하십시오. 실행하는 동안 실행 중이던 모든 프로세스를 기록했습니다ps aux > processes.txt
. 의 출력에는processes.txt
다른 서비스가 포함되지 않습니다. 이는 다른 모든 서비스가 중지되었음을 증명합니다.- 파일 시스템이 여전히 마운트되어 있는지 확인하기 위해
df -Th > df.txt
mount 를 사용하고 기록합니다mount > mount.txt
. 파일 출력에는 모든 파티션이 마운트되었으며 읽기-쓰기 모드에 있음이 표시됩니다.