


: 프로세스를 실행할 때 시스템 리소스를 분리해서 실행할 수 있도록 도와주는 기능
⇒ 컴퓨터 시스템에서도 서로 다른 리소스를 구분하기 위한 식별 방법이 필요
⇒ 이때, 사용하는 기능이 바로 네임스페이스
| 네임스페이스 | 의미 | 역할 |
|---|---|---|
| pid | PID: Process ID | 리눅스 커널의 프로세스 ID를 분리 |
| net | NET: Networking | 네트워크 인터페이스(NET)를 관리 |
| ipc | IPC: Inter Process Communication | 프로세스 간 통신(IPC) 접근을 관리 |
| mnt | MNT: Mount | 파일 시스템의 마운트를 관리 |
| uts | UTS: Unix Timesharing System | 커널과 버전 식별자를 관리 |
도커
: 컨테이너라고 부르는 운영체제 수준의 가상화 방식으로 소프트웨어를 배포하는 방식을 사용하는 PaaS 제품
: 컴퓨터에서 활용하는 리소스를 추상화하는 개념
: 여러 개의 가상머신을 생성함으로써, 단일 컴퓨팅 자원을 여러 개의 논리적인 자원으로 나누어 동작시킬 수 있음

| 구분 | VM (Virtual Machine) | Container |
|---|---|---|
| 실행 단위 | OS 단위 (Guest OS 포함) | 프로세스 단위 |
| 커널 | 각각의 Guest OS가 자체 커널을 가짐 | 호스트 커널을 공유 |
| 격리 수준 | 하드웨어 수준 (완전 독립) | OS 수준 (커널 공유) |
도커 API 요청을 수신하고, 도커 이미지, 컨테이너 등과 같은 도커와 관련된 객체를 관리
SPoF(단일 장애 지점) 문제
: 이 부분이 죽으면 시스템 전체가 죽음
→ containerd 를 분리
즉, CNCF는 클라우드 네이티브 기술의 중심 허브예요. (쿠버네티스, Prometheus, Envoy 같은 프로젝트들이 여기 소속되어 있습니다.)CNCF (Cloud Native Computing Foundation)
= “클라우드 네이티브 기술 생태계를 발전시키기 위한 오픈소스 재단”
- 설립: 2015년
- 소속: 리눅스 재단(Linux Foundation) 산하 단체
- 목적:
- 클라우드 환경에서 애플리케이션을 확장성 있고, 회복력 있게, 효율적으로 운영할 수 있게 돕는 기술을 표준화하고 관리
OCI (Open Container Initiative)
= “컨테이너 기술의 표준 규격을 만드는 오픈소스 프로젝트”
- 설립: 2015년
- 주관: 리눅스 재단(Linux Foundation)
- 참여 기업: Docker, Red Hat, Google, IBM, Microsoft, AWS 등
- 목적:
> 컨테이너 생태계가 “특정 회사 기술에 종속되지 않도록”
>
>
> **표준 컨테이너 포맷과 런타임 명세를 정의**하는 것
> 💡 즉, “Docker만의 기술” → “모든 컨테이너가 따를 수 있는 표준”으로 바꾼 거예요.
| 표준명 | 설명 | 예시 |
|---|---|---|
| 1️⃣ OCI Runtime Specification | 컨테이너를 “어떻게 실행할 것인가” 정의 | runc, crun |
| 2️⃣ OCI Image Specification | 컨테이너 이미지를 “어떻게 패키징·저장할 것인가” 정의 | Docker image, Podman image |
| 3️⃣ OCI Distribution Specification | 컨테이너 이미지를 “어떻게 Registry로 주고받을 것인가” 정의 | Docker Hub, Harbor, GitHub Container Registry |
OCI는 “컨테이너를 만들고 → 저장하고 → 실행하는” 전 과정을 표준화합니다.
[컨테이너 생태계]
├─ OCI Image Spec ← 이미지 구조 (.tar, layers, manifest)
├─ OCI Runtime Spec ← 컨테이너 실행 규칙 (namespace, cgroups 등)
└─ OCI Distribution Spec ← 이미지 전송 프로토콜 (push/pull)
이 표준을 구현한 대표적인 기술들이 아래와 같습니다 👇
| 역할 | 구현체 예시 |
|---|---|
| Runtime Spec | runc, crun, gVisor, Kata Containers |
| Image Spec | Docker, Buildah, Kaniko |
| Distribution Spec | Docker Registry, Harbor, GHCR |
| 기술 | 역할 |
|---|---|
| Docker | 컨테이너 빌드 + 배포 + 실행 툴 (OCI 기반으로 동작) |
| OCI | 컨테이너의 이미지·런타임 표준 정의 |
| containerd / CRI-O | 쿠버네티스가 사용하는 컨테이너 런타임 (OCI 호환) |
| Kubernetes | 여러 컨테이너를 자동 관리하는 오케스트레이션 시스템 |
💡 즉, OCI는 표준,
Docker와 containerd는 그 표준을 구현한 실제 툴,
Kubernetes는 그 툴을 이용하는 상위 플랫폼이에요.
| 항목 | 설명 |
|---|---|
| 이름 | Open Container Initiative |
| 소속 | Linux Foundation |
| 역할 | 컨테이너 실행·이미지·전송 규격의 표준 정의 |
| 대표 규격 | Runtime Spec, Image Spec, Distribution Spec |
| 대표 구현체 | runc, Docker, containerd, CRI-O |
| 목적 | 벤더 종속 없는 컨테이너 생태계 표준화 |
✅ OCI는 컨테이너의 “표준 언어”를 만드는 재단입니다.
Docker는 OCI 규격을 구현한 도구,
Kubernetes는 OCI 규격을 활용하는 플랫폼,
그리고 CNCF는 OCI를 포함한 클라우드 네이티브 생태계 전체를 관리하는 조직이에요.
가상머신 생성
mkdir docker
vagrant init
ii Vagrantfile
vagrant up
https://docs.docker.com/engine/install/centos/
Set up the repository
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
Install Docker Engine
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Start Docker Engine
**$ sudo systemctl enable --now docker**
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
systemctl enable이 하는 일systemctl enable docker 는 “Docker 서비스를 부팅 시 자동 시작하도록 등록”하는 명령입니다. 이때 systemd는 내부적으로 서비스 단위 파일(.service) 을 읽어들여, 그걸 해당 타겟(target) (즉, 실행 레벨에 해당하는 group)에 심볼릭 링크로 연결합니다. 즉 👇/usr/lib/systemd/system/docker.service ← 서비스 정의 파일 (원본)
/etc/systemd/system/multi-user.target.wants/docker.service → 심볼릭 링크 (자동 시작 등록)
| 디렉터리 | 역할 |
|---|---|
/usr/lib/systemd/system/ | 시스템에서 제공하는 기본 서비스 정의 파일들 (Docker, sshd, crond 등) |
/etc/systemd/system/ | 사용자가 수정/활성화한 서비스 설정들이 저장되는 곳 |
/etc/systemd/system/<target>.wants/ | 부팅 시 함께 실행할 서비스들의 링크 목록 |
Docker의 원본 서비스 파일은 /usr/lib/systemd/system/docker.service
enable 명령은 “이 서비스를 부팅 시 자동으로 실행해야 한다”고 systemd에 알려주기 위해
**심볼릭 링크를 `/etc/systemd/system/multi-user.target.wants/` 아래에 추가**합니다.
💡 “심볼릭 링크가 있으면 자동 실행, 없으면 비활성화”
이게 systemd의 enable/disable 내부 로직이에요.
$ sudo systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
→ 이 말은 “부팅 시 multi-user.target(즉, 텍스트 로그인 단계)에서 Docker 서비스를 자동으로 시작하라”는 의미입니다.
즉, systemd는 링크를 보고 어떤 서비스가 자동시작 대상인지 알게 됩니다.
-now 옵션은?-now는 “지금 즉시(start) 서비스도 시작하라”는 의미입니다.
즉, 아래 두 명령을 합친 것과 같습니다 👇
sudo systemctl enable docker # 부팅 시 자동 실행 등록
sudo systemctl start docker # 지금 즉시 실행
| 항목 | 설명 |
|---|---|
| 심볼릭 링크 생성 이유 | systemd가 “부팅 시 자동 실행 대상 서비스”를 구분하기 위해 |
| 원본 파일 위치 | /usr/lib/systemd/system/docker.service |
| 링크 생성 위치 | /etc/systemd/system/multi-user.target.wants/docker.service |
| enable 의미 | 서비스 자동시작 등록 |
| --now 의미 | 즉시 실행도 함께 수행 |
| disable 시 동작 | 심볼릭 링크를 삭제함 (원본 파일은 그대로 남음) |
✅ 한 줄 요약:
systemctl enable은 “서비스를 부팅 시 자동 실행 목록에 등록하기 위해”해당 타겟 디렉토리에 심볼릭 링크를 생성하는 명령이에요.
systemd는 이 링크 존재 여부로 서비스 활성화 상태를 관리합니다.
설치 및 버전 확인
**$ docker --version**
Docker version 28.5.1, build e180ab8
**$ docker -v**
Docker version 28.5.1, build e180ab8
**$ docker version**
Client: Docker Engine - Community
Version: 28.5.1
API version: 1.51
Go version: go1.24.8
Git commit: e180ab8
Built: Wed Oct 8 12:20:03 2025
OS/Arch: linux/amd64
Context: default
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version": dial unix /var/run/docker.sock: connect: permission denied
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version": dial unix /var/run/docker.sock: connect: permission denied
→ 유닉스 소켓은 루트 사용자만 권한이 있음
**$ getent group docker**
docker:x:987:
도커 그룹 엔트리 확인
**$ sudo usermod -aG docker $USER**
현재 사용자 보조 그룹에 도커 그룹 추가
**$ id vagrant**
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),987(docker)
**$ docker version**
Client: Docker Engine - Community
Version: 28.5.1
API version: 1.51
Go version: go1.24.8
Git commit: e180ab8
Built: Wed Oct 8 12:20:03 2025
OS/Arch: linux/amd64
Context: default
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version": dial unix /var/run/docker.sock: connect: permission denied
아직도 permission denied 남
→ 새로운 로그인 세션부터 변경사항이 적용되므로
다시 로그인하면
**$ docker version**
Client: Docker Engine - Community
Version: 28.5.1
API version: 1.51
Go version: go1.24.8
Git commit: e180ab8
Built: Wed Oct 8 12:20:03 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 28.5.1
API version: 1.51 (minimum version 1.24)
Go version: go1.24.8
Git commit: f8215cc
Built: Wed Oct 8 12:17:02 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.7.28
GitCommit: b98a3aace656320842a23f4a392a33f46af97866
runc:
Version: 1.3.0
GitCommit: v1.3.0-0-g4ca628d1
docker-init:
Version: 0.19.0
GitCommit: de40ad0
permission denied 나던 서버 부분도 정상적으로 출력되는 것을 확인 가능
클라이언트 부분 정보는 정상 출력되는데 서버 부분은 권한 제한 걸리는 이유
: 서버 버전 정보를 가져올 때 도커 데몬에 유닉스 소켓으로 요청을 보내기 때문
docker version은 내부적으로 다음 두 단계를 수행
① 클라이언트 버전 출력
- 이건 CLI 실행 파일 자체의 메타데이터이므로
로컬에서 바로 읽어서 출력
→ 즉, 데몬과 통신 불필요.
② 서버(Daemon) 버전 요청
- CLI가 Docker Daemon에게 `/version` REST API 요청을 전송
- 경로: `unix:///var/run/docker.sock`
- 요청 URL: `GET /v1.51/version`
- Daemon이 응답을 반환하면 “Server:” 섹션이 출력
> `docker version` 명령은 서버 버전 확인 시 Docker 데몬에 REST API를 전송하기 때문에,
>
>
> `/var/run/docker.sock` 유닉스 소켓에 접근할 권한이 없으면 **Server 부분만 permission denied** 가 발생
>
Verify that the installation is successful by running the hello-world image:
**$ sudo docker run hello-world**
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete
Digest: sha256:6dc565aa630927052111f823c303948cf83670a3903ffa3849f1488ab517f891
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/

