시작 스크립트
os.startup_scripts는 결과 이미지를 위한 상한이 있는 systemd 원샷 작업을 만듭니다. 각 항목은 셸 명령, 필요한 패키지, 실행 사용자, 순서 유닛을 선언합니다.
시작 스크립트는 run_as가 달리 지정하지 않으면 root 권한 코드입니다. 설치 스크립트와 같은 검토를 받아야 합니다.
정식 형태
{
"os": {
"startup_scripts": [
{
"name": "write-build-marker",
"description": "Create a local readiness marker after networking is available.",
"command": "set -Eeuo pipefail\ninstall -d -m 0755 /var/lib/example\nprintf '%s\\n' ready > /var/lib/example/build-ready",
"packages": [],
"run_as": "root",
"after": "network-online.target"
}
]
}
}필드는 레거시 script 필드가 아니라 description과 command입니다. run_as와 after도 snake_case를 사용합니다. after는 배열이 아니라 systemd 유닛 문자열 하나입니다.
스키마는 최대 32개 항목과 상한이 있는 명령 크기를 받습니다. 검증은 빈 명령과 NUL 바이트를 거부하되, 셸 내용을 안전하거나 멱등하게 만들지 않습니다.
재시도와 부분 실패를 위한 설계
부트는 일부 부작용이 발생한 뒤에 중단될 수 있습니다. 다음 호출이 안전하게 완료되거나 검사 가능한 분명한 상태로 끝나도록 스크립트를 작성하세요.
좋은 패턴은 다음과 같습니다.
- 임시 파일에 쓰고, 검증한 다음 원자적으로 이름을 바꿉니다;
- 사용자, 디렉터리, 구성 항목이 이미 있는지 확인합니다;
- 소유자와 모드를 명시하기 위해
install을 사용합니다; set -Eeuo pipefail을 적용하고 예상되는 0이 아닌 결과를 의도적으로 처리합니다;- 상한이 있는 네트워크 타임아웃과 유한한 재시도 횟수를 사용합니다; 그리고
- 필요한 단계가 모두 성공한 뒤에만 준비 완료 마커를 씁니다.
준비 확인으로 sleep에 의존하지 마세요. 실제 의존성을 프로브하세요.
외부 다운로드
curl ... | sh를 피하세요. 첫 부트에서 아티팩트를 가져와야 한다면:
- 인증서 검증이 있는 HTTPS를 사용합니다;
- 기대하는 아티팩트 또는 소스 버전을 고정합니다;
- 실행 전에 암호 다이제스트 또는 승인된 서명을 검증합니다;
- 연결 타임아웃과 전체 타임아웃을 설정합니다;
- 검증이 실패하면 닫힌 실패로 처리합니다; 그리고
- 자격 증명이나 서명된 URL을 로그에 남기지 않습니다.
진정으로 오프라인 또는 재현 가능한 동작을 원하면, 첫 부트에서 다운로드하는 대신 검토된 내용을 이미지 또는 승인된 패키지 저장소에 넣으세요.
비밀
평문 자격 증명을 레시피, 명령, URL, 생성된 마커에 넣지 마세요. 레시피 JSON과 빌드 로그는 보존되는 증거이며 운영자에게 보일 수 있습니다. 승인된 배포 시점 등록 또는 비밀 전달 메커니즘을 사용하고, 결과 자격 증명을 대상에 한정하세요.
실행 신원
권한이 낮은 서비스 계정을 선호하세요. root가 필요하면 명령을 가장 작은 특권 단계로 줄이고 파일 소유권을 명시하세요. run_as가 유닛이 시작되기 전에 만들어진 계정을 가리키는지 확인하세요.
검증
유닛의 종료 상태만이 아니라 결과를 테스트하세요.
{
"type": "file_contains",
"description": "The startup unit wrote its readiness marker.",
"params": {
"path": "/var/lib/example/build-ready",
"content": "ready"
}
}두 번째 부트, 사용할 수 없는 의존성, 중단된 첫 실행에서의 복구도 테스트하세요. 실패 시 systemctl status와 유닛 저널을 확인하세요.