도커(Docker) 란?
도커란 애플리케이션을 '컨테이너'라는 독자적 패키징 방법을 통해 신속하게 구축, 테스트 및 배포할 수 있는 소프트웨어 플랫폼이다.
도커 vs 가상머신 (Virtual Machine)
컨테이너는 Linux 커널에서 기본 제공하는 프로세스 격리 및 가상화 기능에 의해 실행된다. 여러 프로세스에 리소스를 할당하는 컨트롤 그룹(Cgroups), 어떤 프로세스에서 시스템의 다른 리소스나 영역을 보거나 액세스하는 것을 제한하는 네임스페이스 등과 같은 이러한 기능 덕분에 여러 애플리케이션 구성 요소에서 호스트 운영 체제 단일 인스턴스의 리소스를 공유하는 것이 가능하다. 이는 하이퍼바이저를 통해 여러 가상 머신(VM)이 단일 하드웨어 서버의 CPU, 메모리, 기타 리소스를 공유하는 방식과 매우 비슷하다.
따라서 컨테이너 기술은 VM의 모든 기능 및 이점(애플리케이션 격리, 비용 효과적인 확장성, 삭제 가능성)과 함께 다음과 같이 중요한 장점도 추가로 제공합니다
- 경량화
- 개발자 생산성 향상
- 리소스 효율성 향상
도커 이미지 (Docker Image)
도커 이미지는 컨테이너를 만드는 데 사용되는 읽기 전용(Read-only) 템플릿이다.
컨테이너 실행에 필요한 파일과 설정값 등을 포함하고 있는 도커파일을 만든 후 Dockerfile을 빌드하여 이미지를 만든다.
도커 컨테이너 (Docker Container)
도커 이미지를 실행한 상태이다.
이미지로 컨테이너를 생성하면 이미지의 목적에 맞는 파일이 들어있는 파일 시스템과 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립된 공간이 생성된다.
이것을 도커 컨테이너라고 합니다.
도커 컨테이너는 읽기 전용인 이미지에 변경된 사항을 저장하는 컨테이너 계층(Layer)에 저장합니다.
도커 이미지를 도넛 레시피에 비유한다면, 도커 컨테이너는 해당 레시피를 이용해 만든 도넛으로 비유할 수 있습니다.
하나의 도넛 레시피에서 여러 가지 맛의 도넛을 만들 수 있는 것과 같이, 하나의 도커 이미지로 여러 개의 도커 컨테이너를 만들 수 있습니다.
또한, 기존의 도넛 레시피를 수정하게 되어도, 이미 기존 레시피로 만들어진 도넛에는 영향이 없듯이,
이처럼 도커 이미지를 변경해도 이미 실행 중인 도커 컨테이너에는 영향을 주지 않습니다.
기본적인 도커 명령어
docker [대상] [액션]
-> [대상] : containe(생략가능), image, volume, network 등등
-> [액션] : ls, inspect, start, run 등등
도커 컨테이너 상태
docker (container) create [이미지]
-> 컨테이너를 생성하고, 자동으로 시작하지는 않음
docker create --name testos centos
--name testos로 컨테이너 이름을 testos로 설정
docker rename [현재 이름] [바꿀 이름] 으로 컨테이너 이름 변경 가능
추가 옵션
옵션 | 설명 |
-i (--interactive) | 표준 입력(STDIN)을 활성화 컨테이너와 attach 되어있지 않더라도 표준 입력을 유지 |
-t (--tty) | 컨테이너에 pseudo-terminal을 할당 |
docker ps (= docker container ls)
-> 실행(Up) 중인 컨테이너들의 목록을 확인
root@DH:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
adb6732a399d centos "/bin/bash" 51 seconds ago Up 50 seconds testos2
키워드 | 설명 |
CONTAINER ID | 컨테이너에 할당되는 고유한 컨테이너 ID(전체 중 12자리만 표시) |
IMAGE | 컨테이너를 생성할 때 사용된 이미지 |
COMMAND | 컨테이너가 시작될 때 실행될 명령어 docker run/create 명령어의 맨 끝에 새로운 명령어를 입력해서 컨테이너를 생성할 때 대체 가능 |
CREATED | 컨테이너 생성 후 경과 시간 |
STATUS | 컨테이너 상태 실행 중(Up) / 종료(Exited) / 일시 중지(Pause) |
PORTS | 컨테이너가 개방한 포트와 호스트에 연결된 포트 |
NAMES | 컨테이너 이름 |
옵션 | 설명 |
-a | 실행 중이지 않은 컨테이너를 포함하여 전체 컨테이너 목록 출력 |
--no-trunc | 컨테이너 ID 전체 출력 |
docker start [컨테이너]
-> 생성해둔 컨테이너를 시작
root@DH:~# docker start -ai testos
[root@151f3b70b5a4 /]#
-ai 옵션을 사용해 해당 컨테이너 내부로 접근하여 표준 입력을 받을 수 있도록 하였다.
옵션 | 설명 |
-a | 해당 컨테이너 내부로 접근 |
-i | 표준 입력(STDIN)을 활성화 |
컨테이너를 빠져나가는 방법은 크게 2가지가 있다.
- exit 명령을 통해, /bin/bash가 종료되면서 컨테이너도 종료
- Ctrl + P, Ctrl + Q를 순차적으로 눌러 컨테이너 실행 상태를 유지할 채로 빠져나옴
docker stop [컨테이너]
-> 실행 중인 컨테이너 종료
root@DH:~# docker stop testos
testos
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
151f3b70b5a4 centos "/bin/bash" 8 minutes ago Exited (0) 19 seconds ago testos
컨테이너가 종료(Exited)된 것을 확인할 수 있다.
docker run [이미지]
-> create + start
-> 로컬에 이미지가 있다면 해당 이미지로 생성 및 실행, 없으면 도커허브에서 다운로드 후 실행
-> 컨테이너를 시작하고 command를 샐행
root@DH:~# docker run -dit --name test centos
5d56fc765e3780fb06f5f3d5a66935e1a087087d7b9ab69e979e830773603a81
root@DH:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d56fc765e37 centos "/bin/bash" 1 second ago Up 1 second test
-d 옵션을 사용해 사용자가 직접 컨테이너 안으로 접근하지 않고, 컨테이너의 command를 백그라운드로 실행할 수 있다.
컨테이너를 시작할 때, 명령어의 맨 뒤에 임의로 COMMAND를 정의할 수 있다.
root@DH:~# docker run -it --name date centos /bin/date
Tue Jun 28 08:56:41 UTC 2022
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24a654120847 centos "/bin/date" About a minute ago Exited (0) About a minute ago date
command(/bin/date)가 종료되면서 컨테이너도 함께 종료된 것을 확인할 수 있다.
shell의 환경 정보를 옵션으로 정의하는 것도 가능하다.
root@DH:~# docker run -it --name test -w "/tmpdir" -e "MYNAME=DH" centos
[root@8e01dc01c6f7 tmpdir]# pwd
/tmpdir
[root@8e01dc01c6f7 tmpdir]# echo $MYNAME
DH
옵션 | 설명 |
-w (--workdir) | 컨테이너의 작업 디렉토리 설정 |
-e (--env) | 환경 변수 설정 |
--env-file=[파일명] | 정의해야 하는 환경 변수가 많은 경우 특정 파일을 호출해서 설정 가능 |
restart 옵션을 통해 정해진 규칙에 따라 자동으로 재시작 가능하다.
root@DH:~# docker run -it --name test --restart always centos
[root@8dfcdfd3c5c6 /]# exit
exit
root@DH:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8dfcdfd3c5c6 centos "/bin/bash" 16 seconds ago Up 3 seconds test
동작 중인 컨테이너에서 exit을 하면 종료가 되어야 하는데 restart 옵션을 always로 설정했기 때문에 종료되어도 다시 시작(Up) 된 것을 확인할 수 있습니다.
옵션 | 키워드 | 설명 |
--restart |
no | 재시작하지 않음 |
on-failure | 종료 상태(Exited code)가 0이 아닌 경우 재시작 | |
on-failure:횟수(n) | 종료 상태(Exited code)가 0이 아닌 경우 n회 재시작 | |
always | 항상 재시작 |
docker attach [컨테이너]
-> 컨테이너 내부에 접근하여 STDIN/STDOUT/STDERR를 사용
-> 컨테이너 PID=1 표준 입출력을 이용
root@DH:~# docker run -it --name test centos
[root@c8137246c2de /]# [Ctrl + p, Ctrl + q]
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8137246c2de centos "/bin/bash" 29 seconds ago Up 29 seconds test
root@DH:~# docker attach test
[root@c8137246c2de /]# ps -e
PID TTY TIME CMD
1 pts/0 00:00:00 bash
15 pts/0 00:00:00 ps
docker exec [컨테이너] [명령어]
-> 동작 중인 컨테이너에 새로운 프로세스를 실행
-> command 말고 별도의 명령어를 실행
root@DH:~# docker run -d --name web httpd
4e02c31135d3eb2dda8dcdb8fd83b97d3aa0805ddb50235b5efbc71dfa19b604
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e02c31135d3 httpd "httpd-foreground" 2 seconds ago Up 1 second 80/tcp web
root@DH:~# docker exec -it web /bin/bash
root@4e02c31135d3:/usr/local/apache2#
웹서버 같은 경우는 COMMAND(PID=1)가 httpd로 정의되고, 쉘이 실행되지 않기 때문에 docker attach로 명령 입력이 불가능하다.
때문에 쉘에 접근하기 위해서는 개별적으로 실행을 해줘야 한다.
docker logs [컨테이너]
-> 컨테이너의 PID=1 프로세스의 STDIN/STDOUT/STDERR를 출력 가능
root@DH:~# docker run -dit --name pingtest centos /bin/ping localhost
85421d90d372895c5cc9f0219ffd6235c3536e31c9dde1eacdd641803999d59c
root@DH:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85421d90d372 centos "/bin/ping localhost" 3 seconds ago Up 2 seconds pingtest
root@DH:~# docker logs -f pingtest
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.036 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.069 ms
root@DH:~# docker logs -ft pingtest
2022-06-29T02:40:10.275963929Z PING localhost (127.0.0.1) 56(84) bytes of data.
2022-06-29T02:40:10.276917834Z 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.019 ms
2022-06-29T02:40:11.277869637Z 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.036 ms
옵션 | 설명 |
-f (--follow) | 실시간으로 로그를 추적, 출력 |
-t (--timestamp) | 타임스탬프 출력 |
docker stats [컨테이너]
-> 동작 중인 컨테이너의 상태와 사용 중인 리소스의 양을 확인할 때 사용
-> 상태 확인이 끝나면 Ctrl + C를 눌러 명령을 종료
root@DH:~# docker run -dit --name test --cpus=0.3 stress
e1f401b606f3c1cbee21f2bbe83a656cf22c1382495055076451ceef90aee7d4
root@DH:~# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e1f401b606f3 test 29.31% 752KiB / 12.36GiB 0.01% 906B / 0B 0B / 0B 4
부하 테스트를 할 수 있는 임의의 컨테이너(test)를 실행시킨 후, docker stats으로 확인해 보았다.
키워드 | 설명 |
CONTAINER ID | 컨테이너 ID |
NAME | 컨테이너 이름 |
CPU % | CPU 사용률 |
MEM USAGE / LIMIT | 메모리 사용량 / 컨테이너에서사용할 수 있는 메모리 제한 |
MEM % | 메모리 사용률 |
NET I/O | 네트워크 I/O |
BLOCK I/O | 블록 I/O |
PIDS | 사용 중인 PID의 수 (프로세스의 수) |
docker top [컨테이너]
-> 동작 중인 컨테이너에서 실행되고 있는 프로세스를 확인
root@DH:~# docker run -dit --name test centos
e900da8137a077c9a82f3936899e9ac0d3f167a6a6e759cfacdcce17ef940979
root@DH:~# docker top test
UID PID PPID C STIME TTY TIME CMD
root 3947 3927 0 05:45 ? 00:00:00 /bin/bash
컨테이너 내부 격리 환경에서 각 프로세스는 PID 1번이지만, 전체 운영체제에서의 PID가 출력됩니다.
docker pause/unpause [컨테이너]
-> 컨테이너 일시 중지/일시 중지된 컨테이너 재시작
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e900da8137a0 centos "/bin/bash" 6 minutes ago Up 5 minutes test
root@DH:~# docker pause test
test
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e900da8137a0 centos "/bin/bash" 6 minutes ago Up 6 minutes (Paused) test
root@DH:~# docker attach test
You cannot attach to a paused container, unpause it first
root@DH:~# docker unpause test
test
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e900da8137a0 centos "/bin/bash" 6 minutes ago Up 6 minutes test
docker ps -a로 STATUS에 Paused가 출력되는 것을 확인할 수 있다.
동작 중인 컨테이너를 pause 명령어를 사용하여 일시 중지한 뒤에 attach 명령어로 접근을 시도하면 당연히 접근이 되지 않는다.
unpause 명령어로 일시 중지된 컨테이너를 재시작 해주어야 접근이 가능하다.
docker rm [컨테이너]
-> 컨테이너를 삭제
docker rmi [이미지] -> 이미지를 삭제
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2cbeab5acfb0 centos "/bin/bash" 9 seconds ago Exited (0) 8 seconds ago test2
e900da8137a0 centos "/bin/bash" 12 minutes ago Up 12 minutes test
root@DH:~# docker rm test
Error response from daemon: You cannot remove a running container e900da8137a077c9a82f3936899e9ac0d3f167a6a6e759cfacdcce17ef940979. Stop the container before attempting removal or force remove
root@DH:~# docker rm test2
test2
root@DH:~# docker rm -f test
test
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
rm 명령어를 사용해 종료된 컨테이너를 삭제할 수 있다.
동작 중인(Up) 컨테이너를 삭제하려면 stop 명령어를 사용해 종료(Exited) 후 삭제하거나,
rm 명령어에 -f 옵션을 사용해 삭제할 수 있다.
docker container prune
-> 종료(Exited) 된 컨테이너를 일괄적으로 삭제
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c6044f6e3d7e centos "/bin/bash" 44 seconds ago Exited (0) 43 seconds ago test4
7486f75a31e5 centos "/bin/bash" 51 seconds ago Exited (0) 51 seconds ago test3
b22e767a3965 centos "/bin/bash" 59 seconds ago Up 58 seconds test2
54ca84644b86 centos "/bin/bash" About a minute ago Up About a minute test
root@DH:~# docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
c6044f6e3d7eeda4d692ecb848ec52d01d22681238d5c4d2b2f430df9ae6b06f
7486f75a31e5fb22120de3ed0bd45fa65cfcd5c940981d4625dbc241ea87150f
Total reclaimed space: 0B
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b22e767a3965 centos "/bin/bash" About a minute ago Up About a minute test2
54ca84644b86 centos "/bin/bash" About a minute ago Up About a minute test
prune 명령어를 사용하려면 앞에 [대상]을 명시해주어야 한다.
ex) container, image, network, volume, system
docker cp [복사할 대상] [복사시킬 대상]
-> 컨테이너와 호스트 간의 파일 복사
-> 컨테이너 안의 디렉터리를 지정하려면 [컨테이너명:경로]의 구조로 지정
root@DH:~# touch example.txt
root@DH:~# ls
example.txt
root@DH:~# docker run -dit --name test centos
5e43e97c988e78202f4d6dcb2b68b153c0a3c91e80ac2bdb5b8b7ae2a39f0592
root@DH:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e43e97c988e centos "/bin/bash" 6 seconds ago Up 5 seconds test
root@DH:~# docker cp ~/example.txt test:/
root@DH:~# docker exec test /bin/ls example.txt
example.txt
root@DH:~# docker cp test:/example.txt ~/example2.txt
root@DH:~# ls
example.txt example2.txt
docker diff
-> 컨테이너가 생성된 시점부터 변경된 이력을 확인
-> writable layer의 변경 여부를 확인
-> A(Add)는 추가된 이력, C(Change)는 변경된 이력, D(Delete)는 삭제된 이력을 의미
root@DH:~# docker run -it --name test centos
[root@ba258fff1ae8 /]# useradd containeruser
[root@ba258fff1ae8 /]# [Ctrl + p, Ctrl + q]
root@DH:~# docker diff test
C /home
A /home/containeruser
A /home/containeruser/.bash_logout
A /home/containeruser/.bash_profile
A /home/containeruser/.bashrc
C /etc
A /etc/subuid-
C /etc/subgid
C /etc/passwd-
C /etc/shadow
C /etc/group
A /etc/subgid-
C /etc/subuid
C /etc/gshadow
C /etc/shadow-
C /etc/gshadow-
C /etc/passwd
C /etc/group-
C /var
C /var/log
C /var/log/lastlog
C /var/spool
C /var/spool/mail
A /var/spool/mail/containeruser