본문 바로가기
프로그래밍

[docker] 도커 기초 명령어

by choihyuunmin 2024. 5. 19.

도커를 사용하기 위한 기본 명령어와 작동 방식에 대해 알아보겠습니다.

mac 환경에 docker desktop을 통해 도커를 설치했습니다.

1. 도커 작동 방식

1-1. 도커의 구조

먼저 도커는 크게 세 가지로 구성됩니다.

1) 도커 클라이언트

2) 도커 호스트

3) 도커 레지스트리

의 구조를 가지게 됩니다.

각각 살펴보면, 도커 클라이언트는 사용자가 도커 엔진에 명령을 내리는 도구를 의미합니다. 도커 클라이언트를 통해 도커 호스트에 명령을 내려서 이미지, 컨테이너, 네트워크, 볼륨 등을 관리하는 역할을 합니다.

아래와 같이 docker 명령을 전달하는 터미널로 이해하면 됩니다.

> docker  

Usage:  docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Common Commands:
  run         Create and run a new container from an image
  exec        Execute a command in a running container
  ps          List containers
  build       Build an image from a Dockerfile
  pull        Download an image from a registry
  push        Upload an image to a registry
  images      List images
  login       Log in to a registry
  logout      Log out from a registry
  search      Search Docker Hub for images
  version     Show the Docker version information
  info        Display system-wide information

Management Commands:
  builder     Manage builds
  buildx*     Docker Buildx (Docker Inc., v0.11.0)
  checkpoint  Manage checkpoints
  compose*    Docker Compose (Docker Inc., v2.19.1)
  container   Manage containers
  context     Manage contexts
  dev*        Docker Dev Environments (Docker Inc., v0.1.0)
  extension*  Manages Docker extensions (Docker Inc., v0.2.20)
  image       Manage images
  init*       Creates Docker-related starter files for your project (Docker Inc., v0.1.0-beta.6)
  manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
  plugin      Manage plugins
  sbom*       View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc., 0.6.0)
  scan*       Docker Scan (Docker Inc., v0.26.0)
  scout*      Command line tool for Docker Scout (Docker Inc., 0.16.1)
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

도커 호스트는 도커가 설치되어 있는 물리적 혹은 가상머신의 운영체제 환경을 의미합니다. 도커를 통해 실행되는 컨테이너는 도커 호스트 내에서 작동합니다. 저는 mac에 도커를 직접 설치했으니, 저에게 있어 도커 호스트는 mac 운영체제가 작동중인 맥북이 되겠네요.

마지막으로 도커 레지스트리는 도커 컨테이너를 실행하기 위한 이미지를 저장하거나 배포하는 시스템입니다. 가장 널리 알려진 도커 레지스트리는 dockerhub입니다. 애플리케이션을 이미지 단위로 생성하여 공개 저장소에 올려놓으면 필요에 맞는 사람들이 내려받아서 사용하는 구조입니다. 개발자들이 자주 사용하는 github과 성격이 유사합니다.

공개된 레지스트리만 있는 것이 아닌 사설 저장소도 존재합니다. dockerhub에서 제공하는 registry이미지를 사용하여 local 환경에 사설 저장소를 구축할 수도 있습니다.

도커는 크게 build, pull, run의 과정을 거칩니다.

build는 어플리케이션을 이미지 단위로 만드는 과정을 의미하고, pull은 빌드된 이미지를 호스트에 가져오는 과정,

run은 가져온 이미지를 컨테이너로 실행시키는 역할을 합니다.

+-------------------------+
|        Dockerfile       |
+-------------------------+
            |
            | build
            v
+-------------------------+
|        Image            |
+-------------------------+
            |
            | push
            v
+-------------------------+
|        Docker Hub       |
+-------------------------+
            ^
            | pull
            |
+-------------------------+
|     Local Image Cache   |
+-------------------------+
            |
            | run
            v
+-------------------------+
|         Container       |
+-------------------------+

