systemd 260 + Linux 6.19 핵심 신기능 완전 가이드: mstack, sched_ext, Varlink Metrics 실전 적용

2026년 3월 17일, systemd 260이 공식 릴리스되었습니다. 같은 시기 Linux 커널 6.19도 sched_ext 프레임워크를 대폭 강화했습니다. 이번 릴리스는 단순한 버전 업그레이드가 아닙니다. 30년 넘게 이어온 System V init의 완전한 제거, BPF 기반 커스텀 CPU 스케줄러의 프로덕션 안정화, 그리고 컨테이너/샌드박스 환경을 위한 새로운 마운트 추상화 계층 도입 등 Linux 생태계의 패러다임을 바꾸는 변화가 담겨 있습니다. 이 문서에서는 주요 신기능을 실제 설정 예시와 함께 상세히 살펴봅니다.


1. System V init 지원 완전 제거: 역사의 마침표

systemd 260에서 가장 큰 변화는 System V (SysV) init 스크립트 지원이 완전히 제거된 것입니다. systemd-sysv-generator, rc-local.service, 관련 호환 레이어가 모두 삭제되었습니다. 이는 소프트 데프리케이션이나 단계적 제거가 아닌, 코드 자체의 물리적 삭제입니다.

영향받는 구성 요소

  • /etc/init.d/ 하위 SysV 스크립트 자동 변환 기능 제거
  • rc-local.service 유닛 파일 제거 (/etc/rc.local 자동 실행 불가)
  • systemd-sysv-generator 바이너리 제거

마이그레이션 방법: SysV 스크립트를 systemd 유닛으로 전환

기존에 /etc/init.d/myapp 형태로 관리하던 서비스를 systemd 네이티브 유닛으로 전환하는 방법은 다음과 같습니다.

# 1. 유닛 파일 생성
sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Application Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yaml
ExecStop=/usr/local/bin/myapp --stop
Restart=on-failure
RestartSec=5
User=myapp
Group=myapp
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
# 2. 유닛 활성화 및 시작
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

# 3. 상태 확인
sudo systemctl status myapp.service
journalctl -u myapp.service -f

특히 주의해야 할 점은 /etc/rc.local을 사용하던 환경입니다. 기존 rc.local 기능을 대체하려면 별도의 rc-local.service를 직접 작성해야 합니다.

