Home 모던 리눅스 교과서 6. 애플리케이션패키지 관리컨테이너
Post
Cancel

모던 리눅스 교과서 6. 애플리케이션패키지 관리컨테이너

용어 정리

프로그램

  • 일반적으로 리눅스가 메모리에 로드하고 실행할 수 있는 바이너리 파일 혹은 셸 스크립트를 일컫는다.
    • 이 엔티티를 부르는 또 다른 이름은 실행 파일이다.
    • 실행 파일의 유형에 따라 그 실행을 정확히 무엇이 관리하는지가 결정된다.

      프로세스

  • 프로그램 기반의 실행 엔티티이며ㅑ 슬립 상태가 아닌 한 메인 메모리에 로드되어 CPU나 I/O를 사용한다.

데몬

  • 데몬 프로세스의 줄임말로 서비스라고도 하며 다른 프로세스에 특정 기능을 제공하는 백그라운드 프로세스이다.
    • 예를 들어 프린터 데몬을 사용하면 인쇄가 가능해진다.
    • 그 밖에도 웹 서비스, 로깅, 시간 등 매일 사용하는 유틸리티를 위한 다양한 데몬이 존재한다.

애플리케이션

  • 종속성을 포함한 프로그램. 사용자 인터페이스를 포함한 실질적인 프로그램이다.
    • 일반적으로 검색부터 업그레이드를 위한 설치, 제거에 이르기까지, 프로그램의 전체 수정주기, 구성, 데이터와 연관하여 애플리케이션이라는 용어를 사용한다.

패키지

  • 프로그램과 구성을 포함한 파일을 말한다. 소프트웨어 애플리케이션을 배포하는데 사용된다.

패키지 관리자

  • 패키지를 입력값으로 받아 해당 콘텐츠와 사용자 지침에 따라 리눅스 환경에서 패키지를 설치, 업그레이드, 제거하는 프로그램이다.

공급망

  • 패키지를 기반으로 사용자가 애플리케이션을 찾고 사용할 수 있는 소프트웨어 생산자와 배포자의 모음을 뜻한다.

부팅

  • 리눅스를 사용할 수 있는 상태로 만드는 것을 목표로 하드웨어와 운영체제를 초기화하는 리눅스의 시작 시퀀스를 말한다.
    • 여기에는 커널 로딩과 서비스 프로그램 시작도 포함된다.

리눅스 시작 프로세스

  • 리눅스 부트 프로세스는 일반적으로 하드웨어와 커널이 함께 작동하는 여러 단계에 걸친 작업이다.
    1. 모던 환경에서 UEFI 사양은 부팅 구성과 부팅 로더를 정의한다.
    • 이전 시스템에서는 이 단계에서 POST가 완료되면 기본 I/O하드웨어를 초기화하고, 부트 로더에 제어권을 넘겨준다.
      1. 부트 로더의 목표는 커널을 부트스트랩하는 것이다. 부팅 매체에 따라 세부사항은 다를 수 있다.
    • 부트 로더의 옵션은 다양하며 현재 버전과 이전 레거시 모두 사용할 수 있다.
      1. 커널은 일반적으로 압축된 형태로 /boot 디렉토리에 위치해 있다. 따라서 첫 번째 단계는 커널을 추출해 메인 메모리에 로드하는 것이다. 하위 시스템, 파일 시스템, 드라이버를 초기화 하고 나면 커널은 init 시스템에 제어권을 넘기고 이로써 부팅 프로세스는 적절하게 종료된다.
      2. init 시스템은 시스템 전반에 걸쳐 데몬을 실행할 책임이 있다. 이 init프로세스는 프로세스 계층 구조의 루트이며 프로세스 ID값은 1을 가진다. 즉 PID 1 프로세스는 전통적으로 고아 프로세스도 처리한다.
      3. 일반적으로 이 이후에 환경에 따라 또 다른 사용자 공간 수준의 초기화가 진행된다.
    • 이전에 설명한 것처럼 일반적으로 터미널, 환경, 셸 초기화가 일어난다.
    • 사용자 설정과 구성을 고려해 GUI가 있는 데스크톱 환경용 디스플레이 관리자, 그래픽 서버 등이 시작된다.
  • 사용 가능한 init 시스템들을 비교한 좋은 젠투(Gentoo)위키 페이지가 있다.

