apt purge로 VPN을 지웠는데도 서비스는 부팅 때 여전히 시작된다
apt purge는 패키지 파일을 지울 뿐, 공급업체 스크립트가 설치한 unit을 지우지 않는다. unit과 wants 링크를 지우고, 부팅의 주인을 하나로 정하라.
apt purge는 패키지가 사라졌다고 말하지만, 부팅할 때마다 터널이 다시 올라온다. journal은 계속 자라고, 경로는 되돌아오며, 기계는 아무것도 지워지지 않은 것처럼 행동한다. 공급업체 설치 프로그램은 패키지 관리자가 기록하지 않은 파일을 쓸 수 있으므로 패키지를 지우는 일과 제품을 지우는 일은 서로 다른 작업이다. 아래 runbook은 두 기록을 분리하고 제거를 의도적으로 끝맺는다.
설치 프로그램 둘, 기록 둘
Debian 패키지는 파일 목록을 유지하고, purge는 그 목록이 지목한 것과 패키지 설정만 지운다. 셸 설치 프로그램이나 .run 묶음은 그런 목록을 두지 않는다. 원하는 곳, 대개 /opt, /usr/local, /etc/systemd/system에 쓴다. 이런 경로는 어느 패키지의 파일 목록에도 없으므로 dpkg는 알지도, 보고하지도 않는다. 결국 한 파일 시스템에 설치 주인이 둘 남고, 장부를 쓰는 쪽은 하나뿐이다.
지우기 전에 그 경로를 dpkg에 물어보라. dpkg가 부인하는 경로는 직접 지워도 되고, 같은 답이 나중 업그레이드가 그것을 되돌릴지도 알려 준다.
dpkg -S /etc/systemd/system/acmevpn.service
systemctl list-unit-files | grep -i acmevpn
unit과 wants 링크는 별개의 파일이다
활성화는 설치와 다른 행위다. unit은 [Install] 절에서 대상 관계를 선언하고, systemctl enable가 그 선언을 각 대상의 .wants/ 디렉터리 안 심볼릭 링크로 바꾼다. 이제 경로가 둘 생긴다. unit 파일과, 그것을 부팅 대상으로 끌어들이는 링크다. 파일만 지우면 링크가 아무것도 가리키지 않아 부팅 때 불평이 나온다. 링크만 지우면 unit은 이름으로 시작할 수 있는 채로 남는다. 둘 다 없애야 한다.
순서대로 제거한 뒤 다시 불러와라. systemd가 옛 정의를 메모리에 계속 붙들지 않게 하기 위해서다.
systemctl disable --now acmevpn.service
systemctl show -p FragmentPath -p ExecStart acmevpn.service
sudo rm /etc/systemd/system/acmevpn.service
sudo rm /etc/systemd/system/multi-user.target.wants/acmevpn.service
systemctl daemon-reload
위치를 짐작하지 말고 FragmentPath를 읽어라. 공급업체가 /etc가 아니라 /usr/lib/systemd/system이나 /lib/systemd/system에 썼을 수 있다. 예상한 사본을 지우면 실제로 유효한 쪽이 계속 돌고, 다음 재적재까지 수정은 성공한 것처럼 보인다. 재적재가 끝나면 unit 파일을 다시 나열하고 그 이름이 더 이상 나오지 않는지 확인하라.
이 배치를 살려 두는 바이너리를 찾아라
활성화된 unit은 패키지 데이터베이스가 무엇을 믿든 데몬을 계속 시작한다. 그 프로세스는 터널을 다시 올리고, 경로를 다시 넣고, kill-switch 규칙을 복원할 수 있다. 배치를 살펴보기 전까지 그 행동은 초자연적으로 보인다. ExecStart 경로를 따라가 바이너리가 아직 있는지 확인하라. /opt 아래 남은 실행 파일 하나면 이 배치에는 충분하다. unit을 지우면 예정된 시작이 멈출 뿐, 프로그램이 지워지지는 않는다.
상태 디렉터리도 같은 주의로 다뤄라. 계정 토큰, 생성된 프로필, 캐시된 서버 목록은 /var/lib 아래나 홈 디렉터리에 있고, 이것은 버릴 캐시가 아니라 자격 증명이다. 서비스를 멈춘 뒤 의도적으로 제거하고, 무엇을 가져갔는지 적어 두라.
sudo ls -l /opt/acmevpn /usr/local/bin/acmevpn
sudo find /var/lib -maxdepth 2 -iname "*acme*"
systemctl is-enabled acmevpn.service
부팅 주인을 하나 골라 시험하라
부팅을 주장할 후보는 셋이고, 셋을 다 설치하면 이중 안전이 아니라 경쟁이 된다. 데스크톱 자동 시작 파일은 누군가 로그인한 뒤에야 돌고, systemd unit은 더 일찍 돌지만 화면 없는 클라이언트가 필요하며, cron @reboot 항목은 네트워크 클라이언트에 맞지 않을 수 있는 시각에 발동한다. 공급업체 CLI는 서버 인수를 더 요구할 수 있다. 부팅 때는 이어 갈 이전 세션이 없기 때문이다. 클라이언트가 인증하는 방식에 맞는 후보를 고르고 나머지는 버려라.
기계를 다시 부팅하고 세 가지 독립적 사실을 보며 시험하라. unit 상태, 프로세스 목록, 그리고 검증할 수 있는 무언가로의 새 연결이다. 키링이나 대화형 로그인이 필요한 클라이언트는 올바른 unit 파일이 있어도 부팅 때 실패한다. journal을 읽으면 그렇게 적혀 있다. 서비스 상태만 봐서는 알 수 없다.
묻지 않고 동작하는 자격 증명을 클라이언트에 주거나, 로그인할 때 시작하라. 둘 다 그럴듯하다. 둘을 섞으면 터널 하나에 주인 둘이 생겨 서로 싸운다.
다음 purge가 무엇을 예상해야 하는지 적어 두라
손으로 제거한 뒤 두 가지 사실을 적어라. 어느 설치 프로그램이 이 배치를 만들었는지, 지금 누가 그것을 시작하는지. 그 메모는 다음 purge를 뜻밖의 일에서 점검 항목으로 바꾸고, 일을 한 사람보다 오래 남는다.
개인 디렉터리가 아니라 서비스 설정 옆에 두고 날짜를 적어라. 공급업체 업데이트가 지운 unit을 되살릴 수 있기 때문이다. 몇 달마다 systemctl list-unit-files를 그 메모와 견주면 수정이 아직 쌀 때 복원을 잡아낸다.