paint-brush
Systemd를 사용한 Micro-DevOps: 모든 일반 Linux 서버 강화~에 의해@tylerjl
5,159 판독값
5,159 판독값

Systemd를 사용한 Micro-DevOps: 모든 일반 Linux 서버 강화

~에 의해 Tyler6m2023/09/05
Read on Terminal Reader
Read this story w/o Javascript

너무 오래; 읽다

Kubernetes와 같은 컨테이너 오케스트레이터는 어지러울 정도로 다양한 기능을 제공하지만 복잡성이 추가되는 데 따른 비용을 지불해야 합니까? systemd의 최신 기능이 Linux 워크로드의 보안 및 복원성을 관리하여 더 작은 규모에서 효율적으로 실행하는 데 어떻게 도움이 되는지 알아보세요.
featured image - Systemd를 사용한 Micro-DevOps: 모든 일반 Linux 서버 강화
Tyler HackerNoon profile picture
0-item
1-item

Kubernetes, Nomad 또는 클라우드 호스팅 Paas(Platform-as-a-Service)와 같은 플랫폼은 다양하고 강력한 기능을 제공합니다. 워크로드 확장부터 비밀 관리, 배포 전략에 이르기까지 이러한 워크로드 오케스트레이터는 인프라를 다양한 방식으로 확장하는 데 도움이 되도록 최적화되었습니다.


하지만 운영자는 확장성을 극대화하기 위해 항상 비용을 지불해야 합니까? 때로는 복잡성과 추상화의 비용이 그 이점을 압도하기도 합니다. 대신 많은 빌더는 관리 용이성을 위해 근본적으로 간단한 배포 아키텍처에 의존하게 됩니다. 로드 밸런서 뒤에 있는 두 개의 가상 사설 서버는 컨테이너 호스트 전체에 분산되어 있는 마이크로 서버 클러스터와 비교하여 관리하기가 훨씬 더 간단한 스택입니다. 문제가 발생할 때 디버깅하거나 유지 관리해야 할 때 업그레이드할 움직이는 부품이 적을 때 배당금을 지불하기 시작할 수 있습니다.


많은 최신 Linux 배포판의 기반은 systemd 이며 컨테이너 오케스트레이터 또는 PaaS 시스템과 비교할 수 있는 강력한 기능 세트가 함께 제공됩니다. 이 기사에서는 최신 시스템 기능을 활용하여 관리 문제 없이 다른 대규모 시스템의 많은 기능을 확보하고 일반 Linux 서버를 매우 유능한 애플리케이션 플랫폼으로 강화하는 방법을 살펴보겠습니다.

체계화된 입문서

단일 호스트에서 systemd .service 파일을 작성하는 것은 관리되는 프로세스를 실행하는 이상적인 방법입니다. 대부분의 경우 애플리케이션을 전혀 변경할 필요조차 없습니다. systemd는 다양한 종류의 서비스를 지원하고 그에 따라 조정할 수 있습니다.


예를 들어, 간단한 웹 서비스를 실행하는 방법을 정의하는 다음과 같은 간단한 .service 생각해 보세요.


 [Unit] Description=a simple web service [Service] ExecStart=/usr/bin/python3 -m http.server 8080


systemd 서비스의 기본값을 기억하십시오. ExecStart= 절대 경로여야 하고, 프로세스는 백그라운드로 분기되어서는 안 되며, Environment= 옵션을 사용하여 필수 환경 변수를 설정해야 할 수도 있습니다.


/etc/systemd/system/webapp.service 와 같은 파일에 배치하면 systemctl 로 제어할 수 있는 서비스가 생성됩니다.


  • systemctl start webapp 프로세스를 시작합니다.
  • systemctl status webapp 서비스 실행 여부, 가동 시간, stderrstdout 의 출력, 프로세스 ID 및 기타 정보를 표시합니다.
  • systemctl stop webapp 서비스를 종료합니다.


또한, stderrstdout 으로 인쇄된 모든 출력은 저널링에 의해 집계되고 시스템 저널( journalctl 사용)을 통해 액세스할 수 있거나 --unit 플래그를 사용하여 특별히 대상으로 지정됩니다.


 journalctl --unit webapp


Journald는 기본적으로 저장소를 순환하고 관리하므로 저널을 통해 로그를 수집하는 것은 로그 저장소를 관리하는 좋은 전략입니다.


이 기사의 나머지 부분에서는 이와 같은 서비스를 향상시키는 옵션을 살펴보겠습니다.

