Docker와 Docker Image

진성대·2023년 9월 26일
0

Docker

목록 보기
1/12

도커를 왜 쓸까?

  • 도커의 본질 도커의 철학을 알고 넘어가야한다.

도커 공식 홈페이지

Debug your app, not your environment!

securely build and share any application, anywhere

Docker Image

  • 환경까지 같이 build 하자
  • Application이 구동될 os(환경)과 Application인 source Code를 함께 담고 있다.
  • Application이 구동될 환경을 포함해서 Runtime 에 필요한 파일들의 집합을 담고 있는 것을 Image 라고 한다.

    GitHub에서 구동하고 실행하는 절차는 Application에 어울리는 절차를 담고 있는게 아니라 Source Code만 있다.
    Mac 에서 컴파일 하던지 Ubuntu에서 하던지 각 다른 환경에서 실행을 한다.

Docker 의 본질

  • Cloud native 환경과 밀접하게 연관되어 있다.

docker 컨테이너 서비스를 위한 image

  • docker image는 Contrainer runtime에 필요한 바이너리, 라이브러리 및 설정 값 등을 포함하고, 변경되는 상태 값을 보유하지 않고(stateless) 변하지 않는다. (Immutable, RO)

    기존 이미지 자체는 변경이 불가능 하지만, docker image를 받아서 Container로 만들고 그 Container에서 수정된 정보를 적용해서 신규 이미지로 만드는 작업은 가능하다.

  • 일반적인 컨테이너 애플리케이션 서비스 개발 과정 이해를 통해 Image에 대해 이해


docker image 관련 명령어 workflow

이미지 내려받기 (docker pull)

  • Docker는 hub.docker.com(docker.io)으로 부터 이미지를 제공받거나 제공한다.
  • 또는, 기업의 인프라에 개별적인 private registry서버를 두고, 이곳에 이미지를 pull/push하기도 한다.
docker [image] pull [options] name:[tag]

# version 이나 tag 를 붙이지 않으면 version은 최신 버전 tag는 latest로 다운받는다.

# 기본적으로 docker.io가 default registry로 등록되어 있다.
~$ docker pull debian[:latest]
~$ docker pull library/debian:10
~$ docker pull docker.io/library/debian:10
~$ docker pull index/docker.io/library/debian:10

# 만일, private registry 나 클라우드의 저장소(ECR, GCR 등)의 이미지를 받는다면,
~$ docker pull 192.168.56.101:5000/debain:10
~$ docker pull gcr.io/google-samples/hello-app:1.0


docker image inspect :

  • 생성된 image의 내부 구조 정보를 JSON 형태로 제공.
