[에스넷시스템 부트캠프] TIL Day 28 - Podman 명령어, 컨테이너 생명주기, 이미지

2025. 6. 29. 00:38·TIL
728x90

1. Podman 명령어

1) 이미지 관리 명령어

podman images [options] 

: 현재 사용할 수 있는 이미지 이름 확인

podman imges 명령어 실행 결과

  • REPOSITORY : 등록되어 있는 실제 이름. 리포지토리 사이트 / 네임스페이스 / 이미지 이름으로 구성
  • TAG : 태그 
  • IMAGE ID : 이미지를 생성할 때 자동으로 부여되는 ID
  • CREATED : 이미지가 생성된 시기
  • SIZE : 이미지 사이즈. 하나의 파일이 아닌 base image 위에 여러개의 추가 구성요소로 구성 

 

podman rmi [-f] <<image>:<tag>

: 이미지 삭제. -f로 강제 삭제 가능

 

podman push <registry_url>/<username>/<image>:<tag>

: 이미지 push

 

podman pull [options] <remote_registry_url>/<username>/<image>:<tag>

: 특정 원격 레지스트리에서 이미지 가져오기 

 

podman history [options] <image>:<tag>

: 이미지에 수행된 명령어들의 히스토리 

 

podman search [options] <search_string>

: 이미지 검색

/etc/containers/registries.conf 파일의 [registries.search] 구문에서 레지스트리 순서를 바꿔주면 검색 결과도 그에 따라 바뀜

--format json 옵션을 주면 더 상세한 정보를 볼 수 있음

 

podman build [options] <image>:<tag> [-f <Dockerfile>]

: 새로운 이미지 빌드

보통 podman build -t <tag> . 형태로 많이 쓰임

여기서 .은 현재 디렉토리 밑에 있는 Dockerfile이나 Containerfile을 찾아오는 것을 의미

 

podman tag <image>:<tag> <image>:<new_tag>

: 이미지 태그 이름 변경

 

2) 레지스트리 인증

podman login [options] <image_registry_url>

: 리포지토리에 로그인

 

podman logout [options]

: 리포지토리 로그아웃

 

3) 컨테이너 실행 및 관리 

podman run [options] <repo>/<image>:<tag>

: 이미지를 컨테이너로 구동

어떤 옵션이 오냐에 따라서 구동 방식이 완전히 달라짐

  • -rm : 실행 후 종료
  • --name : 컨테이너 이름 따로 지정. 기본은 랜덤하게 이름 부여
  • -d : 백그라운드에서 실행
  • -it : 내부에서 작업을 해야 할 때 사용 

 

podman stop [options] <container>

: 켜져있는 컨테이너 중지 

 

podman create [options] </repo/image:tag>

: 컨테이너 생성

 

podman start [options] <container>

: 생성된 컨테이너 시작 

 

podman restart [options] <container>

: 이미 종료된 컨테이너 재시작 

 

podman rm [options] <container>

: 정지되어 있는 컨테이너 삭제 

-f 옵션으로 실행 중인 컨테이너 삭제 가능

 

podman wait [options] <container>

: 지정한 컨테이너를 종료될 때까지 기다렸다가 상태 코드 출력

 

podman pause [options] [<container>]

: 컨테이너를 잠시 일시 중지

 

podman unpause [options] [<container>]

: 일시 중지된 컨테이너를 실행

 

4) 상태 확인 및 정보 조회 

podman ps [options]

: 프로세스 확인

-a로 실행중이 아닌 컨테이너도 확인 

 

podman stats [options] [<container>]

: 컨테이너 상태 출력

 

podman inspect [options] <container>

: 현재 컨테이너 내부에 있는 내용을 json 형태로 출력

컨테이너의 네트워크나 내부 파일을 확인하기 위해 주로 사용됨

 

podman top <container>

: 컨테이너 내부 프로세스

 

podman logs [options] <container>

: 컨테이너 로그 출력

 

podman diff [options] <container>