비밀

Kubernetes와 같은 컨테이너 오케스트레이터는 비밀 (보안 데이터 저장소에서 가져와 실행 중인 워크로드에 노출되는 값)을 안전하게 주입하는 기능을 지원합니다. API 키나 비밀번호와 같은 민감한 데이터는 의도하지 않은 노출을 방지하기 위해 환경 변수나 구성 파일과 다르게 처리해야 합니다.


LoadCredential=systemd 옵션은 디스크의 파일에서 중요한 값을 로드하고 이를 안전한 방식으로 실행 중인 서비스에 노출하는 것을 지원합니다. 비밀을 원격으로 관리하는 호스팅 플랫폼과 마찬가지로 systemd는 자격 증명을 환경 변수와 같은 값과 다르게 처리하여 안전하게 유지됩니다.


시스템 서비스에 비밀을 주입하려면 비밀 값이 포함된 파일을 파일 시스템의 경로에 배치하는 것부터 시작하세요. 예를 들어 API 키를 .service 단위에 노출하려면 /etc/credstore/api-key 에서 파일을 생성하여 재부팅 후에도 파일을 유지하거나 /run/credstore/api-key 에서 파일을 영구적으로 유지하지 않도록 합니다( 경로는 임의적일 수 있지만 systemd는 이러한 credstore 경로를 기본값으로 처리합니다. 두 경우 모두 chmod 400 /etc/credstore/api-key 와 같은 명령을 사용하여 파일에 제한된 권한이 있어야 합니다.


.service 파일의 [Service] 섹션에서 LoadCredential= 옵션을 정의하고 콜론( : )으로 구분된 두 값, 즉 자격 증명 이름과 해당 경로를 전달합니다. 예를 들어, /etc/credstore/api-key 파일 "token"을 호출하려면 다음 systemd 서비스 옵션을 정의하십시오.


 LoadCredential=token:/etc/credstore/api-key


systemd가 서비스를 시작하면 비밀은 ${CREDENTIALS_DIRECTORY}/token 형식의 경로 아래에서 실행 중인 서비스에 노출됩니다. 여기서 ${CREDENTIALS_DIRECTORY} 는 systemd에 의해 채워지는 환경 변수입니다. 애플리케이션 코드는 API 토큰이나 비밀번호와 같은 보안 값이 필요한 라이브러리나 코드에서 사용하기 위해 이 방식으로 정의된 각 비밀을 읽어야 합니다. 예를 들어 Python에서는 다음과 같은 코드를 사용하여 이 비밀을 읽을 수 있습니다.


 from os import environ from pathlib import Path credentials_dir = Path(environ["CREDENTIALS_DIRECTORY"]) with Path(credentials_dir / "token").open() as f: secret = f.read().strip()


그런 다음 API 토큰이나 비밀번호가 필요할 수 있는 라이브러리에 대한 비밀 내용과 함께 secret 변수를 사용할 수 있습니다.

다시 시작

Nomad 와 같은 오케스트레이터의 또 다른 기능은 충돌이 발생한 작업 부하를 자동으로 다시 시작하는 기능입니다. 처리되지 않은 애플리케이션 오류로 인해 또는 다른 원인으로 인해 실패한 애플리케이션을 다시 시작하는 것은 복원력이 있는 애플리케이션을 설계할 때 종종 첫 번째 방어선이 되는 매우 유용한 기능입니다.


Restart= systemd 옵션은 systemd가 실행 중인 프로세스를 자동으로 다시 시작할지 여부를 제어합니다. 이 옵션에는 여러 가지 잠재적인 값이 있지만 기본 서비스의 경우 on-failure 설정이 대부분의 사용 사례를 충족하는 데 적합합니다.


자동 재시작을 구성할 때 고려해야 할 또 다른 설정은 RestartSec RestartSec= 옵션 입니다. 이 옵션은 서비스를 다시 시작하기 전에 systemd가 대기하는 시간을 지정합니다. 일반적으로 이 값은 긴밀한 루프에서 실패한 서비스를 다시 시작하고 잠재적으로 프로세스를 다시 시작하는 데 너무 많은 CPU 시간을 소비하지 않도록 사용자 정의해야 합니다. 일반적으로 5s 처럼 너무 오래 기다리지 않는 짧은 값이면 충분합니다.


기간 또는 시간 기반 값을 허용하는 RestartSec= 와 같은 옵션은 필요에 따라 5min 10s 또는 1hour 과 같은 다양한 형식을 구문 분석할 수 있습니다. 자세한 내용은 systemd.time 매뉴얼을 참조하세요.


마지막으로, 다른 두 가지 옵션은 systemd가 결국 포기하기 전에 실패한 장치를 다시 시작하려고 얼마나 적극적으로 시도할지를 지정합니다. StartLimitIntervalSec=StartLimitBurst= 주어진 시간 내에 장치의 시작이 허용되는 빈도를 제어합니다. 예를 들어 다음 설정은 다음과 같습니다.


 StartLimitBurst=5 StartLimitIntervalSec=10


장치는 10초 동안 최대 5번만 시동을 시도할 수 있습니다. 구성된 서비스가 10초 내에 6번째 시작을 시도하면 systemd는 장치 재시작 시도를 중지하고 대신 failed 로 표시합니다.


이러한 모든 설정을 결합하면 .service 단위에 대해 다음 옵션을 포함하여 자동 다시 시작을 구성할 수 있습니다.


 [Unit] StartLimitBurst=5 StartLimitIntervalSec=10 [Service] Restart=on-failure RestartSec=1


이 구성은 서비스가 실패할 경우 서비스를 다시 시작합니다. 즉, 0이 아닌 종료 코드를 사용하는 등 예기치 않게 종료되면 1초를 기다린 후 서비스를 다시 시작하고 전체 과정에서 5회 이상 시작을 시도하면 서비스 다시 시작 시도를 중지합니다. 10초.

서비스 강화

컨테이너 내에서 실행할 때의 주요 이점 중 하나는 보안 샌드박싱입니다. 기본 운영 체제에서 애플리케이션 프로세스를 분할하면 서비스에 존재할 수 있는 모든 취약점이 본격적인 손상으로 확대되기가 훨씬 더 어려워집니다. Docker와 같은 런타임은 cgroup과 기타 보안 기본 요소의 조합을 통해 이를 달성합니다.


예측할 수 없는 작업 부하 동작으로부터 기본 호스트를 보호하는 데 도움이 될 수 있는 유사한 제한을 적용하기 위해 여러 systemd 옵션을 활성화할 수 있습니다.


  • ProtectSystem= /boot/usr 과 같은 민감한 시스템 경로에 대한 쓰기 액세스를 제한할 수 있습니다. 이 옵션에 대한 문서에는 사용 가능한 모든 옵션이 나열되어 있지만 일반적으로 이 옵션을 full 로 설정하는 것이 이러한 파일 시스템 경로를 보호하는 데 적합한 기본값입니다.
  • ProtectHome= 읽기 전용 설정을 사용하여 /home , /root/run/user 디렉터리를 read-only 으로 설정하거나, true 로 설정하면 해당 디렉터리를 서비스의 파일 시스템에 빈 디렉터리로 마운트할 수 있습니다. 애플리케이션이 이러한 디렉터리에 액세스해야 하는 특별한 요구가 있는 경우를 제외하고 이 값을 true 로 설정하면 해당 디렉터리에 대한 불법적인 액세스로부터 시스템을 안전하게 강화할 수 있습니다.
  • PrivateTmp= 구성된 서비스에 대해 별도의 /tmp/var/tmp 유지 관리하므로 이 서비스 및 기타 프로세스에 대한 임시 파일은 비공개로 유지됩니다. 프로세스가 임시 파일을 통해 정보를 공유해야 하는 특별한 이유가 없는 한 이 옵션을 활성화하면 유용합니다.
  • NoNewPrivileges= 실행된 프로세스가 권한을 상승시킬 수 없도록 하여 서비스를 강화하는 또 다른 안전하고 간단한 방법입니다 . 다른 강화 옵션을 사용할 수 있는지 확실하지 않은 경우 일반적으로 활성화하는 것이 가장 문제가 적은 옵션 중 하나입니다.


systemd.exec의 매뉴얼 페이지는 서비스와 같은 실행 가능한 워크로드에 적용되는 다양한 옵션을 탐색하는 데 유용한 리소스입니다.

추가 자료

systemd 프로젝트의 매뉴얼 페이지는 광범위하고 자신의 애플리케이션을 실행하는 데 사용할 수 있는 모든 옵션을 학습하는 데 유용합니다. 웹 서버와 같은 영구 서비스를 실행하든, cron 작업을 대체하기 위해 주기적 .timer 단위를 실행하든, systemd 문서는 유용한 지침을 제공할 수 있습니다.