본문 바로가기

Docker

이미지와 컨테이너

 
 
이전 포스트에서 docker run 명령을 사용하여 Nginx 컨테이너를 실행해 보았다.
 

 

가상화 기술 - 컨테이너 실행

01. 컨테이너 실행 컨테이너를 실행하기 위해서는 터미널에 아래와 같은 명령어를 입력한다. docker run(실행옵션) 이미지명   예를 들어 이미지명이 nginx 인 컨테이너 실행하기 위해서는 다음과

yangheeb.tistory.com

 
이때 사용한 Nginx 이미지컨테이너를 만드는 재료라고 할 수 있는데,
이번 포스트에서는 이 이미지가 무엇인지, 이미지와 컨테이너의 관계가 어떻게 되는지에 대해 알아보자.
 
 
 

01. 이미지


 
서버 프로그램이 실행되기 위해서는 하드웨어와 소프트웨어가 동작해야하는데,
이 소프트웨어를 실행하기 위해서는 3가지가 필요하다.

  • 소프트웨어가 하드웨어의 자원을 사용할 수 있도록 필수 기능을 제공해주는 기본 OS
  • 프로그램을 실행시키기 위해 필요한 구성 요소 ( 패키지, 라이브러리, 프로그래밍언어 .. ) = 의존성 요소
  • 실행시킬 프로그램 ( 개발자가 개발한 애플리케이션 실행 파일 or 다운로드 받은 소프트웨어 )

 
이전 포스트에서 Nginx 웹서버를 컨테이너로 실행했을 때에는
위 하이라이트 부분인 의존 요소를 설치하는 과정이 없이 Nginx라는 이미지 이름만 저장했었다.
 
이 과정에서 서버를 구성하지 않고 한 번에 Nginx 프로그램을 실행할 수 있었던 이유는 

Nginx "이미지"를 통해서 컨테이너를 실행했기 때문이다.

 
 
 
본론으로 돌아와서 이미지의 개념은 아래와 같다. 

파일 시스템에 특정 시점을 저장해 놓은 압축 파일

 
 
Nginx 이미지의 경우,
Nginx 개발사가 OS위에 + Nginx와 구성요소들을 미리 준비하여
이것을 이미지로 저장한 뒤에 공유했기 때문에 바로 컨테이너가 실행되었던 것이다.
 

Nginx 컨테이너 작동과정

 
 
이 docker run 명령을 통해 컨테이너를 실행할 때는
Nginx 이미지 안에 있던 Nginx 프로그램이 함께 실행된다.
 
 
이미지 기능의 장점으로는 아래와 같이 3가지가 있으며,

  • 프로그램을 언제든지 저장된 특정 시점으로 실행 가능 
  • 다른 사람과 공유 가능 ( 가상머신에서의 스냅샷 기능과 유사 )
  • 압축파일의 사이즈가 아주 작음 ( 백업과 스냅샷보다 더 작음 ) -> 인터넷을 통해 저장하고 공유하기 수월

 
 
이미지는 다른 사람이 만든 이미지를 다운받아서 사용할 수 있고, 직접 이미지를 제작할 수 있다.
 
 
 
 

02. 이미지와 컨테이너


 
이미지와 컨테이너의 차이를 알아보기 전에 프로그램과 프로세스의 차이에 대해서 먼저 알아보자.

프로그램 (Program) 프로세스 (Process)
실행 가능한 소프트웨어 프로그램을 실제로 실행중인 상태
실행 상태의 소프트웨어
파일 시스템의 공간을 차지하도록 설치
ex ) 크롬과 같은 애플리케이션을 설치
하나의 프로그램은 여러 개의 프로세스를 실행
 ex ) 크롬 브라우저를 여러 개 실행
오로지 디스크 공간 차지
CPU, 메모리와 같은 리소스를 사용 x
실행 시 CPU, 메모리 등의 리소스를 사용

 
 
이미지와 컨테이너도 프로그램과 프로세스의 관계와 비슷하다.