[
    {
        "Id": "sha256:359570977af25b6ec87f2e0ee1e103e3826bade6175784cf98b04337278b1006",
        "RepoTags": [
            "httpd:2.4"
        ],
        "RepoDigests": [
            "httpd@sha256:5123fb6e039b83a4319b668b4fe1ee04c4fbd7c4c8d1d6ef843e8a943a9aed3f"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-09-20T09:03:33.364033123Z",
        "Container": "cfb386ae0931d0e738f59554849d9237213c4916c2472d9d7d17f13e710c772b",
        "ContainerConfig": {
            "Hostname": "cfb386ae0931",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
...
]

Digest

  • 실제로 이미지가 저장될때 /var/lib/docker/ 에 저장된다.
  • 그때 Digest 값으로 이미지들을 구분한다.

Container

  • 이미지 불변의 법칙
  • 이미지를 build하는 과정에서 container로 만들고 copy or package 만들던지 docker commit 을 통해서 다시 신규 image를 만든다. 그 신규 image가 다시 container로 만든다.
  • step수 만큼 반복 하고 최종 컨테이너 id 가 만들어지는것

ENV

  • 환경값

CMD

  • 이미지는 정적, 컨테이너는 동적이다.
  • 동적인 컨테이너에서는 반드시 내부에 daemon이 돌아야지만 서비스를 할 수 있다.
  • Dockerfile로 만들때 항상 하단에 CMD Keyworddaemon을 돌리는 명령어를 포함시킨다 : 정적 -> 동적으로 변경

이미지 구조 확인

  • docker history : docker image는 Dockerfile을 통해 build 됨.
IMAGE          CREATED      CREATED BY                                      SIZE      COMMENT
359570977af2   7 days ago   /bin/sh -c #(nop)  CMD ["httpd-foreground"]     0B
<missing>      7 days ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>      7 days ago   /bin/sh -c #(nop) COPY file:c432ff61c4993ecd…   138B
<missing>      7 days ago   /bin/sh -c #(nop)  STOPSIGNAL SIGWINCH          0B
<missing>      7 days ago   /bin/sh -c set -eux;   savedAptMark="$(apt-m…   82.4MB
<missing>      7 days ago   /bin/sh -c #(nop)  ENV HTTPD_PATCHES=rewrite…   0B
<missing>      7 days ago   /bin/sh -c #(nop)  ENV HTTPD_SHA256=dbccb84a…   0B
<missing>      7 days ago   /bin/sh -c #(nop)  ENV HTTPD_VERSION=2.4.57     0B
<missing>      7 days ago   /bin/sh -c set -eux;  apt-get update;  apt-g…   11MB
<missing>      7 days ago   /bin/sh -c #(nop) WORKDIR /usr/local/apache2    0B
<missing>      7 days ago   /bin/sh -c mkdir -p "$HTTPD_PREFIX"  && chow…   0B
<missing>      7 days ago   /bin/sh -c #(nop)  ENV PATH=/usr/local/apach…   0B
<missing>      7 days ago   /bin/sh -c #(nop)  ENV HTTPD_PREFIX=/usr/loc…   0B
<missing>      8 days ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      8 days ago   /bin/sh -c #(nop) ADD file:a1398394375faab8d…   74.8MB

이미지 구조 확인

  • download된 layer들은 distribution ID를 부여 받고 docker 전용 경로에 저장된다.
[ec2-user@ip-172-31-36-185 ~]$ sudo su -
[root@ip-172-31-36-185 ~]# cd /var/lib/docker/image/overlay2/distribution/diffid-by-digest/sha256

[root@ip-172-31-36-185 sha256]# ll
total 288
-rw-r--r--. 1 root root 71 Sep 28 04:02 01d159b8db2f24da97028c26bf6622e249e162b1adab06a3644c04f1c9fe2dd3
-rw-r--r--. 1 root root 71 Sep 28 06:31 053327351b4abdb9e49f7fde8334e6883910220be7c3129fd5c5487f5e612487
-rw-r--r--. 1 root root 71 Sep 27 16:37 076ff7a6074cf02eed64156d54feff57becf3f23068504c7109622ba3928f87a
-rw-r--r--. 1 root root 71 Sep 27 16:37 0ee278c19a4a58b76f7d438814d017c1d1ffff9c2f0f0cf6883505aef28b3ba3
-rw-r--r--. 1 root root 71 Sep 28 04:02 0f816efa513d909851c457ae41744fe3ff36ab19ebc2d72687d8c8f0594c93b3
-rw-r--r--. 1 root root 71 Sep 27 13:22 1150b893b52bb9e88099bf997d0295856bd72593bbea3d562f1c8a0cf02321bf
  • 아래 그림과 같은 형태로 이미지는 불변 즉, read only 형태로 만들어지고
  • docker run 명령으로 컨테이너를 생성하면 [Container layer]가 read write로 추가된다.

  • 여러 개의 layer를 하나의 FS으로 사용하게 해주는 기능을 UFS(union filesystem)이라고 한다.

Debian Linux image 에 httpd image 를 설치하면 layer로 httpd layer 가 추가되고 web source를 따로 추가하면 layer로 추가가 된다.

  • docker run을 통해서 실행을 하면 이미지에 대한 snapshot이 컨테이너 내부에 기본적으로 저장이 되고 컨테이너가 실행이 되면 read-write가 가능한 컨테이너 layer가 심어진다.

이미지 올리기 (image push)

  • Dockerfile을 통해 생성된 이미지나 docker commit을 통해 생성된 이미지를 저장하는 곳을 registry라고 한다.
  • Registry는 공개적으로 사용하는 Public registry와 회사 내부에서만 접근되도록 하는 Private registry가 있다.

docker push 를 수행하려면 다음과 같은 작업이 전제 된다.

1) docker login: hub.docker.com에 가입된 본인ID와 암호로 현재 로컬에 계정을 등록한다. (해제는 docker logout)
2) docker tag: hub.docker.com에 본인 계정의 Repositories에 넣기 위한 태그를 수행한다. (tag는 이미지의 새로운 참조명을 넣는 방법. 간혹, OS, 버전 표시로 활용하기도 한다.)

docker login/logout

  • hub.dokcer.com에 회원가입 후 서버에서 docker login을 통해 본인 저장소에 업로드 한다.
  • Docker는 3가지 접근 방법을 제공, 2가지 방법을 확인해 본다.
# "암호"로 접근하는 방법
~$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: (본인계정 확인)
Password:
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

[ec2-user@ip-172-31-36-185 ~]$ docker info | grep Username
 Username: (본인계정 확인)
# 입력한 암호는 암호화 되지 않는다.
# 제공되는 경로를 열어보면 암호코드처럼 생긴 값이 있지만, base64 인코딩 값이다.

docker [image] tag -> push

  • hub.docker.com에 본인 계정의 Repositories에 생성한 이미지를 업로드하기 위해서는 본인계정을 이미지명 앞에 붙여야 docker push 수행 시 계정으로 찾아가 저장된다.
[ec2-user@ip-172-31-36-185 ~]$ docker images
REPOSITORY               TAG             IMAGE ID       CREATED         SIZE
myweb                    v1.0            22bdc5972f40   21 hours ago    41.4MB
nginx                    latest          61395b4c586d   7 days ago      187MB
httpd                    2.4             359570977af2   8 days ago      168MB
portainer/portainer-ce   latest          d7f7a88e1acc   8 days ago      294MB
bash                     latest          3c04497fad88   7 weeks ago     13.9MB
mysql                    5.7-debian      6dca13361869   2 months ago    463MB
nginx                    1.25.0          7d3c40f240e1   3 months ago    143MB
nginx                    1.25.0-alpine   fe7edaf8a8dc   4 months ago    41.4MB
mariadb                  10.2            625e5b493bbb   14 months ago   338MB
centos                   7               eeb6ee3f44bd   2 years ago     204MB
ubuntu                   16.04           b6f507652425   2 years ago     135MB
nginx                    1.19            f0b8a9a54136   2 years ago     133MB

[ec2-user@ip-172-31-36-185 ~]$ docker image tag myweb:v1.0 jinsungdae/myweb:v1.0
[ec2-user@ip-172-31-36-185 ~]$ docker images
REPOSITORY               TAG             IMAGE ID       CREATED         SIZE
myweb                    v1.0            22bdc5972f40   21 hours ago    41.4MB
wlstjdeo00/myweb         v1.0            22bdc5972f40   21 hours ago    41.4MB
nginx                    latest          61395b4c586d   7 days ago      187MB
httpd                    2.4             359570977af2   8 days ago      168MB
portainer/portainer-ce   latest          d7f7a88e1acc   8 days ago      294MB
bash                     latest          3c04497fad88   7 weeks ago     13.9MB
mysql                    5.7-debian      6dca13361869   2 months ago    463MB
nginx                    1.25.0          7d3c40f240e1   3 months ago    143MB
nginx                    1.25.0-alpine   fe7edaf8a8dc   4 months ago    41.4MB
mariadb                  10.2            625e5b493bbb   14 months ago   338MB
centos                   7               eeb6ee3f44bd   2 years ago     204MB
ubuntu                   16.04           b6f507652425   2 years ago     135MB
nginx                    1.19            f0b8a9a54136   2 years ago     133MB
[ec2-user@ip-172-31-36-185 ~]$ docker push jinsungdae/myweb:v1.0
The push refers to repository [docker.io/jinsungdae/myweb]
058e54c811c8: Pushed
8d68b6b128f7: Mounted from library/nginx
c8db7b4be633: Mounted from library/nginx
0fbe8c68abd3: Mounted from library/nginx
664eb87278f9: Mounted from library/nginx
30085473d084: Mounted from library/nginx
d007f013021f: Mounted from library/nginx
f1417ff83b31: Mounted from library/nginx
v1.0: digest: sha256:d95300aed2d82650608f6ac8a4942830eeb851edf4ec55ca70d9fdf13ed68cc4 size: 1989

docker [image] tag

  • hub.docker.com 에 push된 이미지를 다른 위치에서 pull 해보고, docker run 으로 정상 이미지인지 확인해본다.
~$ docker pull jinsungdae/myweb:v1.0
~$ docker run -d -p 8001:80 --name=myweb jinsungdae/myweb:v1.0
~$ curl localhost:8001
  • 이미지를 공유하는 방법
    • registry에 push하여 공유
    • 이미지를 생성하는 Dockerfile과 소스를 Github에 올려 공유
    • 이미지를 docker save를 통해 파일로 백업하여 전달 후 docker load를 통해 공유

docker image 백업 및 이전

  • docker save 명령을 통해 Layer로 구성된 이미지를 *.tar파일로 묶어 파일로 저장
  • 해당 파일을 전달 받은 컴퓨터에서 docker load를 통해 이미지로 등록한다.
[ec2-user@ip-172-31-36-185 save_lab]$ docker image save nginx > nginx1.tar
[ec2-user@ip-172-31-36-185 save_lab]$ ll
total 506340
-rw-r--r--. 1 ec2-user ec2-user 518489600 Sep 28 12:13 nginx1.tar
[ec2-user@ip-172-31-36-185 save_lab]$ docker image save nginx | gzip > nginx.tar.gz
[ec2-user@ip-172-31-36-185 save_lab]$ ls -lh
total 678M
-rw-r--r--. 1 ec2-user ec2-user 184M Sep 28 12:14 nginx.tar.gz
-rw-r--r--. 1 ec2-user ec2-user 495M Sep 28 12:13 nginx1.tar
[ec2-user@ip-172-31-36-185 save_lab]$ docker image save nginx | bzip2 > nginx1.tar.bz2
[ec2-user@ip-172-31-36-185 save_lab]$ ls -lh
total 843M
-rw-r--r--. 1 ec2-user ec2-user 184M Sep 28 12:14 nginx.tar.gz
-rw-r--r--. 1 ec2-user ec2-user 495M Sep 28 12:13 nginx1.tar
-rw-r--r--. 1 ec2-user ec2-user 165M Sep 28 12:16 nginx1.tar.bz2

~$ scp nginx1.tar.gz host2@(server):/home/(이름)/backup/nginx1.tar.gz
-------------------------------------------------------------------------
host2~$ docker image load < nginx1.tar.gz
Load image : nginx:1.0
host2~$ docker images
host2~$ docker un -itd -p 8200:80 nginx:1.0
host2~$ curl localhost:8200

docker image 삭제

  • Docker Hub를 통해 다운로드(Pull)받은 이미지는 종류에 따라 용량이 다르다. 작게는 몇 MB부터 크게는 몇 GB가 넘는 것도 있다.
  • 이미지를 계속 다운로드만 받게 되면 로컬 서버의 저장 용량을 많이 차지하여 공간 부족과 같은 문제를 야기하기도 한다.
  • 이런 문제를 해결하기 위해 앞서 배운 docker image save를 통해 이미지를 백업하거나 주기적으로 업무에 사용하는 이미지와 사용하지 않는 이미지를 구분하여 관리하고, 불필요한 이미지는 삭제하는 것이 좋다.
docker image rm [옵션] {이미지명[:태그] | 이미지ID}
docker rmi [옵션] {이미지명[:태그] | 이미지ID}
# 이미지 전체 삭제 
~$ docker rmi $(docker images -q)

# 특정 이미지명이 포함된 것만 삭제.
~$ docker rmi $(docker images | grep debian)

# 반대로 특정 이미지명이 포함된 것만 제외하고 모두 삭제.
~$ docker rmi $(docker images | grep -v centos)

# 자주 사용하는 명령등을 전역 alias로 적용하여 활용하면 편리하다.
~$ vi .bashrc

# 상태가 exited인 container를 찾아서 모두 삭제
alias cexrm='docker rm $(docker ps --filter 'status=exited' -a -q)'

# 설정한 alias를 적용하고 확인
~$ source .bashrc
~$ alias
aliascexrm='docker rm $(docker ps --filter 'status=exited' -a -q)'

Image를 사용중인 컨테이너가 있을때의 docker Image 삭제

# 현재 centos:7 이미지를 사용 중인 컨테이너가 있다.
~$ docker ps -a

# 이미지를 삭제하면 ?
~$ docker image rm centos:7
Error response from daemon: conflict: unable to remove repository reference "centos:7"

# 해당 컨테이너 stop 후 rm으로 컨테이너 삭제
~$ docker stop 0b5612~~~ (Process 삭제)

~$ docker rm 0b5612~~~ (snapshot 삭제)


docker container registry

  • 기업 내부에서 생성한 프로젝트용 이미지를 public registry에 올리는 경우는 없다.
  • image에 네트워크나 OS 및 미들웨어 설정 등의 정보가 포함되어 있으므로 보안상 Docker Hub와 같이 인터넷을 통해 불특정 다수에게 공개되는 곳에는 올릴 수 없는 경우에는 *"Private Registry"**를 구축한다.
  • Docker registry는 docker image를 회사 서버에서 개별적으로 구축하는 서비스다.
  • 회사 인프라내에 private docker registry를 구축하기 위해서는, Docker Hub에 공개되어 있는 공식 image인 "registry"를 사용한다.
  • 적은 용량의 container service로 사용하기에 적합하다.
[ec2-user@ip-172-31-36-185 save_lab]$ docker pull registry
Using default tag: latest
latest: Pulling from library/registry
7264a8db6415: Already exists
c4d48a809fc2: Pull complete
88b450dec42e: Pull complete
121f958bea53: Pull complete
7417fa3c6d92: Pull complete
Digest: sha256:d5f2fb0940fe9371b6b026b9b66ad08d8ab7b0d56b6ee8d5c71cb9b45a374307
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
[ec2-user@ip-172-31-36-185 save_lab]$ docker images | grep registry
registry                 latest       0030ba3d620c   7 weeks ago     24.1MB

[ec2-user@ip-172-31-36-185 save_lab]$ docker run -d \
> -v /home/ec2-user/registry_data:/var/lib/registry \
> -p 5000:5000 \
> --restart=always \
> --name=local-registry \
> registry
8d2b4736dbe114cbd3e5aabbfa14dd91e351acd335f287c88cc38e41567e6be4

[ec2-user@ip-172-31-36-185 save_lab]$ docker ps | grep registry
8d2b4736dbe1   registry                 "/entrypoint.sh /etc…"   26 seconds ago   Up 24 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp                       local-registry
[ec2-user@ip-172-31-36-185 save_lab]$ sudo netstat -nlp | grep 5000
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      83747/docker-proxy
tcp6       0      0 :::5000                 :::*                    LISTEN      83752/docker-proxy

[ec2-user@ip-172-31-36-185 save_lab]$ curl -X GET localhost:5000/v2/_catalog
{"repositories":[]}

~$ docker image tag myweb:v1.0 192.168.56.101(주소):5000/myweb:v1.0
~$ docker push 192.168.56.101(주소):5000/myweb:v1.0
The push refers to repository [192.168.56.101:5000/myweb]
Get "https://192.168.56.101:5000/v2": http: server gave HTTP response to HTTPS client

~$ sudo vi /etc/init.d/docker
...
DOCKER_OPTS=--insecure-registry 192.168.56.101:5000

~$ sudo vi /etc/docker/daemon.json
{ "insecure-registries": ["192.168.56.101:5000"]}

~$ sudo systemctl restart docker.service

docker container registry 실습

[시나리오] 현재 운용 중인 Hostos1(registry server)과 hostos2(client)를 이용해 private push/pull을 수행해 본다.

~host2$ curl -x GET http://192.168.56.101:5000/v2/_catalog
{"repositories":["myweb"]}

~host2$ curl -X GET http://192.168.56.101:5000/v2/myweb/tags/list
{"name":"myweb", "tags":["v1.0","v1.1"]}

~host2$ docker pull 192.168.56.101:5000/myweb:1.0
~host2$ docker image tag 192.168.56.101:5000/myweb:1.0 dev_http:1.1
~host2$ docker images
~host2$ docker run -d -p 8100:80 --name myweb-server dev_http:1.1
  • 기본 docker registry는 http 접근으로 별도의 인증 절차가 없다.
  • 보안 구성을 위해 별도로 SSL(openssl)로 인증서를 만들어 보안 인증 구성도 가능하다.

cncf image registry

  • private registry opensource library

docker image 를 layer 로 만드는 이유

  1. 재사용성과 효율성:
  • 각 계층은 이전 계층의 변경사항을 캡처합니다. 만약 여러 이미지가 동일한 베이스 이미지나 동일한 라이브러리를 사용한다면, 해당 계층은 디스크에 한 번만 저장되어 공유됩니다. 이로 인해 저장 공간을 절약하고 이미지 다운로드/업로드 시간을 줄일 수 있습니다.
  1. 빠른 빌드 시간:
  • 이미지의 기존 계층에 변경사항이 없다면 Docker는 해당 계층을 다시 빌드하지 않습니다. 이는 이미지 빌드 시간을 크게 단축시키며, 개발자의 작업 효율성을 향상시킵니다.
  1. 버전 관리와 롤백:
  • 각 계층은 변경의 히스토리를 나타내므로, 특정 계층에서 문제가 발생할 경우 이전 계층으로 쉽게 롤백할 수 있습니다.
  1. 모듈화와 재사용:
  • 기본 OS 계층, 소프트웨어 설치 계층, 코드 변경 계층 등으로 이미지를 모듈화하여 관리할 수 있습니다. 이를 통해 특정 계층만 수정하고 재사용할 수 있습니다.
  1. 무결성 및 보안:
  • 각 계층은 읽기 전용입니다. 한번 생성된 계층은 변경되지 않습니다. 이러한 특징은 이미지의 무결성을 보장하며, 이미지가 예상대로 실행될 것임을 확신할 수 있게 해줍니다.
  1. 효율적인 배포:
  • Docker 이미지를 배포할 때 이미 존재하는 계층은 다시 다운로드하지 않습니다. 예를 들어, 베이스 이미지의 계층이 이미 존재하면 새로운 변경사항만 다운로드 받아 효율적인 배포가 가능합니다.
profile
신입 개발자

0개의 댓글