docker create -it
docker start -ai
docker run -it
둘 다 결국 표준입출력 스트림 가상터미널이 열리는 건 똑같음
그러나 왜 start 에는 -ait 가 아니라 -ai 를 쓸까?
→ start 는 컨테이너 실행만 가능하고, 가상터미널은 가지고 있지 않음
→ create 에서 입출력스트림 가상터미널을 이미 만들어놨기 때문에?
→ start 에서는 입력스트림에 붙기만 해도 가상터미널이 열린다?
docker run
: 포어그라운드 실행
CMD 나 ENTRYPOINT 에 정의된 명령이 컨테이너 시작 시 자동 실행됨→ 따라서 무엇을 실행하도록 이미지가 만들어졌느냐가 곧 “컨테이너가 살아있는지”를 결정
Docker 컨테이너는 “리눅스 프로세스를 실행하는 일회용 환경”
docker run -itdocker create -it && docker start -ai
| 항목 | httpd | nginx | ubuntu |
|---|---|---|---|
| 기본 CMD | httpd-foreground | nginx -g "daemon off;" | bash |
| 목적 | 웹 서버 | 웹 서버 | 리눅스 기본 환경 |
| 실행 방식 | 포그라운드 모드 (백그라운드 안 감) | 포그라운드 모드 + 로그 출력 | 쉘 실행 (stdin 없으면 종료) |
| 로그 출력 | 내부 로그 파일 중심 | STDOUT 로그 출력 | 없음 |
| TTY 필요 여부 | 필요 없음 | 필요 없음 | 필요함 (-it 필요) |
| 컨테이너 종료 조건 | httpd 프로세스 종료 시 | nginx 프로세스 종료 시 | bash 종료 시 (입력 끝남) |
PID 1 예시
| 이미지 | 기본 CMD / ENTRYPOINT | 컨테이너 내부의 PID 1 |
|---|---|---|
| ubuntu | bash | bash |
| nginx | nginx -g "daemon off;" | nginx (마스터 프로세스) |
| httpd | httpd-foreground | httpd |
| mysql | docker-entrypoint.sh mysqld | bash (entrypoint 스크립트) 또는 mysqld |
| redis | redis-server | redis-server |
| python (기본) | python3 | python3 |
**docker run -it
Ctrl+P+Q**
**docker run -d
# 실행 후 종료되는 경우
# docker run -it, Ctrl+P+Q 의 과정을 생략
docker run -itd**
**$ docker run --name os3-temp ubuntu:latest hostname
$ docker ps -a**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0873a8a6a0f1 ubuntu:latest **"hostname"** 55 seconds ago Exited (0) 54 seconds ago os3-temp
hostname 을 보고 싶은데 컨테이너가 남으면 일일이 지워야 하는게 귀찮으니까
hostname 만 보고 바로 지워지도록 하려면
$ docker run --rm ubuntu:latest hostname
4f2314f0b6c6
**$ docker run -it --name os3 -e "LAB=docker" ubuntu:latest**
root@7fef3580f96e:/# **echo $LAB**
docker
docker stats
: 실시간 상태 확인 가능
: Ctrl+C 로 종료
docker stats --no-stream
→ 실시간으로 보지 않고 그 순간의 스냅샷을 확인하고 싶을 때
# Ubuntu 이미지를 기반으로
# CPU 사용률이 0.3(=30%)로 제한된 컨테이너 os4 를
# 백그라운드에서 실행
**$ docker run -itd --name os4 --cpus 0.3 ubuntu:latest**
# 실행 중인 컨테이너(os4) 안에서
# dd 명령어를 이용해 CPU를 계속 사용하는 작업을 백그라운드로 실행
**$ docker exec os4 dd if=/dev/zero of=/dev/null &**

