docker

도커 (8)컨테이너이름, rm, v, 요약, 리소스정리, cp, CMD & ENTRYPOINT

finepiz 2022. 2. 26. 17:48

============

container run할 때 이름 안주기

 

C:\docker> docker container ls

CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                     NAMES

2fdfc16ec42c   example/echo:latest   "/bin/bash"              23 seconds ago   Up 22 seconds   0.0.0.0:58496->8080/tcp   zealous_mcnulty ⇐ 해당 컨테이너가 detach 모드로 전환

9317682730d9   example/echo:latest   "go run /echo/main.go"   5 minutes ago    Up 5 minutes    0.0.0.0:58470->8080/tcp   tender_merkle

                          docker container run --name 옵션을 생략하면 임의의 이름을 생성해서 제공

 

웹서버가 하나밖에 없으면 쉽게 제어하려면 이름을 가져가는게 좋다. ID치려면 어려우니까

 

근데 100개 띄우면 이름을 부여하는게 부담스러워진다

->운영환경에선 이름 사용 안해, 자동 부여되도록 해

 

개발할 때나 컨테이너 한 두개 띄울 때 액세스 쉽게 하려고 이름 부여함

포트랑 마찬가지네

 

============

--rm

 

컨테이너를 이름 부여해서 run하는건 좋지 않다

운영할 땐 같은 컨테이너를 여러개 띄울텐데

--name으로 이름 부여하고 같은 run을 두번 입력하면 --name이름 같다고 실행 안됨 유니크해야해

stop해도 같은 이름으로 run안된다

다시 띄우려면 rm해야해

 

- 개발하는 단계에서 ID를 이용해서 access하려고 하면 헷갈림

- 이름을 사용하려고 하면 중복되면 안되고

 

개발 시 컨테이너가 종료되면 자동으로 삭제되게 설정할 수 있다, --rm옵션으로

docker container run --name myreact-app --rm -itd -p 3000 myapp

docker container stop myreact-app

이제 stop하면 지워짐

 

*저거 -P옵션하면 EXPOSE 3000이라고 돼 있으면 3000번 포트를 노출하고, 임의의 포트를 3000과 연결함

 EXPOSE 3000 + -P = -p 3000

 

---

-v

개발단계에서의 얘기

 

PS C:\docker> docker container run --name myreact-app --rm -itd -p 8282:3000 myapp

이 상태에서 리액트 어플리케이션의 내용을 변경하고 싶어

 : 내 PC의 소스 코드를 수정 → docker image build → docker container run

이렇게 해야되는데 빌드하는데 시간이 오래 걸리고...

 

내가 갖고 있는 파일을 실행 컨테이너와 공유할 수 있으면 어떨까?

 

도커는 내가 준 파일을 특정디렉토리에 따놓고 그걸 run만 하고 있는데,

배포말고 개발단계에서는 그 시간을 좀 줄이면 어떨까

호스트의 특정 디렉토리를 컨테이너의 내부와 공유! 복사하고 빌드안해도 되게! 볼륨매핑!

 

VOLUME을 이용해서 호스트의 특정 디렉터리를 컨테이너 내부와 공유해서 복사하고 빌드하는 시간을 단축 

http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter07/11

 

컨테이너를 run하는데 -v옵션을 줘서 

-v 호스트디렉토리 : 컨테이너내부디렉토리

 

호스트 디렉토리를 컨테이너 내부 디렉토리와 연결

내용을 바꾸면 변경자체가 공유돼있기 때문에 바뀐다, 컨테이너 run 중에도 바꿔도 요청 다시하면 바뀐다

 

볼륨 : 호스트와 컨테이너가 공유디렉토리를 쓴다

 

활용(1)

호스트의 변경을 여러 컨테이너에 함께 반영하고 싶을 때

웹서버를 여러개 띄웠는데, 소스코드가 전부 다르면 안되니까

하나의 공유디렉토리를 걸어놓고 모든 컨테이너들이 소스코드를 받아가게

 

활용(2)

컨테이너가 휘발성 객체, 죽을수도 사라질수도

일반적인 서비스용 컨테이너 스프링부트와같은, REST API를 제공하는 얘들은 돌다가 사라져도 또 띄우면 똑같은 동작을 할 수 있다 = stateless, 상태관리하지않고 동작하다 사라지면 또 띄우면 똑같이 동작

 