1-2. 도커의 이미지 및 컨테이너

위에서 build과정을 통해 이미지를 생성한다고 했습니다. 이미지란 무엇일까요?

이미지란 도커의 탄생한 배경에서도 알 수 있듯이, 의존성을 고려할 필요없이 어느 환경에서든 배포 가능하게 필요한 모든 요소를 실행할 수 있게끔 빌드한 패키지입니다. 이미지는 특정 컨테이너의 시점과 상태를 저장한 스냅숏(snapshot) 형태로도 만들어질 수 있습니다.

만들어진 도커 이미지를 통해 동일한 환경의 컨테이너를 생성할 수 있습니다.

도커 컨테이너는 이미지로부터 생성된 인스턴스를 의미합니다.

실행된 컨테이너는 토커 클라이언트를 통해 중지, 재실행, 삭제 등의 명령을 내릴 수 있습니다.

컨테이너는 자체적으로 파일시스템을 가질 수 있습니다.

컨테이너는 자체적으로 파일시스템을 가지게 됩니다. 또한, 커널을 호스트 운영체제와 공유하기 때문에 가상이미지보다 가볍다는 장점이 있습니다. 실제로 컨테이너 내부의 커널을 살펴보게 되면, 호스트 운영체제의 커널과 같은 것을 확인할 수 있습니다.

> uname -a
Linux ubun20-01 5.4.0-177-generic #197-Ubuntu SMP Thu Mar 28 22:51:24 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux

> docker exec -it centos-test /bin/bash
[root@centos-test /]# uname -a
Linux centos-test 5.4.0-177-generic #197-Ubuntu SMP Thu Mar 28 22:51:24 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux

하지만 격리되어 있는 환경이기 때문에 패키지, 라이브러리와 같은 소프트웨어 환경은 호스트와 다르기 때문에 컨테이너 내부에서 설치해주어야합니다.

2. 도커 기초 명령어

도커의 기초 명령어에 대해 알아봅니다.

도커 명령어를 실행하기 위해서는 도커 데몬이 실행되고 있어야합니다.

만약, 도커가 실행되고 있지 않다면 아래와 같은 메시지를 반환합니다.

> docker images 
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

맥과 윈도우 기준으로는 도커 데스크톱을 실행시키면 도커 데몬이 함께 실행됩니다.

리눅스 계열의 운영체제는 시스템 명령어를 통해 실행여부를 확인하고, 만약 실행되고 있지 않다면 직접 실행시켜줍니다.

- 실행중이 아닌 상태

> systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Mon 2024-05-20 11:09:03 UTC; 2s ago

- 실행중인 상태

> systemctl start docker
> systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-05-20 11:09:46 UTC; 11s ago

Active 상태의 deadrunning을 확인합니다.

2-1. 도커 이미지

  • docker images : pull로 가져온 로컬상의 이미지들을 보여줍니다. REPOSITORY는 이미지의 이름, TAG 는 이미지의 버전, IMAGE ID는 이미지의 고유한 아이디를 의미합니다. CREATED는 이미지가 만들어진 시간, SIZE는 이미지의 크기를 의미합니다.

  • docker image pull : 도커 레지스트리에 있는 이미지를 호스트로 가져옵니다.

  • docker image push : 도커 레지스트리로 이미지를 업로드합니다.
  • docker image build : Dockerfile로부터 이미지를 빌드합니다.
  • docker image ls : 이미지의 목록을 확인합니다.(docker images와 같은 결과)
  • docker image rm : 로컬에 있는 도커의 이미지를 삭제합니다.

  • docker image load : tar파일 형태의 이미지를 load합니다.

