카테고리 보관물: Linux

Ligthtsail 하위 인스턴스로 되돌리기

올해 초 워드프레스를 마이그레이션 하는 중에 메모리 문제로 잠깐 상위 인스턴스로 갔다가 되돌아 오겠다는 계획을 했던 적이 있었다. 계획은 그럴 듯 한것 같았으나 “Lightsail 스냅샷으로 하위 인스턴스를 생성할 수 없다“는 사실만 깨닫고 울며 겨자 먹기로 5개월 가량을 비싼 인스턴스를 써왔다.

야, 그런데 이거 정말 안되는 거 맞아?

Gemini에게 물어보니 “안될리가 있겠습니까요”라며 그럴 듯한 마이그레이션 계획은 새워준다. 인스턴스 생성 후에 일일이 설정했던 것들을 알려주면서 이것들도 모두 꼬옥 포함되어야 한다고 당부를 했더니 자기가 bash script로 만들어 줄테니 실행만 하면된다며 backup용 script와 복구용 script를 만들어 쥐어주었다.

Back up script

서버 인증서는 백업하기 보다는 재발급 받는게 나을것 같다고 해서 이것을 제외하고 다른 모든 것들을 백업하는 스크립트를 돌려서 만들어진 파일은 크기가 무려 950MB짜리 초대형 슈퍼 울트라 원 클릭 “full_server_migration_backup.tar.gz”이다.

Restore script

이제 가격이 싼 인스턴스를 생성하고 만들어진 백업 파일과 복원 스크립트를 옮기고 복원 script를 실행시켰더니… 적용하는 중에 EOF 에러가 여기저기에서 떨어지면서 뭔가 동작이 조금 이상했다. 마지막 단계에서는 인증서까지 새로 발급 받으려고 하길래 아직 도메인이 적용되지 않았으니 기다리라고 취소를 눌렀다.

후 폭풍과 뒷 수습

자신감 넘치는 AI들의 속삭임에 속은 게 한 두번이 아니기는 하지만 결과물을 보고는 다시 한 번 놀랄 수 밖에 없었다. 복원했다던 wordpress 폴더는 깔끔하게 비워져 있고 설정된 것이라고는 nginx과 database 그리고 php 환경 정도였다. 실제로는 복원 스크립트라기 보다는 LEMP 설치용 스크립트에 가까웠던 것이다.

wordpress 수동복사

그나마 database는 복원이 되어 있었기 때문에 이전 서버의 /var/www/html/ 경로에 있던 WordPress 파일들을 모두 복사해서 새로운 서버에 올려 주었다.

WordPress 설정파일 임시 설정

백업된 /etc/nginx/conf.d/wordpress.conf에는 HTTPS 관련한 설정이 들어가 있는데, 아직 cert. 업데이트를 하지 않은 상태에서는 이상 동작 하기 때문에 해당 파일을 80번에서 HTTP만 대기 하도록 간단히 임시로 수정한다. 물론 이전 설정 파일은 결국 사용할 것이니까 버리지 않고 백업해 두었다.

Certificate update

사실 인증서 업데이트 항목이 복원용 스크립트에 들어가 있다는게 말이 안된다. Cert update를 한다는 건 도메인을 연결한 상태라는 건데 아직 설정중인 서비스가 어떻게 동작할 지도 모르는 걸 도메인 부터 연결 한다는게 AI 급의 엄청난 자신감이 아니라면 안될말이다.

먼저 HTTP로 서비스가 잘 동작하고 기본적인 복원이 된 것을 확인하고, 그 다음에 도메인을 새로운 인스턴스로 연결해 준 뒤에 certbot을 실행시켜서 인증서를 수동으로 업데이트 했다. Lightsail 인스턴스 페이지에서 HTTPS용 443번 포트를 사용할 수 있도록 방화벽 잊지 않고.

WordPress 설정파일 복원

HTTPS를 위한 인증서를 업데이트 했으니 앞서 백업해 두었던 임시파일을 복원하고 nginx를 재실행 해준다.

