안정적이고 효율적인 리눅스 시스템 운영의 핵심은 체계적이고 사전 예방적인 유지보수 전략에 있다. 프로덕션 환경에서 시스템 유지보수는 단순히 장애 발생 시 대응하는 사후 처리 활동이 아니라, 시스템의 보안, 안정성, 성능을 최상의 상태로 유지하기 위한 지속적인 생명주기 관리 활동이다. 정기적인 소프트웨어 업데이트는 알려진 보안 취약점을 해결하고, 새로운 위협으로부터 시스템을 보호하는 가장 기본적인 방어선이다. 또한, 시스템의 전반적인 안정성을 향상시키고 예기치 않은 다운타임을 방지하는 데 결정적인 역할을 한다. 이러한 유지보수 활동을 일관되고 예측 가능하게 수행하는 것은 현대 IT 인프라 관리의 기본 요건이다.
리눅스 시스템 관리의 패러다임은 개별 시스템을 수동으로 관리하던 방식에서 벗어나, 대규모 인프라를 자동화된 도구로 관리하는 방향으로 발전해왔다. 이러한 변화의 중심에는 패키지 관리와 작업 자동화라는 두 가지 핵심 기둥이 있다.
패키지 관리: 소프트웨어의 무결성과 시스템의 일관성을 보장하는 기반 기술이다. 패키지 관리 시스템은 소프트웨어의 설치, 업데이트, 의존성 해결, 제거 과정을 표준화하고 자동화함으로써, 복잡한 소프트웨어 스택에서 발생할 수 있는 "의존성 지옥(Dependency Hell)"과 같은 고질적인 문제를 해결한다. 이는 관리자가 신뢰할 수 있는 소스로부터 소프트웨어를 공급받고, 시스템 전반의 소프트웨어 버전을 일관되게 유지할 수 있도록 지원한다.
작업 자동화: 관리 효율성과 시스템 신뢰성을 극대화하는 엔진이다. 백업, 로그 순환, 시스템 상태 점검과 같은 반복적이고 필수적인 작업을 자동화함으로써, 인적 오류의 가능성을 최소화하고 관리자가 더 높은 가치를 창출하는 작업에 집중할 수 있도록 한다. 초기의 cron부터 현대의 systemd에 이르기까지, 작업 자동화 도구는 시스템이 정해진 절차에 따라 안정적으로 운영되도록 보장하는 핵심 요소이다.
이러한 도구들은 단순히 편의를 위한 유틸리티가 아니라, 대규모화되고 복잡해지는 현대 컴퓨팅 환경에서 안정성, 보안, 확장성이라는 근본적인 과제를 해결하기 위해 발전해 온 필연적인 결과물이다.
패키지 관리 시스템의 근간은 클라이언트-서버 아키텍처에 기반한 리포지토리 모델이다. 리포지토리는 검증되고 버전이 관리되는 소프트웨어 패키지들과, 각 패키지의 의존성, 버전, 아키텍처 등의 정보를 담은 메타데이터를 호스팅하는 중앙 서버이다. 이 모델은 관리자가 신뢰할 수 있는 단일 소스에서 소프트웨어를 일관되게 공급받도록 보장함으로써, 악성 코드나 변조된 소프트웨어로부터 시스템을 보호하는 중요한 보안 계층 역할을 한다.
Debian 및 Ubuntu와 같은 파생 배포판에서 apt 패키지 관리자는 /etc/apt/sources.list 파일과 /etc/apt/sources.list.d/ 디렉터리에 위치한 파일들을 통해 리포지토리 정보를 참조한다. sources.list 파일의 각 라인은 특정 리포지토리를 정의하며, 다음과 같은 구조를 가진다.
deb http://deb.debian.org/debian/ buster main contrib non-free
deb 또는 deb-src: 아카이브 유형을 지정한다. deb는 컴파일된 바이너리 패키지를, deb-src는 소스 코드 패키지를 의미한다.
URI: 리포지토리 서버의 주소이다 (예: http://deb.debian.org/debian/).
배포판/스위트(Suite): 릴리스 코드명 (예: buster, focal) 또는 릴리스 클래스 (예: stable, testing)를 지정한다.
컴포넌트: 패키지의 라이선스 및 정책 준수 여부에 따라 분류된다.
main: 데비안 자유 소프트웨어 가이드라인(DFSG)을 준수하는 핵심 패키지.
contrib: DFSG를 준수하지만, non-free 컴포넌트에 의존하는 패키지.
non-free: DFSG를 준수하지 않는 패키지.
non-free-firmware: Bookworm 릴리스부터 포함된, DFSG를 준수하지 않는 펌웨어 패키지.
/etc/apt/sources.list.d/ 디렉터리는 서드파티 또는 개인 패키지 아카이브(PPA) 리포지토리를 추가할 때 사용된다. 각 리포지토리를 별도의 .list 파일로 관리함으로써, 메인 sources.list 파일을 수정하지 않고도 리포지토리를 모듈식으로 추가하거나 제거할 수 있어 관리 편의성을 높이고 설정 충돌을 방지한다.
apt update 명령은 이 파일들에 명시된 URI로부터 Packages와 Release 같은 메타데이터 파일을 다운로드하여, 로컬 패키지 캐시를 최신 상태로 갱신하는 역할을 한다. 이후 apt install과 같은 명령은 바로 이 로컬 캐시를 조회하여 패키지 정보를 확인한다.
Red Hat Enterprise Linux(RHEL), Fedora, CentOS 등 RPM 기반 시스템에서는 패키지 관리자(yum 또는 dnf)가 /etc/yum.repos.d/ 디렉터리 내의 .repo 파일들을 통해 리포지토리 설정을 관리한다. 이러한 모듈식 접근은 시스템의 기본 리포지토리와 서드파티 리포지토리를 명확하게 분리하여 관리할 수 있게 한다. 각 .repo 파일은 하나 이상의 리포지토리 섹션을 포함할 수 있으며, 각 섹션은 다음과 같은 주요 필드로 구성된다.
[appstream]
name=CentOS Stream 8 - AppStream
baseurl=http://mirror.centos.org/centos/8-stream/AppStream/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
[repositoryid]: 대괄호로 묶인 고유 식별자(예: [appstream])로, 시스템 내에서 해당 리포지토리를 유일하게 지칭하는 ID이다.
name: 사람이 읽을 수 있는 리포지토리의 설명이다.
baseurl: 패키지와 메타데이터가 위치한 리포지토리의 루트 디렉터리를 가리키는 직접적인 URL이다.
metalink: 가장 빠르거나 가까운 미러 서버 목록을 담고 있는 파일의 URL이다. baseurl과 metalink 중 하나는 반드시 지정되어야 한다.
enabled: 1(활성화) 또는 0(비활성화) 값을 가지며, 해당 리포지토리의 사용 여부를 결정한다.
gpgcheck: 1 또는 0 값을 가지며, 해당 리포지토리에서 다운로드한 패키지의 GPG 서명 검증 여부를 결정한다. 보안을 위해 1로 설정하는 것이 강력히 권장된다.
yum의 후속 버전인 dnf는 성능과 의존성 해결 능력이 개선되었지만, 하위 호환성을 위해 여전히 /etc/yum.repos.d/ 디렉터리를 기본 설정 경로로 사용한다. 이처럼 각 배포판의 리포지토리 설정 방식은 그 철학을 반영한다. Debian의 단일 파일 중심 접근은 중앙화된 아카이브의 일관성을 강조하는 반면, Red Hat 계열의 디렉터리 기반 모듈식 접근은 다양한 서드파티 소프트웨어 공급업체가 공존하는 엔터프라이즈 생태계에 더 적합하게 설계되었다.
의존성(Dependency)이란 특정 소프트웨어 패키지가 정상적으로 작동하기 위해 필요한 다른 라이브러리나 패키지를 의미한다. "의존성 지옥(Dependency Hell)"은 서로 다른 두 패키지가 동일한 의존성 라이브러리의 서로 다른, 호환되지 않는 버전을 요구할 때 발생하는 고질적인 문제이다. 이 경우, 한 패키지를 설치하면 다른 패키지가 작동하지 않게 되어 시스템이 불안정한 상태에 빠질 수 있다.
패키지 관리자는 이러한 문제를 자동화된 방식으로 해결한다. 설치하려는 패키지의 메타데이터를 읽어 필요한 모든 의존성 패키지와 그 버전을 파악하고, 이를 재귀적으로 추적하여 완전한 "의존성 그래프(Dependency Graph)"를 구축한다. 그 후, 그래프 내의 모든 요구사항을 충족하는 패키지 버전들의 조합을 계산하여 한 번에 설치한다. 이 과정은 수동 설치 시 발생할 수 있는 복잡성과 오류를 근본적으로 제거하는 패키지 관리자의 핵심 기능이다.
"unmet dependencies" (충족되지 않은 의존성) 또는 "conflicting requests" (충돌하는 요청)와 같은 오류가 발생했을 때, 다음과 같은 체계적인 접근법을 통해 문제를 진단하고 해결할 수 있다.
apt (Debian/Ubuntu) 시스템:
자동 해결 시도: 가장 먼저 sudo apt --fix-broken install 명령을 실행한다. 이 명령은 apt가 깨진 의존성 관계를 자동으로 탐지하고 수정하도록 시도하는 가장 기본적인 해결책이다.
고급 해결사 사용: apt가 문제를 해결하지 못할 경우, aptitude를 사용해 볼 수 있다. aptitude는 더 정교한 의존성 해결 알고리즘을 가지고 있어, 패키지 다운그레이드나 대체 패키지 제안 등 여러 해결책을 제시하여 사용자가 선택할 수 있게 한다.
문제 원인 분석: apt -o Debug::pkgProblemResolver=yes upgrade와 같이 디버그 옵션을 사용하면, apt의 의존성 해결 로직을 상세히 출력하여 어떤 패키지들이 충돌하고 있는지 구체적인 원인을 파악하는 데 도움이 된다.
리포지토리 및 버전 확인: apt-cache policy <package-name>명령을 실행하면 특정 패키지에 대해 설치 가능한 버전들과 각 버전이 어느 리포지토리에서 제공되는지 확인할 수 있다. 이를 통해 공식 리포지토리와 서드파티 리포지토리 간의 버전 충돌을 명확히 진단할 수 있다.
dnf/yum (RHEL/Fedora) 시스템:
배포판 동기화: dnf distro-sync 명령은 현재 시스템에 설치된 모든 패키지를 활성화된 리포지토리에서 제공하는 최신 버전으로 동기화(업그레이드 또는 다운그레이드)하여 버전 불일치 문제를 해결하는 데 효과적이다.
수동 개입: 명확한 충돌이 발생할 경우, 문제가 되는 패키지를 dnf remove <conflicting_package> 명령으로 제거하거나, dnf swap <old_package> <new_package> 명령을 통해 충돌하는 패키지를 다른 패키지로 교체하여 해결할 수 있다.
서드파티 리포지토리 확인: 시스템의 주 버전 업그레이드 직후, EPEL이나 RPM Fusion과 같은 서드파티 리포지토리에서 아직 새로운 주 버전에 맞는 패키지를 제공하지 않아 충돌이 발생하는 경우가 많다. 이 경우, 해당 리포지토리를 일시적으로 비활성화하거나, 리포지토리 측에서 업데이트된 패키지를 제공할 때까지 기다리는 것이 해결책이 될 수 있다.
대부분의 소프트웨어는 패키지 관리자를 통해 설치하는 것이 권장되지만, 다음과 같은 특정 상황에서는 소스 코드를 직접 컴파일하여 설치해야 할 필요가 있다.
소프트웨어의 가장 최신 버전을 사용해야 할 때 (리포지토리에 아직 등록되지 않은 경우)
특정 기능을 활성화하거나 비활성화하는 등, 배포판에서 제공하는 기본 빌드 옵션과 다르게 커스터마이징이 필요할 때
개발 중인 소프트웨어를 테스트하거나 시스템에 맞게 최적화된 패치를 적용해야 할 때
유닉스 계열 시스템에서 소스 코드를 빌드하는 전통적인 3단계 프로세스는 이식성 문제를 해결하기 위해 설계된 정교한 시스템이다.
./configure (환경 설정)
./configure 스크립트는 단순히 빌드 옵션을 설정하는 것을 넘어, 소프트웨어가 다양한 유닉스 계열 시스템에서 성공적으로 빌드될 수 있도록 하는 이식성의 핵심이다. 이 스크립트는 autoconf와 같은 GNU Autotools에 의해 생성되며, 실행 시 현재 시스템 환경을 정밀하게 탐색한다. C 컴파일러의 종류와 위치, 필수 라이브러리의 존재 여부, 시스템 고유의 헤더 파일 경로 등을 확인한다. 이 탐색 결과를 바탕으로, 소스 코드에 포함된 Makefile.in이라는 템플릿 파일을 사용하여 현재 시스템 환경에 완벽하게 맞춰진 최종 Makefile을 생성한다. 이 과정 덕분에 개발자는 단일 소스 코드를 작성하고, 사용자는 자신의 시스템 환경에 맞춰진 빌드 스크립트를 동적으로 생성할 수 있다.
make (컴파일)
make 유틸리티는 configure 스크립트가 생성한 Makefile을 읽어들여 실제 컴파일 작업을 수행한다. Makefile에는 소스 파일 간의 의존 관계와 각 파일을 컴파일하는 규칙이 정의되어 있다. make의 가장 큰 장점은 효율성에 있다. 각 파일의 최종 수정 시간을 비교하여, 마지막 빌드 이후 변경된 소스 파일과 그에 의존하는 파일들만 선택적으로 재컴파일한다. 이 기능은 대규모 프로젝트에서 전체 코드를 매번 다시 컴파일하는 데 드는 시간을 극적으로 단축시킨다.
make install (설치)
컴파일이 성공적으로 완료된 후, make install 명령을 실행하면 Makefile에 정의된 install 규칙이 수행된다. 이 규칙은 컴파일된 실행 파일, 라이브러리, 설정 파일, 매뉴얼 페이지(man pages) 등을 소스 디렉터리에서 /usr/local/bin, /usr/local/lib와 같은 시스템 표준 경로로 복사하는 역할을 한다. 이 과정은 시스템 디렉터리에 파일을 쓰는 작업이므로, 일반적으로 루트 권한(sudo)이 필요하다.
이 3단계 워크플로우는 다양한 유닉스 환경의 파편화 문제를 해결하기 위한 역사적인 산물이다. 오늘날 패키지 관리자는 이 복잡한 과정을 미리 수행하여 표준화된 환경에 맞는 바이너리 패키지를 제공함으로써 사용자 편의성을 극대화했지만, 이 전통적인 빌드 방식의 원리를 이해하는 것은 시스템의 깊은 수준에서 소프트웨어를 다루는 데 여전히 필수적이다.
| 기능 | apt (Debian/Ubuntu) | yum/dnf (RHEL/Fedora) |
|---|---|---|
| 주 설정 파일 | /etc/apt/sources.list | /etc/dnf/dnf.conf (전역 설정) |
| 추가 리포지토리 | /etc/apt/sources.list.d/ 디렉터리 내 .list 파일 | /etc/yum.repos.d/ 디렉터리 내 .repo 파일 |
| 파일 형식 | 한 줄 형식 (One-line format) | INI 형식 (섹션 기반) |
| 핵심 필드 | deb/deb-src, URI, 배포판, 컴포넌트 | [id], name, baseurl/metalink, enabled, gpgcheck |
| 메타데이터 갱신 | apt update | dnf makecache (보통 자동으로 수행됨) |
cron은 유닉스 계열 시스템에서 가장 널리 사용되는 전통적인 작업 스케줄러이다. 작업 목록은 crontab이라는 파일에 저장되며, 각 항목은 "언제, 무엇을" 실행할지를 정의한다. crontab 항목은 5개의 시간 필드와 1개의 명령 필드로 구성된다.
분(0-59) 시(0-23) 일(1-31) 월(1-12) 요일(0-7, 0과 7은 일요일) /실행할/명령어
이 필드들에는 다음과 같은 특수 문자를 사용하여 더 유연한 스케줄링이 가능하다.
* (별표): 모든 값을 의미한다 (예: "매 분", "매 시간").
, (쉼표): 여러 값을 나열한다 (예: 1,15는 1일과 15일을 의미).
- (하이픈): 값의 범위를 지정한다 (예: 1-5는 월요일부터 금요일까지).
/ (슬래시): 간격을 지정한다 (예: */15는 "15분마다"를 의미).
많은 cron 구현체는 가독성을 높이기 위해 다음과 같은 특수 문자열을 지원한다. 이는 표준은 아니지만 사실상 표준처럼 널리 사용된다.
@reboot: 시스템 부팅 시 한 번 실행.
@yearly (@annually): 매년 1월 1일 자정에 실행 (0 0 1 1 *).
@monthly: 매월 1일 자정에 실행 (0 0 1 * *).
@weekly: 매주 일요일 자정에 실행 (0 0 * * 0).
@daily (@midnight): 매일 자정에 실행 (0 0 * * *).
@hourly: 매시 정각에 실행 (0 * * * *).
하나의 작업을 부팅 시에도 실행하고 매일 특정 시간에도 실행하려면, @reboot 항목과 일반 시간 지정 항목을 각각 별도의 줄로 작성해야 한다.
cron 사용 시 가장 흔하게 마주치는 문제는 사용자의 터미널에서는 완벽하게 실행되던 스크립트가 cron 작업으로 등록하면 실패하는 경우이다. 이 문제의 근본 원인은 cron이 작업을 실행하는 환경이 사용자의 대화형 셸 환경과 완전히 다르다는 점에 있다.
이러한 cron의 동작 방식은 의도된 설계이다. 이는 자동화 스크립트가 특정 사용자의 변덕스러운 셸 환경에 의존하지 않고, 어떤 상황에서도 예측 가능하게 동작하도록 강제하는 역할을 한다. 즉, 스크립트 자체적으로 완전하고 이식 가능하게 작성하도록 유도하는 것이다.
안정적인 해결책:
절대 경로 사용: 가장 안정적이고 권장되는 방법은 crontab에 등록하는 모든 명령어와 스크립트의 경로를 루트 디렉터리(/)부터 시작하는 절대 경로로 명시하는 것이다. 예를 들어, my_script.sh 대신 /home/user/scripts/my_script.sh라고 명시해야 한다.
Crontab 내 PATH 변수 설정: crontab 파일의 맨 위에 PATH=/usr/local/bin:/usr/bin:/bin과 같이 필요한 모든 경로를 포함하는 PATH 변수를 직접 정의할 수 있다. 이 변수는 해당 crontab 파일 내의 모든 작업에 일괄적으로 적용된다.
환경 파일 명시적 로딩: 복잡한 환경 변수 설정이 필요한 작업의 경우, cron 항목 내에서 필요한 환경 변수 파일을 명시적으로 로드(source 또는 .)한 후, 실제 명령을 실행하는 것이 좋다. 이는 스크립트의 의존성을 명확하게 만들어준다.
* * * * *. /home/user/.profile; /path/to/my_script.sh
systemd 타이머는 cron과 같은 독립적인 데몬이 아니라, systemd라는 통합된 시스템 및 서비스 관리자의 일부로서 작동한다. 이는 타이머를 단순한 스케줄러가 아닌, 다른 systemd 유닛(일반적으로 .service 유닛)을 활성화하는 여러 방법 중 하나로 위치시킨다. 바로 이 통합적인 아키텍처가 systemd 타이머의 강력함의 원천이다.
systemd 타이머는 '무엇을 할 것인가'와 '언제 할 것인가'를 명확히 분리하는 2-파일 구조를 채택한다.
.service 유닛: 이 파일은 실행할 작업(What)을 정의한다. Service 섹션의 ExecStart= 지시어를 통해 실행할 명령어의 절대 경로를 지정하고, Type=oneshot (한 번 실행되고 종료되는 스크립트에 적합), User= (작업을 실행할 사용자) 등 작업의 실행 컨텍스트를 상세히 기술한다.
.timer 유닛: 이 파일은 실행 시점(When)을 정의한다. Service 섹션에 스케줄을 명시하며, 이름 규칙에 따라 동일한 이름의 .service 파일을 활성화시킨다 (예: mytask.timer는 mytask.service를 실행).
systemd 타이머는 cron보다 훨씬 다양하고 정밀한 스케줄링 옵션을 제공한다.
캘린더 이벤트 (OnCalendar=): cron과 유사하게 절대적인 시간을 기준으로 작업을 예약한다. 하지만 초 단위의 정밀도를 지원하며, Mon..Fri -- 10:00: (월요일부터 금요일까지 매일 오전 10시 10분대의 매 초)와 같이 더 표현력 높은 구문을 사용할 수 있다.
모노토닉 타이머 (Monotonic Timers): 특정 이벤트를 기준으로 상대적인 시간을 지정하는 기능으로, cron에는 없는 강력한 기능이다.
OnBootSec=: 시스템 부팅 완료 후 경과된 시간을 기준으로 실행 (예: OnBootSec=15min).
OnUnitActiveSec=: 해당 타이머에 연결된 서비스가 마지막으로 활성화된 후 경과된 시간을 기준으로 실행. 이는 "마지막 실행이 끝난 후 X시간 뒤에 다시 실행"과 같은 로직을 구현하는 데 매우 유용하다.
주요 타이머 옵션:
Persistent=true: 시스템이 꺼져 있는 동안 실행 시간이 지났을 경우, 시스템이 부팅된 후 즉시 놓친 작업을 실행한다. 이는 anacron의 기능을 대체한다.
RandomizedDelaySec=: 지정된 시간만큼 실행을 무작위로 지연시킨다. 여러 서버에서 동시에 업데이트를 확인하는 등의 작업을 분산시켜 "서버 폭주(thundering herd)" 현상을 방지하는 데 유용하다.
systemd 타이머는 systemctl 명령어를 통해 일관된 방식으로 관리된다.
/etc/systemd/system/ 경로에 mytask.service와 mytask.timer 파일을 생성한다.
systemd 관리자가 새로운 유닛 파일을 인식하도록 설정을 다시 로드한다: sudo systemctl daemon-reload
시스템 재부팅 후에도 타이머가 자동으로 활성화되도록 설정한다: sudo systemctl enable mytask.timer
타이머를 즉시 시작한다: sudo systemctl start mytask.timer
모든 활성화된 타이머의 상태(마지막 실행 시간, 다음 실행 예정 시간 등)를 확인한다: systemctl list-timers --all
systemd 타이머가 시스템 수준의 작업을 자동화하는 데 있어 근본적으로 우월한 이유는, 그것이 독립적인 스케줄러가 아니기 때문이다. systemd는 본질적으로 서비스를 관리하는 통합 프레임워크이며, 타이머는 서비스를 '활성화'하는 여러 트리거 중 하나일 뿐이다. 따라서 타이머로 실행되는 작업은 일반적인 systemd 서비스와 동일하며, systemd의 강력한 서비스 관리 기능을 모두 상속받는다. 이는 로깅, 리소스 제어, 의존성 관리 측면에서 cron과 비교할 수 없는 구조적 이점을 제공한다.
로깅 및 감사: systemd 타이머로 실행되는 모든 서비스의 표준 출력(stdout)과 표준 에러(stderr)는 자동으로 systemd 저널(journal)에 기록된다. 따라서 journalctl -u mytask.service 명령 하나로 모든 실행 기록과 결과를 손쉽게 추적하고 디버깅할 수 있다. 반면, cron은 기본적으로 실행 결과를 MAILTO 환경 변수에 지정된 이메일로 보내거나, 사용자가 직접 >나 2>&1과 같은 리디렉션을 사용하여 로그 파일을 관리해야 한다.
의존성 및 순서 관리: systemd 타이머의 가장 큰 장점 중 하나이다. .service 파일 내에서 After=network-online.target이나 Wants=mariadb.service와 같은 지시어를 사용하여, 네트워크가 완전히 연결된 후에 또는 데이터베이스 서비스가 실행된 후에만 작업이 시작되도록 보장할 수 있다. cron은 시스템의 다른 서비스 상태를 전혀 인지하지 못하므로, 스크립트 내에서 직접 서비스 상태를 확인하는 복잡한 로직을 구현해야 한다.
리소스 제어: 타이머에 의해 실행되는 작업은 일반 systemd 서비스이므로, cgroups를 통해 리소스 사용량을 정밀하게 제어할 수 있다. .service 파일에 MemoryMax=1G나 CPUShares=512와 같은 지시어를 추가하여 해당 작업이 사용할 수 있는 최대 메모리나 CPU 점유율을 제한할 수 있다. cron은 이러한 리소스 제어 기능을 내장하고 있지 않다.
단순성과 이식성: cron의 명백한 장점은 단순함과 이식성에 있다. 단 한 줄의 설정으로 작업을 예약할 수 있으며, systemd가 없는 구형 시스템이나 BSD, macOS 등 거의 모든 유닉스 계열 운영체제에서 동일한 방식으로 작동한다. systemd 타이머는 두 개의 파일을 작성해야 하는 등 설정이 더 복잡하며, systemd를 사용하는 리눅스 시스템에서만 사용 가능하다.
| 기능 | Cron | systemd 타이머 |
|---|---|---|
| 설정 | 단일 라인 (crontab 파일) | 2개의 유닛 파일 (.service, .timer) |
| 스케줄링 정밀도 | 분 단위 | 초 단위, 마이크로초 단위 정확도 설정 가능 |
| 놓친 작업 처리 | 기본적으로 처리 안 함 (anacron 필요) | Persistent=true 옵션으로 자동 처리 |
| 로깅 | MAILTO로 이메일 전송 또는 수동 리디렉션 | systemd-journald와 자동 통합 (journalctl) |
| 의존성 관리 | 지원 안 함 (스크립트 내에서 직접 구현 필요) | After=, Wants= 등 지시어로 서비스/타겟 의존성 정의 가능 |
| 리소스 제어 | 지원 안 함 | cgroups를 통해 CPU, 메모리 등 정밀 제어 가능 |
| 실행 환경 | 최소한의 환경 (예: 제한된 PATH) | .service 파일에서 Environment=, User= 등으로 완벽 제어 |
| 관리 및 조회 | 여러 파일 분산 (/etc/crontab, cron.d, 사용자별 crontab) | systemctl list-timers --all로 중앙 집중식 조회 |
| 이식성 | 거의 모든 Unix-like 시스템에서 사용 가능 | systemd를 사용하는 Linux 시스템으로 제한됨 |