2-2. 도커 컨테이너

  • docker container run : 생성된 이미지로부터 컨테이너를 실행합니다.
  • docker container ls : 컨테이너의 목록을 확인합니다.

  • docker container run -it : 컨테이너를 실행하고 내부로 진입합니다. it 옵션 뒤에 사용할 쉘을 입력합니다. 보통 bash쉘을 이용합니다.
  • docker container stop : 실행중인 컨테이너를 중지합니다.
  • docker container restart : 하나 이상의 컨테이너를 재실행합니다.
  • docker container rm : 하나 이상의 컨테이너를 삭제합니다.

2-3. 이미지 변경

도커는 레지스트리에서 받은 이미지를 본인의 특성에 맞게 수정한 후 변경된 내용을 적용하여 다시 이미지로 빌드할 수 있는 기능을 제공합니다. docker container commit 명령어를 사용하여 현재 상태의 컨테이너를 이미지 상태로 저장합니다.

ubuntu 이미지를 받아서 실행시키면 net-tools 패키지가 설치되어 있지 않아 ifconfig 명령어를 실행할 수 없습니다.

net-tools를 설치한 ubuntu 컨테이너를 새로운 이미지로 만드는 과정을 실습해보겠습니다.

1) ubuntu 이미지 pull

> docker image pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
9502885e1cbc: Pull complete
Digest: sha256:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

2) ubuntu 컨테이너 실행 및 내부 진입

> docker container run -it ubuntu
root@3380d00c6eb1:/# ifconfig
bash: ifconfig: command not found
root@3380d00c6eb1:/#

ifconfig 명령어를 실행하면 command를 찾을 수 없다는 메시지가 반환됩니다.

3) net-tools 설치 및 컨테이너 commit