: 컨테이너 내부의 파일을 비교

원본 이미지에서 수정된 사항 확인

 

5) 기타 조작 및 유틸리티

podman exec <container> <command>

: 컨테이너 내부에 명령어를 실행

 

podman commit [options] <container> <new_image>:<tag>

: 컨테이너를 실행한 뒤 조작한 상태를 저장

 

podman attach [options] <container>

: 이미 실행중인 컨테이너 접속. 이 명령어보다는 exec를 주로 사용

 

podman port [options] <container>

: 로컬호스트와 컨테이너의 포트 매핑

 

podman mount [options] <container>

: 마운트 경로 확인

 

podman umount [options] <container>

: 마운트 해제 

 

podman export -o <output_filename> <container>

: 컨테이너 파일을 외부에 tar 형태로 내보냄

 

2. Podman에서 사용자 계정 만들기

모든 권한을 가진 root 계정을 컨테이너에서 그대로 사용할 경우 컨테이너 탈출 취약점이 있을 때 호스트 시스템까지 위협할 수 있어 실제 운영 환경에서는 root 계정 대신 일반 사용자 계정을 만들어 사용하는 것이 보안 측면에서 기본 원칙이다. 

 

주의할 점은 su - 사용자명 으로 사용자를 전환하면 로그인 쉘 환경이 완전히 셋업되지 않아 문제가 발생할 수 있기 때문에 직접 해당 계정으로 접속하거나 SSH로 접근하는 방식이 더 안정적이다. 

 

3. 컨테이너의 생명주기

컨테이너 생명 주기 흐름

 

💡 podman run은 pull -> create -> start를 한 번에 처리하는 명령어이다. 

 

💡 이미지 vs 컨테이너
이미지는 애플리케이션을 실행하기 위한 설정과 파일이 담긴 템플릿을오 변경할 수 없다는 특징이 있다. 
컨테이너는 이미지를 기반으로 실행된 독립적인 프로세스로 상태와 데이터가 변화한다는 특징이 있다.  

 

4. 기본 가상 네트워크 구성

Podman은 기본적으로 루트리스 컨테이너에서도 자체 네트워크 namespace를 사용하며, 가상 이더넷(veth) 페어를 통해 호스트와 통신한다. 

  • podman0 : Podman이 자동으로 생성한 브리지 네트워크 인터페이스
  • vetch@if2 : veth pair 중 하나로, 컨테이너와 podman0 브리지를 연결
  • 컨테이너 내부에서는 eth0 인터페이스를 사용하며 이때 IP가 할당됨
  • [컨테이너 eth0] <--> [veth pair] <- -> [vetch0@if2] <--> [podman0 브리지] <--> [호스트 네트워크] 

 

5. [실습] Apache 여러개 동시 실행하기

동일한 서비스라도 호스트에서 포트만 다르게 주면 다수의 컨테이너를 실행할 수 있음

  • web1 - 8081
  • web2 - 8082
  • web3 - 8083

 

6. 컨테이너 리소스

1) 왜 리소스 제한이 필요할까

Podman 컨테이너는 명시적으로 리소스를 제한하지 않으면 CPU, 메모리, 디스크 등 호스트 자원을 무제한으로 사용하는 구조이다. 이로 인해 특정 컨테이너가 과도하게 자원을 사용하면 다른 서비스까지 영향을 줄 수 있다. 

특히 웹 서버, DB, 장기 실행 서비스는 반드시 리소스 제한을 걸어줘야 한다.

 

많은 리소스를 차지하는 컨테이너

 

2) CPU 제한

  • --cpus : 사용할 CPU 코어 수 제한
  • --cpu-shares, -c : CPU 가중치 설정 (기본값 1024)
  • --cpuset-cpuse[코어번호, 코어번호-코어번호] : 컨테이너에 특정 cpu 또는 코어만 사용하도록 제한 

 

