본문 바로가기

내용 복습/devOps

'도커 교과서' 1~2장 정리

도커를 공부하게 된 이유
node.js로 반년정도 공부하면서 배포도 병행해왔지만, 기반 지식 없이 구글링만으로 이어가다보니 문제가 발생해도 어디가 문제인지 전혀 알수 없었기에 모래성을 쌓는 느낌이었습니다. 이번 기회에 도커를 처음부터 배워보겠습니다.

 

1. 컨테이너가 IT 세상을 점령한 이유

기존에는 클라우드 환경으로 이주하려면 IaaS(서비스로서의 인프라)와 PaaS(서비스로서의 플랫폼) 두가지 선택지가 있었다. 전자는 애플리케이션의 각 컴포넌트를 가상 머신에서 동작시키게 된다. 특정 클라우드에 종속되는 신세는 면할 수 있지만 운영비가 상승하고, 후자는 각 컴포넌트를 하나씩 클라우드의 managed service로 옮기는 까다로운 프로젝트를 진행해야 하지만 운영비는 절감할 수 있었다.

도커는 앞에서 언급된 단점이 없는 또 다른 선택지를 제공한다. 도커를 도입하면 애플리케이션의 각 컴포넌트를 컨테이너로 이주한다음 애저·아마존의 서비스나 혹은 직접 구축한 도커 클러스터에서 전체 애플리케이션을 실행할 수 있다. 특정 클라우드에 종속되지 않으므로 원하는 클라우드 서비스나 데이터센터, 심지어 로컬환경에서도 운영 가능하며 낮은 운영비와 이식성도 확보할 수 있다.

컨테이너는 가상 네트워크를 통해 외부에 노출되지 않고 서로 통신할 수 있다. 애플리케이션을 분할해 기능별로 별도의 컨테이너에 배치할 수 있고 단일 모놀리식 애플리케이션을 여러개의 분할된 분산 애플리케이션으로 바꾸는 것도 가능하다. 이런 방식으로 핵심 기능을 작고 독립된 단위로 만들어 따로따로 다루면 변경 내용만 테스트할 수 있고, 해당 기능의 확장성을 조절하거나 필요한 기술만 선택하는 것도 가능해진다.

도커는 서드파티 소프트에어를 도입하는 데도 유용하다. 코드를 작성하지 않고도 새로운 기능을 추가할 수 있는데, 도커 허브에서 공유된 서비스를 이용하면 된다. 또한 어떤 형태의 애플리케이션이라도 도커 클러스터의 컨테이너에서 실행할 수 있다.

이를테면 서버리스가 있는데, 이 기술의 목표는 개발자가 코드를 작성하고 서비스에 푸시하면 서비스가 코드를 빌드하고 패키징하도록 하는 것이다. 함수 사용 측에서 함수를 호출하면 서비스는 해당함수의 인스턴스를 생성해 요청을 처리한다. 이 과정에는 빌드서버도, 파이프라인도, 관리가 필요한 운영환경도 필요없이 플랫폼이 모든 일을 처리하게 하는 것이다.

- 실습환경 초기화 명령어
docker container rm -f $(docker container ls -aq)
- 내려받은 이미지가 차지한 디스크 용량 회수
docker image rm -f $(docker image ls -f reference='diamol/*' -q)

 

 

2. 도커의 기본적인 사용법

도커는 내려받은 데이터를 똑똑하게 관리하므로 이 명령을 언제 실행해도 아무런 문제가 생기지 않는다.
컨테이너를 실행시킬 때 필요한 이미지가 누락되었다면, 다시 내려받아 문제없이 컨테이너를 실행시킬 수 있다.

- 'Hello World' 메시지를 출력하는 컨테이너 실행 명령어
docker container run diamol/ch02-hello-diamol

 

이름이 diamol/ch02-hello-diamol인 도커 애플리케이션 패키지를 내려받고 컨테이너로 애플리케이션을 실행해 메시지를 출력하는 과정이 나타나있다. 처음 위의 명령어를 입력하면 아래의 메시지가 출력되는데, 