root@3380d00c6eb1:/# ifconfig
bash: ifconfig: command not found
root@3380d00c6eb1:/#
root@3380d00c6eb1:/#
root@3380d00c6eb1:/#
root@3380d00c6eb1:/# apt update && apt install net-tools                                                                                             3132 kB                                                                                                                                                                Get:13 http://ports.ubuntu.com/ubuntu-ports noble-security/universe arm64 Packages [18.3 kB]
99% [13 Packages 12.8 kB/18.3 kB 70%]                                                                                                                  3132 kB/s99% [Working]                                                                                                                                          3132 kB/s99% [13 Packages store 0 B]                                                                                                                            3132 kB/s100% [Working]                                                                                                                                         3132 kB/s                                                                                                                                                                Fetched 21.8 MB in 8s (2740 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  net-tools
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 207 kB of archives.
After this operation, 1229 kB of additional disk space will be used.
Get:1 http://ports.ubuntu.com/ubuntu-ports noble/main arm64 net-tools arm64 2.10-0.1ubuntu4 [207 kB]
Fetched 207 kB in 2s (120 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package net-tools.
(Reading database ... 4363 files and directories currently installed.)
Preparing to unpack .../net-tools_2.10-0.1ubuntu4_arm64.deb ...
Unpacking net-tools (2.10-0.1ubuntu4) ...
Setting up net-tools (2.10-0.1ubuntu4) ...
root@3380d00c6eb1:/#
root@3380d00c6eb1:/#
root@3380d00c6eb1:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 65535
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 2102  bytes 22183914 (22.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1141  bytes 78943 (78.9 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
        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
> docker container ls   
CONTAINER ID   IMAGE                       COMMAND                   CREATED             STATUS                 PORTS                              NAMES
3380d00c6eb1   ubuntu                      "/bin/bash"               About an hour ago   Up About an hour                                          agitated_dubinsky

ubuntu 컨테이너의 ID 를 확인합니다.

> docker container commit 3380d00c6eb1 my-ubuntu:0.1
sha256:cea91d86ab7f95f24f31181dc21afe88bae61858ae8b4bf5e1414270473b98d2

위에서 확인한 컨테이너의 ID를 commit하면서 새로운 이름의 이미지를 생성합니다.

4) 새로 생성된 이미지 확인 및 실행

> docker image ls
REPOSITORY                                                TAG                                                                          IMAGE ID       CREATED              SIZE
my-ubuntu                                                 0.1                                                                          cea91d86ab7f   About a minute ago   136MB

다시 이미지 목록을 조회하면, REPOSITORY가 my-ubuntu, TAG가 0.1인 새로 생성한 이미지의 모습을 확인할 수 있습니다.

> docker container run -it my-ubuntu:0.1 
root@ef33640ec5f0:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 65535
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 9  bytes 806 (806.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

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        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

새롭게 생성한 이미지를 컨테이너로 실행시키면 위에서 설치한 net-tools가 적용되어 ifconfig 명령어를 사용할 수 있습니다.

3. 도커 컨테이너 네트워크

앞서 도커의 작동원리에서 살펴봤듯이, 컨테이너는 도커 호스트의 커널을 공유하면서 격리된 환경에서 실행됩니다. 이 때문에 네트워크 인터페이스도 격리됩니다. 도커는 네트워크 드라이버를 통해 호스트와 컨테이너 통신, 컨테이너 간의 통신, 외부 네트워크와 컨테이너와의 통신 등을 수행합니다.

도커 컨테이너를 실행하면 내부 IP를 순차적으로 할당을 하고, 외부와 연결해야 하는 경우 도커 호스트에 veth(virtual eth)라는 네트워크 인터페이스를 생성하고, 이를 도커 컨테이너의 eth와 연결합니다. 이때 컨테이너의 eth와 호스트의 veth를 연결해주는 인터페이스가 있는데, 이를 docker0 인터페이스라고 합니다. docker0 인터페이스는 도커를 설치할 때 자동으로 설치됩니다.

+------------------------------+
|        Docker Host           |
|                              |
|  +-----------------------+   |
|  |   docker0 (bridge)    |   |
|  |                       |   |
|  |  +-------+  +-------+ |   |
|  |  | veth1 |  | veth2 | |   |
|  |  +---+---+  +---+---+ |   |
|  +------|------------|----+  |
|         |            |       |
|         |            |       |
+---------|------------|-------+
          |            |
          |            |
+---------|------------|---------+
| +-------|----+  +----|------+  |
| |  veth1     |  | veth2     |  |
| | (eth0)     |  | (eth0)    |  |
| |            |  |           |  |
| | container1 |  | container2|  |
| +------------+  +-----------+  |
+--------------------------------+

도커 네트워크 드라이버에는 대표적으로 bridge 드라이버, host 드라이버, none 드라이버가 있습니다.

bridge 드라이버는 컨테이너를 생성할 때 기본적으로 제공하는 드라이버입니다. 위에서 살펴본 기본 명령어에서 사용한 docker container 명령을 통해 컨테이너를 실행하면, bridge 드라이버를 통해 네트워크를 생성합니다.

host 드라이버는 컨테이너를 생성할 때 자체적으로 네트워크 인터페이스를 생성하지 않고, 호스트의 네트워크 인터페이스를 공유하는 드라이버입니다.

none 드라이버는 컨테이너에 네트워크 인터페이스를 부여하지 않아 외부와 통신이 되지 않는 드라이버입니다.

도커 네트워크 드라이버는 docker network ls 명령을 통해 확인할 수 있습니다.

> docker network ls 
NETWORK ID     NAME                     DRIVER    SCOPE
1636aa174c3d   airflow-docker_default   bridge    local
80a6c3bf8eda   bridge                   bridge    local
1c88b2134b99   host                     host      local
8284623a46b9   none                     null      local

또한, 도커 컨테이너를 실행할 때 네트워크 드라이버를 지정해서 실행할 수 있습니다. --network에 옵션을 부여해서 컨테이너를 실행합니다.

> docker container run -it --network=none my-ubuntu:0.1
root@31feee61e0c6:/# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        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

network 옵션을 none으로 설정한 뒤 컨테이너 내부에서 ifconfig를 실행하면, eth0 인터페이스가 사라진 모습을 확인할 수 있습니다.

4. 도커 스토리지

도커 컨테이너는 프로세스 단위이기 때문에 언젠가는 종료됩니다. 만약 컨테이너 내부에 중요한 파일이 저장되어 있는데, 컨테이너가 종료되어 버리면 문제가 생길 수 있습니다. 이를 방지하기 위해 도커 스토리지라는 개념을 사용할 수 있습니다.

도커 스토리지는 도커 컨테이너 내에서 생성되는 데이터를 보존하기 위해 사용됩니다.

postgresql 데이터베이스를 통해 자세하게 알아보겠습니다.

> docker image pull postgres
Using default tag: latest
latest: Pulling from library/postgres
24c63b8dcb66: Pull complete
2bb0b7dbd861: Pull complete
1be7148593f2: Pull complete
ecffdb485a88: Pull complete
e5874891808a: Pull complete
ec1ae96b7bb2: Pull complete
b000f830b394: Pull complete
fe575e9f94b3: Pull complete
88603aa07b1f: Pull complete
3047a6162fb2: Pull complete
70e70abfab87: Pull complete
f754c133e57c: Pull complete
94f1eed6a8d9: Pull complete
5524ef0f9661: Pull complete
Digest: sha256:1bf73ccae25238fa555100080042f0b2f9be08eb757e200fe6afc1fc413a1b3c
Status: Downloaded newer image for postgres:latest
docker.io/library/postgres:latest

우선 postgresql 이미지를 다운로드 받습니다.

> docker container run --name postgresql-test -e POSTGRES_PASSWORD=1234 -d postgres
8aeb0072f300d2577cf8bf2559afd790c7a85579153fdf2135c4e54a9ae96110

내려받은 postgresq 이미지를 실행시킵니다. 이때 e 옵션은 환경변수를 설정하는 옵션으로, postgres 의 비밀번호를 설정합니다.

-d 옵션은 백그라운드 실행을 의미합니다.

> docker container exec -it 8aeb0072f300 /bin/bash
root@8aeb0072f300:/# psql -U postgres

컨테이너 내부로 진입한 뒤 postgres에 접속합니다.

 

root@8aeb0072f300:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.

postgres=# CREATE USER user1 PASSWORD '1234' SUPERUSER;
CREATE ROLE
postgres=# CREATE DATABASE test1 OWNER user1;
CREATE DATABASE
postgres=# \c test1 user1
You are now connected to database "test1" as user "user1".
test1=# CREATE TABLE table1 (
test1(#   id INTEGER PRIMARY KEY,
test1(#   name VARCHAR(20)
test1(# );
CREATE TABLE
test1=# INSERT INTO table1 (id, name) VALUES (1, 'choi');
INSERT 0 1
test1=# SELECT * FROM table1;
 id | name
----+------
  1 | choi
(1 row)

user, database, table을 차례대로 생성하고 데이터를 넣었습니다. select를 해보면 데이터가 정상적으로 들어가 있는 것을 확인할 수 있습니다.

이제 컨테이너를 종료시킨후에 다시 실행하고 터미널로 접속해서 데이터의 존재 여부를 확인해보겠습니다.

 

> docker container stop 8aeb0072f300
8aeb0072f300

> docker container start 8aeb0072f300
8aeb0072f300

> docker container exec -it 8aeb0072f300 /bin/bash
root@8aeb0072f300:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.

postgres=# \c test1 user1
You are now connected to database "test1" as user "user1".
test1=#
test1=#
test1=# select * from table1
test1-# ;
 id | name
----+------
  1 | choi
(1 row)

test1=#

데이터가 정상적으로 조회되는 것을 확인할 수 있습니다.

다음으로는 컨테이너를 삭제시킨 뒤에 다시 조회해보겠습니다.

 

> docker container stop 8aeb0072f300
8aeb0072f300

> docker container rm 8aeb0072f300
8aeb0072f300

> docker container run --name postgresql-test -e POSTGRES_PASSWORD=1234 -d postgres
96e0034ba37b8c8f4785bec2f14da8f7731adcfbe8526a12d5fb9c1a9d11917b

> docker container ls
CONTAINER ID   IMAGE                       COMMAND                   CREATED          STATUS                    PORTS                              NAMES
96e0034ba37b   postgres                    "docker-entrypoint.s…"   4 seconds ago    Up 4 seconds              5432/tcp                           postgresql-test


> docker container exec -it 96e0034ba37b /bin/bash
root@96e0034ba37b:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.

postgres=# \c test1 user1
connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "user1" does not exist
Previous connection kept
postgres=#

위에서 보는 바와 같이, 아까 생성한 데이터베이스와 유저를 찾을 수 없다는 에러 메시지가 발생합니다. 컨테이너를 지우고 다시 실행시켰으니 데이터가 사라진 겁니다. 이를 방지하기 위해 도커 스토리지를 사용합니다.

 

 

도커 스토리지는 크게 세가지 종류가 있습니다.

1) bind mount

2) volume

3) tmpfs

각 스토리지의 특성에 대해 살펴보겠습니다.

 

1) bind mounts
+-------------+
| Host System |
| +---------+ |
| |   App   | |      /path/on/host
| +----+----+ |
|      |      |
|      v      |
| +---------+ |
| |  Data   | |      /path/in/container
| +---------+ |
+-------------+

2) Volumes
+-------------+
| Host System |
| +---------+ |
| |  Docker | |       /var/lib/docker/volumes/volume_name
| |  Volume | | 
| | Storage | |
| +----+----+ |
|      |      |
|      v      |
| +---------+ |
| |  Data   | |       /path/in/container
| +---------+ |
+-------------+

3) tmpfs
+-------------+
| Host System |
| +---------+ |
| |  Memory | |       /dev/shm/in/container
| | Storage | | 
| +----+----+ |
|      |      |
|      v      |
| +---------+ |
| |  Data   | |       /path/in/container
| +---------+ |
+-------------+

 

 

5-1) volume