이미지 (Image) 컨테이너 (Container)
프로그램이 실행되기 위한 환경이
모두 포함되어 있는 파일 시스템
실행 상태의 이미지
하나의 이미지로 여러 개의 컨테이너를 실행
압축 파일의 형태로 호스트 머신의 특정 경로에 위치 동일한 이미지에서 실행한 컨테이너는
내부에서 모두 동일한 프로세스로 실행됨
오로지 디스크 공간 차지
CPU, 메모리와 같은 리소스 사용 x
이미지를 컨테이너로 실행하는 순간부터
CPU, 메모리를 사용하게 됨

 
 
 
다만 컨테이너는 가상화 기술이기에 프로그램 - 포로세스 관계와는 달리
이미지 -> 컨테이너 로 전환 과정에서 격리된 공간이 만들어진다는 차이점이 있다.
 
 

정리해보자면, 이미지를 컨테이너로 실행시키는 것은
 

이미지에 저장되어 있는 모든 요소들을 격리된 공간으로 만든 다음,
그 격리된 공간 안에서 프로그램을 프로세스로 실행시키는 단계이다.
 
 
 
 

로컬 이미지 조회

 
로컬 디스크에 저장되어 있는 도커 이미지를 조회할 수 있는 이미지 ls 명령은 아래와 같다.

docker image ls (이미지명)

전체 로컬 이미지 조회

 
"REPOSITORY"는 이미지의 이름을 의미하고, "TAG"는 이미지의 버전을 의미한다.
각각의 이미지는 고유한 아이디를 가지고 있으며, 이미지 생성일과 사이즈를 확인할 수 있다.
필자는 이전에 mysql과 Nginx를 실행했었기 때문에 위와 같이 조회된다.
 
 
 
또한, 도커 이미지 ls 명령 다음 이미지의 이름를 입력하면 특정 이름을 가진 이미지만을 조회할 수 있다.

nginx 이미지 조회

 
nginx 이미지명을 명령에 함께 입력하면서 mysql이 제외되고 nginx 이미지만 조회된다.
 
 
 
 
 
 

하나의 이미지로 여러 컨테이너 실행
docker run -d --name {컨테이너명} 이미지명
  • --name : 이 옵션을 통해 컨테이너의 이름을 설정 // 컨테이너의 이름은 시스템 내에서 중복될 수 x
  • --d : 컨테이너의 로그가 터미널을 점유하지 않고 컨테이너를 백그라운드로 실행시킬 수 있음 

 
 
위 명령어를 바탕으로 동일한 nginx 웹서버를 3개 실행해보자. 
nginx 이미지로 이름이 multinginx1, multinginx2, multinginx3 컨테이너를
백그라운드로 실행되는 것을 확인할 수 있다.
 

하나의 이미지로 여러 컨테이너 실행

 
 
 
 
 

실행 중인 컨테이너 리스트 조회
docker ps
  • ps : 프로세스의 줄임말

 

실행 중인 컨테이너 리스트 조회

 
 
앞서 생성한 multinginx1, multinginx2, multinginx3 컨테이너 뿐만 아니라,
이전에 생성하였던 past-forward 컨테이너도 확인된다.
 
 
multinginx1, multinginx2, multinginx3 컨테이너가 사용하는 이미지는 nginx로 동일하고,
컨테이너가 생성된 시간과, 사용하는 포트, 이름을 확인된다.
 
그리고 컨테이너의 아이디는 각자 모두 다르다는 것을 알 수 있다.
 
 
 
 
 
 

실행 중인 컨테이너 삭제
docker rm -f
  • rm -f : 실행 중인 컨테이너를 삭제 ( 기본 명령인 rm은 실행 중인 컨테이너 삭제 못함 -> -f 옵션 필요 )

 
아래와 같이 "-f" 옵션을 지정하지 않는다면, 실행 중인 컨테이너가 삭제되지 않는다.

 
 
여러 개의 컨테이너를 한 번에 삭제하기 위해서는 띄어쓰기를 기준으로 다음 컨테이너의 이름을 지정하면 된다.
아래와 같이 "-f" 옵션을 사용하여 컨테이너들을 한 번에 삭제할 수 있다.

