안녕하세요! 볼드나인 프론트개발자 김정수입니다.
도커를 사용 중이지만 제대로 알고 사용하고자 생각하여
도커 교과서라는 책으로 공부하게 된 내용을 담았습니다.
아직 완독하지는 않았지만 공부했던 내용을 공유하려고 합니다!
실행 환경
•
•
도커 데스크탑을 사용하는 것을 권장합니다.
도커는 컨테이너라는 경량 단위로 애플리케이션(이하 앱)을 실행하는 기능을 제공하는 플랫폼이다.
기존 클라우드 환경으로 이주하려면 두 가지 선택지가 있었는데.
서비스 인프라 (Iaas)
•
각 컴포넌트들 모두 가상머신 독립적 이주
•
이주 쉬움, 운영비 비쌈
서비스 플랫폼 (PasS)
•
가격이 저렴함.
•
컴포넌트가 클라우드 매니지 서비스에 종속됨 → 이주 과정이 복잡해짐
이 둘과 비교해 보았을 때
•
도커는
◦
특정 클라우드에 종속되지 않으며
◦
이식성이 높고 운영비가 낮다.
라는 장점이 있고, 컨테이너화된 앱은 어떤 환경에서든 동일한 기술 스택으로 동작하게 됩니다.
그래서 레거시 앱의 설계도 재구현에 비교적 적은 리소스를 투자하여
쉽게 현대화해 유연하고 탄력적이며 기민하게 만들 수 있습니다.
도커는 모놀리식 설계든 마이크로서비스든 기존 앱을 클라우드로 이주할 때 유용합니다.
모놀리식
마이크로 서비스
도커를 설치하고 난 후에 해당 명령을 실행하면
docker container run diamol/ch02-hello-diamol
Bash
복사
docker container run 명령은 컨테이너로 앱을 실행하라는 도커 명령입니다.
diamol/ch02-hello-diamol → 이 앱(이미지)은 누구나 내려받을 수 있도록 공유된 것입니다.
run 뒤의 이미지 이름(diamol/ch02-hello-diamo)을
로컬에서 찾고 없다면 docker 패키지를 내려받고 실행하게 됩니다.
이 단계를 빌드, 공유, 실행이라고 부름
다시 위의 명령을 실행하면 로컬에 저장되어 있기 때문에 바로 컨테이너를 실행하게 됩니다.
그런데 결과를 보게 되면 IP 주소는 간헐적으로 바뀌고 컴퓨터 이름은 매번 바뀝니다.
그 이유는 도커 컨테이너는 독립적인 가상 리소스를 가지게 되는데.
(하나의 독립적인 컴퓨터라고 생각하면 편합니다.)
상자 안에서는 상자 밖의 환경을 볼 수 없고
이 상자는 어떤 컴퓨터 상에서 동작하고, 컴퓨터는 여러 개의 상자를 실행할 수 있다.
상자는 서로 독립적인 환경을 갖지만 실행되는 컴퓨터의 CPU, 메모리, OS를 공유한다.
이런 구도가 중요한 이유는 격리와 밀집이라는 조건을 동시에 만족시킬 수 있기 때문입니다.
•
밀집
CPU와 메모리가 허용하는 한 되도록 많은 수의 앱을 실행하는 것을 의미
서로 다른 앱을 동시에 실행하는 데에는 제약이 따름
•
런타임의 버전이 다를 수도 있고
•
서로 호환되지 않는 버전
•
어느 한 앱이 리소스 많이 먹어서 공간이 부족해질 수도 있습니다.
이런 면을 고려하면 앱은 서로 독립된 환경에서 실행되어야 하는데
•
이럴 경우 한 컴퓨터에서 여러 개의 앱 실행이 불가능하기에 밀집이 불가능
이 모순된 조건을 달성하기 위해 가상머신을 사용할 수 있습니다.
•
가상 머신 사용
◦
가상 머신은 앱이 실행될 때 독립적 환경이 생긴다는 점에서 컨테이너와 큰 차이가 없다.
◦
하지만 컨테이너와 달리 호스트 컴퓨터의 OS를 공유하지 않고, 별도의 OS를 필요로 합니다.
▪
각각 자신의 OS를 가진다 → OS는 CPU와 메모리를 상당량 차지합니다.
▪
즉 격리는 달성되지만 밀집은 제공하지 못하는 환경입니다.
•
컨테이너는 이러한 가상머신의 단점을 해결할 수 있다.
◦
각각의 컨테이너는 호스트 컴퓨터 OS를 공유함 밀집
◦
외부와 독립된 환경을 제공함 격리
•
도커를 사용하는 한 컨테이너는 모두 똑같습니다.
◦
모든 앱 위에 관리를 위한 계층이 하나 추가됩니다.
◦
그래서 오래된 자바 앱이나, 어제 만들어진 Go 앱도 모두 같은 방법으로 관리가 가능합니다.
도커를 더 유용하게 사용할 수 있게 몇 가지 간단한 실습을 해보겠습니다.
컨테이너에 원격 컴퓨터에 접속하듯 터미널을 통해 접근하기.
docker container run —interactive —tty <image name>
Bash
복사
•
— interactive 컨테이너 접속된 상태 유지
•
—tty 플래그는 터미널 세션을 통해 컨테이너 조작 가능
이 명령어를 입력하여 대화식 컨테이너를 실행할 수 있습니다.
중요한 점은 로컬 터미널 세션이 열려 있다는 것과 연결된 컴퓨터가 현재 실행 중인 컨테이너 라는 것입니다.
새로운 터미널 세션을 열고 아래의 명령을 입력해 보겠습니다.
docker container ls
Bash
복사
•
도커는 컨테이너가 실행할 때마다 무작위로 생성되는 ID 값을 부여하는데
•
그리고 이 ID 값중 일부분이 호스트명이 됩니다.
다양한 docker container 명령어가 있는데 이때 이 ID 값으로 특정할 수 있습니다.
•
컨테이너에서 실행 중인 프로세스의 목록을 보여줍니다.
docker container top <container id>
Bash
복사
•
대상 컨테이너에서 수집된 모든 로그를 출력합니다.
docker container logs
Bash
복사
•
대상 컨테이너의 상세한 정보를 보여줍니다.
◦
앱에 발생한 문제를 추적하는 데에 유용한 정보가 많습니다.
docker container inspect
Bash
복사
컨테이너를 사용해 웹사이트 호스팅 하기
docker container ls —all
Bash
복사
앞서 컨테이너들을 닫았다면 컨테이너 상태가 전부 Exited 상태인 것을 볼 수 있습니다.
여기서 볼 수 있는 내용 중 두 가지는
•
컨테이너가 종료되었을 때 Exited 상태가 된다.
•
종료된 컨테이너는 CPU나 메모리 자원을 사용하지 않는다.
•
컨테이너가 종료되어도 컨테이너가 사라지지 않는다.
명시적으로 삭제하지 않는 한 그대로 남아있는다.
•
진짜로 호스팅 실습하기
docker container run --detach --publish <8088:80> <image 이름>
Bash
복사
•
—detach
◦
컨테이너를 백그라운드에서 실행함 컨테이너 ID를 출력
◦
도커 설치시 호스트 컴퓨터의 네트워크 계층에 도커가 끼어들어
호스트 컴퓨터의 네트워크 트래픽을 도커가 가로채서 컨테이너에 전달 가능합니다.
◦
컨테이너는 기본적으로 외부 환경에 노출되지 않습니다.
각 컨테이너는 고유의 IP 주소를 가지지만, 이 IP 주소는 도커 내부 가상 네트워크 주소라서
컨테이너의 포트를 공개한다는 것은 도커가 호스트 컴퓨터의 포트를 주시하다가
해당 포트로 들어오는 트래픽을 전달해 주는 것입니다.
•
— publish 컨테이너의 포트를 호스트 컴퓨터에 공개.
앞선 예제는 호스트 컴퓨터의 8080번 포트로 들어온 트래픽이 컨테이너의 80번 포트로 전달됩니다.
•
컨테이너 상태를 알 수 있는 명령어 (CPU, 메모리 네트워크 등의 정보)
docker container stats <container id>
Bash
복사
•
컨테이너 삭제 명령어
docker container rm <container id>
# --force 실행중인 컨테이너도 삭제 가능
Bash
복사
컨테이너 실행 원리
•
도커 엔진
◦
도커의 관리 기능을 맡는 컴포넌트
◦
새로운 이미지가 필요하면 이미지를 내려받으며 이미 있던 이미지라면 이전 이미지 사용
◦
호스트 OS와 함께 컨테이너와 가상 네트워크 등 도커 리소스 만드는 일 담당
◦
도커엔진은 항시 동작하는 백그라운드 프로세스
◦
도커 API는 도커 엔진의 설정을 수정하면
이 API의 외부 컴퓨터 호출할 수 없도록 차단하거나 허용 가능
•
도커 CLI
◦
실제 docker 명령을 사용할 때 도커 API를 호출하는 것이 도커 CLI
도커엔진과 상호작용할 수 있는 유일한 방법은 API를 통하는 방법
•
원격 컴퓨터에서 실행 중인 도커를 조작할 수 있도록 CLI가 요청하는 곳을 변경할 수 있다.
◦
빌드 환경, 운영환경, 테스트 환경 등 서로 다른 환경에서 동작하는 컨테이너를 관리하려면 이런 방법을 써야 합니다.
◦
도커 API는 OS와 상관없이 동일하게 사용 가능합니다.
도커 엔진은 containerd라는 컴포넌트를 통해 컨테이너를 실제 관리하는데,
호스트 OS가 제공하는 기능을 통해 가상환경을 만들게 됩니다.
도커 이미지 만들어보기
도커 허브에 공유된 이미지 사용하기
•
도커가 가장 먼저 이미지를 찾기 위해 접근하는 저장소는 도커 허브이다.
•
이 이미지를 제공하는 저장소를 레지스트리라고 한다.
•
도커 허브는 무료로 제공되는 공개 레지스트리다.
•
이미지를 내려받는 과정을 보면 여러 건의 파일을 동시에 내려받습니다.
•
이들 각각의 파일을 이미지 레이어라고 부릅니다.
•
물리적으로 여러 개의 작은 파일로 구성됩니다.
•
작은 파일들을 도커가 조립해서 내부 파일 시스템을 만듭니다.
•
이미지를 (없으면) 내려받고 실행하겠습니다.
docker container run -d --name web-ping diamol/ch03-web-ping
Bash
복사
•
-d 플래그
◦
—detach의 축약형(백그라운드 동작)
•
—name
◦
컨테이너의 이름 지칭 가능
◦
컨테이너 ID 대신 사용 가능
•
컨테이너의 이름이 web-ping인 컨테이너의 로그 확인!
docker container logs web-ping
Bash
복사
계속 어느 주소(지은이의 블로그 주소)로 요청을 보내고 있는데,
요청의 주소를 변경해 보겠습니다.
•
환경 변수
◦
OS에서 제공하는 키-값 쌍입니다.
◦
호스트 운영체제의 것을 가져오는 게 아니라
컨테이너의 호스트명이나 IP 주소처럼 도커가 부여해 줍니다.
docker rm -f web-ping # 실행중인 컨테이너를 삭제
docker container run --env TARGET=google.com diamol/ch03-web-ping
## 환경변수 TARGET을 변경하여 다시 실행
Bash
복사
•
log를 출력해 보면 요청을 보내는 주소가 TARGET에 적힌 값으로 적용된 것을 볼 수 있습니다.
•
도커 이미지는 설정값의 기본값을 포함해 패키징 되지만
컨테이너 실행 시 값을 임의로 변경할 수 있습니다. → —env <env_key>= <env_value>
•
호스트 컴퓨터에도 고유 환경 변수가 있지만
컨테이너는 도커가 부여한 환경 변수만을 가집니다.
Dockerfile 작성
•
일련의 인스트럭션으로 구성됩니다.
•
대문자로 서술되어 있지만 소문자도 무방합니다.
•
인스트럭션 몇 가지 종류들
◦
FROM → 이미지는 다른 이미지로부터 출발한다. (브랜치 같은 개념)
◦
ENV → 환경 변수 값을 지정하기 위한 인스트럭션
◦
WOKRDIR → 컨테이너 이미지 파일 시스템에 디렉터리를 만들고
해당 디렉터리를 작업 디렉터리로 지정하는 인스트
◦
COPY → 로컬 파일 시스템의 파일 혹은 디렉터리를 컨테이너 이미지로 복사하는 인스트럭션
◦
CMD → 도커가 이미지로부터 컨테이너 실행 시 실행할 명령을 지정하는 인스트럭션
컨테이너 이미지 빌드하기
•
이미지의 이름, 패키징에 필요한 경로를 추가해 주어야 합니다.
docker image build --tag web-ping . # .(dot) 현재 작업 디렉터리 지칭
Bash
복사
•
—tag 인자 값은 이미지의 이름입니다.(없으면 latest로 적힙니다.)
successfully buillt라는 메시지가 나왔다면 성공적으로 빌드 된 것입니다!
docker image ls 'w*' # w로 시작하는 태그명을 가진 이미지 목록
Bash
복사
이렇게 빌드 된 이미지는 도커 허브에서 내려받은 이미지와 똑같이 사용할 수 있습니다.
도커 이미지와 이미지 레이어 이해하기
•
도커 이미지
◦
패키징에 포함시킨 모든 파일
◦
이미지 레이어가 모인 논리적 대상
◦
레이어는 도커엔진의 캐시에 물리적으로 저장된 파일
◦
이미지 레이어 여러 이미지와 컨테이너에서 공유
◦
node.js가 앱이 실행되는 컨테이너를 여러 개 실행한다면
컨테이너는 모두 런타임이 들어 있는 이미지 레이어를 공유
앞서 만들었던 web-ping 이미지는 node 이미지를 기반으로 두어
OS와 런타임 레이어를 공유하게 됩니다.
기반 레이어(node) 위에 추가한 app.js 파일은 불과 몇 KB밖에 되지 않는데.
몇 가지 명령어를 통해 확인해 볼 수 있습니다.
•
image ls 명령어
◦
이미지의 논리적 용량이 해당 이미지가 실제로 차지하는 용량을 나타내는 것은 아닙니다.
image ls
Bash
복사
•
system df 명령어 실제 용량 확인 가능합니다.
•
이미지 레이어를 여러 이미지가 공유한다면 공유되는 레이어는 수정할 수 없어야 합니다.
•
도커는 애초에 이미지 레이어를 읽기 전용으로 만들어 이러한 문제를 방지합니다.
이미지 레이어 캐시를 이용한 Dockerfile 최적화
•
파일을 수정하고 이미지 다시 빌드 하면 새로운 이미지 레이어가 생김
•
인스트럭션의 결과가 이전 빌드와 같다면 이전에 캐시 된 레이어를 재사용
•
도커는 캐시에 일치하는 레이어가 있는지 확인하기 위해 해시값을 이용
•
기존 이미지 레이어에 해시값이 일치하는 것이 없다면 캐시 미스가 발생
◦
인스트럭션이 실행
◦
한 번 인스트럭션이 실행되면 그다음에 오는 인스트럭션은 수정된 것이 없더라도 모두 실행
◦
잘 수정되지 않는 인스트럭션이 앞으로, 자주 수정되는 게 뒤에 오도록 배치돼야 한다.
마치며
저는 막연하게 느껴졌던 도커를 이론적인 내용과 실습을 해보면서
조금이나마 더 가까워진(?) 느낌이 들었습니다.
도커교과서의 일정 부분을 살짝 맛보았는데 어떠셨을까요?
긴 글 읽어주셔서 감사합니다!