도커 이미지

날짜
Sep 23, 2024
태그
docker
설명
이미지를 관리하는 기본적인 방법

도커 이미지

 
모든 컨테이너는 이미지를 기반으로 생성된다. 도커는 DockerHub 라는 중앙 이미지 저장소에서 이미지를 내려받는다. 누구든 이미지를 내려받을 수 있기때문에 공유가 쉽다.
 
docker [create, run, pull]의 명령어로 이미지를 내려받을때 도커 허브에서 해당 이미지를 검색한 후 내려받게 된다. 하지만 도커허브에는 누구나 이미지를 올릴 수 있기 때문에 공식 라벨이 없는 이미지는 사용법을 찾을 수 없거나 제대로 동작하지 않을 수 있다.
 
 
도커허브에 업로드되어 있는 ubuntu 이미지
도커허브에 업로드되어 있는 ubuntu 이미지
 

도커이미지 생성

이미지를 내려받아 사용할 수도 있겠지만 실무에서는 특정 개발 환경을 직접 구축한 뒤 이미지를 직접 생성하는 경우가 생긴다.
 
>>> docker run -it --name commit_test ubuntu:14.04 root@23490f8:/ echo test_first >> first
컨테이너를 생성하고 내부에 first라는 이름의 파일을 생성해 기존 이미지와 다른 환경을 만든다.
 
컨테이너 환경을 이미지로 만든다.
컨테이너 환경을 이미지로 만든다.
잘 만들어졌다!
잘 만들어졌다!
 
직전에 만든 이미지를 기반으로 두번째 컨테이너를 생성하고 커밋한다.
직전에 만든 이미지를 기반으로 두번째 컨테이너를 생성하고 커밋한다.
 

이미지 구조 이해

docker inspect ubuntu:14.04 명령어 실행 결과
docker inspect ubuntu:14.04 명령어 실행 결과
docker inspect commit_test:first 명령어 실행 결과
docker inspect commit_test:first 명령어 실행 결과
docker inspect commit_test:second 명령어 실행 결과
docker inspect commit_test:second 명령어 실행 결과
Layers 를 확인해보면 같은 이미지 기반으로 레이어가 씌워진걸 확인할 수 있다.
 
 
commit_test:first 이미지를 삭제하려고 하면 에러가 발생한다.
commit_test:first 이미지를 삭제하려고 하면 에러가 발생한다.
이미 사용중인 컨테이너가 존재하는 경우, 이미지를 삭제할 수 없다. -f 명령어로 강제 삭제하려고 하면 실제 이미지를 삭제하진 않고, 이미지 이름만 삭제한다.
 
이미지를 사용중인 컨테이너를 삭제한 후에 이미지를 제거하면 정상 제거된다.
이미지를 사용중인 컨테이너를 삭제한 후에 이미지를 제거하면 정상 제거된다.
 

이미지 추출

추출되어야하지만 용량 부족으로 내려받을 수 없었음..
추출되어야하지만 용량 부족으로 내려받을 수 없었음..
>>> docker load -i ubuntu_14_04.tar
내려 받은 파일을 다시 docker에 로드할 수 있다.
 

이미지 배포

이미지를 생성했다면 이를 다른 도커 엔진에 배포할 방법이 필요한데, 이때 도커의 이미지 구조인 레이어 형태를 이용하지 않으면(위와 같이 파일로 추출-배포) 매우 비효율적이다.
 
만든 이미지 파일을 다른 도커 엔진에서 사용하려면 어떻게 해야 할까?
  • 공식 도커 허브 이미지 저장소 사용(Public)
  • 사설 도커 저장소 사용(Private)
 

공식 도커 허브 저장소

도커 허브에 회원가입 후 Public 저장소를 생성했다.
도커 허브에 회원가입 후 Public 저장소를 생성했다.
 

사설 도커 저장소