Unable to find image 'diamol/ch02-hello-diamol:latest' locally
latest: Pulling from diamol/ch02-hello-diamol

 

docker container run 명령은 컨테이너로 애플리케이션을 실행하라는 도커 명령이다. 이 애플리케이션은 미리 도커로 실행되도록 패키징돼 누구나 내려받을 수 있도록 공유된 것이다. 이 패키지를 도커에서는 '이미지'라고 한다. 이미지를 이용해 컨테이너를 실행하려면 먼저 이미지가 있어야하기에 pull 한 후 실행하는 과정을 볼 수 있다.
또한 출력되는 부분에서는 컴퓨터의 이름, 운영체제 종류, 네트워크 주소 등을 확인할 수 있는데, 이 과정에서 도커를 사용하는 워크플로의 핵심을 볼 수있다. 이 과정은 빌드, 공유, 실행으로 이루어져 있는데, 아무리 복잡한 애플리케이션도 이 과정을 거친다. 그리고 도커를 실행할 수 있는 환경이라면 어디서든 실행할 수 있도록 도커 이미지를 만들 수 있다. 이런 방법으로 도커의 핵심이 이식성이 확보되는 것이다. 

조금 전의 명령을 한번 더 입력해보면 이미지를 이미 내려받았기 때문에 이미지를 내려받는 부분이 사라지고 바로 컨테이너를 실행하는 메시지가 출력된다. 같은 컴퓨터를 사용하므로 운영체제, 아키텍쳐의 내용은 같지만 컴퓨터 이름과 네트워크 주소에 대한 내용은 달라진다.

 

컨테이너의 구조를 보면 호스트명, IP주소, 파일 시스템까지 모두 도커가 만들어낸 가상의 리소스다. 컨테이너는 서로 독립적인 환경을 갖지만 실행되는 컴퓨터의 CPU와 메모리, 운영체제를 공유한다. 이런 구조가 중요한 이유는 격리와 밀집이라는 조건을 동시에 만족할 수 있기 떄문이다. 밀집은 CPU와 메모리가 허용하는 한 되도록 많은 수의 애플리케이션을 실행하는 것을 의미한다. 하지만 여러 애플리케이션을 동시에 실행하는 데엔 제약이 따르고 서로 독립된 환경에서 실행되어야 한다. 하지만 그럴경우 다시 밀집을 달성할 수 없어 모순된다.

 

이것을 해결하기 위해 가상머신을 도입했지만 컨테이너와 달리 호스트 컴퓨터의 운영체제를 공유하지 않고 별도의 운영체제를 필요로 한다. 각각의 가상머신은 자신만의 운영체제를 별도로 갖는데, 애플리케이션이 사용해야 할 CPU와 메모리자원을 상당량 차지하고 운영체제의 라이선스 비용, 업데이트 설치비용이 단점이다. 결국 가상머신은 격리는 달성할 수 있지만 밀집은 제공하지 못한다. 컨테이너는 이런 단점을 해결할 수 있는데, 각각의 컨테이너는 호스트 컴퓨터의 운영체제를 공유하므로 필요한 리소스가 크게 경감되어 실행도 빠르고 가상머신에 비해 많은 수를 실행할 수 있다.

 

- 터미널 세션을 통해 컨테이너 조작하는 병령어
docker container run --interactive --tty diamol/base

 

--interactive 플래그를 사용하면 컨테이너에 접속한 상태가 되고 --tty는 터미널 세션을 통해 컨테이너를 조작하겠다는 의미이다. 명령어를 입력하면 diamol/base로부터 대화식 컨테이너를 실행하며, / #으로 표시되는데 이 프롬프트는 컨테이너 내부에 접속된 터미널 세션이다. hostname과 date 명령어를 사용해 컨테이너 내 환경을 확인할 수 있다.

도커 자체는 호스트 컴퓨터의 아키텍처나 운영체제와 상관없이 동일하게 동작하지만, 컨테이너에 들어 있는 애플리케이션은 운영체제나 아키텍처를 가릴 수 있다. 결국 컨테이너의 내용물이 무엇이든 컨테이너를 다루는 방법은 환경과 상관없이 동일하다.