systemd

  • systemd는 처음에 initd를 대체하는 init 시스템이었지만 최근에는 로깅, 네트워크 구성, 네트워크 시간 동기화와 같은 기능을 포함하는 강력한 관리자이다.
  • 특히 systemd는 다음을 통해 이전 init 시스템의 단점을 해결한다.
    • 여러 배포판에서 리눅스의 시작을 관리할 수 있는 통일된 방법 제공
    • 빠르고 이해하기 쉬운 서비스 구성 구현
    • 모니터링, 리소스 사용 제어, 내장된 감사 기능을 포함한 최신 관리 제품군 제공
  • 무엇을 언제 어떻게 실행할지 systemd에 지시하는 방법은 유닛을 통해 이뤄진다.

유닛

  • systemd의 유닛은 기능 및 대상 리소스에 따라 의미 체계가 다른 논리 그룹이다.
  • 유닛의 종류
    • service 유닛 : 서비스나 애플리케이션을 관리하는 방법 설명
    • target 유닛 :종속성 캡처
    • mount 유닛 : 마운트 지점 정의
    • timer 유닛 : 크론 작업 등에 대한 타이머 정의
  • 이보다 조금 중요도가 낮은 유닛의 유형으로는 다음과 같은 것이 있다
    • socket : 네트워크나 IPC 소켓을 설명
    • device : udev나 sysfs 파일시스템 전용
    • automount : 자동 마운트 지점 구성
    • swap : 스왑 공간 설명
    • path : 경로 기반 활성화용
    • snapshot : 변경사항이 일어난 후 시스템의 현재 상태를 재구성할 수 있음
    • slice : cgroup과 연관됨
    • scope : 외부에서 생성된 시스템 프로세스 세트를 관리
  • systemd에게 인식되려면 유닛은 한 파일로 직렬화돼야 한다.
  • systemd는 여러 위치에서 유닛 파일을 찾는다. 가장 중요한 파일 경로 세가지는 다음과 같다.
    • /lib/systemd/system : 패키지가 설치한 유닛
    • /etc/systemd/system : 시스템 관리자가 구성한 유닛
    • /run/systemd/system : 비지속적 런타임 수정사항

systemctl로 관리하기

  • systemd와 상호 작용해 서비스를 관리하기 위해 사용하는 도구가 systemctl이다.
  • 자주 사용하는 명령
명렁사용케이스
systemctl enable XXX.service서비스 활성화. 시작할 준비를 갖춤
systemctl daemon-reload모든 유닛 파일을 다시 로드하고 전체 종속성 트리를 다시 생성함
systemctl start XXX.service서비스 시작
systemctl stop xxx.service서비스 정지
systemctl restart xxx.service서비스 정지 후 재시작
systemctl reload xxx.service서비스에 reload 명령을 보냄. restart로 돌아감
systemctl kill xxx.service서비스 실행 중지
systemctl status xxx.service일부 로그를 포함해서 서비스 상태에 대해 간단 요약
  • 종속성 관리와 쿼리, 전체 시스템 제어 등 이 표 이외에도 systemctl에는 많은 명령이 있다.
  • systemd생태계에는 사용하기 편리하며 최소한 이름 정도는 알아둬야 하는 커맨드라인 도구가 많다.
  • 다음은 그 중 일부이다.
    • bootctl : 부트로더 상태를 확인하고 사용 가능한 부트로더를 관리할 수 있다.
    • timedatectl : 시간과 날짜 관련 정보를 설정하고 볼 수 있다.
    • coredumpctl : 저장된 코어 덤프를 처리할 수 있다. 문제 해결 시 이 도구를 사용해보자.

journalctl로 모니터링하기

  • journal은 systemd의 구성요소다.
  • 기술적으로 이는 systemd-journald 데몬이 관리하는 바이너리 파일로, systemd 구성요소가 기록하는 모든 메시지를 한곳에 모은 것이다.
  • 추후에 자세히 언급할 것이다. 우선 지금은 systemd가 관리하는 로그를 볼 수 있는 도구가 journalctl이라는 점만 알아두면 된다.

예제: greeter 스케줄링

  • 실제로 동작하는 systemd를 살펴본다.
  • 간단한 사용 사례로 아래와 같은 greeter 앱을 매시간 시작한다고 가정해본다. ```bash #!/usr/bin/env bash

set -o errexit set -o errtrace set -o pipefail

name=”${1}”

if [ -z “$name”] then printf “You are awesome\n” else printf “Hello %, you are awesome!\n” ${name} fi

1
2
3
4
5
6
7
8
9
10
- 먼저 service 유형의 systemd 유닛 파일을 정의한다.
  - 이 유닛은 systmed에게 greeter 앱을 어떻게 시작해야 하는지 알려준다.
```bash
[Unit]
Description=My Greeting Service