# rc-local.service 직접 생성 (systemd 260부터 내장 유닛 없음)
sudo tee /etc/systemd/system/rc-local.service << 'EOF'
[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local
After=network.target

[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=journal
StandardError=journal
RemainAfterExit=yes
GuessMainPID=no

[Install]
WantedBy=multi-user.target
Alias=rc-local.service
EOF

sudo systemctl enable --now rc-local.service

최소 커널 요구사항 상향

systemd 260은 커널 베이스라인을 Linux 5.4에서 5.10으로 올렸습니다. 실제 운영 환경에서는 5.14 LTS 또는 6.6 LTS 이상을 권장합니다. 또한 glibc 2.34, OpenSSL 3.0, Python 3.9 이상이 필요합니다.


2. mstack: 컨테이너를 위한 차세대 마운트 추상화

systemd 260의 핵심 신기능 중 하나는 mstack (Mount Stack)입니다. OverlayFS와 bind-mount를 구조화된 디렉토리 레이아웃으로 선언적으로 정의할 수 있는 새로운 메커니즘입니다. 컨테이너 이미지와 서비스 런타임 환경을 자기 완결적인 디렉토리로 패키징하는 데 특히 유용합니다.

mstack 기본 개념

.mstack/ 접미사를 가진 디렉토리는 복합 디렉토리 계층으로 처리됩니다. 그 안의 파일과 서브디렉토리가 OverlayFS 레이어를 정의합니다.

# mstack 디렉토리 구조 예시: foobar.mstack/
foobar.mstack/
  layer@0.raw  ->  ../base.raw      # 하위 레이어 (베이스 이미지, 심볼릭 링크)
  layer@1.raw  ->  ../app.raw       # 상위 레이어 (앱 레이어, 심볼릭 링크)
  rw/                               # 쓰기 가능한 레이어 (실제 디렉토리)

이 구조에서 foobar.mstack/를 마운트하면 systemd가 자동으로 base.raw와 app.raw를 OverlayFS로 겹쳐 쌓고, rw/를 최상위 쓰기 레이어로 설정합니다.

systemd-mstack CLI 도구 사용법

# mstack 마운트
sudo systemd-mstack mount /path/to/foobar.mstack /mnt/myapp

# 마운트 상태 확인
systemd-mstack list

# mstack 언마운트
sudo systemd-mstack umount /mnt/myapp

# mstack 구조 검증
systemd-mstack verify /path/to/foobar.mstack

서비스 유닛에서 RootMStack 설정

서비스 유닛에서 RootMStack= 파라미터를 사용하면 서비스가 시작될 때 mstack을 자동으로 마운트하고, 종료 시 자동 언마운트합니다.

[Unit]
Description=Containerized Web Application
After=network.target

[Service]
Type=simple
# mstack 디렉토리를 서비스 루트로 사용
RootMStack=/var/lib/myapp/foobar.mstack
ExecStart=/usr/bin/mywebapp
User=webapp
DynamicUser=true

# 추가 격리 설정
PrivateNetwork=false
PrivateTmp=true
ReadOnlyPaths=/etc
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

nspawn 컨테이너에서 mstack 활용

# systemd-nspawn과 함께 mstack 사용
sudo systemd-nspawn \
  --mstack=/var/lib/containers/debian.mstack \
  --machine=mycontainer \
  --boot

# 임시 VM 생성 (ephemeral 옵션 - systemd 260 신규)
sudo systemd-vmspawn \
  --image=/var/lib/vms/ubuntu-26.04.raw \
  --ephemeral \
  -- /bin/bash

mstack의 가장 큰 장점은 Docker나 별도의 컨테이너 런타임 없이도 systemd 네이티브로 레이어드 파일시스템을 구성할 수 있다는 점입니다. 특히 불변 인프라(Immutable Infrastructure) 패턴을 구현할 때 강력합니다.


3. CPUSchedulingPolicy=ext: 서비스별 BPF 스케줄러 적용

systemd 260에서 CPUSchedulingPolicy= 설정에 새로운 값 ext가 추가되었습니다. 이를 통해 특정 서비스를 Linux 커널의 sched_ext (BPF 확장 스케줄러) 클래스로 실행할 수 있습니다. 게임 서버, 실시간 데이터 처리, 지연 시간에 민감한 네트워크 서비스 등에 최적화된 스케줄링 정책을 적용하는 것이 가능해졌습니다.

서비스 유닛에서 ext 스케줄러 설정

[Unit]
Description=Low-Latency Network Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/low-latency-server
# BPF 확장 스케줄러(sched_ext) 사용
CPUSchedulingPolicy=ext
# Transparent Huge Pages 세밀 제어 (systemd 260 신규)
MemoryTHP=always

[Install]
WantedBy=multi-user.target
# 실행 중인 프로세스의 스케줄링 정책 확인
chrt -p $(pgrep low-latency-server)

# sched_ext 활성화 여부 확인
cat /sys/kernel/sched_ext/root/ops

4. Linux 6.19의 sched_ext 혁신: eBPF 스케줄러 완전 실전화

Linux 6.12에서 처음 도입된 sched_ext는 6.19에서 프로덕션 수준으로 성숙했습니다. eBPF 프로그램으로 완전히 커스텀 CPU 스케줄러를 구현하고 런타임에 교체할 수 있는 이 기능은 Google, Meta 등 대형 기업이 실제 데이터센터 서버에 적용하면서 급속도로 안정화되었습니다.

6.19에서 추가된 핵심 개선 사항

4-1. 오작동 스케줄러 자동 복구 (Fault Recovery)

가장 중요한 개선입니다. 이전 버전에서는 BPF 스케줄러가 무한 루프에 빠지거나 오동작하면 시스템 전체가 응답 불능 상태에 빠질 수 있었습니다. 6.19에서는 Bypass Mode가 도입되어, 스케줄러 장애 감지 시 밀리초 내에 기본 CFS(Completely Fair Scheduler)로 자동 복구합니다.

# sched_ext 상태 및 현재 활성 스케줄러 확인
cat /sys/kernel/sched_ext/root/ops

# 스케줄러 장애 이력 확인
cat /sys/kernel/sched_ext/root/error

# 커널 로그에서 sched_ext 이벤트 추적
dmesg | grep -i sched_ext

4-2. Bypass Mode의 per-CPU DSQ 구조

기존에는 여러 태스크가 affinity 제약이 다른 채로 하나의 공유 DSQ(Dispatch Queue)에 몰리면, 실행할 수 없는 태스크를 탐색하는 CPU들이 시스템을 마비시키는 문제가 있었습니다. 6.19에서는 bypass 모드가 per-CPU DSQ + 로드 밸런서 방식으로 전환되어 이 문제를 근본적으로 해결했습니다.

4-3. Lockless Peek 연산

DSQ(Dispatch Queue)에서 태스크를 미리 조회할 때 기존에는 락을 획득해야 했습니다. 6.19에서는 lockless peek 연산이 추가되어, 고빈도 스케줄링 루프에서의 락 경합이 크게 감소했습니다. 고부하 워크로드에서 최대 15% 지연 시간 감소 효과가 보고되었습니다.

4-4. 계층적 스케줄러(Hierarchical Scheduler) 기반 작업

컨테이너나 cgroup 계층을 인식하는 계층적 스케줄링을 위한 기반 코드가 6.19에 포함되었습니다. 이를 통해 향후 cgroup 별로 다른 BPF 스케줄링 정책을 적용하는 것이 가능해질 예정입니다.

sched_ext 실전 설치 및 사용 (Arch Linux / CachyOS)

# 커널 설정 확인 (6.12+ 커널 필수)
uname -r
grep CONFIG_SCHED_CLASS_EXT /boot/config-$(uname -r)

# scx 도구 패키지 설치 (Arch Linux)
sudo pacman -S scx-scheds

# Ubuntu/Debian (PPAor backport 필요)
sudo add-apt-repository ppa:arighi/sched-ext
sudo apt update
sudo apt install scx

사용 가능한 scx 스케줄러 목록 및 특성

# 사용 가능한 스케줄러 목록 확인
ls /usr/lib/scx/

# scx_simple: 가장 단순한 FIFO/vtime 스케줄러 (학습/테스트용)
sudo scx_simple

# scx_simple FIFO 모드로 실행 (선착순 스케줄링)
sudo scx_simple -f

# scx_bpfland: 대화형 워크로드 최적화 (데스크톱 환경 권장)
sudo scx_bpfland

# scx_rustland: Rust 유저스페이스 스케줄러 (유연성 최우선)
sudo scx_rustland

# scx_lavd: 지연 시간 인식 가상 데드라인 스케줄러 (게이밍/실시간)
sudo scx_lavd

# 스케줄러 실행 중 통계 출력
sudo scx_simple -v
# 현재 활성 스케줄러 확인
cat /sys/kernel/sched_ext/root/ops
# 출력 예: scx_bpfland

# 스케줄러 중지 (Ctrl+C 또는)
sudo pkill scx_bpfland
# -> 자동으로 기본 CFS로 복귀

scx_simple BPF 코드 구조 이해

sched_ext 스케줄러의 내부 구조를 이해하면 커스텀 스케줄러 개발에 도움이 됩니다. 핵심은 sched_ext_ops 구조체의 콜백 함수들입니다.

/* 커널 설정 확인 */
/*
  CONFIG_SCHED_CLASS_EXT=y
  CONFIG_BPF=y
  CONFIG_DEBUG_INFO_BTF=y
  CONFIG_BPF_JIT=y
*/

/* BPF 스케줄러 핵심 콜백 구조 (개념 예시) */
struct sched_ext_ops {
    /* CPU 선택: 태스크를 어느 CPU에서 실행할지 결정 */
    s32 (*select_cpu)(struct task_struct *p, s32 prev_cpu, u64 wake_flags);

    /* 큐잉: 태스크를 디스패치 큐에 넣음 */
    void (*enqueue)(struct task_struct *p, u64 enq_flags);

    /* 디스패치: 다음 실행할 태스크를 CPU에 할당 */
    void (*dispatch)(s32 cpu, struct task_struct *prev);

    /* 실행 시작: 가상 시간(vtime) 추적 시작 */
    void (*running)(struct task_struct *p);

    /* 실행 종료: 가상 시간 업데이트 */
    void (*stopping)(struct task_struct *p, bool runnable);
};

scx_lavd로 게임 서버 최적화 예시

# LAVD (Latency-Aware Virtual Deadline) 스케줄러 실행
# - 지연 시간에 민감한 워크로드에 우선권 부여
# - 배치 작업과 대화형 작업을 자동으로 구분
sudo scx_lavd --autopilot

# 특정 cgroup에 우선순위 지정
sudo scx_lavd --cgroup-weight /system.slice=100 --cgroup-weight /user.slice=200

# 성능 모니터링
sudo scx_lavd --verbose 2>&1 | grep -E "(lat|cpu|util)"

5. Varlink Metrics: 구조화된 시스템 메트릭 수집

systemd 260에서 도입된 Varlink Metrics 프레임워크는 systemd 컴포넌트들이 /run/systemd/report/ 하위 Varlink 엔드포인트를 통해 구조화된 데이터를 노출하게 합니다. 새로운 systemd-report 도구로 이를 JSON 형식으로 수집할 수 있습니다.

# 전체 시스템 메트릭 수집
systemd-report

# JSON 포맷으로 출력
systemd-report --json=pretty

# 특정 컴포넌트 메트릭
systemd-report --unit=nginx.service

# Varlink 엔드포인트 목록 확인
ls /run/systemd/report/
# systemd-report 출력 예시 (JSON)
{
  "Timestamp": "2026-04-21T09:30:00Z",
  "CPUUsage": 12.5,
  "MemoryUsed": 4294967296,
  "MemoryAvailable": 12884901888,
  "Units": [
    {
      "Name": "nginx.service",
      "CPUTimeUSec": 1234567,
      "MemoryCurrent": 52428800,
      "TasksCurrent": 4
    }
  ]
}

이를 Prometheus나 Grafana와 연동하면 기존 node_exporter와 유사한 메트릭 수집 파이프라인을 systemd 네이티브로 구성할 수 있습니다.

# systemd-report를 Prometheus push gateway로 전송하는 스크립트 예시
#!/bin/bash
METRICS=$(systemd-report --json=short)
CPU=$(echo $METRICS | jq '.CPUUsage')
MEM=$(echo $METRICS | jq '.MemoryUsed')

curl -X POST http://pushgateway:9091/metrics/job/systemd_report \
  -d "systemd_cpu_usage $CPU
systemd_memory_used_bytes $MEM
"

6. MemoryTHP: 서비스별 Transparent Huge Pages 제어

기존에는 /sys/kernel/mm/transparent_hugepage/enabled를 통해 시스템 전체에 일괄 적용하거나, cgroup의 memory.thp.limit_in_bytes를 수동 조정해야 했습니다. systemd 260의 MemoryTHP= 설정으로 서비스 단위의 세밀한 THP 제어가 가능해졌습니다.

[Service]
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf

# Transparent Huge Pages 설정
# always: 항상 THP 사용 (대용량 메모리 서비스에 유리)
# madvise: madvise() 호출한 영역만 THP 사용
# never: THP 비활성화 (지연 시간 민감 서비스)
MemoryTHP=madvise

# THP 붕괴 방지 (페이지 분열 방지)
MemorySwapMax=0
# 실행 중 서비스의 THP 상태 확인
cat /proc/$(pgrep redis-server)/smaps | grep -i huge

# 시스템 전역 THP 통계
grep -i huge /proc/meminfo

7. FANCY_NAME: OS 식별 정보 현대화

systemd 260에서는 /etc/os-release에 새로운 필드 FANCY_NAME=이 추가되었습니다. 기존 PRETTY_NAME이 평문 텍스트만 허용했던 것과 달리, FANCY_NAME은 ANSI 이스케이프 시퀀스와 유니코드를 지원합니다.

# /etc/os-release 예시 (배포판 커스터마이징)
cat /etc/os-release
NAME="MyLinux"
VERSION="1.0"
PRETTY_NAME="MyLinux 1.0"
FANCY_NAME="\e[1;34mMyLinux\e[0m 1.0"
ID=mylinux
ID_LIKE=debian
VERSION_ID="1.0"
HOME_URL="https://mylinux.example.com"
# neofetch, fastfetch 등에서 FANCY_NAME 활용
fastfetch
# -> ANSI 색상이 적용된 OS 이름 표시

8. 업그레이드 전 체크리스트

systemd 260으로 업그레이드하기 전 반드시 확인해야 할 사항들입니다.

1단계: 기존 SysV 서비스 감사

# SysV 스크립트 잔존 여부 확인
ls /etc/init.d/

# systemd로 관리되지 않는 SysV 서비스 목록
systemctl list-units --type=service | grep -v systemd

# 레거시 서비스 전환 가이드 출력
systemctl help-compat

2단계: 커널 버전 확인

# 현재 커널 버전 확인
uname -r

# 최소 요구사항: Linux 5.10
# 권장: Linux 5.14 LTS 또는 6.6 LTS 이상

# Debian/Ubuntu 커널 업그레이드
sudo apt install linux-image-6.6-generic

# Arch Linux
sudo pacman -Syu linux linux-headers

3단계: 의존성 확인

# glibc 버전 확인 (2.34 이상 필요)
ldd --version

# OpenSSL 버전 확인 (3.0 이상 필요)
openssl version

# Python 버전 확인 (3.9 이상 필요)
python3 --version

4단계: systemd 업그레이드

# Arch Linux (이미 260 포함)
sudo pacman -Syu systemd

# Fedora
sudo dnf upgrade systemd

# 업그레이드 후 버전 확인
systemctl --version
# 출력: systemd 260 (260-xxx)

# 업그레이드 후 데몬 리로드
sudo systemctl daemon-reexec

마무리

systemd 260과 Linux 6.19는 Linux 운영체제의 관리 방식을 한 단계 더 현대화합니다. SysV의 완전한 제거는 과거와의 단절이지만, mstack을 통한 선언적 컨테이너 환경 구성, sched_ext를 통한 워크로드 최적화 CPU 스케줄링, Varlink Metrics를 통한 통합 모니터링 등 그 공백을 충분히 메우는 강력한 대안들이 제공됩니다. 특히 sched_ext의 프로덕션 안정화는 단순한 기능 추가를 넘어, BPF 기술이 시스템의 가장 핵심적인 영역인 CPU 스케줄링까지 침투했음을 의미합니다. 서버 운영자와 시스템 개발자 모두 이번 변화를 적극적으로 검토하고 마이그레이션 계획을 세우는 것을 권장합니다.