Redis설치

Redis에 대한 내용이 백업과 복원에서 완전히 빠져 있어서 웹사이트가 실행되지 못하고 있었다. Redis를 설치하고 실행해 주었다.

Imagick 설치와 메모리 부족

이제 WordPress의 건강상태 화면을 확인했더니 php-pecl-imagick 모듈이 설치되지 않아서 건강하지 못한 상태라고 한다. 문제는 여기에서 터졌는데 512MB의 미약한 RAM 크기로는 이 패키지를 설치하는 중에 요구되는 메모리 피크를 감당하지 못하고 설치에 실패했다. 그러고 보니 애초에 비싼 인스턴스로 옮겨갔던 이유도 백업 프로그램 동작 중에 RAM 피크를 감당하지 못해서 문제가 생겼던 것인데 지금도 똑같은 문제가 생기고 있었다.

Swap 확장

“아! 그때는 왜 이생각을 못했을까.”

AI가 해결책이라고 알려준 이 방법은 사실 예전에 비싼 인스턴스로 옮기기 전에도 시도해 봤어야 했다. 현재 기본적으로 주어지는 400MB의 sawp에 추가로 1GB를 할당하고 설치를 재실행했더니, 시간이 좀 걸리기는 했어도 문제 없이 설치가 되었다. “비싼돈 쓰기 전에 swap 확장 부터!” 값진 교훈을 AI로 부터 의도치 않게 전수 받아 마음에 새겨둔다.

한가지 특이했던 점은 새로 만든 1GB swap 공간을 연결하기전에 swap off를 실행하지 않았더니 기존의 크기와 합쳐서 1.4GB의 swap이 인식되었다는 점이다. Swap 공간을 부팅 이후에도 계속 사용하도록 /etc/fstab에 추가해 두었다.

공격 대비

지난번에 “Lightsail 서버가 자꾸 죽어서” 확인했던 XMLRPC와 search flood attack에 대해 새 서버에 대비가 잘 되어 있는지 확인하는 스크립트를 만들어 달라고 했더니 뚝딱 만들어 주었는데 이것은 별 문제 없이 잘 돌려서 확인할 수 있었다.

그 동안 수고 많았다 비싼 친구야

인스턴스에 변경이 있을 때 마다 올리던 버전이 이제는 어느새 6.0이 되었다. 새로운 인스턴스의 건강 상태와 동작을 최종 확인한 다음 1GB, 40GB 짜리 비쌌던 인스턴스는 이제 은퇴하고 다시 예전의 기본 tier로 돌아 오게 되었다.

Smoke test를 위한 GitHub Self-hosted Runner 설정

Unittest가 개발 과정에서 논리를 점검하는데 유용하기는 하지만 이세상에는 integration test가 담당해야 하는 부분도 엄연히 존재한다. 각각의 컴포넌트들이 잘 작성되었다 할지라도 이것을 통합했을 때의 동작을 보장하는 것은 또 다른 이야기 이기 때문이다.

이 부분을 커버하기 위한 목적으로 가상의 데이터를 생성하고 프로그램의 처음 시작 부분부터 마지막 출력 부분까지(E2E) 점검하는 스크립트를 만들어 두었다. 문제는 unittest 만큼이나 이 스크립트를 자주 돌리지 않을 뿐 아니라 종종 커밋할 때 까먹는 다는 것이다.

가만, 이런 귀찮을 걸 안까먹으려고 CI를 설정해 두지 않았던가!

몇몇 리소스들을 찾아보니 GitHub workflow에서 제공하는 VM에서 docker를 돌리는 것에는 문제가 없다고 한다. 그래서 기존에 Lint와 Unitest를 수행하던 CI script에 추가로 E2E를 위한 smoke test script를 수행하는 부분을 추가하고 돌려봤더니 안타깝게도 docker instance 생성 후에 pip로 패키지들을 설치하다고 공간이 모자라서 오류가 나고 있었다.