[Service]
Type=oneshot
ExecStart=/Users/inderby/bash-project
  • 다음으로 매시간 greeter 서비스를 시작하도록 timer 유닛을 정의해준다. ```bash [Unit] Description=Runs Greeting service at th top of the hour

[Timer] OnCalendar=hourly

1
2
3
4
5
6
7
- 이제 systemd가 인식할 수 있도록 두 유닛 파일을 /run/systemd/system에 복사해준다.
  - 해당 디렉터리에 timer 유닛을 복사해두면 systemd는 자동으로 이를 선택하기 대문에 이제 greeter 타이머를 사용할 수 있게 되었다.
  - 참고 : 우분투 같은 데비안 기반 시스템은 기본적으로 service 유닛을 활성화하고 시작한다. 하지만 레드햇 계열 시스템은 명시적인 systemctl start greeter.timer 명령 없이는 서비스를 시작하지 않는다.
- greeter 타이머의 상태를 확인하는 명령어는 아래와 같다.
```bash
sudo systemctl status greeter.timer
  • 동작 여부를 판별하기 위해서는 아래와 같은 명령어를 통해 로그를 확인할 수 있다.
    1
    
    journalctl -f -u greeter.service # journalctl을 이용해 greeter.service 유닛(-u로 선택)의 로그를 보고 따라가기(-f)
    

리눅스 애플리케이션 공급망

  • 공급망(supply chain)이란 소비자에게 제품을 공급하는 조직이나 개인들의 시스템을 뜻한다.
  • 리눅스 애플리케이션 공급의 세 가지 영역은 다음과 같다.

  • 소프트웨어 유지 보수 담당자
    • 소프트웨어 아티팩트를 생성해(예컨대 저장소에 패키지로) 올리는 개별 개발자, 오픈소스 프로젝트, 독립 소프트웨어 공급업체와 같은 회사가 포함된다.
  • 저장소
    • 앱의 일부 혹은 전체가 메타데이터와 함께 포함된 패키지가 있다.
    • 일반적으로 패키지는 앱의 종속성도 캡처하며, 여기서 종속성이란 앱이 작동하기 위해 필요한 다른 패키지다.
    • 이는 라이브러리, 일종의 내보내기나 가져오기, 또는 기타 서비스 프로그램일 수 있다.
      • 이런 종속성을 최신 상태로 유지하기란 어렵다
  • 도구(패키지 관리자)
    • 대상 시스템 쪽에서 패키지 관리자를 사용해 저장소에 위치한 패키지를 조회하고, 설치하고, 업데이트하고, 삭제할 수 있다.
    • 앱과 그 종속성을 나타내는 패키지는 하나 이상일 수 있다
  • 전통적인 패키지 관리자, 컨테이너 기반 솔루션 등 패키지와 종속성 관리에 사용할 수 있는 옵션은 매우 다양하다.

  • 패키지와 종속성 관리를 위한 세 가지 주요 카테고리 옵션은 아래와 같다.
  • 전통적인 패키지 관리자
    • 이 카테고리에서는 일반적으로 저수준 도구와 고수준 도구를 구분한다.
    • 패키지 관리자가 종속성을 해결 할 수 있고 고수준 인터페이스(설치, 업데이트, 제거)를 제공하는 경우 이를 고수준 패키지 관리자라고 부른다.
  • 컨테이너 기반 솔루션
    • 이를 사용하기 좋은 곳이 (이것만이 주요 사례는 아니다)바로 애플리케이션 관리다.
    • 즉 쉽게 테스트할 수 있고 프로덕션으로 바로 배포 가능한 앱을 간단하게 만들 수 있기 때문에 개발자는 컨테이너를 좋아한다.
  • 최신 패키지 관리자
    • 이들은 데스크톱 환경에 뿌리를 두고 있으며 여기서 주요 목표는 최종 사용자가 앱을 최대한 쉽게 사용하는 것이다.

패키지와 패키지 관리자

  • 이절에서는 오랫동안, 어떤 경우에는 수십 년 동안 사용돼온 패키지 형식과 패키지 관리자에 대해 이야기한다.
  • 이들은 보통 두가지 주요 리눅스 배포 제품군인 레드햇 계열(RHEL, 페도라, 센트OS 등)과 데비안 기반 시스템(데비안, 우분투 등)에서 유래된 것이다.
  • 아래의 두 가지 개념에 관해 이야기 한다.
    • 패키지 그 자체
      • 엄밀히 말하면 압축된 파일 하나며, 메타데이터가 포함되어 있다.
    • 도구(패키지 관리자라고 불림)
      • 대상 시스템에서 해당 패키지를 처리해 앱을 설치하고 유지 관리한다.
      • 패키지 관리자는 보통 사용자를 대신해 저장소와 상호 작용하고 패키지의 로컬 캐시를 유지 관리한다.