먼저 volume은 도커에 의해 관리되는 저장소입니다.

> docker volume ls
DRIVER    VOLUME NAME
local     04aefe99a1c6f9068b682b466db8daf14a0f062cee3113e12c16020d03a8acad
local     77d3370f36a7c865a536b29c39a5997d72872a0c1a06d51e0e939eb8687cfc75
local     airflow-docker_postgres-db-volume
local     airflow_postgres-db-volume
local     ccd866ec403c31f62cf91b025d992d506477793889842de43717bc90c12feb43
local     cdcd395883f1d8029f40e23f9d5e20b674c464e55f1563c816b9bd81f671acfe

> docker volume create myvolume1
myvolume1

> docker volume ls
DRIVER    VOLUME NAME
local     04aefe99a1c6f9068b682b466db8daf14a0f062cee3113e12c16020d03a8acad
local     77d3370f36a7c865a536b29c39a5997d72872a0c1a06d51e0e939eb8687cfc75
local     airflow-docker_postgres-db-volume
local     airflow_postgres-db-volume
local     ccd866ec403c31f62cf91b025d992d506477793889842de43717bc90c12feb43
local     cdcd395883f1d8029f40e23f9d5e20b674c464e55f1563c816b9bd81f671acfe
local     myvolume1

docker volume을 통해 관리할 수 있습니다.

 