3) 메모리 제한

  • --m, --memory : 컨테이너가 사용할 최대 메모리. 물리 메모리 + 스왑 메모리 합산 값
  • --memory-reservation : 최소 보장 메모리 설정
  • --oom-kill-disable : OOM 킬러 비활성화 -> 해당 옵션은 안 켜는 게 좋음

 

4) DISK 제한

  • --device-read-iops : 초당 디스크 읽기 IOPS 제한
  • --device-write-iops : 초당 디스크 쓰기 IOPS 제한
  • --blkio-weight : 디스크 I/O 가중치 (기본값 : 500)

 

 

7. 이미지

podman run 명령을 사용할 때마다 해당하는 이미지가 로컬에 없으면 원격 레지스트리에서 pull해온다. 이때 각 이미지의 레이어(blob)는 별도로 저장되기 때문에 중복 사용하지 않도록 최적화되어 있찌만 다양한 이미지가 쌓이면 스토리지 사용량은 계속 증가하게 된다.

 

1) 레지스트리

podman info 명령을 통해 기본 레지스트리 목록을 확인할 수 있다.

  • docker.io : Docker 공식 이미지 제공
  • registry.access.redhat.com : 로그인 없이 접근 가능
  • registry.redhat.io : Red Hat 서브스크립션 필요
  • quay.io : Red Hat이 운영하는 오픈 이미지 허브, 자동화 및 보안 스캔 지원

 

2) 이미지 레이어

컨테이너 이미지를 생성하면, 파일 시스템의 변경 사항을 반영하는 여러 개의 계층(layer)이 생성된다. 
이 레이어들은 각각 독립적인 스냅샷(snapshot)으로 관리되며, 중복된 데이터는 하나의 레이어만 사용해 저장 공간을 효율적으로 절약할 수 있다. 

 

컨테이너 실행 시 내부 동작

1. 기존 이미지의 읽기 전용 레이어 스냅샷 복원

2. 쓰기 가능한 새로운 레이어가 추가되어 이 위에 변경 사항 기록

3. 모든 변경 사항은 신규 레이어에 저장되므로 이미지와 컨테이너가 완전히 격리됨

=> 이러한 구조 덕분에 이미지를 기반으로 한 여러 컨테이너가 서로 영향을 주지 않고 독립적으로 실행될 수 있다. 

Container Layer (R/W)
├── jobs2 Layer (R/O)
├── jobs1 Layer (R/O)
└── base image Layer (R/O)

 

이 구조는 VMware의 VMDK 스냅샷 구조와 유사
-> VMDK 원본은 R/W였지만, 스냅샷 이후 R/O로 바뀌고 변경은 별도 계층에 저장

 

 

3) Union FS & OverlayFS 구조

  • Podman의 파일 시스템은 UnionFS, 그 중에서도 OverlayFS를 기본으로 사용
  • 컨테이너 실행시 여러 레이어를 병합하여 하나의 파일 시스템으로 제공
  • 읽기 전용 + 쓰기 가능 -> 병합

 

💡 UnionFS란?
여러 디렉토리를 하나의 디렉토리처럼 병합해 보여주는 파일 시스템을 말한다.

 

3-1) 주요 디렉토리 구성

디렉토리  설명
lower 읽기 전용 이미지 레이어 (다수 가능)
upper 컨테이너의 쓰기 계층 (변경 사항 저장)
merged 컨테이너가 실제 사용하는 병합 파일 시스템
work OverlayFS의 내부 작업 디렉토리 (메타데이터 저장)
diff 변경된 내용을 별도 저장한 계층으로 가장 최신 레이어( 의존성 관련 파일이나 사용자 설정 등이 존재) 

 

3-2) OverlayFS의 장점

  • 중복 제거와 효율적 저장
    • 동일한 레이어는 여러 컨테이너에서 공유 가능
    • 같은 이미지를 기반으로 한 컨테이너들은 공통 레이어를 재사용하여 저장 공간 절약
    • 변경 사항만 최상단 쓰기 계층에 기록되므로 디스크 I/O도 줄어듦
  • 빠른 컨테이너 생성 속도
    • 기존 이미지 레이어를 복사하지 않고 그대로 사용
    • 파일 변경이 있을 때만 복사하는 CoW(Copy-on-Write) 방식 사용
  • 메모리 효율성
    • 실제 파일 복사를 최소화
    • 많은 컨테이너가 실행되어도 공통된 이미지 영역은 단 한번만 로딩

 