도커 사설 저장소를 사용하면 개인 서버에 이미지를 저장할 수 있는 저장소를 만들 수 있다. 이는 컨테이너로 구현되므로 이에 해당하는 도커 이미지가 존재한다. 이 이미지는 도커 허브에서 공식으로 제공하고 있다.
 
>>> docker run -d --name myregistry \ -p 5000:5000 \ # 기본적으로 저장소 컨테이너는 5000번 포트를 사용 --restart=always \ # 컨테이너가 정지될 때마다 다시 시작하도록 설정 registry:2.6
이미지를 관리하는 도커 컨테이너를 생성한다.
>>> curl localhost:5000/v2/
notion image
 

사설 저장소에 이미지 push 하기

>>> docker tag my-image-name:0.0 ${DOCKER_HOST_IP}:5000/my-image-name:0.0
이미지의 이름을 추가한다.
>>> docker push 172.17.0.1:5000/my-image-name:0.0 The push refers to repository [172.17.0.1:5000/my-image-name] Get "https://172.17.0.1:5000/v2/": http: server gave HTTP response to HTTPS client
https를 사용하지 않은 레지스트리 컨테이너에 접근하려고 했을때 오류가 발생한다.
DOCKER_OPTS="--insecure-registry=172.17.0.1:5000"
>>> vim /lib/systemd/system/docker.service [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// \ --containerd=/run/containerd/containerd.sock \ --insecure-registry=172.17.0.1:5000 <추가> ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always >>> systemctl daemon-reload >>> systemctl restart docker
http 통신이 가능하도록 수정
>>> docker push 172.17.0.1:5000/my-image-name:0.0
설정 후 다시 push
push가 성공했다.
push가 성공했다.
>>> sudo curl localhost:5000/v2/_catalog {"repositories":["my-image-name"]}
사설 저장소에 이미지가 올라간 내용을 확인할 수 있다.
 

Nginx 서버로 접근 권한 생성

지금까지 방법으로 별도의 인증없이 레지스트리 컨테이너에 이미지를 올릴 수 있다. 도커 허브의 login 과정이 있던 것 처럼 레지스트리 컨테이너에 미리 정의된 계정으로 로그인하도록 설정할 수도 있다.
 
로그인 인증 기능은 보안을 적용해야 하기 때문에 self-Signed 인증서와 키를 발급해 TLS를 적용한다. 명령어를 차례로 입력해 self-signed ROOT 인증서 파일을 생성한다. 이때 인증서 정보를 입력하는 칸은 전부 공백으로 입력해도 된다.
>>> mkdir certs >>> openssl genrsa -out ./certs/ca.key 2048 # RSA 개인 키를 생성, 생성된 개인 키를 ./certs/ca.key 파일에 저장, 키의 길이를 2048비트로 설정 >>> openssl req -x509 -new -key ./certs/ca.key -days 10000 -out ./certs/ca.crt # openssl ~~: 새로운 인증서 서명 요청(CSR)을 생성, 앞서 생성한 개인 키(ca.key)를 사용하여 CRT를 생성 # -out ~~: 생성된 CSR을 ./certs/ca.crt 파일에 저장
notion image
 
>>> openssl genrsa -out ./certs/domain.key 2048 # RSA 개인 키를 생성, 생성된 개인 키를 ./certs/domain.key 파일에 저장, 키의 길이를 2048비트로 설정 >>> openssl req -new -key ./certs/domain.key -subj /CN=172.17.0.1 -out ./certs/domain.csr # openssl ~~: 새로운 인증서 서명 요청(CSR)을 생성, 앞서 생성한 개인 키(domain.key)를 사용하여 CSR을 생성 # -subj ~~: 요청할 인증서의 주체(도메인 또는 IP)를 설정합니다. CN(Common Name)에 IP 주소 172.17.0.1을 지정 # -out ~~: 생성된 CSR을 ./certs/domain.csr 파일에 저장 >>> echo subjectAltName=IP:172.17.0.1 > extfile.cnf # extfile.cnf라는 파일을 생성하여 subjectAltName 확장을 지정 # subjectAltName: 인증서에 대한 추가적인 이름을 지정, IP 주소(172.17.0.1:5000)를 지정, 브라우저나 도커 클라이언트가 인증서의 CN(Common Name) 외에, 이 IP도 신뢰하도록 만듬 >>> openssl x509 -req -in ./certs/domain.csr -CA ./certs/ca.crt -CAkey ./certs/ca.key -CAcreateserial -out ./certs/domain.crt -days 10000 -extfile extfile.cnf # openssl ~~: 인증서 서명 요청(CSR)을 기반으로 인증서를 생성 # -in ~~: 앞서 생성한 CSR을 입력으로 사용 # -CA ~~: CSR을 서명할 루트 인증서(자체 서명된 인증서)를 지정 # -CAkey ~~: 루트 인증서의 개인 키를 사용하여 서명 # -CAcreateserial: 서명할 때 사용할 일련 번호를 자동으로 생성 # -out ~~: 최종 생성된 인증서를 domain.crt 파일에 저장 # -days ~~: 인증서의 유효 기간을 10,000일로 설정 # -extfile ~~: ubjectAltName 확장을 포함시키기 위해 이전에 생성한 extfile.cnf 파일을 참조
결과로 domain.crt인증서 파일이 생성, 이 파일은 172.17.0.1:5000에 대한 SSL/TLS 통신에 사용
notion image
>>> htpasswd -c htpasswd googie >>> mv htpasswd certs/
로그인 하지 않으면 설치하라는 안내 메시지가 출력된다.
로그인 하지 않으면 설치하라는 안내 메시지가 출력된다.
>>> apt-get install apache2-utils
 
# vim certs/nginx.conf upstream docker-registry { server registry:5000; } server { listen 443 ssl; server_name 172.17.0.1; ssl_certificate /etc/nginx/conf.d/domain.crt; ssl_certificate_key /etc/nginx/conf.d/domain.key; client_max_body_size 0; chunked_transfer_encoding on; location /v2/ { # 특정 버전의 Docker 클라이언트를 차단하는 설정 if ($http_user_agent ~ "^(docker/1\.(3|4|5(\.[0-9]+)?-dev)|Go ).*$") { return 404; } proxy_pass http://docker-registry; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 900; } auth_basic "registry.localhost"; auth_basic_user_file /etc/nginx/conf.d/htpasswd; add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always; }
 
docker stop myregistry; docker rm myregistry docker run -d --name myregistry --restart=always registry:2.6 docker run -d --name nginx_frontend \ -p 443:443 \ --link myregistry:registry \ -v $(pwd)/certs/:/etc/nginx/conf.d \ nginx:1.9 docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}" docker login https://172.17.0.1
신뢰할 수 없는 인증서(self-signed)를 사용하여 저장소 컨테이너 로그인 실패
신뢰할 수 없는 인증서(self-signed)를 사용하여 저장소 컨테이너 로그인 실패
 
