컨테이너
- 샌드박스(sandbox)화된 런타임 환경
- 샌드박스화되었다는 의미는 프로세스가 보호된 영역에서 동작한다는 것이다.
- 따라서 호스트 시스템에 부정적인 영향을 미치는 것으로부터 보호한다.
패키징 기술 (Packaging technology)
- 컨테이너 기술은 패키징(packaging) 기술로 간단히 표현할 수 있다.
- 패키징의 대상은 애플리케이션과 이것이 동작할 수 있는 환경이다.
- 자신이 동작할 수 있는 환경을 포함하고 있으므로 쉽게 배포가 가능하다.
- 컨테이너 기반 애플리케이션 패키징
Standard
: 규격화된 컨테이너 사용Portable
: 컨테이너는 이동이 가능Light weight
: 표준 컨테이너에 담을 수 있는 용량의 제한Security & Protection
: 컨테이너별 보안과 안전장치
가상화 vs 컨테이너
- 가상화에서는 물리적 컴퓨터 시스템 전체를 가상머신으로 만들고 그 운영체제를 가상머신에 설치한 상태로 배포한다.
ex. VMWare 머신 위에서 운영체제를 여러 개 띄운다.- 여러 운영체제가 하나의 하드웨어를 공유하고 운영체제들이 각 커널을 가진다.
- 서로 독립된 운영체제를 구동하므로 컨테이너보다 오버헤드가 증가한다.
- 반면 컨테이너들은 컨테이너를 구동하는 운영체제의
커널(kernel)
을 공유한다.
ex. Docker 이미지 여러 개를 하나의 운영체제 위에 띄운다.- 커널이란 하드웨어 시스템으로 접근할 수 있는 터널이라고 생각하면 쉽다.
- 따라서 하나의 운영체제 안에서 여러 커널을 공유하므로 가상화보다 오버헤드가 적다.
컨테이너 기술의 역사
- 컨테이너의 핵심 기술은 분리(isolation)에 기반을 둔다.
- Unix V7: chroot를 통해 프로세스 간 분리를 할 수 있게됨
- FreeBSD Jail: Jail이라는 독립된 작은 시스템으로 나눠 커널을 공유
- Linux VServer: Jail처럼 운영체제 수준의 가상화로 시스템 리소스를 분리
- Solaris Containers: 존(zone) 개념 도입해 자원 분리
- Open VZ: 리눅스 커널 패치로 자원을 분리할 수 있는 기능 제공
- Process Container: 컴퓨터 자원 프로세스 사용량을 제한/격리하기 위함
LXC
: chroot의 확장된 형태로 현재 통용되는 컨테이너 기술의 시초
도커가 이를 컨테이너 엔진으로 초기에 사용함Docker
- 한번 구축하면 어느곳에서나 실행할 수 있는
Build Once, Run Anyway
실현 - 프랑스의 dotCloud 회사에서 시작한 프로젝트이다.
- 플랫폼에 사용할 기반 기술로 컨테이너를 활용하려는 목적이었다.
- 따라서 플랫픔 서비스를 제공하기 위해 필요한 기술들을 도커에 적용하게 되었다.
- 이에 따라 리눅스 컨테이너를 보편화할 수 있는 도커가 탄생했다.
- 한번 구축하면 어느곳에서나 실행할 수 있는
Kubernetes
- 구글에서 2015년 7월에 오픈소스로 공개했다.
- 2016년에 쿠버네티스를 CNCF(Cloud Native Computing Foundation)에 기증했다.
- 따라서 VMWare, Azure, AWS, 도커에서 쿠버네티스를 자신의 인프라에서 지원할 수 있게 되었다.
- 컨테이너화된 워크로드와 서비스를 관리할 수 있는 대표 오케스트레이션 툴이다.
- Container Security Issue
- 컨테이너를 적용한 앱들이 활발하게 사용되면서 Dirty COW와 같은 보안문제가 발생했다.
리눅스 커널에서 readonly 메모리 복사할 때 race condition을 발생시키는 이슈
이를 통해 write 권한을 얻을 수 있어, 일반 권한 사용자가 root 권한 상승 시도
- 컨테이너를 적용한 앱들이 활발하게 사용되면서 Dirty COW와 같은 보안문제가 발생했다.
- OCI(Open Container Initiative)
- 도커가 컨테이너 기반의 서비스 활성화에 기여한 것은 사실이다.
- 그러나 특정한 솔루션에 과도하게 의존하는 것을 경계하기 위해 컨테이너 포맷과 런타임에 대한 개방형 표준을 만들었다.
- OCI 표준을 따르는 런타임으로 CRI-O(Container Runtime Interface-OCI)가 개발되었다.
- 초기 컨테이너 런타임은 도커만 있었지만, CRI-O, RKT, Containerd가 등장했다.
- 컨테이너 런타임을 제어하는 것을 오케스트레이션이라고 한다.
이에 대한 표준을 따르는 구현체가 바로 쿠버네티스이다.
컨테이너 vs 가상머신
(1) 머신 가상화
App1 App2 App3
Bins/Lib Bins/Lib Bins/Lib
게스트 OS 게스트 OS 게스트 OS
--------- 하이퍼바이저 ---------
-------- 인프라스트럭처 --------
(2) 컨테이너
App1 App2 App3
Bins/Lib Bins/Lib Bins/Lib
-------- 컨테이너 엔진 --------
---------- 운영체제 ----------
-------- 인프라스트럭처 --------
- 컨테이너는 가상화인가? Not Exactly
- 컨테이너에서 동작하는 앱이 독립된 환경에서 실행되고 다른 컨테이너 앱에 영향을 미치지 않는다는 점은 가상화와 유사하다.
- 그러나 컨테이너는 가상화처럼 가상머신별 독립된 운영체제가 동작할 수 없다. (ex. VMWare)
- 컨테이너는 운영체제를 분리하는 게 아니라, 앱을 운영체제로부터 독립시킨다.
- x86 리눅스는 x86 리눅스 컨테이너를, x86 윈도우 운영체제는 x86 윈도우 컨테이너를 써야 한다.
- 즉, 서로 다른 운영체제 기반의 컨테이너는 단일 머신에서 실행될 수 없다.
- 가상화는 하이퍼바이저를 이용해 여러 개의 운영체제를 실행하기 때문에 컨테이너처럼 경량 구조가 아니다.
컨테이너가 유리한 경우
- 애플리케이션이
멀티서비스(multiservice)
아키텍처인 경우
마이크로서비스(microservice)라고 한다.
독립적으로 배포할 수 있는 소규모 서비스의 모음
ex. 카카오 결제 서버 하나가 죽어도 다른 서비스들은 돌아가는 것 - 애플리케이션이 동작하는 서버의 수를 최소화하고자 하는 경우
- 클라우드 네이티브 애플리케이션을 개발하고자 하는 경우
- 애플리케이션 개발환경이 배포환경과 유사한 경우
가상머신이 유리한 경우
- 애플리케이션이
모놀리식(monolithic)
아키텍처인 경우
모든 서비스(결제, 쇼핑, 스토리지 등)를 하나의 인스턴스로 관리하는 전통적인 구조
하드웨어 메모리를 늘리는 식으로 업그레이드를 할 수밖에 없다. - 서로 다른 운영체제가 필요한 경우
- 플랫폼에 고정된 스토리지 시스템이 필요한 경우
- 운영체제의 많은 기능이 필요한 경우
도커 (Docker)
- 응용프로그램을 컨테이너로 실행하고 관리할 수 있는 오픈소스 프로젝트이다.
- 도커를 이용해 앱이 수행될 인프라스트럭처와 앱을 분리할 수 있고 쉽고 빠르게 배포할 수 있다.
- 리눅스에서 운영체제 수준의 가상화를 제공하는
PaaS
제품이라고 볼 수 있다. - 컨테이너 안의 소프트웨어들은 동작에 필요한 모든 파일들을 포함하고 있다.
- 도커는 실행되는 시스템의 제약을 받지 않으므로 물리머신 혹은 가상머신에서도 실행될 수 있다.
- 컨테이너는 이미지로 저장된다.
이미지는 실행가능한 패키지이고, 코드/런타임/라이브러리/환경변수/설정파일이 들어 있다.
생성되는 컨테이너는docker ps
명령어로 도커 컨테이너를 확인할 수 있다.
구동 방식
- 도커 컨테이너를 실행하기 위해서는 도커 엔진이 필요하다.
- 도커 엔진은 클라이언트-서버 애플리케이션이다.
도커 데몬, REST API, CLI 3가지 컴포넌트로 구성된다. - docker CLI를 통해 도커 컨테이너, 이미지, 네트워크, 데이터 볼륨 등을 관리한다.
- docker CLI는 REST API를 통해 도커 데몬과 통신을 하는 구조이다.
데몬(demon)
은 background process를 의미한다고 이해하면 쉽다.
도커 아키텍처
- 클라이언트-서버 아키텍처이다.
- 도커 클라이언트에서 도커 데몬과 REST API를 통해 통신하여 컨테이너를 생성/실행/배포한다.
- 서버와 클라이언트가 동일한 시스템에서 설치되거나 혹은 각각 별도의 시스템에서 설치될 수 있다.
- 도커 데몬은 레지스트리에서 이미지를 도커 호스트로 내려받아 컨테이너 인스턴스를 생성한다.
생성되는 도커 이미지, 컨테이너, 네트워크, 볼륨 등을도커 오브젝트(docker object)
라고 한다.
구조와 관련된 주요 컴포넌트
- 도커 데몬: 도커 호스트에서 동작하는 데몬 프로세스로, 도커 오브젝트들을 관리한다.
- 도커 클라이언트:
docker run
과 같은 명령어를 도커 데몬에 요청하는 역할을 한다. - 도커 레지스트리: 도커 이미지를 저장하는 역할로, 도커 허브로 혹은 프라이빗으로도 구축할 수 있다.
- 도커 이미지
- 읽기전용 템플릿으로, 동작에 필요한 파일들을 포함하고 레지스트리에 등록해 배포할 수 있다.
Dockerfile
을 이용해 사용자의 커스텀 이미지를 생성할 수도 있다.- Dockerfile을 변경해 이미지를 재빌드하면 수정된 레이어들만 재빌드된다.
- 따라서 도커 이미지가 가상머신에 비해 가볍고 크기가 작으며 빠르게 빌드되는 것이다.
- 도커 컨테이너
- 도커 이미지의 실행 버전, 즉 인스턴스이다.
- 도커 사용자는 컨테이너에 여러 개의 네트워크 인터페이스를 통해 접근 가능하다.
- 현재 실행 중인 컨테이너를 기반으로 새로운 도커 이미지를 생성할 수도 있다.
도커 클라이언트가 도커 데몬에 보내는 명령 수행과정
$ docker run -i -t ubuntu /bin/bash
(1) 우분투 이미지가 로컬에 없다면 기본 레지스트리인 도커 허브에서 우분투를 로컬로 다운로드한다.
(2) 도커는 다운로드된 이미지로부터 새로운 컨테이너를 생성한다.
(3) 도커는 파일시스템을 생성된 컨테이너에 최상위 레이어로 할당한다.
(4) 컨테이너에 네트워크 인터페이스를 생성해 추가하고 기본 네트워크에 연결한다. (IP 주소도 할당됨)
(5) 컨테이너를 시작하고 /bin/bash
를 실행한다.
(6) exit 명령을 입력하면 컨테이너가 중지된다. (삭제는 아니므로 재실행 혹은 삭제할 수 있음)
도커 기반 서비스가 배포될 때 관여되는 주요 컴포넌트
- 인프라스트럭처: 호스트머신들의 집합으로 네트워크, 저장시스템 등을 모두 포함한다.
- 호스트 OS: 인프라스트럭처에 설치된 리눅스와 같은 운영체제이다.
- 도커: 도커 데몬을 의미하며 클라이언트에서 들어온 다양한 도커 명령을 수행한다.
- 노드: 컨테이너가 수행되는 시스템으로(worker), 독립적인 물리시스템 혹은 가상머신일 수도 있다.
- 스웜
- 도커 노드들을 클러스터로 묶어주는 컨테이너 오케스트레이션 도구이다.
- 워커노드와 매니저노드(스웜 클러스터를 제어하고 워커노드에 적절한 컨테이너 배치)로 구분된다.
- 워커노드에서 도커 컨테이너가 실행된다.
- 서비스
- 동일한 목적을 위해 구성된 애플리케이션들의 집합이다.
- 동일한 서비스 내에 속한 앱들은 컨테이너로 실행되고 스웜 워커노드들에 분산 배치된다.
- 동일한 서비스 내의 컨테이너는 모두 동일한 이미지에서 생성된다.
- 그러나 동일한 서비스에 포함된 컨테이너들이 동일한 노드에 있을 필요는 없다.
- 스택: 서비스들을 그루핑한 것으로, 스택 내 서비스들은 상호 연계되어 있다.
도커 기반 기술
- Go 언어로 작성되었고, 리눅스 커널이 제공하는 네임스페이스나 유니온 파일 시스템 등을 제공한다.
- 유니온 파일 시스템은 물리적으로 서로 다른 파일시스템이더라도 사용자에게는 하나로 보인다.
즉, 하나의 디렉터리에서 서로 다른 파일시스템 내용을 통합해 보여준다. - 도커는 리눅스에서 제공하는 기능들을 컨테이너 포맷으로 만들어 단일 파일로 생성해낸다.
- 도커 이미지는 레이어로 구성된 파일인데 레이어를 단계적으로 쌓아 최종 도커 이미지를 빌드한다.
- 따라서 최상위 레이어는 하단에 있는 레이어에 의존성을 갖게 된다.
- 각 레이어는 파일과 디렉터리로 구성되고 읽기전용이어서 수정하려면 쓰기 권한을 가진 레이어를 생성해야 한다.
- 빌드될 때는 기존 이미지와의 차이(diff)를 새로운 레이어로 생성한다.
- 컨테이너가 실행될 때 생성되는 새로운 파일이나 디렉터리 등의 결과물도 새로운 레이어가 된다.
- 새로운 레이어가 생성되면 커밋(commit)되었다고 말한다.
- 도커는 새로운 레이어가 생성될 때마다 이미지를 만든다.
- 최하단의 레이어가 가장 근간이 되는 레이어이고 다른 레이어들은 이를 기반으로 빌드된다.
- 따라서 빈번히 수정되는 레이어는 최상단에 오도록 구성해야 한다.
설치해보기
- 도커 데스크톱
- 도커가 설치되었는지 확인
docker --version
튜토리얼 진행해보기
$ docker run --name repo alpine/git clone https://github.com/docker/getting-started.git
$ docker build -t docker101tutorial .
$ docker run -d -p 80:80 --name docker-tutorial docker101tutorial
$ docker tag docker101tutorial roomyhan/docker101tutorial
- Clone container
- Build image
- Run container
- Save and share image
도커 명령어 실행해보기
$ docker run -d -p 80:80 docker/getting-started
// 위 명령어는 튜토리얼을 진행했다면 안해도 됨
$ docker --version
$ docker image ls
$ docker container ls
$ docker container ls --all
docker image ls
현재 도커가 관리하고 있는 이미지 확인docker container ls
이미지로부터 생성된 현재 도커 컨테이너 확인
--all
옵션을 주면 이전에 수행되었던 컨테이너들을 확인할 수 있다.
nginx 띄워보기
// 이미지 목록 확인
docker images
// Docker Hub 이미지 검색
docker search nginx
// Docker Hub 이미지 다운로드 => 6개의 이미지 레이어 다운로드(mac os는 확인 불가 https://iamjjanga.tistory.com/50)
docker pull nginx
// 이미지 목록 확인
docker images
// 컨테이너 목록 확인
docker ps
// 컨테이너 생성 => 기본이 백그라운드 실행
docker create -p 80:80 --name webserver nginx
// 컨테이너 목록 확인 => status created
docker ps -a
// 컨테이너 실행
docker start webserver
// 컨테이너 목록 확인 => status up
docker ps -a
// 페이지 확인
localhost:80
// 컨테이너 로그 확인
docker logs webserver
// 컨테이너 프로세스 확인
docker top webserver
// 컨테이너 세부 정보 확인 => ip, image, resource 등
docker inspect webserver
// 컨테이너 세부 정보 확인 필터 => ip 확인 (IPAddress)
docker inspect --format '{{.NetworkSettings.IPAddress}}' webserver
// 컨테이너 접속 후 bash 쉘 사용 => -i:interactive / -t:terminal
docker exec -it webserver /bin/bash
// nginx 웹 문서 접근
cd /usr/share/nginx/html/
// nginx 웹 문서 변경
echo "ethan's HOMEPAGE" > index.html
// nginx 쉘 종료
exit
// 페이지 확인
localhost:80
// 컨테이너 중지
docker stop webserver
// 컨테이너 목록 확인
docker ps
// 이미지 삭제
docker rmi nginx
// 컨테이너 목록 확인
docker ps -a
// 컨테이너 삭제
docker rm webserver
// 컨테이너 목록 확인
docker ps -a
// 이미지 삭제
docker rmi nginx