| 옵션 | 의미 |
|---|---|
-i | interactive — 표준 입력을 열어둠 (입력 가능 상태 유지) |
-t | tty — 가상 터미널 할당 (터미널 모드) |
-d | detach — 백그라운드 모드로 실행 (터미널에 붙지 않음) |
--name os4 | 컨테이너 이름을 os4로 지정 |
--cpus 0.3 | 이 컨테이너가 사용할 수 있는 CPU 시간 비율을 30%로 제한 |
ubuntu:latest | 사용할 베이스 이미지 지정 |
| 부분 | 의미 |
|---|---|
docker exec os4 | 이미 실행 중인 컨테이너 os4 내부에서 명령 실행 |
dd | 파일 복사 유틸리티 (Data Duplicator) |
if=/dev/zero | 입력 파일(input file): 무한히 0을 출력하는 장치 |
of=/dev/null | 출력 파일(output file): 데이터를 모두 버리는 장치 |
& | 명령을 백그라운드에서 실행 |
dd if=/dev/zero of=/dev/null 은 무한 루프 형태의 CPU 연산을 계속 수행 (0을 읽어서 버리는 일을 계속 반복 → 매우 CPU 집약적)-cpus 0.3 으로 제한되어 있으므로, 실제 호스트 CPU 점유율은 약 30% 정도로 제한됨**$ docker run -itd --name os4 --memory 1024m ubuntu:latest**
# 할당 메모리 크기 업데이트
**$ docker update --memory 1400m os4**
**$ docker run -itd --name os-final ubuntu:latest**
백그라운드에서 실행되는 컨테이너 생성
attach**$ docker attach os-final
root@57f434c69026:/# exit**
exit
**$ docker ps -a**
... STATUS PORTS NAMES
... Exited (0) 4 seconds ago os-final exit 로 빠져나가면 ubuntu 의 PID 1 인 "/bin/bash” (=표준입출력)이 종료되므로 컨테이너도 종료됨exec**$ docker start os-final**
os-final
**$ docker exec -it os-final /bin/bash
root@57f434c69026:/# ps -ef**
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:30 pts/0 00:00:00 /bin/bash
root 9 0 0 10:31 pts/1 00:00:00 /bin/bash
root 18 0 0 10:33 pts/2 00:00:00 /bin/bash
root 26 18 0 10:33 pts/2 00:00:00 ps -ef
**root@57f434c69026:/# exit**
exit
**$ docker ps**
.. STATUS PORTS NAMES
... Up 5 minutes os-finalpty
: 가상터미널
: pts 의 일부
pts/0 , pts/1 , pts/2
: 새로운 터미널 세션이 만들어질 때마다 뒤 숫자가 증가
이렇게 열면 exit 로 터미널을 빠져나와도 메인프로세스(PID 1, run -itd 로 백그라운드 실행 중인 터미널)는 종료되지 않으므로 컨테이너는 계속 실행됨. 종료되지 않음.
docker top
**$ docker top os-final**
UID PID PPID C STIME TTY TIME CMD
root 41643 41619 0 10:30 pts/0 00:00:00 /bin/bash
root 41692 41619 0 10:31 pts/1 00:00:00 /bin/bash
docker logs
: 대표적으로 표준입출력, 에러 등의 메세지가 기록됨
# mysql 컨테이너 생성 및 백그라운드 실행
**$ docker run -d --name db-fail public.ecr.aws/docker/library/mysql:5.7
# 비정상 종료
$ docker ps -a**
... STATUS PORTS NAMES
... Exited (1) 44 seconds ago db-fail
# 왜 비정상 종료됐는지 에러 로그 확인
**$ docker logs db-fail**
2025-10-20 10:43:04+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.44-1.el7 started.
2025-10-20 10:43:04+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-10-20 10:43:04+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.44-1.el7 started.
2025-10-20 10:43:05+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of the following as an environment variable:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
# 이미지 태그 추가(너무 길어서)
$ docker tag public.ecr.aws/docker/library/mysql:5.7 mysql:5.7
# log 에 뜬 패스워드 에러를 해결하고 실행
**$ docker run -d --name db-good -e "MYSQL_ROOT_PASSWORD=qwer" mysql:5.7
$ docker ps**
... STATUS PORTS NAMES
... Up 6 seconds 3306/tcp, 33060/tcp db-good
# 에러 로그 없는 거 확인 가능
**$ docker logs db-good
...**
2025-10-20T10:47:56.717750Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2025-10-20T10:47:56.743144Z 0 [Note] Event Scheduler: Loaded 0 events
2025-10-20T10:47:56.744334Z 0 [Note] mysqld: ready for connections.
Version: '5.7.44' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
docker cp [파일] [컨테이너 이름:디렉토리 경로]
**$ touch host-file.txt**
**$ docker cp host-file.txt os-final:/tmp/**
Successfully copied 1.54kB to os-final:/tmp/
**$ docker exec os-final cat /tmp/host-file.txt**
docker cp [컨테이너 이름:디렉토리 경로] [파일]
**$ docker run -d --name web3 --rm httpd:latest
$ docker cp web3:/usr/local/apache2/htdocs/index.html /tmp/index.html**
Successfully copied 2.05kB to /tmp/index.html
**$ cat /tmp/index.html**
<html><body><h1>It works!</h1></body></html>
| 옵션 | 설명 |
|---|---|
-d | 백그라운드(detached) 모드로 실행 |
--name web3 | 컨테이너 이름을 web3로 지정 |
--rm | 컨테이너가 종료될 때 자동으로 삭제 |
httpd:latest | 실행할 이미지 |
: 원본 이미지 파일시스템과 상태 비교
docker diff
**$ docker diff os-final**
C /tmp
A /tmp/host-file.txt
C /root
A /root/.bash_history
# os-final 파일 시스템에서 파일 하나 삭제
**$ docker exec os-final rm /tmp/host-file.txt**
# 파일시스템 변경 내역 리스트에서 사라짐
# 삭제됐다고 표시되지 않음(원래 파일시스템에 있는 파일이 아니었기 때문에)
**$ docker diff os-final**
C /root
A /root/.bash_history
# 원본 이미지 파일시스템에 있던 파일 삭제
**$ docker exec os-final rm /bin/ls**
# 삭제 내역 확인 가능
**$ docker diff os-final**
C /root
A /root/.bash_history
C /usr
C /usr/bin
D /usr/bin/l
: 파일시스템
컨테이너 네트워크는 격리되어 있음
**$ docker run -itd --name net-test-1 public.ecr.aws/docker/library/rockylinux:9**
**$ docker exec -it net-test-1 bash**
**[root@7ee000012391 /]# dnf install -y net-tools iproute
[root@7ee000012391 /]# 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:bd:c7:cd:7b:4a txqueuelen 0 (Ethernet)
RX packets 3318 bytes 20294619 (19.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2318 bytes 153142 (149.5 KiB)
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
host 의 네트워크
$ ifconfig
**docker0**: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::b093:7cff:fe56:5210 prefixlen 64 scopeid 0x20<link>
ether b2:93:7c:56:52:10 txqueuelen 0 (Ethernet)
RX packets 5974 bytes 270750 (264.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8337 bytes 54824973 (52.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
**enp0s3**: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
inet6 fd17:625c:f037:2:a00:27ff:feed:ab98 prefixlen 64 scopeid 0x0<global>
inet6 fe80::a00:27ff:feed:ab98 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:ed:ab:98 txqueuelen 1000 (Ethernet)
RX packets 773141 bytes 1058874843 (1009.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 89966 bytes 6763529 (6.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.56.12 netmask 255.255.255.0 broadcast 192.168.56.255
inet6 fe80::a00:27ff:fe4f:ae73 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:4f:ae:73 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13 bytes 970 (970.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 2 bytes 144 (144.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 144 (144.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
**veth94a5f7f**: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::c0be:ff:fe86:135b prefixlen 64 scopeid 0x20<link>
ether c2:be:00:86:13:5b txqueuelen 0 (Ethernet)
RX packets 2318 bytes 153142 (149.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3319 bytes 20294689 (19.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0는 veth 쌍을 통해 docker0에 연결 [컨테이너 내부]
eth0 (veth의 한쪽 끝)
│
│
┌───┴─────────────┐
│ Host │
│ │
│ vethXXXX (반대쪽) ─────┐
│ │
│ vethYYYY (다른 컨테이너)│
│ │
│ ┌─────────────────┴─────┐
│ │ docker0 (가상 브리지) │ ← 컨테이너들 내부 통신 허브
│ └─────────────────┬─────┘
│ │
│ (NAT via iptables)
│ │
│ enp0s3 (물리 NIC)
│ │
│ [외부 네트워크]
└──────────────────────────┘
컨테이너 eth0 ─┐
│
컨테이너 eth0 ─┤ (여러 개의 veth들이 연결)
│
[ docker0 ]
│
▼
(호스트 커널의 라우팅 테이블)
│
NAT (iptables MASQUERADE)
│
▼
[ enp0s3 NIC ]
│
[ 외부 네트워크 ]
**$ docker network create prod-net**
ffde2dfe78ffa8e4a58537af8a592c3b511b53cceab557f5780329c0dbe57fd9
**$ docker network ls**
NETWORK ID NAME DRIVER SCOPE
f927f2c1e57a bridge bridge local
81a81a4e3cb8 host host local
013a5c209a59 none null local
ffde2dfe78ff prod-net bridge local
**$ docker run -d --name prod-web --network prod-net httpd
$ docker run -d --name prod-db --network prod-net -e MYSQL_ROOT_PASSWORD=1234 mysql:5.7
$ docker ps**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
156589d72125 mysql:5.7 "docker-entrypoint.s…" 55 seconds ago Up 55 seconds 3306/tcp, 33060/tcp prod-db
49060989a818 httpd "httpd-foreground" About a minute ago Up About a minute 80/tcp prod-web
7ee000012391 public.ecr.aws/docker/library/rockylinux:9 "/bin/bash" 25 minutes ago Up 25 minutes net-test-1
# exec 으로 bash 가상터미널 접속
**$ docker exec -it prod-web bash**
root@49060989a818:/usr/local/apache2#
# 핑 설치
root@49060989a818:/usr/local/apache2# apt-get update && apt-get install -y iputils-ping
# db ip 주소가 아닌 컨테이너 이름으로 요청 보내도 정상적으로 보내짐
root@49060989a818:/usr/local/apache2# ping -c 4 prod-db
PING prod-db (172.18.0.3) 56(84) bytes of data.
64 bytes from prod-db.prod-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.295 ms
64 bytes from prod-db.prod-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.343 ms
64 bytes from prod-db.prod-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.198 ms
64 bytes from prod-db.prod-net (172.18.0.3): icmp_seq=4 ttl=64 time=0.262 ms
--- prod-db ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 0.198/0.274/0.343/0.052 ms
사용자 브리지 장점
$ docker run -d --name prod-web --network prod-net -p 8080:80 httpd
: 을 기준으로 좌우를 나눔호스트 포트:컨테이너 포트
해당 포트로 외부에 개방?
**$ docker run -it --rm --name none-box --network none public.ecr.aws/docker/library/busybox sh**
Unable to find image 'public.ecr.aws/docker/library/busybox:latest' locally
latest: Pulling from docker/library/busybox
80bfbb8a41a2: Pull complete
Digest: sha256:2f590fc602ce325cbff2ccfc39499014d039546dc400ef8bbf5c6ffb860632e7
Status: Downloaded newer image for public.ecr.aws/docker/library/busybox:latest
**/ # ifconfig**
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
루프백 주소만 존재
--network host
$ docker run -d --name host-web --network host public.ecr.aws/docker/library/nginx
docker0, veth, 포트포워딩 같은 가상 네트워크 계층이 존재 X[브라우저]
↓
[호스트 enp0s3:80]
↓ (직접)
[컨테이너 nginx:80]
이미 점유된 포트를 할당하려고 하면 에러남