>>> cp certs/ca.crt /usr/local/share/ca-certificates/ >>> update-ca-certificates
notion image
 
>>> service docker restart >>> docker start nginx_frontend
도커 재시작, nginx 컨테이너 시작
>>> docker login https://172.17.0.1
로그인 성공!
로그인 성공!
 
ubuntu@ip-172-31-9-147:~$ sudo curl -u googie:12341234 -X GET https://172.17.0.1/v2/_catalog {"repositories":[]}
현재 저장소에는 아무런 이미지도 존재하지 않는다.
 
>>> docker tag my-image-name:0.0 172.17.0.1/my-image-name:0.0 >>> docker push 172.17.0.1/my-image-name:0.0
저장소 컨테이너에 이미지를 push 할 수 있다(https로 로그인했으므로 자동으로 443포트로 인식)
계속 Retry를 반복하다가 500에러 발생
계속 Retry를 반복하다가 500에러 발생
 
>>> sudo journalctl -u docker.service
Sep 23 03:35:14 ip-172-31-9-147 dockerd[98105]: failed to start daemon, ensure docker is not running or delete /var/run/docker.pid: process with PID 97> Sep 23 03:35:14 ip-172-31-9-147 systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
실패하는 원인은 /var/run/docker.pid 파일이 이미 존재
 