RPM 패키지 관리자

  • 원래 레드햇에서 만들었지만 현재는 다양한 배포판에서 널리 사용된다.
  • .rpm 파일 형식은 리눅스 표준 베이스에서 사용되며 바이너리나 소스 파일을 포함할 수 있다.
  • 패키지는 암호로 검증할 수 있으며 패치 파일을 통한 델타 업데이트를 지원할 수 있다.
  • RPM을 사용하는 패키지 관리자는 다음과 같다.
    • yum : 아마존 리눅스, 센트OS, 페도라, RHEL에서 사용
    • DNF : 센트 OS, 페도라, RHEL에서 사용
    • 자이퍼(Zypper) : 오픈수세(openSUSE)와 수세 리눅스 엔터프라이즈에서 사용
  • RPM이 실제로 동작하는 모습
    • 새로운 개발자 환경이 있고 yum을 사용해 go 프로그래밍 언어 툴 체인을 설치하려 한다고 가정해 보겠다. ```bash sudo yum search golang # 고 패키지를 검색한다.

sudo yum install golang # 고 패키지 설치

sudo yum info golang

1
2
3
4
5
6
7
8
9
10
11
12
### 데비안 deb
- deb패키지와 .deb 파일 형식은 데비안 배포판에서 시작됐으며, deb 패키지는 바이너리나 소스 파일도 포함할 수 있다.
- dpkg처럼 종속성 관리가 없는 저수준 패키지 관리자와 apt-get, apt, aptitude 같은 고수준의 패키지 관리자를 포함해 많은 패키지 관리자가 deb를 사용한다.
- 우분투가 데비안 기반의 배포판이라는 점을 감안할 때 deb 패키지는 데스크톱과 서버 모두에서 널리 사용된다.
- deb 패키지의 실제 동작
  - apt로 curl 유틸리티를 설치한다고 가정해보자.
    - apt는 HTTP API와 상호 작용하며 다양한 위치에서 파일을 다운로드하는 데 유용한 도구이다.
```bash
apt search curl # curl 패키지 검색 
apt install curl # 설치
apt show curl # 검증

프로그래밍 언어별 패키지 관리자

  • C/C++ : Conan과 vcpkg를 포함한 다양한 패키지 관리자가 있다.
  • Go : 내장된 패키지 관리가 있다(go get, go mod)
  • Node.js : npm 등이 있다.
  • Java : maven과 nuts 등이 있다.
  • Python : pip와 pyPM이 있다
  • Ruby : rubygems와 Rails가 있다
  • Rust : cargo가 있다.

컨테이너

  • 이 책에서는 컨테이너를 리눅스 네임스페이스, cgroup, 때때로 CoW 파일시스템을 사용해 애플리케이션 수준의 종속성을 관리를 제공하는 리눅스 프로세스 그룹으로 이해한다.
  • 하지만 컨테이너의 사용 사례는 로컬 테스트와 개발부터 분산 시스템 작업(예 : 쿠버네티스에서의 컨테이너화된 마이크로서비스 작업)에 이르기까지 다양하다.
  • 개발자와 시스템 관리자에게는 컨테이너가 매우 유용하지만 최종 사용자에게는 더 고수준의 도구를 사용해 애플리케이션을 관리하는 쪽이 더 편할 것이다.
  • 리눅스에서 컨테이너 자체는 새로운 것이 아니다.
    • 하지만 도커 덕분에 컨테이너는 메이저 영억으로 편입됐다.
  • 그전에는 개발자가 아닌 시스템 관리자를 대상으로 컨테이너를 도입하려는 여러 시도가 있었다.
    • 리눅스 V서버, OpenVZ, LXC, lmctfy
  • 이 모든 접근 방식의 공통점은 네임 스페이스, cgroup과 같이 리눅스 커널이 제공하는 기본 빌딩 블록을 사용해 사용자가 애플리케이션을 실행할 수 있게 한다는 점이다.
  • 도커는 기존 개념을 혁신하고 2가지 획기적인 요소를 도입했다.
    • 하나는 컨테이너 이미지를 통해 패키징을 정의하는 표준화된 방법
    • 다른 한 가지는 인간 친화적인 사용자 인터페이스(docker run)이다.
  • 도커에서 컨테이너 이미지가 정의되고 배포되는 방식과 컨테이너가 실행되는 방식은 현재 OCI 핵심 사양의 기반이 됐다.
  • 3가지 핵심 OCI 컨테이너 사양
    • 런타임 사양 : 운영과 수명주기 단계를 포함해 런타임이 지원해야 하는 것을 정의한다.
    • 이미지 형식 사양 : 메타데이터와 계층을 기반으로 컨테이너 이미지가 구성되는 방식을 정의한다.
    • 배포 사양 : 컨테이너 이미지가 전달되는 방식, 컨테이너와 관련해 저장소가 효과적으로 동작할 수 있는 방식을 정의한다.
  • 컨테이너와 관련된 또 다른 개념은 불변성이다.
    • 한번 구성되면 사용 중에 변경할 수 없다는 의미다.
    • 즉 변경하려면 새로운(정적) 구성과 새 리소스(프로세스)를 생성해야 한다.