실행 중인 컨테이너 삭제

 
 
multinginx1, multinginx2, multinginx3 컨테이너가 삭제되고,
기존에 만들어 두었던 past-forward만 남아있다.
 
 
 
 
 

03. 이미지의 메타데이터 (Metadata)


 

메타데이터란,

이미지에 대한 정보를 기술하는 데이터이다.
즉 데이터에 대한 데이터를 의미한다.
 
앞서 이미지를 실제로 압축된 파일이라고 정의하였는데,
실제로 하나의 이미지는 압축된 파일 + 파일의 정보가 저장되어 있는 메타데이터로 구성된다.
 

이미지 구성

 

 

메타데이터에는 많은 정보들이 저장되어 있는데, 

그 중 env 필드는 애플리케이션이 사용하는 환경설정 값을 의미하고,

cmd는 이미지를 컨테이너로 실행할 때 명령어를 지정할 수 있는 것을 의미한다.

 

 

 

이미지의 세부 정보 조회
docker image inspect 이미지명

 
아래는 nginx 이미지의 세부 정보 조회, 즉 메타데이터를 조회해보자.

 

C:\Users\user>docker image inspect nginx
[
    {
        "Id": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2024-05-03T19:49:21Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.5",
                "NJS_VERSION=0.8.4",
                "NJS_RELEASE=3~bookworm",
                "PKG_RELEASE=1~bookworm"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "ArgsEscaped": true,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 187659947,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/82b734a0083bd76189c6d01f9a3f8ead6afd2ad69f9f7a6917b6559b17abe5d6/diff:/var/lib/docker/overlay2/57ba52d8cb7335037f55fde09cc2c92725e49a2a71f1ff5ab0b9e5d48793baaa/diff:/var/lib/docker/overlay2/646c729787839fba1dacaefe5a0b6093978d313f293cf68d185bcbeb02a69bad/diff:/var/lib/docker/overlay2/c0f99695f9c4aa1c4c5d47f4bb946f0b50464876063ed5b2dcfcc92c9fc9694f/diff:/var/lib/docker/overlay2/9d1a7fd0aff23c81b410b388a6bab392daab9f60ea6d23d5fb74e54bcba56297/diff:/var/lib/docker/overlay2/e43d0e07b0eaeb263997acbcfb3770b54dbd32f1d4fb01caa2c785a796cef8a4/diff",
                "MergedDir": "/var/lib/docker/overlay2/832d65f3b421467777795fb3c71cf2271d650f7a1f248bc7eb20a6e5c4d0fdd8/merged",
                "UpperDir": "/var/lib/docker/overlay2/832d65f3b421467777795fb3c71cf2271d650f7a1f248bc7eb20a6e5c4d0fdd8/diff",
                "WorkDir": "/var/lib/docker/overlay2/832d65f3b421467777795fb3c71cf2271d650f7a1f248bc7eb20a6e5c4d0fdd8/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:5d4427064ecc46e3c2add169e9b5eafc7ed2be7861081ec925938ab628ac0e25",
                "sha256:fc1cf9ca5139883943cc519cc3c57f0855395618f56d6431490fa735461156f1",
                "sha256:747b290aeba888738176dcbf7382eb0f660f27e785b839592918b8ed291d5792",
                "sha256:9f4d73e635f122031c04047f0e87fb224bef098a28700439bb4e72d0619aaad6",
                "sha256:56f8fe6aedcdee31bdee17249b1e18434ce7ab5a1814e2193773b54d7f9db39a",
                "sha256:7d2fd59c368c60f74214fc47399dcc35ef8513e26890a0c6004835bceabeb4c6",
                "sha256:14773070094ddc0debcea4f38f0daa7dd8116858387e0c238fa96ae8047bc07e"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

 
 "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.5",
                "NJS_VERSION=0.8.4",
                "NJS_RELEASE=3~bookworm",
                "PKG_RELEASE=1~bookworm"
            ],

 

와 같이 표현된 Env는 =를 기준으로 왼쪽이 key, 오른쪽이 값으로 구성되고,

소프트웨어 버전과 프로그램을 실행할 때 필요한 파일 경로 같은 정보가 지정되어 있다.

 

 

"Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],

 

그리고 이미지를 컨테이너로 실행할 때 cmd 필드에 있는 위 명령어가 실행된다.

 

 

nginx 이미지를 설정 변경사항 없이 기본 메타데이터만으로

defaultCmd 라는 새로운 컨테이너를 실행해보자.

설정 변경사항 없이 컨테이너 실행

 
 

컨테이너의 세부 정보 조회
docker container inspect 컨테이너명

 
위에서 실행하였던 defaultCmd 컨테이너의 세부 정보이다.

이미지에서의 메타데이터 부분 env,cmd 필드 내용이 동일한 것을 확인할 수 있다.

C:\Users\user>docker container inspect defaultCmd
[
    {
        "Id": "e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe",
        "Created": "2024-05-16T09:34:12.081091463Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 73613,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2024-05-16T09:34:12.664895261Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070",
        "ResolvConfPath": "/var/lib/docker/containers/e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe/hostname",
        "HostsPath": "/var/lib/docker/containers/e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe/hosts",
        "LogPath": "/var/lib/docker/containers/e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe/e5fca4a77571e3a24c35ca9fbf9bde0c733bdf98f98c81631f5fdb9f4e8d4dbe-json.log",
        "Name": "/defaultCmd",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                52,
                179
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": [],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware",
                "/sys/devices/virtual/powercap"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/c391451a642ccc07c2c665552789c6a868bc4e3080203d1be70741ef0a748e29-init/diff:/var/lib/docker/overlay2/832d65f3b421467777795fb3c71cf2271d650f7a1f248bc7eb20a6e5c4d0fdd8/diff:/var/lib/docker/overlay2/82b734a0083bd76189c6d01f9a3f8ead6afd2ad69f9f7a6917b6559b17abe5d6/diff:/var/lib/docker/overlay2/57ba52d8cb7335037f55fde09cc2c92725e49a2a71f1ff5ab0b9e5d48793baaa/diff:/var/lib/docker/overlay2/646c729787839fba1dacaefe5a0b6093978d313f293cf68d185bcbeb02a69bad/diff:/var/lib/docker/overlay2/c0f99695f9c4aa1c4c5d47f4bb946f0b50464876063ed5b2dcfcc92c9fc9694f/diff:/var/lib/docker/overlay2/9d1a7fd0aff23c81b410b388a6bab392daab9f60ea6d23d5fb74e54bcba56297/diff:/var/lib/docker/overlay2/e43d0e07b0eaeb263997acbcfb3770b54dbd32f1d4fb01caa2c785a796cef8a4/diff",
                "MergedDir": "/var/lib/docker/overlay2/c391451a642ccc07c2c665552789c6a868bc4e3080203d1be70741ef0a748e29/merged",
                "UpperDir": "/var/lib/docker/overlay2/c391451a642ccc07c2c665552789c6a868bc4e3080203d1be70741ef0a748e29/diff",
                "WorkDir": "/var/lib/docker/overlay2/c391451a642ccc07c2c665552789c6a868bc4e3080203d1be70741ef0a748e29/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "e5fca4a77571",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.5",
                "NJS_VERSION=0.8.4",
                "NJS_RELEASE=3~bookworm",
                "PKG_RELEASE=1~bookworm"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "nginx",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"
            },
            "StopSignal": "SIGQUIT"
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "ebfeea547dba688c1cbb594c8ad57541bce7e37069179f9e2b2170e59384497f",
            "SandboxKey": "/var/run/docker/netns/ebfeea547dba",
            "Ports": {
                "80/tcp": null
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "155e09d8a059640b458c4978e7841aad294cab7b1370222492f2da755ccc3b0c",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:02",
                    "NetworkID": "d01f9cd240a93f8b30699731d82796d57023ab4dfc7b7bc42722be82b2d4404b",
                    "EndpointID": "155e09d8a059640b458c4978e7841aad294cab7b1370222492f2da755ccc3b0c",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]

 
 
 
이미지를 컨테이너로 실행하면서

이미지의 메타데이터에 있는 cmd와 env 필드들을 덮어 씌워보자.

 

필드를 덮어씌우는 것은 일반적으로 일어나는 것은 아니지만,

메타데이터가 무엇인지에 대해 자세히 알아보기 위해 실습을 해보겠다.

 

우선 "customCmd"라는 새로운 컨테이너를 실행하여 nginx 이미지에 cmd를 수정해보자.

 

 

 

컨테이너 실행 시 메타데이터의 cmd 덮어쓰기
docker run 이미지명 (실행명령)
C:\Users\user>docker run --name customCmd nginx cat usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

 

defaultCmd의 경우

nginx 웹서버가 지속적으로 실행되는 데몬 프로세스이기 때문에 "-d" 옵션을 주었지만, 


customCmd의 경우 커스텀 cmd 컨테이너를 실행하면서

아래와 같이 cmd를 일회성 명령인 cat 명령으로 수정하였다.

 

그리고 cat 뒤에 usr/share/nginx/html/index.html 파일을 지정하여

서버는 요청을 받았을 때 nginx 웹서버가 아닌 아래와 같은 index.html 파일을 응답하게 된다.

 

 

 

그래서 기존 defaultCmd 컨테이너의 cmd 필드 내용이 아래와 같았다면,

"Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],

 

덮어씌운 customCmd 컨테이너의 cmd 필드 내용은 다음과 같다.

 "Cmd": [
                "cat",
                "usr/share/nginx/html/index.html"
            ],

 

 

여기서 중요한 점은, customCmd 컨테이너는 이미지의 데이터를 복사해서 만들어지기 때문에

기존 이미지의 메타데이터 내용이 바뀌지는 않는다는 사실이다.

 

 

 

컨테이너 실행 시 메타데이터의 env 덮어쓰기
docker run --env KEY=VALUE 이미지명

 
 앞서 Env는 =를 기준으로 왼쪽이 key, 오른쪽이 값으로 구성되고,

소프트웨어 버전과 프로그램을 실행할 때 필요한 파일 경로 같은 정보가 지정되어 있다고 하였다.

 

이번에는 이미지 메타데이터에 지정된 환경 변수를 덮어 씌워보겠다.

실습용 이미지 devwikirepo/envnodecolorapp을 다운로드 받고,

실습용 이미지의 메타데이터를 확인해보자.
 

 

아래와 같이 실습용 이미지를 다운 받고

C:\Users\user>docker pull devwikirepo/envnodecolorapp
Using default tag: latest
latest: Pulling from devwikirepo/envnodecolorapp
2ff1d7c41c74: Pull complete
b253aeafeaa7: Pull complete
3d2201bd995c: Pull complete
1de76e268b10: Pull complete
d9a8df589451: Pull complete
6f51ee005dea: Pull complete
5f32ed3c3f27: Pull complete
0c8cc2f24a4d: Pull complete
0d27a8e86132: Pull complete
d0b6b2117c56: Pull complete
d4af36b4bf4a: Pull complete
7a7d94d85ef8: Pull complete
Digest: sha256:982b6f0d4e65f3dc3394ed1057f35a09fb7e4968f48e1658031952988fcaa096
Status: Downloaded newer image for devwikirepo/envnodecolorapp:latest
docker.io/devwikirepo/envnodecolorapp:latest


devwikirepo/envnodecolorapp 이미지 메타데이터의 내용을 확인하는 과정이다.

C:\Users\user>docker image inspect devwikirepo/envnodecolorapp
[
    {
        "Id": "sha256:726a4f86a67e7d08d9171e8c5deba93e145083e358e14496eb57f7fd86837b3a",
        "RepoTags": [
            "devwikirepo/envnodecolorapp:latest"
        ],
        "RepoDigests": [
            "devwikirepo/envnodecolorapp@sha256:982b6f0d4e65f3dc3394ed1057f35a09fb7e4968f48e1658031952988fcaa096"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2024-01-01T06:21:47.244974792Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "node",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "3000/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NODE_VERSION=14.21.3",
                "YARN_VERSION=1.22.19",
                "COLOR=red"
            ],
            "Cmd": [
                "npm",
                "start"
            ],
            "ArgsEscaped": true,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "/app",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 916289570,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/f276dcb63fe5ec62a5265456d63d54a1ac3871a4537ec4e31d60add235728906/diff:/var/lib/docker/overlay2/68bec41d5da25cf48f06ac8f7ddb1c178f836158699207eeb10d61638d4b754e/diff:/var/lib/docker/overlay2/ca397cd69ac73f9e258162f6ab8b21a94262e9b0b85a3c5542f9d0c73242b106/diff:/var/lib/docker/overlay2/4c9f053622c29f252baff2633356ae8da97f738229e80f2da4ebb9c1c63d060c/diff:/var/lib/docker/overlay2/88422a513307f996c5589bc8804d1a6e4d195ac7911aec062570ed5c2b82f1a5/diff:/var/lib/docker/overlay2/9bd041e6ddba8b8cbccaec9445400da89be7a6ecb536506c120480a937116418/diff:/var/lib/docker/overlay2/b10d11798061603f31eda2280df7e619eaa51dd278322aa712d82c099365c741/diff:/var/lib/docker/overlay2/17381a64fef826043e7658c192ab3e6db22a9585c1c38b1634990cfa9207a5e6/diff:/var/lib/docker/overlay2/3814b5cce710d7dfc7c06fb4be3f6a8d4267b2304c71647a05869e55e10053c0/diff:/var/lib/docker/overlay2/5485976af01c42097b8a5fcc0fe54937b7ea699909c3907e0e13cba5da984e37/diff:/var/lib/docker/overlay2/4865a708a6584f0a8b756ecc8c78d5f343a93a30a67e936268336f974c03d7b5/diff",
                "MergedDir": "/var/lib/docker/overlay2/9256e7ec6b5653a503e41d8ed8aa06d9736a83d61a3d3f119d561214099d5615/merged",
                "UpperDir": "/var/lib/docker/overlay2/9256e7ec6b5653a503e41d8ed8aa06d9736a83d61a3d3f119d561214099d5615/diff",
                "WorkDir": "/var/lib/docker/overlay2/9256e7ec6b5653a503e41d8ed8aa06d9736a83d61a3d3f119d561214099d5615/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:b2dba74777543b60e1a5be6da44e67659f51b8df1e96922205a5dde6b92dda3c",
                "sha256:f1186e5061f20658954f6bfdfaead0abc5ed2371d70f707da05206e868a226ab",
                "sha256:fe0fb3ab4a0f7be72784fcab5ef9c8fda65ea9b1067e8f7cdf293c12bcd25c13",
                "sha256:c45660adde371317a1eafb102ee1d33b059328ec73a01b5c2461c4d04a40ecec",
                "sha256:e01a454893a9a11115c598e5dec158ded8bd41326046c993c81b76b6a963590b",
                "sha256:cb81227abde588a006a8b7ceac6034a303813efadc2c711fabf7b224649d183f",
                "sha256:f8a91dd5fc84e4e5a1f261cf306ba1de28894524326d86eec0d74e9c0d22baec",
                "sha256:3c777d951de2c488f73618f92b2adee8bd5de6f77e36bab51d57583bc487b99b",
                "sha256:0d5f5a015e5d65973cce1dbab5aa60ce0836dbf2b3c9eabcb6efc89db1db3221",
                "sha256:2c2c2d6915ecbbc6939b3d80a0b800ff1bec6d6e90f30943a77198ad392a5797",
                "sha256:e57ecbb84cded9ca13582528286f225e0295c10e0dfd0b8fdf6e54dc67fe4974",
                "sha256:c29775dceac870a23281add6b2dea5b1b59b165fbb9354e11f7664655030d89c"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

 

"Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NODE_VERSION=14.21.3",
                "YARN_VERSION=1.22.19",
                "COLOR=red"
            ],
            "Cmd": [
                "npm",
                "start"
            ],

 
env 필드의 내용을 보시면 이렇게 color라는 키에 red라는 값을 가지고 있는 것을 확인할 수 있다.

env 필드에서의 color red 값을 덮어 씌워보겠다.

 

 

다운 받은 이 이미지를 컨테이너로 실행하고

C:\Users\user>docker run -d -p 8080:3000 --name defaultColorApp devwikirepo/envnodecolorapp
48bbe5edd9b0fa4f12d72be5145fc0a408ed761210e1eefe641282b8b156d5f0

 

기존의 "COLOR = red" env 필드 내용이 아닌

"COLOR = blue" 내용을 덮어 씌운 후 blueColorApp이라는 컨테이너를 실행시켜보자.

C:\Users\user>docker run -d -p 8081:3000 --name blueColorApp --env COLOR=blue devwikirepo/envnodecolorapp
384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54

 

이 blueColorApp의 메타데이터 내용을 확인해보면

C:\Users\user>docker container inspect blueColorApp
[
    {
        "Id": "384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54",
        "Created": "2024-05-17T10:40:23.050702695Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "npm",
            "start"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 34194,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2024-05-17T10:40:23.487374532Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:726a4f86a67e7d08d9171e8c5deba93e145083e358e14496eb57f7fd86837b3a",
        "ResolvConfPath": "/var/lib/docker/containers/384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54/hostname",
        "HostsPath": "/var/lib/docker/containers/384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54/hosts",
        "LogPath": "/var/lib/docker/containers/384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54/384e9530797f8ab0588200a808be0c5cb059356a18652b661a339050e7be5f54-json.log",
        "Name": "/blueColorApp",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {
                "3000/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8081"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                30,
                120
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": [],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware",
                "/sys/devices/virtual/powercap"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/0c89fcea5891326a94e60e38c6f1fa1136e820bbb1f600c13dece6a7a9b5ffe9-init/diff:/var/lib/docker/overlay2/9256e7ec6b5653a503e41d8ed8aa06d9736a83d61a3d3f119d561214099d5615/diff:/var/lib/docker/overlay2/f276dcb63fe5ec62a5265456d63d54a1ac3871a4537ec4e31d60add235728906/diff:/var/lib/docker/overlay2/68bec41d5da25cf48f06ac8f7ddb1c178f836158699207eeb10d61638d4b754e/diff:/var/lib/docker/overlay2/ca397cd69ac73f9e258162f6ab8b21a94262e9b0b85a3c5542f9d0c73242b106/diff:/var/lib/docker/overlay2/4c9f053622c29f252baff2633356ae8da97f738229e80f2da4ebb9c1c63d060c/diff:/var/lib/docker/overlay2/88422a513307f996c5589bc8804d1a6e4d195ac7911aec062570ed5c2b82f1a5/diff:/var/lib/docker/overlay2/9bd041e6ddba8b8cbccaec9445400da89be7a6ecb536506c120480a937116418/diff:/var/lib/docker/overlay2/b10d11798061603f31eda2280df7e619eaa51dd278322aa712d82c099365c741/diff:/var/lib/docker/overlay2/17381a64fef826043e7658c192ab3e6db22a9585c1c38b1634990cfa9207a5e6/diff:/var/lib/docker/overlay2/3814b5cce710d7dfc7c06fb4be3f6a8d4267b2304c71647a05869e55e10053c0/diff:/var/lib/docker/overlay2/5485976af01c42097b8a5fcc0fe54937b7ea699909c3907e0e13cba5da984e37/diff:/var/lib/docker/overlay2/4865a708a6584f0a8b756ecc8c78d5f343a93a30a67e936268336f974c03d7b5/diff",
                "MergedDir": "/var/lib/docker/overlay2/0c89fcea5891326a94e60e38c6f1fa1136e820bbb1f600c13dece6a7a9b5ffe9/merged",
                "UpperDir": "/var/lib/docker/overlay2/0c89fcea5891326a94e60e38c6f1fa1136e820bbb1f600c13dece6a7a9b5ffe9/diff",
                "WorkDir": "/var/lib/docker/overlay2/0c89fcea5891326a94e60e38c6f1fa1136e820bbb1f600c13dece6a7a9b5ffe9/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "384e9530797f",
            "Domainname": "",
            "User": "node",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "3000/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "COLOR=blue",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NODE_VERSION=14.21.3",
                "YARN_VERSION=1.22.19"
            ],
            "Cmd": [
                "npm",
                "start"
            ],
            "Image": "devwikirepo/envnodecolorapp",
            "Volumes": null,
            "WorkingDir": "/app",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f5107fe42415c8c907bc12625ae18dc364c482aa3348fa81e24900d70de36086",
            "SandboxKey": "/var/run/docker/netns/f5107fe42415",
            "Ports": {
                "3000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "8081"
                    }
                ]
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "294d95e0268674e2a6b07b83770b1045c75dd7a596cf2e1d3931a26b1f3efe0c",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.4",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:04",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:04",
                    "NetworkID": "d01f9cd240a93f8b30699731d82796d57023ab4dfc7b7bc42722be82b2d4404b",
                    "EndpointID": "294d95e0268674e2a6b07b83770b1045c75dd7a596cf2e1d3931a26b1f3efe0c",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.4",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]


"Env": [
                "COLOR=blue",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NODE_VERSION=14.21.3",
                "YARN_VERSION=1.22.19"
            ],

"COLOR=blue" 로 바뀐 것을 확인할 수 있다.    
 

 

 

환경 변수 값을 읽어서 환경 변수별로 다른 색을 출력하는 결과를 확인할 수 있었다.

 

 

 

 

04. 컨테이너의 라이프사이클 (Lifecycle)


 

생성 단계

컨테이너를 실행 하기 위한 격리된 공간이 만들어지는 상태

즉 네트워크, 스토리지, 환경 변수 같은 모든 리소스가 격리된 공간인 컨테이너로 분리된 상태

하지만 아직 내부에서 프로세스가 실행 되고 있는 상태는 아니므로 호스트 OS의 리소스를 사용하지 x

docker create 명령어를 입력하면 생성 됨

 

실행 단계

docker start 명령어를 입력하면 컨테이너의 메타데이터인 CMD 값이 사용되며 컨테이너가 실행 상태가 됨

컨테이너 내에서 프로세스가 실행중이기 때문에 실제로 CPU와 메모리를 사용하게 됨

docker run =  docker created + docker start

 

재시작 하기
docker restart : 실행 중인 프로세스에 재시작 신호를 보내며 10초 뒤에 이 신호가 동작하게 된다.

 

일시정지 단계

docker pasue 로 실행 중인 프로세스에 일시정지 신호를 보내며 10초 뒤에 이 신호가 동작하고 일시정지가 됨

현재 상태를 모두 메모리에 저장해두게 되며 메모리만 사용할 뿐 CPU는 사용하지 않게됨 

 

종료 단계

docker stop 로 실행 중인 프로세스에 종료 신호를 보내며

10초 뒤에 이 신호가 동작하고 실행중인 프로세스를 완전히 중단시켰다는 뜻

즉, 메모리와 CPU 사용 모두 중단이 되며 종료된 컨테이너를 시작할 경우 당연히 처음부터 다시 실행됨

 

삭제 단계

docker rm 으로 컨테이너를 삭제할 수 있으며 모든 상태에서 컨테이너를 삭제할 수 있음

단, 실행 상태인경우 -f 옵션을 사용해야함

 

 

 

 

 

 

위 포스트는 개발자를 위한 쉬운 도커 강의를 정리한 글입니다.

 

개발자를 위한 쉬운 도커 | 데브위키 - 인프런

데브위키 | 현업 개발자가 도커를 사용한 경험을 녹여낸 새로운 커리큘럼으로 기존 교재 및 강의와 차별된 강의를 제공합니다. 단순한 명령어 사용법이 아닌 도커를 왜 사용해야하는지 대한 근

www.inflearn.com

 

 

'Docker' 카테고리의 다른 글

컨테이너의 상태 (State)  (1) 2024.07.05
이미지 레지스트리  (0) 2024.05.17
가상화 기술 - 컨테이너 실행  (1) 2024.05.16