- 실행중인 모든 컨테이너 보기
docker container ls
- 대상 컨테이너에서 실행중인 프로세스 목록
docker container top f1
- 대상 컨테이너에서 수집된 모든 로그 출력
docker container logs f1
- 대상 컨테이너의 상세한 정보
docker contianer inspect f1
- 세션 종료
exit

 

도커는 컨테이너를 실행할 때마다 무작위로 생성한 ID 값을 부여하고, 이 중 일부분이 호스트명이 된다. 이 때 컨테이너를 특정하려면 컨테이너 ID의 처음 몇글자를 지정하면 된다. 위 예시의 'f1'이 바로 그것이다. 

그리고 도커는 애플리케이션의 표준 출력으로부터 로그를 수집하는데, 조금 전 살펴본 logs에서는 입력한 명령과 출력된 내용을 모두 볼 수 있었지만 실제 애플리케이션이 실행된 컨테이너에서는 애플리케이션이 출력하는 로그만 보인다.

inspect는 컨테이너에서 발생한 문제를 추적하는 데 유용한 정보가 제공되며 자동처리에 유용한 JSON 포맷으로 되어있다. 위의 명령들은 문제를 해결하기 위해 일상적으로 사용할 명령들이다.

 

대화식 컨테이너를 실행할 때 컨테이너 내부에 접속된 터미널 세션을 만들고 세션이 종료될 때 컨테이너도 종료되는 컨테이너였다. exit을 입력하여 세션을 끝내면 모든 컨테이너가 종료되므로 ls 명령어를 치면 실행중인 컨테이너가 없다고 나올 것이다.

 

- 상태와 상관없이 모든 컨테이너 목록 확인
docker container ls --all

 

컨테이너 내부의 애플리케이션이 실행 중이어야 컨테이너 상태로 실행 중을 출력하니, 애플리케이션 프로세스가 종료되면 컨테이너의 상태도 Existed가 된다. 종료된 컨테이너는 CPU 자원이나 메모리를 사용하지 않는다. 즉, 대화식 컨테이너의 경우 터미널 세션을 종료하는 시점에 종료된다. 그리고 종료된 컨테이너도 명시적으로 삭제하지 않는 한 그대로 남아있다. 또한 컨테이너의 파일 시스템이 그대로 남아 있으므로 호스트 컴퓨터의 디스크 공간을 계속 점유한다.

그럼 백으라운드에서 계속 동작하게 하려면 어떻게 해야될까? 도커를 사용하는 주목적은 웹 사이트, 배치프로세스, 서버 애플리케이션 실행 등이므로 이런 형태가 주된 사용처이다.

 

- 간단한 연습용 페이지(아파치 + HTML)
docker container run --publish 8088:80 diamol/ch02-hello-diamol-web

위의 diamol/ch02-hello-diamol-web 이미지는 아파치 웹서버와 HTML 페이지를 담고 있는데, 컨테이너를 실행하면 실제 웹서버를 통해 웹페이지가 제공된다. 백그라운드에서 동작하면서 네트워크를 주시(listen)하게 하려면 두개의 플래그를 적용하면 된다.

  • --detach: 컨테이너를 백그라운드에서 실행하며 컨테이너 ID를 출력한다.
  • --publish: 컨테이너의 포트를 호스트 컴퓨터에 공개한다.

-- detach 플래그를 적용해 실행한 컨테이너는 마치 리눅스 데몬이나 윈도우의 백그라운드로 동작하며 겉으로 드러나니 않는다. 도커를 설치하면 호스트 컴퓨터의 네트워크 계층에 도커가 끼어들게 되는데, 그러면 호스트 컴퓨터에서 들고나는 네트워크 트레픽을 모두 도커가 가로채서 그중 필요한 것을 컨테이너에 전달할 수 있다.