3-3) OverlayFS의 한계 및 주의

  • 파일 삭제는 진짜 삭제가 아님
    • 예를 들어 컨테이너 내에서 rm -rf A 명령으로 파일을 삭제해도,
      실제로는 하위 읽기 전용 레이어의 파일을 지운 것이 아니라 ‘가린 것’입니다.
    • 이를 위해 upper 레이어에는 화이트아웃 마커(whiteout marker)가 생성
    • 이 마커는 해당 파일이 "삭제되었음"을 표시하는 역할만 하며, 물리적으로 lower 레이어의 파일이 제거되는 것은 아님
  • 삭제한 파일도 공간을 차지함
    • 삭제된 것처럼 보이지만 .wh.* 마커와 fake 디렉토리로 인해 upper 레이어의 용량은 줄어들지 않고 늘어남
    • 이로 인해 컨테이너 정리 시에는 이미지 prune이나 재빌드가 필요할 수 있음
  • 복잡한 파일 시스템 연산에는 적합하지 않음
    • 기본 파일 시스템에 비해 연산이 많고, 작업 중간에 병합하거나 겹치는 레이어가 많으면 성능 저하 가능성도 있음

 

4) Build

Dockerfile → podman build → 이미지 생성 → podman run → 컨테이너 실행

 

  • Dockerfile의 각 명령어(RUN, COPY, ADD)는 개별 레이어를 생성
  • 이미지를 기반으로 새로운 컨테이너 실행 시, 기존 이미지 레이어는 그대로 두고 R/W 계층만 따로 생성됨

 

 

8. 이미지 빌드 파일

컨테이너 이미지 빌드는 지속적으로 재사용 가능한 실행 환경을 만드는 과정이다. 
Docker는 Dockerfile, Podman은 기본적으로 Containerfile이라는 이름을 사용하지만, 실질적인 문법은 동일하다. 

 

1) 기본 구조

  • FROM <image> [AS <name>]  : 사용할 베이스 이미지
  • RUN  : 이미지에 작성되는 각종 작업
    • - shell from : RUN <command> / 디폴트 쉘로 실행, 변수 확장 가
    • - exec from : RUN ["executable", "param1", "param2"] / 쉘을 경우하지 않고 실행, 원칙적으로 변수 확장 불가
    • - cache 미사용시 : --no-cache
  • COPY : 파일 또는 디렉토리 복사
  • ADD : COPY와 유사하나 네트워크를 이용해 파일 복사 
  • CMD : 기본 명령어 인자
  • ENTRYPOINT : 주 실행 파일 
  • EXPOSE : 포트 지정

 

2) [실습] Containerfile로 이미지 생성해보기

2-1) 기본 Containerfile 작성

FROM docker.io/library/rockylinux:9.2

RUN dnf list
RUN dnf -y install httpd
RUN dnf clean all
RUN sed -i s/Listen\ 80/Listen\ 8080/ /etc/httpd/conf/httpd.conf

ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]

 

  • dnf list, install, clean, sed 등 각각의 명령어를 개별 RUN으로 작성
  • 이 경우 각 RUN 명령어마다 레이어 1개씩 생성됨 → 레이어가 많아짐

2-2) 이미지 빌드 및 확인

이미지 빌드
이미지 확인

2-3) 이미지 히스토리 분석

이미지 히스토리

  • 총 7개 레이어 확인됨
    → ENTRYPOINT, CMD, sed, clean, install, list, base image
  • 각 RUN마다 layer가 하나씩 쌓인 것을 볼 수 있음
    → sed, clean, install, list = 각각 따로 기록됨

 