그에 비해서 mysql서버는 계속 달라, 데이터가 쌓여, stateful한 서비스

이건 컨테이너가 죽어버리면 거기있던 데이터가 날아가버리면 안된다

stateful한 서비스들은 데이터 유지관리보관해야하는 기능이 필요하다, persistence하게 관리해야한다

이때 볼륨매핑을 씀

mysql이죽어서 다른 mysql이 올라오더라도 같은 상태로. 데이터를 컨테이너내부가 아니라 볼륨매핑을 통해 호스트측에다가

여러개의 컨테이너에게 동일한 최신데이터를 줘야할 때!

 

============

요약

 

제일 중요한건 -itd 옵션

입력과 출력을 공유하고

detach모드로 동작시키고

 

도커파일을 만들어서 내가만든 리액트, 자바를 이미지화

 

실행중인 컨테이너에 attach할 때

attach -> 빠져나오면 컨테이너가 죽어 그래서 detach키를 통해서 detach모드로 빠져나와야

exec해서 쉘을 실행 -> 해당 컨테이너에 쉘이 제공돼야하는 경우 그렇게 빠져나오면 컨테이너의 메인프로세스는 동작하므로 컨테이너가 중지안됨

 

--rm 하면 개발환경에서 유용

포트바인딩은 -p

컨테이너 port는 고정돼도 상관없다 컨테이너마다 전부 8080이어도 괜찮

호스트port는 걔마다 달라야해, 운영단계에선 일일이 지정해주는것보단 지정하지 않고 자유롭게 배정될 수 있도록 하는게 방법

 

이미지만들때 사용자 입력 안들어가게 : -y말하는거겠지

파일사이즈줄이기 : &&말하는거겠지

 

============

0)

컨테이너도 하나의 컴퓨터니까 포트도 여러개고

거기에 서버프로그램 여러개 두면, 각각 포트가 필요할텐데(컨테이너 안에 db, 스프링부트, 리액트 각각 설정에 포트를 써놨을 텐데)

EXPOSE를 보다가, 왜 Dockerfile에서 왜 딱히 저 여러개랑 각각 다른 호스트 포트랑 연결하는 설정이 없는것 같냐

이미지 만들때도 -p옵션에서 하나만 연결하고

->컨테이너에 서버를 여러개 둘 수 있다o, 얘네 각각 바깥 포트 몇번이랑 연결할지 설정할 수 있다o

 = 컨테이너 하나에 DB, 리액트, 스프링부트 둘 수 있고 명령어나 Dockerfile로 각각 다른 호스트 포트와 연결할 수 있다

->근데! 좋은 설계는 컨테이너 당 프로그램 하나 돌리는게 깔끔한거고 원칙이래!이게 바로 시원한 답변이었다

->좋은 설계는 DB, 리액트, 스프링부트를 각각 컨테이너 하나씩에만 둔다 서로 연결을 할 수 있는 방법이 있다(당연), 쉽게하는 건 도커컴포즈지

 

============

리소스 정리 (모든 컨테이너와 이미지를 삭제)

PS C:\Users\myanj> docker container rm -f $(docker container ls -aq)

PS C:\Users\myanj> docker image rm -f $(docker image ls -aq)

 

============ 

cp(▽볼륨매핑하면 될걸 왜..)

nginx (웹 서버) 이미지를 이용해서 컨테이너를 생성 

PS C:\Users\myanj> mkdir c:\docker\webroot

PS C:\Users\myanj> docker run -itd --name mywebserver -p 8080:80 nginx

 

이제 컨테이너 내부의 파일을 수정해보려고해

 

attach해서 들어가봤더니 리스닝중이야

detach모드 : 컨+p+q로 해서

exec로 다시 해보자

 

(1)

PS C:\Users\myanj> docker container attach mywebserver

2022/01/26 00:38:40 [notice] 39#39: signal 28 (SIGWINCH) received

2022/01/26 00:38:40 [notice] 38#38: signal 28 (SIGWINCH) received

:

Ctrl + p + q ⇒ detach 모드로 전환

 

(2)

PS C:\Users\myanj> docker container exec -it mywebserver /bin/bash

root@bca3ef603d99:/#

 

root@bca3ef603d99:/# cd /usr/share/nginx/html/ ⇐ nginx의 기본 웹 루트 디렉터리

root@bca3ef603d99:/usr/share/nginx/html# ls