리눅스 네임 스페이스

  • 리눅스는 리소스에 대해 global view를 가지고 있었다.
  • 프로세스가 리소스(예 : 파일 시스템, 네트워킹, 사용자)에 대한 local view를 가질 수 있도록 리눅스는 네임스페이스를 도입했다.
  • 즉 리눅스 네임스페이스는 모두 리소스 가시성에 관한 것이며 운영체제 리소스의 다양한 측면을 격리하는 데 사용할 수 있다.
    • 이 맥락에서 격리란 대부분 프로세스가 무엇을 보는지와 관련이 있으며 보안 관점에서 볼 때 반드시 엄격한 경계는 아니다.
  • 네임스페이스를 생성하려면 다음과 같은 3가지 관련 시스템 콜을 원하는 대로 상황에 맞게 사용할 수 있다.
    • clone : 실행 컨텍스트의 일부를 부모 프로세스와 공유할 수 있는 자식 프로세스를 만드는데 사용된다.
    • unshare : 기존 프로세스에서 공유된 실행 컨텍스트를 제거하는 데 사용된다.
    • setns : 기존 프로세를 기존 네임스페이스에 결함하는 데 사용된다.
  • 이 시스템 콜은 다양한 플래스를 매개변수로 사용하므로 새로 생성, 가입, 탈퇴하려는 네임스페이스를 세밀하게 제어할 수 있다.
    • CLONE_NEWNS : 파일시스템 마운트 지점에 사용한다. /proc/$PID/mounts를 통해 확인할 수 있다.
    • CLONE_NEWUTS : 호스트 명과 도메인 이름 격리를 만들 때 사용한다. unname -n과 hostname -f를 통해 확인할 수 있다.
    • CLONE_NEWIPC : 시스테V IPC 객체나 POSIX 메시지 큐 같은 프로세스 간 통신의 리소스 격리를 할 때 사용한다. /proc/sys/fs/mqueue, /proc/sys/kernel, /proc/sysvipc를 통해 확인할 수 있다.
    • CLONE_NEWPID : PID 번호 공간 격리(PID 내부/PID 외부 네임스페이스)를 할 때 사용한다. /proc/$PID/status를 통해 세부 정보를 수집할 수 있다.
    • CLONE_NEWNET : 네트워크 디바이스, IP 주소, IP 라우팅 테이블, 포트 번호 같은 네트워크 시스템 리소스의 가시성을 제어하는 데 사용한다. ip netns list, /proc/net, /sys/class/net을 통해 확인할 수 있다.
    • CLONE_NEWUSER : 네임스페이스 내부/외부에서 UID + GID를 매핑하는 데 사용한다. id명령과 /proc/$PID/uid_map, /proc/$PID/gid_map을 통해 매핑을 조회할 수 있다.
    • CLONE_NEWCGROUP : 네임 스페이스에서 cgroup을 관리하는 데 사용한다. /sys/fs/cgroup, /proc/cgroups, /proc/$PID/cgroup을 통해 확인할 수 있다.

리눅스 cgroup

  • 네임 스페이스가 가시성에 관한 것이라면 cgroups은 다른 종류의 기능을 제공한다.
  • 바로 프로세스 그룹을 구성하는 메커니즘이다.
  • cgroup을 계층 구조와 함께 사용하면 시스템 리소스 사용을 제어할 수 있다.
  • 또한 리소스 사용 추적을 할 수 있다.
  • cgroups은 선언형 유닛으로, 그리고 컨트롤러는 특정 리소스 제한을 적용하거나 사용량을 보고하는 커널 코드로 생각하자.
  • 현재 cgroup은 v1과 v2로 나뉘어 있다.
    • 결국 v2가 v1을 대체할 것이긴하다.