2-4) 여러 명령어를 병합하여 레이어 최적화

FROM docker.io/library/rockylinux:9.2

LABEL description="httpd web server" \
      created="2025-06-27" \
      authors="dbfl0461@gmail.com"

RUN dnf list && \
    dnf -y install httpd && \
    dnf clean all && \
    sed -i s/Listen\ 80/Listen\ 8080/ /etc/httpd/conf/httpd.conf

ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]

EXPOSE 8080 8081

 

  • 여러 명령어를 &&로 묶어 하나의 RUN으로 작성 → 레이어 수를 하나로 줄임
  • 불필요한 레이어 생성을 방지하고 이미지 크기도 소폭 최적화
  • LABEL과 EXPOSE는 문서적/정보적 목적

2-5) 최종 빌드 결과 

 

  • dnf list + install + clean + sed가 모두 1개의 레이어로 통합됨
  • 전체 레이어 수가 기존 대비 4~5개 감소
  • 레이어 최적화 성공! (RUN 병합 덕분에 더 깔끔한 이미지 생성)

 

 

 

9. 서비스로 만들기

1) 왜 서비스로 만들까?

일반적으로 podman run으로 컨테이너를 실행하면 로그인 세션 종료 시 컨테이너도 함께 종료된다.

하지만 서비스로 등록하면 시스템 재부팅 후에 자동 시작, 로그아웃 후에도 컨테이너 유지, systemctl을 통해 관리할 수 있어진다.

 

2) [실습] 실행 중인 컨테이너를 서비스로 등록하기

2-1) 서비스 유닛 파일 생성

서비스 유닛 파일 생성

2-2) 서비스 등록 및 자동 실행 설정 

systemctl daemon-reload --user

systemctl --user enable --now container-web.service

 

 

10. [실습] 두 개 이상의 컨테이너끼리 연결하기 (WordPress + DB)

1) 방화벽 포트 오픈

외부에서 WordPress 접속을 허용하려면 방화벽에서 8080 포트를 열어야 한다.

firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

 

2) Podman 네트워크 생성

컨테이너 간 통신을 위해 사용자 정의 네트워크를 생성한다.

podman network create wordpress-net

 

 

3) 볼륨 생성 및 연결하기

 

 

podman run --rm --name wordpressdb \
  --network wordpress-net -d \
  -e MARIADB_ROOT_PASSWORD=pw \
  -e MARIADB_DATABASE=wordpress \
  -e MARIADB_USER=wp_user \
  -e MARIADB_PASSWORD=wp_pass \
  -v wordpressdb:/var/lib/mysql \
  ldb:latest
  
  
  podman run -d --rm --name wordpress \
  --net wordpress-net \
  -e WORDPRESS_DB_HOST=wordpressdb:3306 \
  -e WORDPRESS_DB_USER=wp_user \
  -e WORDPRESS_DB_PASSWORD=wp_pass \
  -e WORDPRESS_DB_NAME=wordpress \
  -p 8080:80 \
  -v /home/consvc/data/wp_data:/var/www/html:Z \
  lwp:latest
  • -v로 볼륨 연결
  • --rm으로 기존 데이터 유지 하도록 설정

 

[에러] Error: failed to start pasta: fork/exec /usr/bin/pasta: exec format error 해결

1) 문제 

Podman은 루트리스 컨테이너를 지원해서 사용자를 생성한 후 터미널에서 ssh로 생성한 사용자로 접속해서 사용하고자 했다. 근데 search나 images, pull 명령어는 제대로 됐는데 run만 하려고 하면 아래와 같이 에러가 발생했다. 

놓친게 있나 해서 복습 영상도 봤지만 무용지물.. 

2) 원인

rootless 네트워크 백엔드인 pasta가 없어서 생긴 문제였다. 

3) 해결

결국 dnf -y install pasta를 수행하니까 정상적으로 작동했다.

podman을 제대로 설치했는데 왜 pasta 관련된 파일이 망가졌을까..?? 