50x.html  index.html

root@bca3ef603d99:/usr/share/nginx/html# cat index.html ⇐ 브라우저를 통해서 확인한 페이지

<!DOCTYPE html>

<html>

<head>

 :

 :

 

근데 vi해보니까 없어서 exit로 빠져나옴(다운받아서 해도 되지만 그냥 나옴)

 

(3)

컨테이너의 파일을 가져와서, 수정하고, 다시 넣으려고 해

cp :

▽앞에것을 복사, 뒤의 것이 복사할 곳.  : 로 컨테이너인지 호스트인지를 구분

 

docker container cp mywebserver:/usr/share/nginx/html .

앞에 있는걸 . 로 가져와

한칸 띄우기 전까지 SRC, 뒤에것이 목적지

 

============

수정을 한 뒤 수정한 index.html 파일을 컨테이너 내부로 복사

PS C:\docker\webroot> docker container cp .\html\index.html mywebserver:/usr/share/nginx/html\index.html

 

확인할땐 웹서버로 요청을 해보든지

cat으로 하든지

PS C:\docker\webroot> docker container exec mywebserver cat /usr/share/nginx/html/index.html

 

============

commit

 

이때 ! 변경된 내용을 포함하고 있는 컨테이너를 이미지로 저장, 

-a : 저작자

-m : 커밋메시지

 

컨테이너 이름 다음에 이름을 주기
PS C:\docker\webroot> docker commit -a "만든사람 myanjini" -m "새로운 컨텐츠를 포함한 웹 서버" mywebserver mynewwebserver

sha256:4ce4c3809f8968157c11fcd46f124d0b51e34ec43cb52a5884d363aa55c51721

 

PS C:\docker\webroot> docker image ls

REPOSITORY       TAG       IMAGE ID       CREATED          SIZE

mynewwebserver   latest    4ce4c3809f89   21 seconds ago   141MB

nginx            latest    605c77e624dd   3 weeks ago      141MB

 

============

생성한거 도커허브에 등록하기

1.태그바꾸기

docker image tag 

내 계정명이 포함돼있는 새로운 이름으로 해야해

docker image tag mynewwebserver:latest myanjini/mynewwebserver:1.0

(처음에 commit할 때 이름줘도 된다)

 

2.

docker push 이미지명

PS C:\docker\webroot> docker push myanjini/mynewwebserver:1.0

 

 

============

도커 허브에 등록된 이미지를 이용(▽원래있는걸로하잖아)해서 새로운 컨텐츠를 포함한 컨테이너를 실행

docker container run --name mynewwebserver -d -p 9090:80 이미지이름

PS C:\docker\webroot> docker container run --name mynewwebserver -d -p 9090:80 myanjini/mynewwebserver:1.0

 

============

CMD vs ENTRYPOINT

도커파일에서 두개 다 컨테이너가 실행됐을 때 명령어를 실행해주는 기능

 

이재홍 아저씨 문서에 다 있다

http://www.pyrasis.com/book/DockerForTheReallyImpatient/Chapter07/06

 

============

CMD

FROM ubuntu

CMD  ["echo", "Hello"]

 

PS C:\docker> docker image build -t cmd_img -f Dockerfile_cmd .

PS C:\docker> docker container run cmd_img

Hello

 

근데?

PS C:\docker> docker container run --help

Usage:  docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

:

 

PS C:\docker> docker container run cmd_img echo World

World

 

World만 나와

 

⇐ Dockerfile의 CMD 내용을 container run 명령에서 전달된 명령어로 덮어써서 실행

 

============

ENTRYPOINT

FROM ubuntu

ENTRYPOINT  ["echo", "Hello"]

PS C:\docker> docker image build -t entrypoint_img -f Dockerfile_entrypoint .

PS C:\docker> docker container run entrypoint_img

Hello

 

PS C:\docker> docker container run entrypoint_img echo World

Hello echo World

 

뒤의 명령어가 인자값으로 사용이 된다

▽그냥 echo Hello echo World가 이어 쓰이나봐?

 

이렇게 두개가 동작하는 방식이 다르다

ENTRYPOINT는 전달하는게 파라미터값으로 반영 : 컨테이너가 실행될 때 그 명령어가 쓰여야된다고 만드는애가 지정하는 것 

CMD는 덮어쓰임 : 경우에 따라 실행되는 명령어가 바뀌어도 되는 경우