컨테이너를 실행할 때 --mount 명령어를 통해 볼륨과 컨테이너를 마운트할 수 있습니다.

> docker container run -e POSTGRES_PASSWORD=1234 --mount type=volume,source=myvolume1,target=/var/lib/postgresql/data -d postgres
4267f1fc85b6f21114c9a1f6d2125ce3f8e7d8677de06e5d4e78ed8839aaf6a9

이 때 주의할 점은 --mount 옵션의 내용을 구분할 때 쓰는 컴마(,)를 띄어쓰기 없이 사용해야합니다.

source는 도커의 volume명, target은 컨테이너 내부의 경로를 의미합니다. 위 명령어는 myvolume1 볼륨과 컨테이너 내부의 /var/lib/postgresql/data 경로를 연결한다는 것을 의미합니다.

위에서 진행했던 postgresql 데이터를 생성하는 과정을 똑같이 해보겠습니다.

 

> docker container exec -it 4267f1fc85b6 /bin/bash
root@4267f1fc85b6:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.

postgres=# CREATE USER user1 PASSWORD '1234' SUPERUSER;
CREATE ROLE
postgres=# CREATE DATABASE test1 OWNER user1;
CREATE DATABASE
postgres=# \c test1 user1
You are now connected to database "test1" as user "user1".
test1=# CREATE TABLE table1 (
test1(#   id INTEGER PRIMARY KEY,
test1(#   name VARCHAR(20)
test1(# );
CREATE TABLE
test1=# INSERT INTO table1 (id, name) VALUES (1, 'choi');
INSERT 0 1
test1=#
test1=# SELECT * FROM table1;
 id | name
----+------
  1 | choi
(1 row)

 

다시 컨테이너를 삭제하고 생성합니다.

> docker container stop 4267f1fc85b6
4267f1fc85b6

> docker container rm 4267f1fc85b6
4267f1fc85b6

> docker container run -e POSTGRES_PASSWORD=1234 --mount type=volume,source=myvolume1,target=/var/lib/postgresql/data -d postgres
004b0acda87119e52f8269bccaf6385f4a136eddcfa4ac61eb6e3eeb57c804c4

 

컨테이너 내부로 진입하여 postgresql에 접속한 뒤 데이터를 확인해봅니다.

root@004b0acda871:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.

postgres=# \c test1 user1
You are now connected to database "test1" as user "user1".
test1=# SELECT * FROM table1;
 id | name
----+------
  1 | choi
(1 row)

데이터가 정상적으로 들어있는 것을 확인할 수 있습니다.

이렇게 volume은 도커 엔진에서 관리하는 데이터 저장소라고 이해할 수 있습니다.

 

도커 volume은 inspect 명령어를 사용해서 정보를 확인할 수 있습니다.

> docker volume inspect myvolume1
[
    {
        "CreatedAt": "2024-05-25T04:53:41Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/myvolume1/_data",
        "Name": "myvolume1",
        "Options": null,
        "Scope": "local"
    }
]

 

 

 

5-2) bind mount

bind mount는 호스트의 특정 디렉토리와 도커 컨테이너의 디렉터리를 연결하는 방법입니다.

간단하게 실습해보겠습니다.

> mkdir docker-test
> cd docker-test
> touch 1.txt
> ls
1.txt

docker-test라는 디렉터리를 만들고 그 안에 1.txt 파일을 생성했습니다.

 

~/Workspace/docker-test > docker container run -e POSTGRES_PASSWORD=1234 --mount type=bind,source=/Users/choi/Workspace/docker-test,target=/work -d postgres
393441dec5b52307041d11dfe9127b593353ad29e30679b48a335a86c8e12101

docker container를 실행시킵니다. mount 옵션의 type은 bind로 지정, source는 호스트의 경로, target은 컨테이너의 경로를 의미합니다.

이제 컨테이너의 내부로 접속해보겠습니다.

 

~/Workspace/docker-test > docker container exec -it 393441dec5b /bin/bash
root@393441dec5b5:/# cd work/
root@393441dec5b5:/work# ls
1.txt
root@393441dec5b5:/work#

접속해서 work 디렉토리로 이동하면 밖에서 생성했던 1.txt가 존재하는 것을 확인할 수 있습니다.

이렇게 호스트의 특정 디렉토리와 컨테이너의 디렉토리를 연결하는 방법을 bind mount라고 합니다.

 

 


출처 : 한권으로 배우는 도커&쿠버네티스

https://product.kyobobook.co.kr/detail/S000213057687