cgroup v1

  • cgroup v1을 이용하면 필요에 따라 새로운 cgroup과 컨트롤러를 추가할 수 있는 애드혹 접근 방식을 사용할 수 있다.
  • v1 cgroups과 컨트롤러는 다음과 같다.
    • CFS 대역폭 제어 : cpu cgroup을 통해 사용되며 지원된다.
    • CPU 사용량 정산 컨트롤러 : cpuacct cgroup을 통해 사용되며 지원된다.
    • cpusets cgroup : 작업에 cpu와 메모리를 할당할 수 있다.
    • 메모리 리소스 컨트롤러 : 작업의 메모리 동작을 분리할 수 있다.
    • 디바이스 화이트리스트 컨트롤러 : 디바이스 파일 사용을 제어할 수 있다.
    • freezer cgroup : 배치 작업 관렝 사용된다.
    • 네트워크 분류기 : 패킷에 다른 우선 순위를 할당하는데 사용됨
    • 블록 IO 컨트롤러 : 블록 I/O를 조절할 수 있다.
    • perf_event 명령 : 성능 데이터를 수집할 수 있다.
    • 네트워크 우선순위 cgroup : 네트워크 트래픽의 우선 순위를 동적으로 설정할 수 있다.
    • HugeTLB 컨트롤러 : HugeTLB 사용을 제한할 수 있다.
    • 프로세스 번호 컨트롤러 : 특정 제한에 도달한 후 cgroup 계층이 새로 프로세스 생성을 중지 시킬 때 사용된다.

cgroup v2

  • v1에서 배운 교훈을 바탕으로 cgroup 완전히 다시 작성한 것이다.
  • cgroup의 일관된 구성과 사용은 물론이고, (중앙 집중식이고 균일한) 문서의 측면에서 봐도 그렇다.
  • 프로세스 별로 구분되는 cgroup v1 설계와 달리, cgroup v2는 단일 계층 구조만 가지며 모든 컨트롤러가 동일한 방식으로 관리된다.
  • v2 컨트롤러는 다음과 같다.
    • CPU 컨트롤러 : CPU 주기의 분산을 제어한다. 다양한 모델(weight, max)을 지원하고 사용량 보고를 포함한다.
    • 메모리 컨트롤러 : 사용자 공간 메모리, dentry와 inode같은 커널 데이터 구조, TCP 소켓 버퍼를 지원하는 다양한 제어 매개변수로 메모리 분산을 제어한다.
    • I/O 컨트롤러 : 가중치 기반과 절대 대역폭, 혹은 IOPS 제한으로 I/O 리소스의 분산을 제어하고 바이트와 IOPS 읽기/쓰기에 대해 보고한다.
    • 프로세스 번호(PID) 컨트롤러 : v1 버전과 유사
    • cpuset 컨트롤러 : v1버전과 유사하다.
    • device 컨트롤러 : eBPF 위에 구현된 디바이스 파일에 대한 접근을 관리한다.
    • rdma 컨트롤러 : RDMA 리소스의 분산과 연산을 제어한다.
    • HugeTLB 컨트롤러 : v1버전과 유사하다.
  • 또한 v2에는 스칼라 리소스(다른 cgroup 리소스처럼 추상화 할 수 없음)에 대해 리소스 제한과 추적 메커니즘을 허용하는 기타 cgroup이 있다.
    1
    
    systemctl status # cgroup을 트리 형식으로 출력
    

쓰기 시 복사(CoW) 파일시스템

  • 컨테이너의 세 번째 빌딩 블록은 쓰기 시 복사 파일시스템으로, 이들은 빌드 시 사용되며, 애플리케이션과 모든 종속성을 배포 가능한 독립 파일 하나로 패키징한다.
  • CoW 파일 시스템은 주로 바인드 마운트와 함께 사용되어 종속성이 서로 다른 콘텐츠를 효율적인 방식으로 계층화한다.

