240122 도커(개요, play with docker)
컨테이너 기술이란?
- 컨테이너는 애플리케이션을 언제든 실행 가능하도록 필요한 모든 요소를 하나의 런타임 환경으로 패키징한 논리적 공간을 말한다.
- 이러한 패키징 기술을 docker에서는 Dockerfile 이라는 이름의 파일(대소문자 구분함!)에 적힌 스크립트를 통해 구현(코드형 인프라)
- 도커는 컨테이너를 사용할 수 있도록 도와주는 것
하나의 OS위에 여러개를 배포하면 생기는 문제
: 프로그램 하나가 죽어버리면 다른 프로그램도 죽는다.
Infrastructure
: 하드웨어 및 기기로 구성된 시스템 전반을 나타낸다.
Host Operating System
: 물리적인 서버 또는 호스트 컴퓨터에서 실행되는 운영 체제로, 하이퍼바이저에게 자원을 할당하고 가상 머신들을 관리한다.
Hypervisor
: 가상 환경을 생성하고 관리하는 소프트웨어로, 호스트 운영 체제 위에서 실행되어 가상 머신에게 필요한 자원을 분배한다. 프로세스의 개수만큼 서버를 두지 않아도 가상 환경을 효율적으로 운영할 수 있다.
Hypervisor로 자원을 나눠도 Guest OS도 운영체제이기 때문에 무거운 경향이 있다. 그래서 왼쪽처럼 커널이 4개(Host Operating System, Guest OS 3개)가 아닌 오른쪽 그림 처럼 하나(Operating System) 위에서 격리 기술을 사용하게 된다. 이 기술 중 점유율이 가장 높은 것이 도커이다.
한마디로, 애플리케이션과 종속 항목을 하나로 묶어, 실행하게 해주는 운영 시스템을 가상화한 경량의 격리된 프로세스라고 볼 수 있다.
- microVM 이라고도 부름
- 운영체제 수준의 가상화 제공
- 독립성을 갖기 때문에 다른 컨테이너에 영향을 주지 않는 stateless 환경 제공
컨테이너 기술은 개인 데스크탑 뿐만 아니라 기업 내의 온프레미스 서버, AWS와 같은 퍼블릭 클라우드까지 언제 어디서든 빠르고 효율적으로 배포 가능하며, 확장성 또한 가지고 있다.
- 이를 통해 서버구성, OS설치, 네트워크, 개발 도구 구성 등의 반복적이고 불편한 작업에 시간을 낭비하지 않고 개발자는 애플리케이션 개발 그 자체에 집중할 수 있게 된다.
- 컨테이너는 우리가 개발한 최소한의 Image(OS + 실행할 프로그램을 구성한 하나의 단위)를 통해 실행되므로 경량이다.
- 컨테이너 이미지 생성의 Best practice 중 하나는 이미지 경량화이다.
- 일반 서버 환경에서의 애플리케이션 실행과 달리 언제든 프로세스 수준의 속도로 빠르게 실행(run)할 수 있고, 한 번에 여러 개의 컨테이너를 동시에 실행 가능하다.
- Docker에서는 docker compose 기술을 통해 구현한다.
- 개인 환경이던 클라우드 환경이던 어떤 OS, 어떤 환경에서도 동작 가능한 이식성을 보유하고 있다.
- 컨테이너 자체 애플리케이션 환경에 대한 관리만 요구되므로 지속적 서버관리 비용을 절감할 수 있다.
- 개발팀과 운영팀의 업무 분리로 각자의 업무와 세분화된 관리에 집중할 수 있다. 즉, 컨테이너는 DevOps workflow 구성에 최적이다.
컨테이너 사례
앞서 설명한 컨테이너의 특징을 활용할 수 있는 대규모 어플리케이션 서비스부터 앱 서비스까지 여러 기업의 다양한 애플리케이션 환경에서 사용 중이다.
- 구글 웹,앱 서비스
- 에어비앤비 추천서비스
- 넷플릭스 추천 서비스
- 당근마켓 딥러닝 기반 추천 서비스
- 엔씨소프트 게임 서비스
- 삼성전자 헬스 케어 서비스
- 타다 배차 서비스
- 토스 금융 서비스
컨테이너는 어떤 타입으로 생성되나요?
- 컨테이너 패키징 메커니즘 시스템 / 애플리케이션 / 라우터 컨테이너
- 시스템(or OS) 컨테이너
- 호스트OS 위에 Ubuntu와 같은 배포판 리눅스 Image를 통해 배포되는 컨테이너다.
- 또다른 VM의 형태이고, 내부에 다양한 애플리케이션 및 라이브러리 도구를 설치, 실행 가능하다.
- 대표적으로 LXC, LXD, OpenVZ, Linux Server, BSD Jails 등이 있다.
- 딱 OS정도까지만 설치해서 실행되는 유형이다.
2. 애플리케이션 컨테이너
- 단일 애플리케이션 실행을 위해 해당 서비스를 패키징하고 실행하도록 설계된 컨테이너다.
- 3-tier 애플리케이션과 같은 경우 각 tier(frontend-backend-DB)를 개별 컨테이너로 실행하여 연결한다.
- 대표적으로 Docker container runtime, Rocket 등이 있다.
- OS와 해당 OS위에서 돌아갈 어플리케이션까지 같이 설치해서 실행되는 유형이다.
Docker의 시작
2013년 3월 Pycon에서 Docker에 대해서 창시자인 솔로몬 하익스가 소개해 시작되었다.
Docker는 무엇인가?
- 여러 계층의 어플리케이션을 컨테이너로 분리, 연결하여 실행하는 마이크로서비스 아키텍처 프로젝트에 유용하다.
- 애플리케이션의 인프라(runtime)는 이미지를 통해 제공하고 퍼블릭 혹은 프라이빗하게 공유 가능
- 깃허브와 유사한 방식(open share)으로 Docker Hub에서 제공함
- 이렇게 제공된 Image를 기반으로 Application 서비스를 제공, 이를 컨테이너화(Containerization)할 수 있다.
가상화(virtualization)?
- 일반적으로 서버, 스토리지, 네트워크, 애플리케이션 등을 가상화하여 하드웨어 리소스를 효율적으로 사용하는데 그 목적이 있고 이를 통해 기업은 효율적인 자원 활용, 자동화된 IT 관리, 빠른 재해 복구 등의 장점을 가질 수 있다.
- 물리적 하드웨어 유지 관리 대신 소프트웨어적으로 추상화된 가상화를 통해 제한된 부분을 쉽게 관리하고 유지할 수 있다.
- 하이퍼바이저 기반의 가상머신(VM, Virtual Machine)을 통해 수행한다.
- Vmware, VirtualBox 등
가상화 기술의 역사
1991 ~ : 리눅스 프로세스 격리 : 리눅스, LXC
2010 ~ : Virtual Machine 가상화기술 : VMware, virtualbox
2013 ~ : 컨테이너 가상화기술 : dotcloud, docker
2015 ~ : 컨테이너오케스트레이션 : 쿠버네티스, AWS, Azure, docker swarm, GCP
컨테이너 가상화 vs VM 가상화
- 두 가지 가상화 모두 실행하고자 하는 애플리케이션 프로세스 및 종속 요소와 소스 등을 패키지, 즉 이미지화 하여 HostOS와 격리된 환경을 제공한다.
- 다만, VM가상화는 실제 호스트 운영체제와 같이 별도의 GusetOS를 두고 원하는 애플리케이션을 설치하는 하드웨어 수준의 가상화를 구현하고
- 컨테이너 가상화는 VM가상화에 비해 경량이면서 호스트 운영체제의 커널을 공유하는 운영체제(OS)수준의 가상화를 구현한다.
- 따라서 컨테이너 가상화는 원하는 애플리케이션 환경을 빠르게 번들링하여 패키징한다.
- 기본적으로 우분투 리눅스 기반으로 도커라이즈 했다.(우분투를 유지보수하는 캐노니컬이 LXC를 지원했기 떄문)
Container는 가상머신이다?
Container는 hypervisor와 완전히 다른데 궁극적으로는 hypervisor와 유사한 형태의 "가상화"를 목표로 하고 있지만 hypervisor는 OS 및 커널이 통째로 가상화되는 반면에 container는 간단히 보면 filesystem의 가상화만을 이룬다.
container는 호스트 PC의 커널을 공유하고 따라서 init(1) 등의 프로세스가 떠있을 필요가 없으며, 따라서 가상화 프로그램과는 다르게 적은 메모리 사용량, 적은 overhead를 보인다.
컨테이너화(containerization) 기술
- 리눅스 컨테이너 기술은 LXC를 이용한 시스템 컨테이너화로 시작
- OS 수준의 가상화 도구
- cgroup, namespace등의 커널기술을 공유해 컨테이너에 제공
namespaces
VM에서는 각 게스트 머신별로 독립적인 공간을 제공하고 서로가 충돌하지 않도록 하는 기능을 갖고 있다. 리눅스에서는 이와 동일한 역할을 하는 namespaces 기능을 커널에 내장하고 있다. 현재 리눅스 커널에서는 다음 6가지 namespace를 지원하고 있다
- mnt (파일시스템 마운트): 호스트 파일시스템에 구애받지 않고 독립적으로 파일시스템을 마운트하거나 언마운트 가능
- pid (프로세스): 독립적인 프로세스 공간을 할당
- net (네트워크): namespace간에 network 충돌 방지 (중복 포트 바인딩 등)
- ipc (SystemV IPC): 프로세스간의 독립적인 통신통로 할당
- uts (hostname): 독립적인 hostname 할당
- user (UID): 독립적인 사용자 할당
cgropus (Control Groups)
cgroups(Control Groups)는 자원(resources)에 대한 제어를 가능하게 해주는 리눅스 커널의 기능이다. cgroups는 다음 리소스를 제어할 수 있다.
- 메모리
- CPU
- I/O
- 네트워크
- device 노드(/dev/)
- 초기 도커는 LXC를 그대로 응용해서 사용했음
- 현재는 containerd, runC를 이용하도록 변경되었음
- 커널 기술 공유를 통해 컨테이너를 생성하도록 도와주는 runC
- 생성된 컨테이너의 라이프사이클을 관리하는 containerd
- 사용자 환경에서 명령을 전달하는 dockerd
docker는 1.11버전부터 실제로 위와 같은 구조로 작동하고 있다.
containerd는 OCI 구현체(주로 runC)를 이용해 container를 관리해주는 daemon이다.
Docker engine 자체는 이미지, 네트워크, 디스크 등의 관리 역할을 하고 있으며,
여기서 Docker engine과 containerd 각각이 완전히 분리된 덕분에
Docker engine 버전을 올릴 때 Docker engine을 재시작해도 container의 재시작 없이 사용할 수 있게 된다.
play with docker를 활용한 맛보기
도커 이미지 (Docker Image)
- 도커 이미지란 도커 컨테이너를 생성하기 위한 바이너리 파일
도커 컨테이너 (Docker Container)
- 도커 컨테이너란 도커 이미지를 통해 실행되는 하나의 프로세스
- 원본 저장소에 있는 Docker File로부터 Docker Image를 내려받고 해당 이미지를 실행하여 여러 개의 컨테이너가 실행되는 구조
- 즉, 도커 이미지와 도커 컨테이너는 1 : N 구조로 되어 있다.
- 도커 이미지는 읽기 전용으로 도커 컨테이너에서 수정이 일어나도 원본 이미지에는 영향을 주지 않는다.
- 운영체제 상에서 프로그램과 프로세스 관계라고 볼 수 있음.
도커 이미지 이름 구성
도커 이미지 이름은 아래 3가지로 구성되어 있음
- 저장소 이름 (Repository name)
- 이미지 이름 (Image name)
- 이미지 태그 (Image tag) - 버전 정보나 릴리즈 태그같은 정보
예시
- OracleRepo/mysql-server:8.0.13 - OracleRepo저장소에 mysql-server이미지 8.0.13 버전
- OracleRepo/mysql-server - 태그 생략시 가장 최근 릴리즈(latest) 사용
- mysql-server:5.1.12 - 저장소 생략시 기본 저장소인 도커 허브로 인식
- mysql-server - 태그와 저장소 생략시 기본저장소와 latest 릴리즈 사용
labs.play-with-docker.com 에 접속하면
아래와 같이 브라우저에서 아무런 추가 조치 없이
도커를 체험해볼 수 있는 Play With Docker(이하 pwd)를 제공한다.
접속하면 도커 설치 없이 간단한 샌드박스 페이지가 열리고
가상의 인스턴스 환경에서 도커 명령어 등을 연습해볼수 있다.
옆에 add new instance를 클릭하면 인스턴스가 생성된다.
도커 이미지 받아오기
이미지를 받아오는것은 마치 함수 정의와 마찬가지로, 해당 이미지를 사용할 수 있는 상태로 준비만 하는것이지
실행까지 담보하지는 않는다.
$ docker pull 이미지명orDockerHub의레포지토리명:버전-기타옵션
도커 컨테이너 실행 방법
- 도커 컨테이너 실행 방법은 크게 2가지가 있다.
- 생성 및 시작을 한번에 하는 방법과 따로 하는 방법이 있다.
- 2가지 방법 모두 공통사항으로 image가 없으면 repository에서 자동 pull을 하게 된다.
- 도커 컨테이너 생성 및 시작을 한번에 하는 방법
$ docker run [image]
2. 도커 컨테이너 생성과 시작을 따로하는 방법
$ docker create [image] // 컨테이너 생성
$ docker start [container] // 컨테이너 시작
도커명령어 써보기
$ docker pull nginx:1.23.1-alpine
nginx 이미지를 1.23.1버전이면서 alpine 옵션이 적용된 형태로 받아오라는 의미다.
받은 다음
$ docker images
를 입력하면 받아진 이미지 목록에 추가된다.
$ docker run -d -p 8001:80 --name=webserver1 nginx:1.23.1-alpine
docker run으로 해당 이미지를 컨테이너로 띄울 수 있다.
-d
: detach 모드로 해당 컨테이너가 백그라운드에서 돌아감을 의미한다.
-p
: 포트바인딩이라고 부르는 특이한 연결방식으로 8001은 host의 포트이며, 이것으로 접속시
컨테이너의 80번 포트와 연결된다. 그림으로 자세히 보겠습니다.
--name=컨테이너이름(임의로지정가능)
: 말 그대로 식별할 수 있는 이름을 추가로 지정한다.
그리고 그 뒤에 어떤 이미지를 활용해 컨테이너를 띄울지 설정한다.
지금 우리가 받은 이미지가 애초에 nginx:1.23.1-alpine뿐이므로 그대로 실행한다.
돌아가는 컨테이너(사실상 프로세스단위로 돌아간다고 봐도 된다.)
조회는
$ docker ps
위 명령어를 사용한다.
CONTAINER_ID는 랜덤하게 배정되며, NAMES도 지정 안하면 랜덤하게 배정된다.
IMAGE는 말 그대로 컨테이너를 띄우는데 사용한 이미지가 조회된다.
PORTS에는 host포트→연동된 컨테이너의 포트 로 잡힌다.
그와 동시에 위와 같이 HOST가 오픈한 포트에 접속할 수 있도록 링크가 열리는데.
오른쪽 OPEN PORT에 숫자가 나열되지 않는다면 직접 버튼을 눌러서 해당 포트를 열어도 된다.
엔진엑스 서버가 오픈되면 아래와 같은 창이 열린다.
8002번 포트로 81번을 통해 컨테이너2에 접속은 가능하지만 실행포트를 80으로 설정했다면
실행이 불가능하다. 위의 사진처럼 정상적으로 작동하지 않는다.
두 개의 컨테이너에서 80번을 실행포트로 사용 가능한 이유는 컨테이너는 격리되어 있기 때문이다.