여러가지 원인이 있겠지만 정확히 어떤 것이 원인이었는지는 찾지 못했다.

 

 

💡pasta는 무슨 역할을 할까?

pasta는 Podman의 rootless 네트워크를 위해 사용되는 유틸리티이다. 풀 네임은 Packet Automagically Spliced Through Address translation 으로 rootless 모드에서 사용자 네트워크 네임스페잇를 호스트와 연결해주는 가상 네트워크 레이어이다. 
사용 권한만으로 NAT와 포트포워딩 같은 동작을 가능하게 해준다. 


Podman에서 rootless 네트워크 방식에는 pasta 말고도 여러 가지가 있는데 대표적으로 slirp4netns와 bridge가 있다. 

 

✍️ 하루 회고

오늘은 실습 도중 podman run 명령어에서 에러가 발생해서 당황했다.
처음에는 명령어 입력 실수인 줄 알고 복습 영상을 다시 보며 따라 해봤지만, search, pull, images 등은 잘 동작하는 반면 run만 계속 실패했다.

결국 원인은 pasta 패키지 미설치였고, dnf -y install pasta를 한 뒤에는 정상적으로 컨테이너가 실행되었다.
Podman이 rootless 컨테이너를 실행할 때 네트워크 설정을 위해 pasta를 사용하는 걸 이번 기회에 처음 알게 되었다.

다만, 처음부터 pasta가 왜 설치되어 있지 않았는지, 혹은 왜 문제가 생겼는지는 정확히 파악하지 못한 게 아쉬운 부분이다.
그래도 덕분에 rootless 네트워크 구조와 Podman 내부 동작 방식에 대해 조금 더 관심을 가지게 된 하루였다.

 

728x90

'TIL' 카테고리의 다른 글

[에스넷시스템 부트캠프] TIL Day 30 - 쿠버네티스 아키텍처  (0) 2025.07.01
[에스넷시스템 부트캠프] TIL Day 29 - Podman Volume, Compose, 쿠버네티스  (0) 2025.06.30
[에스넷시스템 부트캠프] TIL Day 27 - Docker  (0) 2025.06.26
[에스넷시스템 부트캠프] TIL Day 26 - AWS 개념 2  (1) 2025.06.25
[에스넷시스템 부트캠프] TIL Day 25 - AWS 개념 1  (0) 2025.06.25
'TIL' 카테고리의 다른 글
  • [에스넷시스템 부트캠프] TIL Day 30 - 쿠버네티스 아키텍처
  • [에스넷시스템 부트캠프] TIL Day 29 - Podman Volume, Compose, 쿠버네티스
  • [에스넷시스템 부트캠프] TIL Day 27 - Docker
  • [에스넷시스템 부트캠프] TIL Day 26 - AWS 개념 2
yulee_to
yulee_to
  • yulee_to
    yulee
    yulee_to
  • 전체
    오늘
    어제
    • 전체 글 (144) N
      • CS (2)
        • OS (0)
        • DB (0)
        • Network (2)
      • Develop (21)
        • Spring (9)
        • Java (12)
        • Python (0)
        • Algorithm (0)
        • 기타 (0)
      • PS (39)
        • C++ (39)
        • Java (0)
      • TIL (37) N
      • Book (39)
        • 자바의 신 (32)
        • 스프링 입문을 위한 자바 객체 지향의 원리와 이해 (7)
      • ETC (4)
        • Blog (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    부트캠프후기
    클라우드 활용 네트워크 엔지니어 부트캠프
    aws
    자바의 신
    객체지향
    1일1백준
    에스넷시스템
    GodOfJava
    C++
    스터디
    알고리즘
    스프링 입문
    에스넷시스템 부트캠프
    boj
    멀티캠퍼스it부트캠프
    자바
    백준
    TiL
    Java
    EC2
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
yulee_to
[에스넷시스템 부트캠프] TIL Day 28 - Podman 명령어, 컨테이너 생명주기, 이미지
상단으로

티스토리툴바