컨테이너는 기본적으로 외부 환경에 노출되지 않는다. 고유한 IP주소를 같지만 도커가 관리하는 내부 가상 네트워크의 주소지 호스트 컴퓨터가 연결된 물리 네크워크에 연결된 것이 아니다. 컨테이너 포트를 공개하는 것은 도커가 호스트 컴퓨터의 포트를 주시하다가 해당 포트로 들어오는 트레픽을 컨테이너로 전달해 주는 것이다. 예제에서는 8088번 포트로 들어온 트레픽이 컨테이너의 80번 포트로 전달되었다.

호스트 컴퓨터가 연결된 물리 네트워크의 컴퓨터는 컨테이너의 IP 주소에 접근할 수 없다. 왜냐하면 이 주소는 도커 내부에만 존재하는 주소이기 때문이다. 그러나 포느가 공개된다면 컨테이너로 트래픽을 전달할 수는 있게 되는 것이다. 그리고 호스트 컴퓨터의 포트로 지정한 8088을 이용해 localhost:8088 페이지에 접근할 수 있다. 이 HTTP 요청은 로컬 컴퓨터에서 보낸 것인데, HTTP 응답은 컨테이너로부터 나온 것이다. 이 컨테이너의 애플리케이션은 계속 실행된 상태이므로 컨테이너도 계속 실행된 상태가 된다.

 

- 실시간 CPU, 메모리, 네트워크, 디스크 사용량 확인
docker container stats
- 컨테이너 삭제 (강제)
docker container rm --force
- 모든 컨테이너 삭제(주의 필요)
docker container rm --force $(docker container ls --all --quiet)

--force 플래그면 실행중인 컨테이너라도 바로 삭제할 수 있다.

 

도커를 구성하는 컴포넌트는 여러가지가있다.

  • 도커 엔진 : 관리 기능의 컴포넌트로, 로컬 이미지 캐시를 담당하여 새로운 이미지가 필요하면 이미지를 내려받고 기존 이미지가 있다면 그것을 쓴다. 호스트 운영체제와 함께 컨테이너와 가상 네트워크 등 도커 리소스를 만드는 일도 담당한다. 항시 동작하는 백그라운드 프로세스이다.
  • 도커 API :  표준 HTTP 기반 REST API다. 엔진의 설정을 수정하면 이 API를 네트워크를 경유해 외부 컴퓨터로부터 호출할 수 없도록 차단/허용할 수 있다.
  • 도커 명령행 인터페이스(CLI) : API의 클라이언트다. 우리가 docker 명령을 사용할 때 실제로 도커 API를 호출하는 것이다. 도커 엔진과 상호작용할 수 있는 유일한 방법은 API를 통하는 것이고 그것의 접근 허용범위는 몇가지 선택할 수 있으며 CLI를 통해 API에 요청을 전달하는 구조이다.

 

연습문제

위의 아파치 웹서버와 index.html로 이루어진 웹페이지를 수정하는 것이다. 일단 컨테이너에 접속한다.

 

docker exec -it <컨테이너_ID 또는 이름> /bin/bash

여기서 bash가 작동하지 않아 /bin/sh로 했다. 다음 cd를 이용해 파일 경로로 이동하여 ls로 파일이 있는지 확인한다. 여기서는 문제에 경로가 주어졌다.

vi <파일명>으로 파일에 접속해 i를 눌러 수정후 ecs + :wq로 빠져나왔다. localhost를 새로고침하니 수정사항이 잘 반영되었다.

git commit할 때 수정해본 적이 있긴한데 수정을 저렇게 하지 않게 되니 잘 사용하지 않았다. 오랜만에 기억을 되살리는 기회가 되었다.

 

 

 

이 블로그의 내용은 직접 구매한 책의 내용을 정리한 것에 불과하고 책을 구매한다면 더 깊은 내용을 경험할 수 있고 제공되는 파일을 활용하여 쉽게 학습하실 수 있습니다.(광고아님)

출처: 도커 교과서

 

https://www.yes24.com/Product/Goods/111408749

 

도커 교과서 - 예스24

도커 전문가가 알려주는 실전에 강한 도커 사용법!입문자에게 딱 맞는 구성으로 시작하자!200개의 실습으로 실전 투입을 위한 준비를 마치자!이 책은 저자가 수년에 걸쳐 완성한 ‘하루 1시간 학

www.yes24.com