도커

  • 도커 사에서 개발하고 대중화한 인간 친화적 컨테이너 구현물이다.
  • 도커를 사용하면 프로그램과 종속성을 쉽게 패키징하고 이를 데스크톱부터 클라우드까지 다양한 환경에서 실행할 수 있다.
  • 도커의 독특한 점은 빌딩 블록(네임스페이스, cgroup, CoW 파일시스템, 바인드 마운트)이 아니다.
  • 도커의 특별함은 이런 빌딩 블록을 결함할 때 네임스페이스와 cgroup 같은 저수준 비트 관리의 복잡성을 숨겨서 사요요하기 쉽게 만드는 방식을 썼다는 점이다.
  • 도커에는 이미지와 실행 컨테이너라는 두 가지 주요 개념이 존재한다.
    • 컨테이너 이미지 : 실질적인 디렉토리인 JSON 파일과 계층의 메타데이터를 포함하는 압축된 아카이브 파일이다.
      • 도커 데몬은 필요에 따라 컨테이너 레지스트리에서 컨테이너 이미지를 가져온다.
    • 런타임 아티팩트로서의 컨테이너 : 이 컨테이너는 필요에 따라 시작, 중지, 종료, 제거할 수 있다. 도커 데몬과의 상호 작용에는 클라이언트 CLI 도구를 사용하며, 이 CLI 도구는 데몬에 명령을 보내고 데몬은 컨테이너 빌드, 실행과 같은 작업을 각각 차례로 실행한다.
  • 자주 사용되는 도커 명령어
명령어설명사용 예
run컨테이너 실행엔진에스를 데몬으로 실행하고 종료시 컨테이너 제거: docker run -d --rm nginx:1.21
ps컨테이너 나열모든 컨테이너 나열 : docker ps -a
inspect저수준 정보 출력컨테이너 IP 쿼리용: docker inspect -f ''
build로컬에서 컨테이너 이미지 생성현재 디렉터리와 태그를 기반으로 이미지 빌드: docker build -t some:tag .
push컨테이너 이미지를 레지스트리로 업로드AWS 레지스트리로 푸시 : docker push public.ecr.aws/some:tag
pull레지스트리에서 컨테이너 이미지를 다운로드AWS 레지스트리에서 풀 : docker pull public.ecr.aws/some:tag
images로컬 컨테이너 이미지 나열특정 레지스트리의 이미지 나열: docker images ubuntu
image컨테이너 이미지 관리사용하지 않는 모든 이미지 삭제: docker image prune -all

컨테이너 이미지

  • 컨테이너 이미지를 빌드하는 방법에 대한 지침을 정의할 때는 Dockerfile이라고 불리는 일반 텍스트 파일 형식을 사용한다.
  • 도커 파일에 포함될 수 있는 지시문은 다양하다
    • 기본 이미지 : 빌드/실행 단계에 대해 여러 개일 수 있음(FROM)
    • 메타 데이터 : 제작 정보(LABEL)
    • 인자와 환경변수 : ARGS, ENV
    • 빌드타임 사양 : 계층별로 어떻게 이미지가 생성되었는지를 정의함: COPY, RUN 등
    • 런타임 사양 : 컨테이너 실행 방법을 정의함: CMD, ENTRYPOINT
  • docker build 명령을 사용하면 애플리케이션을 나타내는 파일 컬렉션(소스 또는 바이너리 형식)을 도커 파일과 함께 컨테이너 이미지로 전환한다.
  • 이 컨테이너 이미지는 직접 실행하거나 레지스트리에 등록함으로써, 달ㄴ 사람들이 내려받아 실행하게 배포할 수 있는 아티팩트다.

실행 컨테이너

  • 컨테이너는 대화형 입력이나 데몬으로 실행될 수 있다.
  • docker run 명령은 환경변수, 노출할 포트, 마운트할 볼륨 같은 런타임 입력 세트와 컨테이너 이미지를 사용한다.
  • 이 정보를 사용해 도커는 필요한 네임스페이스와 cgroup을 생성하고 컨테이너 이미지에 정의된 애플리케이션을 시작한다.

에제; 컨테이너화한 greeter

1
2
3
4
5
6
7
8
9
10
11
12
13
# 베이스 이미지 지정
FROM ubuntu:20.04
# LABEL을 통해 일부 데이터를 할당한다
LABEL org.opencontainers.image.authors="Michael Hausenblas"
# 셸 스크립트를 복사한다. 이는 바이너리, JAR 파일, 파이썬 스크립트일 수 있다.
COPY greeter.sh /app/
# 작업 디렉터리를 지정한다.
WORKDIR /app
# 이 행과 다음 행은 앱을 실행하는 사용자를 정의한다. 이렇게 하지 않으면 불필요하게 root로 실행된다.
RUN chown -R 1001:1 /app
USER 1001
# 무엇을 실행할지 정의한다.
ENTRYPOINT ["/app/greeter.sh"]