>>> sudo systemctl start docker >>> docker push 172.17.0.1/my-image-name:0.0
도커 재실행, 다시 push, 그리고 또 실패.
 
ubuntu@ip-172-31-9-147:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 6.8G 6.7G 25M 100% / tmpfs 479M 0 479M 0% /dev/shm tmpfs 192M 1.1M 191M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/xvda16 881M 133M 687M 17% /boot /dev/xvda15 105M 6.1M 99M 6% /boot/efi tmpfs 96M 12K 96M 1% /run/user/1000 ubuntu@ip-172-31-9-147:~$ sudo docker system prune -a WARNING! This will remove: - all stopped containers - all networks not used by at least one container - all images without at least one container associated to them - all build cache Are you sure you want to continue? [y/N] y Deleted Containers: 236f235f1fb087acb26f0db43036b83c5a5f1fa3e1d0f95d2821b7b88e0bfc6d 8ccaf6f77159657f1c11b765386f817fde2b65bced0ef88646fc13b9c0eb94cc f3bb3b8475cbc7e2d500a7b1228e9db8ec11785f9b70b2e7f4f35a219a4e62e6 7ef102791504220c7bfcd20aa09e94273b011258379ac2104960fce08f3e3bd0 29bbff849f6701077174cece66ddb70dbe1af6264b141e4fac4036c58c3da7e3 ef0f3d09443be92cca0833b7a696aa94a3ad93e1aacae4ea4de84c6b6a34ef97 d58d22201f21960c7d947f156cd6426b24d8c69971b84c23476e1861abeba1df 5434e05a62d15b9fa67105946b6c32f1cacac4cf2fb526dfdf109be6271864e2 b50cd78d9aef0af19b2d9fd1b9cbf485b0a763545d47b29853a41c9bfd4aec3c 4067630328bf240921b71b97889a944a45390417214229d65dc0ec4a548d3662 Deleted Images: untagged: alicek106/fluentd:mongo untagged: alicek106/fluentd@sha256:ae06399ae52a4534908c08a40d1eb7cb29699f4f4008064d311f22e3f97f1086 deleted: sha256:36a0f4961dfb06921712b10752ed778eebae82a4b410cfd399b31428cdebfbb7 deleted: sha256:8db0241b5b5281174c17db096a181475a242dd45de624b1488b15e9e71d0b277 deleted: sha256:55124a9cad3491edf4d62997920c00cc6146f1c2e255616382902b5d7737de9b deleted: sha256:8dacd35f2eb2270caaa9f070ed7e599225266ee8b299278218d84d3218af86d3 deleted: sha256:1e7ddcc04ad73b8433a0d1eaf6a6f05321d6aa159c81329c305c1bdcde0c1007 deleted: sha256:f57bc02c510ff15780116b4aed8dcc7e114409c1f9f5d932201eda2867b497be deleted: sha256:307e0058bc9fa2e0085e5ad806f13a629c1814da025ae5e88e7bee9d627a3896 deleted: sha256:3ca23aab1c9a3b1c07b5950d8e4100883c7e5f7ae68f267eda3b37450f2d735b deleted: sha256:072c6c4dbb92dcadff9f897c2ff88df5c1f6432970d436d16b8222f2fda213cc deleted: sha256:60ab55d3379d47c1ba6b6225d59d10e1f52096ee9d5c816e42c635ccc57a5a2b untagged: nginx:latest untagged: nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3 deleted: sha256:39286ab8a5e14aeaf5fdd6e2fac76e0c8d31a0c07224f0ee5e6be502f12e93f3 deleted: sha256:d71f9b66dd3f9ef3164d7023cc99ce344d209decd5d6cd56166c0f7a2f812c06 deleted: sha256:634d30adf8a2232256b2871e268c8f0fdb2c348374cd8510920a76db56868e16 deleted: sha256:f230be3f4e104c7414b7ce9c8d301f37061b4e06afe010878ea55f858d89f7f3 deleted: sha256:c5210c8480131b7dbc5ad8adc425d68cd7a8848ee2e07de3c69cb88a4b8fd662 deleted: sha256:d4f588811a337e0b01da46772d02f7f82ee5f9baff6886365ffb912d455f4f53 deleted: sha256:d73e21a1e27b0184b36f6578c8d0722a44da253bc74cd72e9788763f4a4de08f deleted: sha256:8e2ab394fabf557b00041a8f080b10b4e91c7027b7c174f095332c7ebb6501cb untagged: mongo:latest untagged: mongo@sha256:1a7b344b3ee8b07190fa15555726333e38f5db0a3bfb38b2ce9a1d3973b060be deleted: sha256:81a05b7283523bfe55eb2a90a39789c1bb3bbe95c14efcb4b014ef3e35a5e95e deleted: sha256:2b8e9ac3a426b183e7f8492f6f22c70e2b1d65e1c1a247411eaac3f199ec02cf deleted: sha256:af43f03e41e4b7b8997ccce7b0c9a09f0d82f479c130288ac6b32afb4c1aa236 deleted: sha256:0fa5bf9de901f47195be5f6ed874cbef896c045c3ef83d5f0f452aa1c28877a7 deleted: sha256:5c962e7fd265c034c5959c8199e9b43bec2b112adc26add6336a41259f211383 deleted: sha256:2ea3ae59c4b2a722870d57119064f92fc9c504bede1a1d23df2152bc8e9e4b55 deleted: sha256:bc9a703fd3ce53758af898262ac60c16ce07271d58a7f0cd85ee3ef41e3f5d72 deleted: sha256:48f5e4a39414e7581b1bdb8cdae050d1fee21037e4beb06a3cd5b5f9c2a8b130 deleted: sha256:1b9b7346fee7abbc7f5538eaa23548bd05a45abe8daf6794024be0c8ad7d60bb untagged: 172.17.0.1/my-image-name:0.0 untagged: 172.17.0.1:5000/my-image-name:0.0 untagged: 172.17.0.1:5000/my-image-name@sha256:f63eee3537f580bf42d4ad3da21ab57e01be3f0b1e4719eac480e095f5f9ab5a untagged: googieyu/my-image-name:0.0 untagged: googieyu/my-image-name@sha256:f63eee3537f580bf42d4ad3da21ab57e01be3f0b1e4719eac480e095f5f9ab5a untagged: my-image-name:0.0 deleted: sha256:a9dff8c5b43712a7748ec441abf0f3ff44cc7212561b5313851f5e70b64389fb deleted: sha256:f399d6fa885d6968c1691132405999ea9e799f64de86a429eee12e15d47710fb untagged: mongo:4.4 untagged: mongo@sha256:52c42cbab240b3c5b1748582cc13ef46d521ddacae002bbbda645cebed270ec0 deleted: sha256:d896c071ac6936bcb205f35c17a556b9cabf54733c4e1f4d68cda1348424d65d deleted: sha256:9770d60bea41920e69fd9c7a66d2a029979dd53fc32999611067fb0f9583a31d deleted: sha256:b67f913c5556a12c2fca5f20f1143f66fcd6f44bfff821d489c2153758bfc002 deleted: sha256:2d5fe7b2409e5f94be3b254b2d8f2f63317e57b9ef49b903da48236b7e0bb781 deleted: sha256:5ae8e3694b517a7bb6b76ceccf7d4506a6e0c89f0410e62616578c586d98c535 deleted: sha256:3bfff9e4ddd39aaacc94f04f379fc23f06e655d4e765f3af390f757e36bacd18 deleted: sha256:3f6bf8dcee12c86866a845f8326cef3429004d2466444f9fd5da8c7b943bc6a2 deleted: sha256:02483bf799c5a02a67ea1bcd2a526b01d6f881aaf7947ad74434957990d0efbb deleted: sha256:4a1518ebc26e2e4c26f1c5d78a36d41d87d2fd4a7e4ad37c5f9033f2eb52f26b untagged: ubuntu:14.04 untagged: ubuntu@sha256:64483f3496c1373bfd55348e88694d1c4d0c9b660dee6bfef5e12f43b9933b30 deleted: sha256:13b66b487594a1f2b75396013bc05d29d9f527852d96c5577cc4f187559875d0 deleted: sha256:e08f4f554d8df6b04f441fcdfe207b6314d3c709daa2b1ef66f79bbfb529b8c4 deleted: sha256:c28d0c854fd56736ef4456e3c1c4276a28159751dc13fd1b340bd38d69473f7e deleted: sha256:f2fa9f4cf8fd0a521d40e34492b522cee3f35004047e617c75fadeb8bfd1e6b7 Total reclaimed space: 1.797GB
디스크 용량을 100% 사용중이다. 사용하지 않는 컨테이너를 모두 제거했다.
 
