이번에는 Docker Container 명령어들에 데하여 한번 알아보겠습니다.
이미지는 읽기 전용의 불변 값으로 만들어집니다. 이러한 이미지를 바탕으로 도커 엔진은 컨테이너를 생성할 수 있습니다. 이때 이미지와 함께 읽고 쓰기가 가능한 레이어를 추가해서 만들어지는 것이 컨테이너 입니다. 이번에는 컨테이너 구동, 접근, 로그, 운영 등의 명령을 다뤄보겠습니다. 이미지와 마찬가지로 컨테이너 명령도 dockerd 데몬이 제공하는 docker CLI API를 통해 제공됩니다.
도커 이미지는 컨테이너 동작과 관련된 콘텐츠를 제공하고 이를 바탕으로 컨테이너의 동작이 이루어 집니다. 따라서 컨테이너 명령 대부분이 서비스 실행 및 운영과 관련되어 있습니다.
Container는 Process다
도커 컨테이너는 앞서 배운 도커 이미지를 기반으로 만들어지는 스냅숏(snapshot)입니다. 이 스냅숏은 읽기 전용의 도커 이미지 레이어를 (불변의 유닉스 파일 시스템을) 복제한 것이고, 그 위에 읽고 쓰기가 가능한 컨테이너 레이어를 결합하면 컨테이너가 됩니다. 이러한 레이어들만 가지고 애플리케이션이 동작하는 것일까요?
컴퓨터 애플리케이션의 동작은 프로세스(process)를 통해 이루어집니다. “컨테이너는 격리된 공간에서 프로세스가 동작하는 기술.” 이라는 말을 기억 해보겠습니다. 컨테이너는 바로 프로세스 격리 기술(namespaces, cgroups, chroot)의 표준으로 정의된 OCI(Open Container Initiative)로 컨테이너 포맷과 런타임에 대한 개방형 업계 표준을 만들기 위한 목적으로 리눅스 파운데이션(Linux Foundation)의 지원을 받아 구성된 오픈 프로젝트 입니다.
명령어 docker run을 사용하면 컨테이너가 동작하게 되고, 가상의 격리 환경에 독립된 프로세스가 동작합니다. 마치 서버 호스트 운영체제가 독립적으로 동작하는 것과 유사하다고 보시면 됩니다. 예를 들어, 리눅스 호스트 운영체제를 부팅하면 PID 1번은 init(systemd) 프로세스가 동작하며 이 프로세스는 나머지 모든 시스템 프로세스의 부모 프로세스가 됩니다.
이처럼 독립된 호스트 운영체제는 init 프로세스와 같은 최상위 부모 프로세스가 필요합니다. 그럼 도커 컨테이너의 PID 1번 프로세스는 init 프로세스일까? 간단한 테스트를 통해 확인해 보갰습니다.
# 현재 host에서 실행중인 shell process id
toby@tobykakao:~$ echo $$
3271
# centos 8 버전 이미지 다운로드 후 Container bash 모드로 접속
toby@tobykakao:~$ docker run -it centos:8 bash
[root@9edeb3472cb8 /]# echo $$
1
[root@9edeb3472cb8 /]# exit
exit
# 다른 터미널에서 실행중인 PID 조회
toby@tobykakao:~$ ps -ef | grep 3271
toby 3271 3263 0 11:38 pts/0 00:00:00 bash
toby 13626 3271 99 11:57 pts/0 00:00:00 ps -ef
toby 13627 3271 0 11:57 pts/0 00:00:00 grep --color=auto 3271
# /proc와 하위 namespace(ns) 경로 확인
toby@tobykakao:~$ cd /proc/3271
toby@tobykakao:/proc/3271$ ls -l
total 0
dr-xr-xr-x 2 toby toby 0 Nov 1 11:59 attr
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 autogroup
-r-------- 1 toby toby 0 Nov 1 11:59 auxv
-r--r--r-- 1 toby toby 0 Nov 1 11:59 cgroup
--w------- 1 toby toby 0 Nov 1 11:59 clear_refs
-r--r--r-- 1 toby toby 0 Nov 1 11:55 cmdline
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 comm
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 coredump_filter
-r--r--r-- 1 toby toby 0 Nov 1 11:59 cpuset
lrwxrwxrwx 1 toby toby 0 Nov 1 11:55 cwd -> /proc/3271
-r-------- 1 toby toby 0 Nov 1 11:55 environ
lrwxrwxrwx 1 toby toby 0 Nov 1 11:54 exe -> /usr/bin/bash
dr-x------ 2 toby toby 4 Nov 1 11:55 fd
dr-xr-xr-x 2 toby toby 0 Nov 1 11:59 fdinfo
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 gid_map
-r-------- 1 toby toby 0 Nov 1 11:59 io
-r-------- 1 toby toby 0 Nov 1 11:59 ksm_merging_pages
-r-------- 1 toby toby 0 Nov 1 11:59 ksm_stat
-r--r--r-- 1 toby toby 0 Nov 1 11:59 latency
-r--r--r-- 1 toby toby 0 Nov 1 11:59 limits
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 loginuid
dr-x------ 2 toby toby 0 Nov 1 11:55 map_files
-r--r--r-- 1 toby toby 0 Nov 1 11:55 maps
-rw------- 1 toby toby 0 Nov 1 11:59 mem
-r--r--r-- 1 toby toby 0 Nov 1 11:59 mountinfo
-r--r--r-- 1 toby toby 0 Nov 1 11:59 mounts
-r-------- 1 toby toby 0 Nov 1 11:59 mountstats
dr-xr-xr-x 54 toby toby 0 Nov 1 11:59 net
dr-x--x--x 2 toby toby 0 Nov 1 11:59 ns
-r--r--r-- 1 toby toby 0 Nov 1 11:59 numa_maps
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 oom_adj
-r--r--r-- 1 toby toby 0 Nov 1 11:59 oom_score
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 oom_score_adj
-r-------- 1 toby toby 0 Nov 1 11:59 pagemap
-r-------- 1 toby toby 0 Nov 1 11:59 personality
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 projid_map
lrwxrwxrwx 1 toby toby 0 Nov 1 11:55 root -> /
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 sched
-r--r--r-- 1 toby toby 0 Nov 1 11:59 schedstat
-r--r--r-- 1 toby toby 0 Nov 1 11:59 sessionid
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 setgroups
-r--r--r-- 1 toby toby 0 Nov 1 11:59 smaps
-r--r--r-- 1 toby toby 0 Nov 1 11:59 smaps_rollup
-r-------- 1 toby toby 0 Nov 1 11:59 stack
-r--r--r-- 1 toby toby 0 Nov 1 11:38 stat
-r--r--r-- 1 toby toby 0 Nov 1 11:59 statm
-r--r--r-- 1 toby toby 0 Nov 1 11:55 status
-r-------- 1 toby toby 0 Nov 1 11:59 syscall
dr-xr-xr-x 3 toby toby 0 Nov 1 11:59 task
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 timens_offsets
-r--r--r-- 1 toby toby 0 Nov 1 11:59 timers
-rw-rw-rw- 1 toby toby 0 Nov 1 11:59 timerslack_ns
-rw-r--r-- 1 toby toby 0 Nov 1 11:59 uid_ma
# 호스트 운영체제의 PID 1번과 현재 host에서 실행중인 shell process 비교
toby@tobykakao:/$ sudo ls -l /proc/1/ns
total 0
lrwxrwxrwx 1 root root 0 Nov 1 11:34 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 Nov 1 11:35 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 net -> 'net:[4026531840]'
lrwxrwxrwx 1 root root 0 Nov 1 11:55 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Nov 1 12:00 uts -> 'uts:[4026531838]'
toby@tobykakao:/$ sudo ls -l /proc/3271/ns
total 0
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 net -> 'net:[4026531840]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 time -> 'time:[4026531834]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 user -> 'user:[4026531837]'
lrwxrwxrwx 1 toby toby 0 Nov 1 12:01 uts -> 'uts:[4026531838]'
위의 내용을 정리해 보면 docker run~ 수행 시 PID 네임스페이스 커널 기능을 통해 시스템의 1번 프로세스(init)의 PID(4026531836)를 공유하고 그 하위로 프로세스를 격리합니다. 이렇게 격리된 프로세스를 루트로 변경하는 chroot 커널 기능을 통해 독립된 1번 PID를 갖게 되고, 컨테이너 동작 시 필요한 자원에 대한 할당은 cgroups 커널 기능을 통해 이루어집니다.
따라서, 도커 컨테이너를 이해하기 위해서는 컨테이너에 제공되는 커널 기술을 이해하는 것이 중요합니다. 이제부터 컨테이너를 실행, 운영, 관리하는 명령어에 대해 알아보겠습니다.
Container 실행
컨테이너의 실행을 위해 docker run 명령을 사용하면 해당 도커 이미지 복사본 스냅숏 레이어 위에 읽고 쓰기가 가능한 컨테이너 레이어를 추가한 뒤 docker start 명령으로 컨테이너를 시작합니다. 이렇게 실행된 컨테이너를 조회하는 방법은 docker ps 명령을 사용하는 것입니다. 리눅스 명령어인 ps(Process Status)는 리눅스 호스트에서 실행 중인 프로세스를 조회하는 방법을 제공합니다. 이처럼 컨테이너 또한 프로세스라는 의미에서 docker ps 명령어를 사용하는 것입니다.
docker run은 상당히 많은 옵션을 가지고 있습니다. 그만큼 컨테이너 내부의 애플리케이션 동작을 세세하게 제어할 수 있다는 의미이기도 하다. 여기서는 주요 옵션만 다뤄보겠습니다. 한번 docker run 명령을 사용하기 전에 수동으로 컨테이너를 제어하는 과정을 실습해 보겠습니다.
# docker create는 run과 달리 container 내부 접근을 하지 않고 생성(snapshot)만 수행
toby@tobykakao:/$ docker create -it --name container-test1 ubuntu:14.04
Unable to find image 'ubuntu:14.04' locally
14.04: Pulling from library/ubuntu
d1a5a1e51f25: Pull complete
75f8eea31a63: Pull complete
a72d031efbfb: Pull complete
Digest: sha256:64483f3496c1373bfd55348e88694d1c4d0c9b660dee6bfef5e12f43b9933b30
Status: Downloaded newer image for ubuntu:14.04
513f21b43af310b4769680c0e795f087aca3e2b9c6a93998036a1f410cc6aead
toby@tobykakao:/$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
513f21b43af3 ubuntu:14.04 "/bin/bash" About a minute ago Created container-test1
# docker ps 명령의 status를 보면 start가 아닌 'created'임을 알 수 있다
# 생성된 snapshot을 동작시킨다.
toby@tobykakao:/$ docker start container-test1
container-test1
toby@tobykakao:/$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
513f21b43af3 ubuntu:14.04 "/bin/bash" 3 minutes ago Up 4 seconds container-test1
# Container에 접속해 보겠습니다. (docker attach 명령은 실행중인 어플리케이션 컨테이너에 단순한 조회 작업시에 유용)
toby@tobykakao:~$ docker attach container-test1
root@513f21b43af3:/#
root@513f21b43af3:/# exit
exit
# 빠져나온 컨테이너가 강제 종료되어 삭제된다.
toby@tobykakao:~$ docker rm container-test1
container-test1
- 위의 작업으로 Docker run을 수행하면 다음과 같이 나옵니다.
toby@tobykakao:~$ docker attach container-test1
root@513f21b43af3:/#
root@513f21b43af3:/# exit
exit
toby@tobykakao:~$ docker rm container-test1
container-test1
toby@tobykakao:~$ docker run -it --name container-test1 ubuntu:14.04 bash
root@f534ea7ec0c3:/# exit
exit
toby@tobykakao:~$ docker rm container-test1
container-test1
# 다른 터미널에서 docker ps를 통해 실행된 container를 조회한다
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb81a4675f5 ubuntu:14.04 "bash" 45 seconds ago Up 44 seconds container-test1
# 컨테이너의 호스트명을 조회한다.
$ docker run -it --name container-test1 ubuntu:14.04 hostname
6938b859424f
추가되는 docker run의 특징은 호스트 서버에 ubuntu:14.04 이미지가 다운로드되어 있지 않아도 로컬에 존재하지 않는 이미지를 도커 허브에서 자동으로 다운로드한다는 점과 마지막에 해당 컨테이너에 실행할 명령을 입력하면 컨테이너 동작과 함께 처리된다는 점이 있습니다.
docker run = [pull] + create + start + [command]
docker run에서 자주 사용하는 옵션은 아래 표에 정리해 보겠습니다.
옵션 | 설명 |
-i, --interactive | 대화식 모드 열기 |
-t | TTY(단말 디바이스) 할당 |
-d, --detach=true | 백그라운드에서 컨테이너 실행 후 컨테이너 ID 등록 |
--name | 실행되는 컨테이너에 이름 부여(미지정 시 자동으로 부여됨; 딕셔너리 워드 랜덤 선택) |
--rm | 컨테이너 종료 시 자동으로 컨테이너 제거 |
--restart | 컨테이너 종료 시 적용할 재시작 정책 지정 (no, on-failure, always, unless-stopped) |
--env | 컨테이너의 환경 변수 지정 (--env-file은 여러 환경 변수를 파일로 생성하여 지정하는 방법) |
-v, --volume=호스트경로:컨테이너경로 | 호스트 경로와 컨테이너 경로의 공유 볼륨 설정 (Bind mount) |
-h | 컨테이너의 호스트명 지정 (미지정 시 컨테이너 ID가 호스트명으로 등록) |
-p [Host 포트]:[Container 포트], --publish | 호스트 포트와 컨테이너 포트 연결 |
-P, --publish-all=[true | false] | 컨테이너 내부의 노출된 (expose)된 포트를 호스트 임의의 포트에 게시 |
--link=[container:container_id] | 동일 호스트의 다른 컨테이너와 연결 설정으로 IP가 아닌 컨테이너의 이름을 이용해 통신 |
한번 여러가지 docker run 명령을 사용해 보겠습니다.
toby@tobykakao:~$ docker pull mysql:8.0
8.0: Pulling from library/mysql
8b4274ea61c5: Already exists
08ba006fa9b4: Already exists
92a1aa4ee2ea: Already exists
df48654477e3: Already exists
a3bc7a62e19a: Already exists
ac2152ccfb17: Pull complete
4855413356a2: Pull complete
e050fccf8a37: Pull complete
f0f86890bcfb: Pull complete
92dde3d18839: Pull complete
ad11f03a0bf4: Pull complete
Digest: sha256:bf79508626d6cad5bd82ea762109690e42467b1eefedab27946eccd69ab23069
Status: Downloaded newer image for mysql:8.0
docker.io/library/mysql:8.0
toby@tobykakao:~$ docker images | grep mysql
mysql8 1.0 257c7d00682b 35 hours ago 618MB
mysql 8 07b15f39a8d0 2 weeks ago 600MB
mysql 8.0 e5b1f8113899 2 weeks ago 608MB
toby@tobykakao:~$ docker run -it mysql:8.0 /bin/bash
bash-5.1# cat /etc/os-release
NAME="Oracle Linux Server"
VERSION="9.4"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Oracle Linux Server 9.4"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:9:4:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"
ORACLE_BUGZILLA_PRODUCT="Oracle Linux 9"
ORACLE_BUGZILLA_PRODUCT_VERSION=9.4
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=9.4
# Container Stop - docker ps -a로 조회
toby@tobykakao:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b89bf83a0bf6 mysql:8.0 "docker-entrypoint.s\u2026" 5 minutes ago Exited (1) 2 seconds ago interesting_volhard
9edeb3472cb8 centos:8 "bash" 28 minutes ago Exited (0) 27 minutes ago optimistic_blackwell
b0efa09a7449 centos:8 "bash" 29 minutes ago Exited (130) 28 minutes ago sweet_hofstadter
da6c698a2077 httpd:latest "/bin/bash" 4 days ago Exited (129) 4 days ago webserver
2f2917a74b78 nginx "/docker-entrypoint.\u2026" 3 weeks ago Exited (255) 2 weeks ago 0.0.0.0:80->80/tcp, :::80->80/tcp webapp
8ad81ee3e360 busybox "echo 'Hello World'" 3 weeks ago Exited (0) 3 weeks ago zealous_jones
12a314e0ce74 busybox "sh" 3 weeks ago Exited (0) 3 weeks ago clever_archimedes
1d28ecb555b4 busybox "sh" 3 weeks ago Exited (0) 3 weeks ago
# 컨테이너 stop! 후 docker ps -a로 조회.
toby@tobykakao:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba5adeb0ddcb mysql:5.7 "docker-entrypoint.s…" 54 seconds ago Exited (0) 3 seconds ago competent_chaplygin
...
# docker start로 컨테이너 이름, ID를 통해 시작 가능.
toby@tobykakao:~$ docker start ba5adeb0ddcb
ba5adeb0ddcb
# docker ps
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba5adeb0ddcb mysql:5.7 "docker-entrypoint.s…" About a minute ago Up 5 seconds 3306/tcp, 33060/tcp upbeat_ellis
# docker exec를 이용하여 container에 접근.
toby@tobykakao:~$ docker exec -it ba5adeb0ddcb bash
root@ba5adeb0ddcb:/# cd /var/lib/mysql
root@ba5adeb0ddcb:/var/lib/mysql# ls
... dockerdb
# 종료시키지 않고 컨테이너를 빠져나가려면 ctrl + p + q를 동시에 입력.
root@ba5adeb0ddcb:/#
# 컨테이너 내부 IP 확인. 컨테이너 이름은 도커에서 자동 지정됨.
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4f8e315344ef mysql:5.7 "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 3306/tcp, 33060/tcp flamboyant_nash
$ docker inspect flamboyant_nash | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.5",
"IPAddress": "172.17.0.5",
# 컨테이너 재접속.
toby@tobykakao:~$ docker exec -it flamboyant_nash bash
root@ba5adeb0ddcb:/#
# 위 실습과 같은 명령을 다른 터미널에서 새로 실행하면 새로운 컨테이너가 새로운 이름으로 실행됨.
toby@tobykakao:~$ docker run -it mysql:5.7 bash
root@ba5adeb0ddcb:/#
Container 모니터링 도구 cAdvisor Container 실행
MacBook - ARM64 환경에서는 작동 X → 지원 안함. (제가 테스트 해보기엔..? 아닐수도 있습니다.)
- 서비스 운영을 하면서 필요한 시스템 Metric(CPU/메모리 사용률, 네트워크 트래픽 등)을 모니터링 하면서 특이사항이 있을 때 대응하기 위해 모니터링을 수행하는 역할을 합니다.
- 그러나 컨테이너라는 환경에서는 기존 모니터링 도구로는 container 모니터링 진행이 어렵습니다.
- 이러한 문제점을 해결하고 컨테이너를 모니터링하기 위한 도구로 구글에서 제공하는 cAdvisor(Container Advisor)를 많이 사용합니다.
toby@tobykakao:~$ docker run \
> --volume=/:/rootfs:ro \
> --volume=/var/run:/var/run:rw \
> --volume=/sys:/sys:ro \
> --volume=/var/lib/docker/:/var/lib/docker:ro \
> --publish=9559:8080 \
> --detach=true \
> --name=cadvisor \
> google/cadvisor:latest
Unable to find image 'google/cadvisor:latest' locally
latest: Pulling from google/cadvisor
ff3a5c916c92: Pull complete
44a45bb65cdf: Pull complete
0bbe1a2fe2a6: Pull complete
Digest: sha256:815386ebbe9a3490f38785ab11bda34ec8dacf4634af77b8912832d4f85dca04
Status: Downloaded newer image for google/cadvisor:latest
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
3c7f1ebd39ec1a4a66e9c4d204c7fadf40dd79d8bdc8356d133e53fad693a46a
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
08878e469965 google/cadvisor:latest "/usr/bin/cadvisor -..." 38 seconds ago Up 37 seconds 0.0.0.0:9559->8080/tcp cadvisor
웹 서비스 실행을 위한 Ngnix 컨테이너 실행 예제
Ngnix 컨테이너 실행 실습을 한번 해보겠습니다.
# Nginx 이미지를 다운로드
toby@tobykakao:~$ docker pull nginx:1.18
1.18: Pulling from library/nginx
15cb40b9c4df: Pull complete
f54db86c19cf: Pull complete
da53e28db95d: Pull complete
6d4f0a6cbe0d: Pull complete
2d9307d825c8: Pull complete
Digest: sha256:e90ac5331fe095cea01b121a3627174b2e33e06e83720e9a934c7b8ccc9c55a0
Status: Downloaded newer image for nginx:1.18
docker.io/library/nginx:1.18
# 이미지 확인
toby@tobykakao:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql8 1.0 257c7d00682b 4 days ago 618MB
debian latest d36fff645336 2 weeks ago 139MB
mysql 8 07b15f39a8d0 2 weeks ago 600MB
mysql 8.0 e5b1f8113899 2 weeks ago 608MB
nginx latest 048e09038596 4 weeks ago 197MB
busybox latest 63cd0d5fb10d 5 weeks ago 4.04MB
daehyunbigbread/httpd 3.0 721aa0022a96 3 months ago 178MB
debian-httpd 2.0 721aa0022a96 3 months ago 178MB
httpd latest 721aa0022a96 3 months ago 178MB
ubuntu 14.04 55b7b4f7c5d6 2 years ago 187MB
centos 8 e6a0117ec169 3 years ago 272MB
nginx 1.18 9b05b72dd160 3 years ago 126MB
google/cadvisor latest eb1210707573 5 years ago 69.6MB
# Nginx 컨테이너를 실행. 하나의 Nginx 서버 구동으로 보면 됨.
toby@tobykakao:~$ docker run --name webserver1 -d -p 8001:80 nginx:1.18
4185646d8fc886a5be5eabef950bd64553a61058a57c8f2900343b8be99b9d7f
- -d : 백그라운드 실행
- --name : 컨테이너 이름 지정
- -p : 호스트 포트와 컨테이너 포트 매핑 (호스트 8001 포트를 컨테이너의 80 포트로 연결)
# 컨테이너 상태 확인
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4185646d8fc8 nginx:1.18 "/docker-entrypoint.\u2026" 19 seconds ago Up 19 seconds 0.0.0.0:8001->80/tcp, [::]:8001->80/tcp webserver1
# 호스트의 8001 포트가 열린 것을 확인
toby@tobykakao:~$ sudo netstat -nlp | grep 8001
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 3879/docker-proxy
tcp6 0 0 :::8001 :::* LISTEN 3894/docker-proxy
# 접속 테스트
toby@tobykakao:~$ curl localhost:8001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 컨테이너의 리소스 사용량 실시간 확인
toby@tobykakao:~$ docker stats webserver1
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
4185646d8fc8 webserver1 0.00% 1.961MiB / 3.811GiB 0.05% 4.15kB / 1.27kB 0B / 20.5kB 2
# 컨테이너의 실행 중인 프로세스 표시
toby@tobykakao:~$ docker top webserver1
UID PID PPID C STIME TTY TIME CMD
root 3936 3916 0 11:52 ? 00:00:00 nginx: master process nginx -g daemon off;
message+ 3982 3936 0 11:52 ? 00:00:00 nginx: worker process
# 컨테이너 내부의 접근 로그를 실시간 확인 (-f: 실시간, -t: 마지막 로그까지).
$ docker logs -f webserver1
192.168.56.1 - - [01/Mar/2021:07:00:57 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36" "-"
...
# 컨테이너를 정지한다. (docker stop -t 10 webserver1, 옵션은 10초 후 정지)
@tobykakao:~$ docker stop webserver1
webserver1
# 컨테이너가 중지됨 확인.
toby@tobykakao:~$ curl localhost:8001
curl: (7) Failed to connect to localhost port 8001 after 0 ms: Couldn't connect to server
# 컨테이너 시작.
toby@tobykakao:~$ docker start webserver1
webserver1
# 접속 확인
toby@tobykakao:~$ curl localhost:8001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# Docker가 설치된 host의 ip 확인, 앞에 있는 주소를 사용하면 됨
toby@tobykakao:~$ hostname -I
192.168.64.7 172.17.0.1 fdaa:7355:ced7:d2ee:e1bb:425a:89e1:b26b fdaa:7355:ced7:d2ee:809b:7cff:fe76:af3b
# 브라우저를 이용한 접근 시도, 이 주소를 웹페이지에 입력하면 됨.
http://[도커가 설치된 호스트의 IP]:8001/
# 서버 주소 확인 (구동 확인 목적)
toby@tobykakao:~$ curl http://192.168.64.7:8001/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# nginx의 index.html 내용을 변경하여 테스트해 보자.
$ vi index.html
<h1> Hello, Jpub Docker. </h1>
# 도커 cp 명령을 통해 컨테이너 내부 index.html 파일 경로에 복사한다.
toby@tobykakao:~$ docker cp index.html webserver1:/usr/share/nginx/html/index.html
Successfully copied 2.05kB to webserver1:/usr/share/nginx/html/index.html
# curl로 변경된 내용 확인
toby@tobykakao:~$ curl localhost:8001
<h1> Hello, Kakao Docker. </h1>
# 연결된 브라우저에서 [F5]를 눌러 새로고침 한다.
Docker Container의 일시정지(pause), 일시정지 해제(unpause), 재시작(restart)사용
docker pause 명령은 지정된 컨테이너의 모든 프로세스를 일시 중단합니다. 리눅스에서는 freezer cgroup을 사용합니다.
# 프로세스를 일시 중지할 때 SIGSTOP 신호가 사용된다.
toby@tobykakao:~$ docker pause webserver1
webserver1
# 컨테이너 상태 확인 (Paused 상태로 표시됨)
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4185646d8fc8 nginx:1.18 "/docker-entrypoint.\u2026" 21 minutes ago Up 14 minutes (Paused) 0.0.0.0:8001->80/tcp, [::]:8001->80/tcp webserver1
# docker unpause 명령은 지정된 컨테이너의 모든 프로세스에서 일시 중단을 해제한다.
toby@tobykakao:~$ docker unpause webserver1
webserver1
# 컨테이너 상태 확인 (Paused 상태 해제됨)
toby@tobykakao:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4185646d8fc8 nginx:1.18 "/docker-entrypoint.\u2026" 21 minutes ago Up 15 minutes 0.0.0.0:8001->80/tcp, [::]:8001->80/tcp webserver1
- 컨테이너를 재시작하는 것은 기존 컨테이너의 프로세스를 정지하고 새로운 컨테이너 프로세스를 시작하는 것입니다.
- 컨테이너 동작에는 영향을 주지 않고, 호스트의 프로만 변경됩니다.
# (8001은 위 실습에서 nginx의 호스트 연결 포트를 사용)
toby@tobykakao:~$ ps -ef | grep 8001
root 4946 1175 0 11:59 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8001 -container-ip 172.17.0.2 -container-port 80
root 4958 1175 0 11:59 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 8001 -container-ip 172.17.0.2 -container-port 80
toby 5681 4796 50 12:16 pts/0 00:00:00 grep --color=auto 8001
# 컨테이너 재시작
toby@tobykakao:~$ docker restart webserver1
webserver1
# 재시작 후 확인
toby@tobykakao:~$ ps -ef | grep 8001
root 5753 1175 0 12:16 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8001 -container-ip 172.17.0.2 -container-port 80
root 5760 1175 0 12:16 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 8001 -container-ip 172.17.0.2 -container-port 80
toby 5843 4796 0 12:16 pts/0 00:00:00 grep --color=auto 8001
'☁️ Cloud' 카테고리의 다른 글
[Docker] Docker 명령어 활용 Part.2 (0) | 2024.10.31 |
---|---|
[Docker] Docker 명령어 활용 Part.1 (0) | 2024.10.31 |
[Cloud] Docker Installation Check (도커 설치 확인) (0) | 2024.10.11 |
[Cloud] Ubuntu에 Docker Community Edition (CE) 설치 (0) | 2024.10.08 |
[Cloud] Docker Install (도커 설치 with UTM, Ubuntu install) (0) | 2024.10.07 |