도커 클라이언트 -> 도커 호스트 -> 도커 레지스트리
<- <-

: 붕어빵 틀
: 컨테이너 형태로 소프트웨어를 배포하기 위해 필요한 모든 요소(코드, 라이브러리, 설정 등)를 실행할 수 있는 포맷으로 컴파일 및 빌드한 패키지
: 붕어빵 틀로 찍어서 나온 붕어빵
: 도커 이미지를 실행할 수 있는 인스턴스(instance)
가상머신과 같은 개념 x
도커 엔진과 운영체제를 공유
⇒ 컨테이너는 도커 엔진이 설치되어 있는 호스트 운영체제를 이용
**$ sudo docker run hello-world
#1**
Unable to find image 'hello-world:latest' locally
#2
latest: Pulling from library/hello-world
#3
17eec7bbc9d7: Pull complete
#4
Digest: sha256:6dc565aa630927052111f823c303948cf83670a3903ffa3849f1488ab517f891
#5
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Digest = Docker 이미지의 고유한 식별자(ID) 이자,
이미지 내용 전체를 해싱(SHA256) 해서 얻은 무결성 검증값(fingerprint)
- Docker 이미지는 여러 레이어(layer) 로 구성됨
- 각 레이어의 바이너리 데이터(파일 시스템 스냅샷)를 모두 해싱해서
최종적으로 합쳐진 이미지 전체의 **SHA256 해시**를 계산함
이 해시값이 바로 Digest (예: sha256:6dc565a...)
Digest는 Docker 이미지의 내용을 SHA256으로 해싱한 고유 지문이며,
Docker는 이 값을 이용해 이미지 무결성 검증을 수행함
Digest
Digest 의 역할
| 역할 | 설명 |
|---|---|
| 고유 식별자 | 같은 이름과 태그(hello-world:latest)라도 실제 내용이 다르면 Digest가 다름 |
| 무결성 검증 | Docker가 이미지를 받을 때 서버의 Digest와 클라이언트가 계산한 Digest를 비교해 “내용이 변조되지 않았는지” 확인 |
| 캐시 판단 기준 | docker pull 시 Digest가 동일하면 “이미 최신 버전”으로 인식 |
| 보안 측면 | Digest를 직접 지정해 이미지 버전을 고정할 수 있음 (태그보다 안전함) |
Digest와 Tag의 차이
| 구분 | Tag | Digest |
|---|---|---|
| 형식 | :latest, :v1.0.0 | @sha256:6dc565aa... |
| 의미 | 사람이 관리하는 버전 이름 | 이미지 내용에 기반한 고유 해시값 |
| 변경 가능성 | 태그는 다른 이미지로 덮어쓸 수 있음 | Digest는 절대 불변 |
| 사용 예시 | hello-world:latest | hello-world@sha256:6dc565aa630927... |
💡 태그(tag) 는 “이름표”,
Digest 는 “지문”
Digest는 해시 함수인가?
Digest 자체는 해시 함수가 아니라, 해시 결과값(hash output) 입니다.
실제로 사용하는 해시 함수는 SHA256 (Secure Hash Algorithm 256-bit).
SHA256은 단방향 함수(one-way function) 로,
입력(이미지 데이터)이 조금이라도 바뀌면 전혀 다른 해시가 나오므로
**무결성 검사에 이상적**입니다.
👉 따라서 “Digest가 무결성 검사를 시행한다”기보다는,
Digest는 무결성 검사를 위한 해시값으로 사용된다
가 정확한 표현이에요.
Docker가 Digest를 검증하는 과정
docker pull 시,
Docker Hub(Registry)는 이미지의 메타데이터와 Digest를 응답합니다.
클라이언트는 다운로드한 실제 데이터의 SHA256을 계산합니다.
서버에서 받은 Digest와 일치하는지 비교합니다.
불일치하면 다운로드 실패 (변조 방지)
이 과정을 통해 이미지의 무결성(integrity) 과 신뢰성(trust) 을 확보합니다.
정리 요약
| 항목 | 설명 |
|---|---|
| Digest 정의 | 이미지 전체의 해시값(SHA256) |
| 형식 | sha256:<64자리 해시> |
| 기능 | 이미지 무결성 확인, 고유 식별자 역할 |
| 태그와 차이 | 태그는 이름표, Digest는 고유 지문 |
| 사용 예시 | docker pull hello-world@sha256:6dc565aa... |
| 무결성 검사 여부 | Docker는 Digest 비교로 무결성 검사 수행 ✅ |
docker image pull {이미지 이름:태그 이름}
**$ docker image pull ubuntu**
#1
Using default tag: latest
#2
latest: Pulling from library/ubuntu
#3
4b3ffd8ccb52: Pull complete
#4
Digest: sha256:66460d557b25769b102175144d538d88219c077c678a49af4afca6fbfc1b5252
#5
Status: Downloaded newer image for ubuntu:latest
#6
docker.io/library/ubuntu:latest
**$ docker image pull python:3.11.6**
3.11.6: Pulling from library/python
90e5e7d8b87a: Pull complete
27e1a8ca91d3: Pull complete
d3a767d1d12e: Pull complete
711be5dc5044: Pull complete
48b2d58a56e9: Pull complete
f4b2d251d97d: Pull complete
289cc84fca99: Pull complete
d2774833febd: Pull complete
Digest: sha256:2a725c9721f737a2944244c98c714d24f8bcfaddd9f5c15083cbaa024f7fce54
Status: Downloaded newer image for python:3.11.6
docker.io/library/python:3.11.6
docker image pull python:3.11.6
: 앞선 실습과 다르게 이미지 태그 이름을 명시해 3.11.6 태그의 파이썬 이미지 다운로드
[Image Index] ← 여러 플랫폼용 매니페스트의 목록
├── [Manifest #1] ← ex. amd64
│ ├── config.json
│ └── layers[]
├── [Manifest #2] ← ex. arm64
│ ├── config.json
│ └── layers[]
└── ...
[Image Index] ← 여러 플랫폼용 매니페스트의 목록
├── [Manifest #1] ← ex. amd64
│ ├── config.json
│ └── layers[]
├── [Manifest #2] ← ex. arm64
│ ├── config.json
│ └── layers[]
└── ...
즉,이미지 인덱스(Image Index, manifest list)
→ 여러 플랫폼(예: amd64, arm64)별 매니페스트의 “목차”
매니페스트(Manifest)
→ 하나의 플랫폼 이미지의 “설계도”
Config + Layers
→ 그 설계도를 실제 파일과 실행 정보로 구현한 “내용물”
| 구성 요소 | 파일 형태 | 역할 |
|---|---|---|
| Image Index (Manifest List) | index.json | 여러 아키텍처용 매니페스트를 나열 (예: x86_64, arm64 등) |
| Manifest | manifest.json | 특정 플랫폼용 이미지의 레이어 목록과 config 참조 |
| Config | config.json | 환경변수, 명령어, Entrypoint, 사용자 등 실행 정보 |
| Layers | layer.tar | 실제 파일시스템(각 명령의 변경사항) |
index.json (또는 “manifest list”)
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:aabbcc...", // 특정 매니페스트의 식별자
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:dd1122...", // ARM64 버전
"platform": {
"architecture": "arm64",
"os": "linux"
}
}
]
}
→ 즉, 하나의 이미지 이름(hello-world:latest) 에
여러 플랫폼용 이미지(= 매니페스트) 버전이 들어있을 수 있습니다.
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"digest": "sha256:ccddeeff...",
"size": 7023
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:17eec7bbc9d7...",
"size": 12345
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:998877aaccff...",
"size": 45678
}
]
}
config.digest → 실행 정보(config.json)
layers[].digest → 각 파일시스템 스냅샷(layer.tar)의 해시
{
"architecture": "amd64",
"os": "linux",
"config": {
"Env": ["PATH=/usr/local/bin"],
"Cmd": ["/hello"],
"Entrypoint": null,
"WorkingDir": "/"
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:17eec7bbc9d7...",
"sha256:998877aaccff..."
]
}
}
각 레이어는 압축된 .tar.gz 파일 (layer.tar)
예: apt-get install, COPY, RUN 등의 결과로 변경된 파일만 포함
OverlayFS로 합쳐져 하나의 루트 파일시스템으로 제공됨
| 단계 | 이름 | 역할 | 파일 예시 |
|---|---|---|---|
| 1️⃣ | Image Index | 여러 아키텍처별 매니페스트의 목록 | index.json |
| 2️⃣ | Manifest | 하나의 플랫폼 이미지 정의서 (config + layers 참조) | manifest.json |
| 3️⃣ | Config | 이미지 실행 설정, 환경변수, 명령 등 | config.json |
| 4️⃣ | Layers | 실제 파일시스템 데이터 (rootfs) | layer.tar |
graph TD
A[Image Index (Manifest List)]
A --> B1[Manifest - amd64]
A --> B2[Manifest - arm64]
B1 --> C1[Config.json]
B1 --> D1[Layer 1 (tar)]
B1 --> D2[Layer 2 (tar)]
B2 --> C2[Config.json]
B2 --> D3[Layer 1 (tar)]
B2 --> D4[Layer 2 (tar)]
Docker 이미지는
Image Index(=Manifest List) → Manifest → Config + Layers
로 구성된 계층 구조를 가지며,
인덱스는 여러 플랫폼 버전의 매니페스트를,
매니페스트는 해당 플랫폼의 파일시스템(Layers) 과 실행 설정(Config) 을 정의합니다.
docker image ls
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
hello-world latest 1b44b5a3e06a 2 months ago 10.1kB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
docker container run [이미지명]
**$ docker container run ubuntu**
아웃풋이 따로 출력되지 않음
아무일도 일어나지 않음
할일을 지정해주지 않았기에 할일이 없어서 바로 off 됨
docker container ls
**$ docker container ls**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
어떤 컨테이너도 실행되고 있지 않음
docker container ls -a
**$ docker container ls -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4a19f0dc5751 ubuntu "/bin/bash" 3 minutes ago Exited (0) 3 minutes ago naughty_borg
816cb7c5cd4c hello-world "/hello" 2 hours ago Exited (0) 2 hours ago goofy_chatelet
실행 중인 컨테이너와 정지 상태인 컨테이너 모두 확인
docker container run -it [이미지 이름]
**$ docker container run -it ubuntu**
root@6fedab338d1a:/#
-iti
: interactive
: 표준 입력(STDIN)을 열어놓는다는 의미
-i 옵션만 주면 표준 입력만 열림t
: tty
: 가상 터미널
- `-t` 옵션만 주면 터미널에 진입하지만 어떤 입력도 먹지 않음
⇒ 가상 터미널을 통해 키보드 입력을 표준 입력으로 컨테이너에 전달
root@6fedab338d1a : 사용자 이름과 호스트 이름이 변경된 것을 확인 가능root컨테이너 idrun ubuntu : 실행 후 바로 종료run -i ubuntu : 출력되는데 프롬프트가 안보임run -t ubuntu : 프롬프트는 보이지만 입력 불가root@6fedab338d1a:/# **ls**
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
다른 터미널 창에서 컨테이너 목록 다시 확인
**$ docker container ls**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6fedab338d1a ubuntu "/bin/bash" 34 minutes ago Up 34 minutes gracious_sanderson
STATUS 가 Up 인 컨테이너가 보임
run -t ubuntu 를 해도 위에 뜸
→ 종료 시그널을 전달할 수 없기에 Ctrl+C 로 빠져나와도 Up 상태로 남아있게 됨
컨테이너 종료
exit 입력docker container stop [컨테이너 id] : 약 10초 후에 컨테이너가 종료됨docker container kill [컨테이너 id] : 즉시 종료됨 : 그러나 위험docker stop 과 docker kill 은 모두 컨테이너를 종료하는 명령이지만, “어떻게 종료하느냐(시그널 처리)”가 다릅니다. 하나씩 단계적으로 살펴볼게요 👇| 항목 | 설명 |
|---|---|
| 공통 목적 | 컨테이너 내부 프로세스를 종료하기 위함 |
| 결과 | 컨테이너가 “exited” 상태로 바뀜 |
| 대상 | 컨테이너 내 PID 1 프로세스 (일반적으로 애플리케이션 프로세스) |
“정상 종료 요청” (Graceful shutdown)
--time 옵션으로 변경 가능) 동안 기다림 4️⃣ 아직 종료되지 않으면 SIGKILL 신호를 보냄 (강제 종료)docker stop <container>
# 또는
docker stop --time=5 <container> # 5초 후 강제 종료
| 항목 | 설명 |
|---|---|
| 종료 신호 | SIGTERM → (지연 후) SIGKILL |
| 종료 절차 | 정상적인 shutdown (cleanup, flush 등 가능) |
| 안전성 | 안전함 |
| 속도 | 느림 (기본 10초 기다림) |
stop은 “문 닫기 전에 정리 좀 하고 나가세요” 라고 요청하는 명령이에요.
“즉시 강제 종료” (Forceful shutdown)
docker kill <container>
또는 특정 신호로도 종료할 수 있음:docker kill --signal SIGINT <container>
| 항목 | 설명 |
|---|---|
| 종료 신호 | SIGKILL (또는 지정한 신호) |
| 종료 절차 | 비정상적인 즉시 중단 |
| 안전성 | 낮음 (데이터 유실 위험) |
| 속도 | 빠름 |
kill은 “지금 당장 꺼!” 하는 명령이에요 — 애플리케이션에게 정리할 기회를 주지 않습니다.
| 구분 | docker stop | docker kill |
|---|---|---|
| 보내는 신호 | SIGTERM → (대기 후) SIGKILL | SIGKILL (또는 지정 신호) |
| 종료 방식 | 정상 종료 (graceful) | 즉시 종료 (force) |
| cleanup 수행 기회 | 있음 | 없음 |
| 기본 대기 시간 | 10초 (--time 옵션 변경 가능) | 없음 |
| 안전성 | 안전함 | 위험함 (데이터 손상 가능) |
| 속도 | 느림 | 빠름 |
| 사용 예시 | 웹서버나 DB 등 정상 종료 필요한 서비스 | 멈추지 않는 컨테이너 강제 종료 |
$ docker stop nginx
# -> nginx 프로세스가 SIGTERM 수신 후 로그 flush, 연결 종료 후 정상 종료
$ docker kill nginx
# -> nginx 프로세스가 SIGKILL 수신 후 바로 종료 (세션, 로그 flush 안 됨)
✅ docker stop 은 정상 종료(SIGTERM → SIGKILL)
✅
docker kill은 즉시 강제 종료(SIGKILL)→ stop = polite (정상적), kill = brutal (즉시 강제)
kill(), waitpid())을 사용하는지까지 리눅스 시그널 플로우 형태로 그려드릴까요?root@6fedab338d1a:/# exit
exit
종료한 컨테이너에 다시 접속하고 싶다면
docker container start [컨테이너 ID]
**$ docker container start 6fedab338d1a**
6fedab338d1a
**$ docker container ls**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6fedab338d1a ubuntu "/bin/bash" 44 minutes ago Up About a minute gracious_sanderson
docker container attach [컨테이너 ID]
: 컨테이너 내부에 접속
**$ docker container attach 6fedab338d1a**
root@6fedab338d1a:/# history
1 ls
2 exit
3 history
종료됐다가 재시작된 것이지, 삭제됐다가 재생성된 것이 아니므로 히스토리 확인 가능
# Ctrl+P
root@6fedab338d1a:/# **history**
1 ls
2 exit
3 history
4 exit
5 history
# Ctrl+P+Q: 종료하지 않고 터미널만 빠져나옴
root@6fedab338d1a:/# **read escape sequence**
# 컨테이너 목록 확인
**$ docker container ls -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6fedab338d1a ubuntu "/bin/bash" 51 minutes ago Exited (137) 18 seconds ago gracious_sanderson
4a19f0dc5751 ubuntu "/bin/bash" About an hour ago Exited (0) About an hour ago naughty_borg
816cb7c5cd4c hello-world "/hello" 3 hours ago Exited (0) 3 hours ago goofy_chatelet
# hello-world 컨테이너 삭제
**$ docker container rm 816cb7c5cd4c**
816cb7c5cd4c
# 삭제된 거 확인 가능
**$ docker container ls -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6fedab338d1a ubuntu "/bin/bash" 52 minutes ago Exited (137) About a minute ago gracious_sanderson
4a19f0dc5751 ubuntu "/bin/bash" About an hour ago Exited (0) About an hour ago naughty_borg
Up 상태인(동작 중인) 컨테이너는 삭제 불가
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
hello-world latest 1b44b5a3e06a 2 months ago 10.1kB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
# hello-world 이미지 삭제
**$ docker image rm hello-world**
Untagged: hello-world:latest
Untagged: hello-world@sha256:6dc565aa630927052111f823c303948cf83670a3903ffa3849f1488ab517f891
Deleted: sha256:1b44b5a3e06a9aae883e7bf25e45c100be0bb81a0e01b32de604f3ac44711634
Deleted: sha256:53d204b3dc5ddbc129df4ce71996b8168711e211274c785de5e0d4eb68ec3851
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
docker container ls -a 에서 컨테이너가 하나라도 존재하는 이미지는 삭제 불가
**$ docker container prune
$ docker container ls -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
stop 된 모든 컨테이너 삭제
docker ps
== docker container ls
$ docker rm -f $(docker ps -aq)
== docker rm -f $(docker container ls -aq)
모든 컨테이너를 삭제
$(docker ps -aq)
docker ps : 컨테이너 목록-aqa
: 실행 중이지 않은 컨테이너까지 모두 출력
q
: 컨테이너의 ID 만 출력
⇒ 모든 컨테이너의 ID 출력
ubuntu 이미지를 public.ecr.aws/docker/library/ubuntu 해당 이미지로 변경
**$ docker image pull public.ecr.aws/docker/library/ubuntu**
**$ docker tag public.ecr.aws/docker/library/ubuntu ubuntu**
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 About a minute ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
public.ecr.aws/docker/library/ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
**$ docker image rm public.ecr.aws/docker/library/ubuntu**
Untagged: public.ecr.aws/docker/library/ubuntu:latest
Untagged: public.ecr.aws/docker/library/ubuntu@sha256:66460d557b25769b102175144d538d88219c077c678a49af4afca6fbfc1b5252
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 About a minute ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
터미널1
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
$ docker container run -it ubuntu
root@2995f8506568:/# **ifconfig**
bash: ifconfig: command not found
컨테이너 내부 IP 를 확인하려고 ifconfig 명령어를 입력한다고 해서 ifconfig 명령어를 사용할 수는 없음
→ net-tools 를 설치해야 가능
# net-tools 설치
$ docker container attach 2995f8506568
root@2995f8506568:/# **apt update && apt install net-tools**
# 이제 됨
root@2995f8506568:/# **ifconfig**
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 2a:03:c4:36:c5:51 txqueuelen 0 (Ethernet)
RX packets 4983 bytes 34526156 (34.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3534 bytes 195242 (195.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
터미널2
# 현재 컨테이너의 스냅샷 이미지 저장
**$ docker container commit 2995f8506568 my-ubuntu:0.1**
sha256:e416ca5d44c4dafdf64e32695deee256ad743e3bf134b4e71fce12beea401132
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 About a minute ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
기존 컨테이너 종료 후 새롭게 만든 my-ubuntu 이미지를 컨테이너로 실행
**root@2995f8506568:/# exit**
exit
**[vagrant@docker ~]$ docker container ls -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2995f8506568 ubuntu "/bin/bash" 14 minutes ago Exited (0) 7 seconds ago kind_carson
**$ docker container rm 2995f8506568**
2995f8506568
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 6 minutes ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
**$ docker container run -it my-ubuntu:0.1**
root@6a700bd5fbb4:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether fe:b8:0e:ef:88:bb txqueuelen 0 (Ethernet)
RX packets 8 bytes 736 (736.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3 bytes 126 (126.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
**root@6a700bd5fbb4:/# exit**
exit
docker search
: Docker Hub (공식 이미지 저장소) 에서 이미지를 검색하는 명령
**$ docker search centos**
NAME DESCRIPTION STARS OFFICIAL
centos DEPRECATED; The official build of CentOS. 7779 [OK]
corpusops/centos centos corpusops baseimage 0
dockette/centos My Custom CentOS Dockerfiles 1
eclipse/centos CentOS based minimal stack with only git and… 1
centos/postgresql-10-centos7 PostgreSQL is an advanced Object-Relational … 21
...
Official 이미지인지 확인 가능 등
docker inspect
: Docker 객체(컨테이너, 이미지, 볼륨, 네트워크 등)의 상세 JSON 메타데이터를 출력
**$ docker inspect ubuntu**
[
{
"Id": "sha256:97bed23a34971024aa8d254abbe67b7168772340d1f494034773bc464e8dd5b6",
"RepoTags": [
"ubuntu:latest"
],
"RepoDigests": [
"ubuntu@sha256:66460d557b25769b102175144d538d88219c077c678a49af4afca6fbfc1b5252"
],
"Parent": "",
"Comment": "",
"Created": "2025-10-01T13:01:37.838375075Z",
"DockerVersion": "26.1.3",
...
즉, docker search 는 원격 API를, inspect 는 로컬 Docker Daemon API를 사용
| 구분 | docker search | docker inspect |
|---|---|---|
| 목적 | Docker Hub 등 원격 저장소에서 이미지 검색 | 로컬 Docker 엔진의 객체 상세 정보 조회 |
| 대상 | 이미지 이름(검색어) | 컨테이너, 이미지, 네트워크, 볼륨 등 |
| 출력 형식 | 표 형태 (요약) | JSON 형태 (상세) |
| 정보 수준 | 개요 수준 | 매우 세부 수준 |
| 사용 위치 | 원격 (인터넷 연결 필요) | 로컬 (Docker Daemon 필요) |
| 예시 | docker search ubuntu | docker inspect nginx |
docker save -o
: Docker 이미지의 내보내기(export)
docker load -i
: Docker 이미지의 가져오기(import)
⇒ Docker Hub를 거치지 않고 이미지 파일을 직접 주고받고 싶을 때 사용하는 명령
**$ docker save -o my_image.tar ubuntu:latest
$ ls**
my_image.tar
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 13 minutes ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
**$ docker image rm ubuntu:latest**
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:66460d557b25769b102175144d538d88219c077c678a49af4afca6fbfc1b5252
**$ docker load -i my_image.tar**
Loaded image: ubuntu:latest
**$ docker image ls**
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu 0.1 e416ca5d44c4 15 minutes ago 135MB
ubuntu latest 97bed23a3497 2 weeks ago 78.1MB
python 3.11.6 0dba5a08d425 24 months ago 1.01GB
| 명령어 | 동작 | 방향 |
|---|---|---|
docker save | 이미지를 tar 파일로 내보냄 (Export) | 로컬 → 파일 |
docker load | tar 파일에서 이미지를 불러옴 (Import) | 파일 → 로컬 |
docker save는 이미지를 파일로 백업,
docker load는 그 파일을 다시 Docker에 복원하는 명령둘 다 Docker Hub 없이 이미지 전달이 가능하다는 게 핵심
docker export / docker import 와의 차이점
| 명령어 | 대상 | 포함 정보 | 목적 |
|---|---|---|---|
| docker save/load | 이미지 | 모든 레이어 + 메타데이터 (완전한 이미지 구조) | 이미지 백업/복원용 |
| docker export/import | 컨테이너 | 파일시스템 스냅샷 (실행 상태 기반) | 컨테이너 상태 복제용 |
docker create
: docker 컨테이너 생성
**$ docker create --name os2 ubuntu:latest**
**$ docker ps -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4c22e2d5688 ubuntu:latest "/bin/bash" 25 seconds ago Created os1
6a700bd5fbb4 my-ubuntu:0.1 "/bin/bash" 15 minutes ago Exited (0) 15 minutes ago elegant_gauss
os1 이라는 name 을 가진 컨테이너 생성됨
→ STATUS: Created
**$ docker create -it --name os1 ubuntu:latest**
name : os1 이라는 name 을 가진 컨테이너를 생성함-it : 컨테이너가 나중에 실행될 때 표준 입력 및 tty 가 할당되도록 설정docker run
== create + start