다른 컨테이너 도구

  • OCI 컨테이너 작업을 위해 도커를 무조건 사용할 필요는 없다.
  • 그 대안으로 레드햇이 주도하고 후원하는 포드맨(podman)과 빌다(buildah)를 사용할 수 있다.
  • 이렇게 데몬이 없는 도구를 사용해도 OCI 컨테이너 이미지를 빌드하고 실행할 수 있다.
  • 또한 다음과 같이 OCI 컨테이너, 네임스페이스, cgroup 작업을 보다 쉽게 해주는 많은 도구가 있다.
    • containerd : 이미지 전송과 저장에서부터 컨테이너 런타임 감시까지, OCI 컨테이너 수명주기를 관리하는 데몬
    • skopeo : 컨테이너 이미지 조작을 위해 사용(복사, 매니페스트 검사 등)
    • systemd-cgtop : cgroup을 인식하는 top의 변종이며 리소스 사용량을 대화식으로 보여준다.
    • nsenter : 지정된 기존 네임 스페이스에서 프로그램을 실행할 수 있다.
    • unshare : 특정 네임스페이스로 프로그램을 실행할 수 있다.(플래그를 통해 설정(혹은 등록)할 수 있다.)
    • lsns : 리눅스 네임스페이스에 대한 정보를 나열한다.
    • cinf : 프로세스 ID와 관련된 리눅스 네임스페이스와 cgroup에 대한 정보를 나열한다.

최신 패키지 관리자

  • 배포에 특화된 경우가 대부분인 기존 패키지 관리자 외에도 새로운 종류의 패키지 관리자가 있다.
  • 이런 최신 솔루션은 대부분 컨테이너를 사용하고 교차 배포나 대상이 특정된 환경을 목표로 한다.
    • 예를 들어 리눅스 데스크톱 사용자가 GUI앱을 쉽게 설치할 수 있는 경우다.
  • 종류
    • Snap : 캐노니컬사가 설계하고 홍보하는 소프트웨어 패키징, 배포 시스템이다. 세련된 샌드박싱 설정과 함께 제공되며 데스크톱, 클라우드, IoT 환경에서 사용할 수 있다.
    • Flatpak : cgroup, 네임스페이스, 바인드 마운트, seccomp을 빌딩 블록으로 사용하며 리눅스 데스크탑 환경에 최적화됐다. 처음에는 리눅스 배포판 세계의 레드의 일부로 시작됐지만 이제는 페도라, Mint, 우분투, 데비안, 오픈수세, 크롬을 포함한 수십 가지 배포판에서 사용할 수 있다.
    • AppImage : 수년 동안 사용되어 왔으며 하나의 앱은 하나의 파일과 같다는 개념을 추구한다. 즉 대상 리눅스 시스템에 이미 포함된 종속성 외에는 추가 종속성이 필요하지 않다.
      • 시간이 지남에 따라 데스크톱에 통합하기 위한 효율적인 업데이트부터 소프트웨어 카탈로그에 이르기까지 AppImage에 흥미로운 기능이 많이 도입됐다.
    • Homebrew : 원래는 맥 OS 세계에서 나왔지만 리눅스에서도 사용할 수 있으며 점점 인기를 얻고 있다. 루비로 작성됐으며 강력하면서도 직관적인 사용자 인터페이스가 있다.

정리

  • 이 장에서는 리눅스 애플리케이션을 설치, 유지 관리, 사용하는 방법과 관련된 다양한 주제를 다뤘다.
  • 먼저 기본적인 애플리케이션 용어를 정의한 다음 리눅스 시작 프로세스를 살펴보고 시작과 구성요소를 관리하는 현재의 표준 방식인 systemd에 대해 설명했다.
  • 리눅스는 애플리케이션을 배포하기 위해 패키지와 패키지 관리자를 사용한다.
  • 이와 연관된 다양한 관리자에 대해 이야기하고 개발, 테스트, 종속성 관리에 컨테이너를 사용하는 방법에 대해 살펴봤다.
  • 도커 컨테이너는 리눅스 기본 요소(cgroup, 네임스페이스, CoW 파일시스템)를 사용해요 애플리케이션 수준의 종속성 관리를 제공한다.
  • 마지막으로 Snap 등 앱 관리를 위한 맞춤형 솔루션을 살펴봤다.
This post is licensed under CC BY 4.0 by the author.

모던 리눅스 교과서 5. 파일 시스템

모던 리눅스 교과서 7. 네트워킹