이미지는 코드와 코드를 돌리기 위한 여러 툴을 가지고 있습니다.
컨테이너는 이미지로 만들어진 인스턴스라 보시면 됩니다.
정리하자면 이미지는 클래스, 컨테이너는 인스턴스와 매치가 됩니다.
이미지를 가져오는 방법을 알아보겠습니다.
Docker Hub에 많은 이미지들이 있어요.
예를 들어 Node.JS 이미지는 아래 커맨드로 가져올 수 있습니다.
docker pull node
run 커맨드를 쓰면 Docker Hub에서 이미지의 newest 버전을 다운로드한 다음 컨테이너를 돌리게 됩니다.
docker run node
docker run node 입력해 보시면 아무 일도 없이 끝나요. 뭐가 어떻게 됐는지 알고 싶죠?
docker ps -a
-a, all 옵션을 준 ps 커맨드로 node 컨테이너가 어떻게 되어 있는지 볼 수 있어요.
docker run -it node
run 뒤에 it 옵션을 더하면 호스트에 interactive 세션이 만들어집니다.
이렇게 되면 컨테이너와 그 바깥에서 커뮤니케이션을 할 수가 있죠.
위 커맨드를 돌려 보시면 node 셸로 들어간다는 걸 알 수가 있습니다.
이제 우리만의 이미지를 만들어 봅시다.
Dockerfile을 만들어 주세요.
FROM
WORKDIR
COPY
RUN
EXPOSE
CMD
이미지는 레이어 베이스입니다.
이게 무슨 말이냐면 이미지를 빌드하거나 다시 빌드할 때
Dockerfile에 있는 코드 라인을 하나씩 보면서
새로운 코드 라인 또는 처음으로 바뀐 라인을 찾았으면 거기서부터
그 밑의 모든 라인들을 Docker가 (다시) 보게 됩니다.
코드 라인 하나하나를 레이어라 부르며, 그래서 이미지를 레이어 베이스 아키텍처로 되어 있다 합니다.
또한 한 번 빌드된 레이어들은 모두 캐시에 담깁니다.
Dockerfile을 바꾸지 않고 이미지를 다시 빌드하면
빌드가 정말 빠르게 이루어지는 것을 볼 수 있는데,
이것이 레이어들이 캐시에 담겨 있기 때문입니다.
어떤 이미지로 컨테이너를 돌리게 되면 컨테이너 레이어가 이미지 레이어 맨 위에 올라갑니다.
스택을 생각하시면 됩니다.
Dockerfile의 첫 번째 라인이 첫 번째 이미지 레이어가 되어 스택에 쌓이는 모습이요.
이미지가 바뀌지 않았다면 새 컨테이너를 만들지 않아도 됩니다.
Exited status인 컨테이너를 재시작할 수 있거든요.
docker start 컨테이너_ID 또는 이름
다만 run 커맨드와 start 커맨드의 결과가 같은 것은 아닙니다.
run 커맨드는 컨테이너를 foreground에서, start 커맨드는 컨테이너를 background에서 돌립니다.
Foreground에서 돌아가는 컨테이너를 attached 컨테이너,
background에서 돌아가는 컨테이너를 detached 컨테이너라 합니다.
하지만 이것은 그냥 커맨드마다 디폴트 세팅이 그렇게 되어 있는 것뿐이고요,
여러분이 바라는 세팅으로 돌릴 수 있습니다.
run 커맨드에 -d 옵션을 붙이거나 start 커맨드에 -a 옵션을 붙이면 됩니다.
docker attach 커맨드도 있는데 이것은 돌아가고 있는 detached 컨테이너랑 터미널을 이어 줍니다.
아니면 그냥 로그만 가져오면 된다! 할 때 docker logs 커맨드가 있습니다.
이거는 리얼타임으로 가져오는 건 아니고 컨테이너에서 프린트된 로그들을 모두 보여 줍니다.
아니면 docker logs에 -f, follow 옵션을 줘서 tracking할 수도 있고요.
컨테이너에서 돌릴 애플리케이션에서 유저와 인터랙션을 할 수 있습니다.
docker run 커맨드에 -i, interactive 옵션을 주면 됩니다.
이 옵션을 주면 컨테이너와 인터랙션을 할 수 있습니다.
Attached 컨테이너든, detached 컨테이너든 상관없습니다.
여기에 -t, tty 옵션을 같이 주는 게 좋은데요, 인터랙션할 터미널을 만든다고 생각하시면 됩니다.
docker start 커맨드라면 -a, -i 옵션을 줘야 합니다. -ai로 줄일 수 있습니다.
안 쓰는 컨테이너를 docker rm 커맨드로 지울 수 있습니다.
docker rm $1, $2, $n, ...
아니면 docker run 커맨드로 컨테이너를 돌릴 때 --rm 옵션을 넣어 주시면
컨테이너가 할 일을 끝냈을 때 알아서 없어집니다.
아, 이미지 리스트를 뽑고 싶을 때는 docker images 커맨드를 씁니다.
그리고 이미지를 지울 땐 docker rmi 커맨드를 씁니다.
다만 이미지를 지울 때는 이 이미지를 쓰고 있는 컨테이너가 없어야 합니다.
쓰지 않고 있는 이미지를 한 번에 지울 수 있는 docker image prune 커맨드도 있답니다.
이미지에는 코드와 애플리케이션 환경이 들어가 있죠.
만들어진 컨테이너의 사이즈는 그렇게 크지 않습니다.
이미지 위에 올라간 하나의 레이어일 뿐이거든요.
docker image inspect 커맨드로 이미지를 디테일하게 살펴볼 수 있습니다.
중요하게 볼만한 것으로는..
정도가 있습니다.
RootFS에 있는 레이어에는 Dockerfile에서 만들어진 레이어 말고도 여러 다른 레이어들이 있습니다.
예를 들면 FROM으로 가져오는 이미지 레이어들도 있어요.
돌아가고 있는 컨테이너에 어떤 파일을 주거나, 컨테이너로부터 어떤 파일을 받을 수 있습니다.
docker cp 커맨드를 쓰세요, 파일 또는 폴더를 컨테이너 안이나 바깥으로 복사할 수 있습니다.
docker run --name 이름 컨테이너_ID
컨테이너는 위 커맨드와 같이 이름만 주면 끝입니다.
이미지에는 이름뿐만 아니라 태그가 있습니다, name:tag 꼴입니다.
예를 들면 node:14 또는 node:12처럼요.
이렇게 보시니 태그가 어떤 느낌인지 아시겠죠?
이미지의 이름은 이미지 그룹 같은 느낌이에요. node처럼요.
태그는 이미지 그룹 안에서 이 이미지의 버전 같이 쓰일 수 있습니다.
docker build -t or --tag name:tag
이미지 공유를 위한 두 가지 방법을 알려 드릴게요.
이미지를 공유하기 위해 Docker Hub 또는 private registry를 쓰세요.
Docker Hub는 official Docker image registry입니다.
이미지 process, save, deploy 등에 쓰일 수 있는 여러 서비스들을 가지고 있습니다.
하지만 웬만하면 private registry를 많이 쓰게 될 거예요.
docker push IMAGE_NAME
docker pull IMAGE_NAME
Docker Hub에서 리포지터리 만들어 보시면 알겠지만 그냥 이미지입니다.
로컬에게 이미지가 Docker에서 만들어졌음을 알게 하려면,
이미지 이름을 여러분의 Docker 아이디/이미지 이름으로 바꿔 주시면 됩니다.
이를 위해 docker tag 커맨드를 써서 이름을 바꿔 봅시다.
커맨드 이름이 tag이긴 하지만 이름도 바꿀 수 있습니다, 심지어 태그를 안 줘도 돼요.
그리고 docker tag는 이름을 바꾼다기보다는 새 이름을 가진 똑같은 이미지를 복제하는 것입니다.
그리고 퍼블릭 리포지터리라고 하더라도 push 하는 것은 리밋이 걸려 있습니다.
이를 위해 docker login 커맨드로 로그인을 해야 합니다.
Push 하려고 하는 이미지의 Docker 아이디와 로그인한 이미지가 같아야 하죠.
데이터를 가져올 때는 로그인하지 않아도 되고요.
Priviate registry를 쓸 때는 push, pull 키워드와 IMAGE_NAME 사이에 registry에 대한 어드레스가 있어야 합니다.
그냥 쓰면 Docker Hub에 push, pull 하는 거예요.
docker run 커맨드로 정해 준 이미지가 로컬에 없으면 registry에서 이미지를 찾습니다.
로컬에 이미지가 있다면 바로 돌리고 (업데이트 체크 안 함),
그렇지 않다면 registry에서 이미지를 찾는데 recently 버전을 씁니다.