VM에서 띄우는 docker 자체는 동작하지만 디스크 공간 같은 리소스는 충분히 주어지지 않는 것이다. 보다 높은 데이터 공간을 위해 비싼 요금제를 사용하는 것도 고려해 볼 수 있겠지만, 매번 CI를 수행할 때마다 docker instacne들을 모두 재생성 한다면 시간도 오래 걸릴 것이어서 별로 합리적인 해결 방안은 아닐 것 같다.

그래서 생각한 결론은 Self-hosted runner를 살리는 것이다. 이것 용도로 컴퓨터를 설정해야 하고 항상 네트워크에 물려 있도록 해야 하는 귀찮음은 있지만 비싼 GitHub 요금제나 instance 생성에 걸리는 시간은 아낄 수 있을것 이라 생각해서 이다.

Self-hosted runner를 설정하는 과정은 어렵지 않다. GitHub의 Actions 항목에서 Runners -> Self-hosted runner를 선택하고 “New runner” 버튼을 누르면 자세한 설정 명령어가 나오는데, 그대로 복사 붙여넣기만 하면 된다.

기존의 Lint / Unittest를 수행하는 CI는 그대로 GitHub에서 수행하고, 새로 추가된 smoke test만 self-hosted runner에서 돌리도록 해서 총 6분정도가 소요된다. 이 정도면 쓸만하다.

결론

GitHub 요금제를 올리는 방법도 있지만, 스스로 유지보수가 가능하다면 self-hosted runner를 사용해서 docker instance의 재생성을 막고 부가적인 환경 설정을 자유롭게 하는 방법도 고려해 볼만 하다.

WordPress “다른 업데이트가 진행중 입니다” 문제 해결

WordPress의 새로운 버전이 나와서 업데이트를 시도했는데, 아무런 응답이 없더니 다시 업데이트 메뉴로 들어갔을 때 이 상태였다. 혹시나 하는 마음에 5분 정도를 기다렸다가 다시 들어가 봤을 때도 마찬가지 였다.

WordPress는 중복된 버전 업데이트 시도를 막기 위해서 lock을 걸고 업데이트가 끝나면 이것을 해제 하는데 어떤 이유에서 인지 중간에 발생한 오류로 lock이 풀리지 않는 모양이다.

WordPress Update Lock

Update를 위해 Wrodpress가 설정하는 lock은 wordpress database의 wp_options table에 있다. 업데이트가 진행중이라는 메세지가 오랫동안 없어지지 않는 상태라면 wp_config.php에 적어둔 DB access 정보를 참조해서 해당 테이블에 접근해 core_updater.lock이 설정되어 있는지 확인해 보자.

mysql -u litcoder -p --database wordpress

SELECT * FROM wp_options WHERE option_name = 'core_updater.lock';

이 query에서 결과가 출력된다면 현재 lock이 걸려 있는 상태이다. 참고로 여기에서 option_value의 값은 lock이 설정된 unix time을 의미한다.

Lock 제거

반드시 현재 진행되고 있는 업데이트가 없고 이것이 비 정상적인 상황이라는 확신이 있을 때만 다음의 명령어로 lock을 삭제해 주자.

DELETE FROM wp_options WHERE option_name = 'core_updater.lock';

그리고 나서 재시도 해보면 해당 오류가 없어진 것을 볼 수 있을 것이다.

결론

시대가 시대인 만큼 wp-config.php를 읽어서 자동으로 lock을 해제해 주는 script를 “딸깍”으로 만들어 gist에 올려 두었다. 필요한 경우가 있다면 다음의 명령어를 터미널에 복붙하면 된다. 참고로 실행에 sudo 권한이 필요한 이유는 wp_config.php에 접근하기 위해서이다.

curl -sSL https://gist.githubusercontent.com/litcoder/\
27e0f3538762bfd3b0fcfdeea01d2867/raw/\
d7bb16761d4449408bb1c8dbee55931fccec20e7\
/wp-unlock-update.sh | sudo bash