ubuntu@ip-172-31-9-147:~$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry 2.6 10b45af23ff3 4 years ago 28.5MB nginx 1.9 c8c29d842c09 8 years ago 183MB
사용중이지 않은 모든 이미지 파일이 제거됐다.
 
ubuntu@ip-172-31-9-147:~$ sudo docker pull googieyu/my-image-name:0.0 0.0: Pulling from googieyu/my-image-name 2e6e20c8e2e6: Pull complete 0551a797c01d: Pull complete 512123a864da: Pull complete e89b1d14b431: Pull complete Digest: sha256:f63eee3537f580bf42d4ad3da21ab57e01be3f0b1e4719eac480e095f5f9ab5a Status: Downloaded newer image for googieyu/my-image-name:0.0 docker.io/googieyu/my-image-name:0.0 ubuntu@ip-172-31-9-147:~$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE googieyu/my-image-name 0.0 a9dff8c5b437 13 days ago 197MB registry 2.6 10b45af23ff3 4 years ago 28.5MB nginx 1.9 c8c29d842c09 8 years ago 183MB
도커 허브에 있는 이미지를 내려받았다.
 
ubuntu@ip-172-31-9-147:~$ sudo docker tag my-image-name:0.0 172.17.0.1/my-image-name:0.0 Error response from daemon: No such image: my-image-name:0.0 ubuntu@ip-172-31-9-147:~$ sudo docker tag googieyu/my-image-name:0.0 172.17.0.1/my-image-name:0.0 ubuntu@ip-172-31-9-147:~$ sudo docker push 172.17.0.1/my-image-name:0.0 The push refers to repository [172.17.0.1/my-image-name] 3176d458de2b: Layer already exists 83109fa660b2: Layer already exists 30d3c4334a23: Layer already exists f2fa9f4cf8fd: Pushed 0.0: digest: sha256:f63eee3537f580bf42d4ad3da21ab57e01be3f0b1e4719eac480e095f5f9ab5a size: 1152 ubuntu@ip-172-31-9-147:~$ sudo curl -u googie:12341234 -X GET https://172.17.0.1/v2/_catalog {"repositories":["my-image-name"]}
현재 이미지는 googieyu/my-image-name:0.0으로 존재, 이미지를 푸시할 레지스트리 주소(172.17.0.1/my-image-name:0.0)로 다시 태그, 이번엔 사설 저장소로 푸시 성공.
 

사설 저장소 RESTful API

 

사설 저장소 옵션 설정

 

댓글

guest