Docker
컨테이너
- 도커(Docker)는 바로 Docker Hub라는 소프트웨어 저장소와 함께 빠르게 성장했고, 그 결과 개발자들은 쉽게 애플리케이션을 포장하고, 컨테이너 방식으로 실행할 수 있게 되었습니다.
- 컨테이너 기술의 장점
- 실행 환경에 구애받지 않고 애플리케이션을 실행할 수 있다!
- 의존성 충돌 문제를 해결해 준다.
- 개발과 배포 환경을 일치시킨다.
- 수평 확장을 쉽게 해준다.
- 각 서버에 새로운 내용을 배포하기 쉽게 만들어준다
- 어떤 프로그램(A) 실행에 다른 프로그램(B)이 반드시 필요한 경우, "프로그램 A는 프로그램 B에 의존 관계를 가지고 있다"고 말합니다.
의존성 충돌
예를 들어, 워드프레스(wordpress)라는 프로그램이, php라는 프로그램에 대해 의존 관계를 가질 때에, 특정 php 버전을 요구하는 경우가 생길 수 있습니다.
그런데 동일한 컴퓨터에 php를 반드시 필요로 하는 drupal이라는 프로그램을 실행시켜야 하는데, 만일 drupal이 php 7 버전이 아닌 6 버전을 사용할 때에만 제대로 작동한다고 가정해 봅시다.
일반적으로 한 컴퓨터에 여러 버전의 동일한 애플리케이션이 설치되지 않으므로, 이 경우에는 php의 의존 관계를 가지고 있는 다른 두 애플리케이션 중에 하나는 제대로 된 실행을 보장할 수 없습니다.
이런 상황을 우리는 "의존성이 충돌한다"라고 말합니다.
- 해결방안
- 컨테이너 기술은 바로 이 문제를 해결합니다. 컨테이너 기술은 애플리케이션을 컨테이너 내에 구성합니다. 즉, 컨테이너에서 실행 중인 애플리케이션은 어떠한 의존성도 공유하지 않고, 각자 고유의 의존성을 포함하고 있다
)
- 각 컨테이너가 철저하게 실행 환경이 격리되어 있기 때문에 가능한 것
- 컨테이너 기술을 바탕으로 한 컴퓨터 안에 여러 대의 컨테이너가 존재하고, 이를 통해 애플리케이션 실행 환경이 격리되어 있음
- 컨테이너 하나하나가 애플리케이션 실행과 관련해서 높은 수준의 격리를 제공하기 때문입니다.
- 컨테이너는 무엇을 격리하고, 어떤 자원들을 독립적으로 소유할까?
- 프로세스
- 특정 컨테이너에서 작동하는 프로세스는 기본적으로 그 컨테이너 안에서만 액세스할 수 있습니다.
- 컨테이너 안에서 실행되는 프로세스는 다른 컨테이너의 프로세스에게 영향을 줄 수 없습니다.
- 네트워크
- 기본으로 컨테이너 하나에 하나의 IP 주소가 할당되어 있습니다.
- 파일 시스템
- 컨테이너 안에서 사용되는 파일 시스템은 구획화되어 있습니다. 그래서 해당 컨테이너에서의 명령이나 파일 등의 액세스를 제한할 수 있습니다.
가상 머신(Virtual Machine, 이하 VM)
- 하나의 호스트(주인) 컴퓨터 위에 여러 개의 독립적인 컴퓨터가 작동할 수 있게 하는 기술
- 애플리케이션으로는 VMware, VirtualBox, Parallels
개발환경
- 애플리케이션을 실행시키기 위해 OS나 JDK, Node.js와 같은 런타임 환경의 버전을 얼추 비슷하게 맞춰야 하는 것은 물론이고, 시스템 환경 변수를 애플리케이션에 맞게 구성해야 제대로 작동하는 경우도 있다.
- 이러한 과정 중에 발생하는 사소한 실수나 사전 설치 항목의 부재는 문제 해결에 많은 시간을 소모하게 합니다.
- 해결방안
- 애플리케이션 구성 자체가 컨테이너화되면 (이때 보통 Docker Compose라는 툴을 이용합니다) YAML 파일 하나 + 명령어 하나로 모든 애플리케이션 실행 환경 구성이 완료된다.
docker-compose up
- OS에 상관없이 즉시 애플리케이션 실행 환경을 만들 수 있습니다.
- 개발을 컨테이너 위에서 진행할 경우, 모든 개발팀이 동일한 환경 하에 개발을 진행할 수 있습니다.
- Amazon Web Service의 EC2 상에 도커를 설치하거나, 또는 좀 더 편리하게 도커 컨테이너를 EC2 서버에서 실행할 수 있게 하는 서비스인 ECS를 이용하여 보다 쉽게 애플리케이션을 배포할 수 있습니다.
- 서비스 제공자들은 이러한 트래픽 분산을 위해 프록시 서버를 운영하며, 프록시 서버는 여러 대의 동일한 검색 서버 중 한 군데를 이용할 수 있도록 돕습니다.
- 이러한 서버를 리버스 프록시의 한 종류인 '로드 밸런서'라고 부릅니다
- 더 많은 트래픽으로 인한 서버 증설에 컨테이너 기술은 아주 활발하게 이용되고 있습니다.
- 동일한 애플리케이션 구성(이미지)을 바탕으로 새로운 서버에 해당 애플리케이션을 컨테이너로 실행하고, 로드 밸런서에 이 서버를 추가하기만 하면 됩니다.
- 이러한 기술을 응용하여, 새로운 버전의 애플리케이션을 여러 서버 중 몇 대에만 운영하여 테스트하는 방법도 가능
- 이를 통해 새 버전의 애플리케이션에서 발생할 수 있는 문제들을 미리 확인하고, 이러한 문제가 사용자 전체에게 영향을 끼치지 않도록 만들 수도 있습니다.
이미지
- 실행되는 모든 컨테이너는 이미지로부터 생성됩니다. 이미지는 애플리케이션 및 애플리케이션 구성을 함께 담아놓은 템플릿으로, 이를 이용해 즉시 컨테이너를 만들 수 있습니다.
- 이미지를 이용해 여러 개의 컨테이너를 생성할 수 있습니다. 이를 이용해 앞서 설명한 애플리케이션의 수평 확장이 가능합니다.
- 이미지는 기본 이미지(base image)로부터 (마치 git을 사용하는 것처럼) 변경 사항을 추가/커밋해서 또 다른 이미지를 만들 수도 있습니다.
**레지스트리**
- 이미지는 레지스트리에 저장됩니다. 대표적인 이미지 레지스트리로는 Docker Hub, Amazon ECR이 있습니다. 도커 CLI에서 이미지를 이용해 컨테이너를 생성할 때, 호스트 컴퓨터에 이미지가 존재하지 않는다면, 기본 레지스트리로부터 다운로드 받게 됩니다.
- 레지스트리(Registry)
- Docker Hub : https://hub.docker.com/
- 도커 이미지를 관리하는 공간입니다.
- 특별히 다른 것을 지정하지 않는다면, 도커 허브(Docker Hub)를 기본 레지스트리로 설정합니다.
- 레지스트리는 Docker Hub, Private Docker Hub, 회사 내부용 레지스트리 등으로 나뉠 수 있습니다.
- 레포지토리(Repository)
- 레지스트리 내에 도커 이미지가 저장되는 공간입니다.
- 이미지 이름이 사용되기도 합니다.
- GitHub의 레포지토리와 유사하게 생각하시면 됩니다.
- 태그(Tag)
-
같은 이미지라고 할지라도 버전 별로 안의 내용이 조금은 다를 수 있습니다.
-
해당 이미지를 설명하는 버전 정보를 주로 입력합니다.
-
특별히 다른 것을 지정하지 않는다면 latest
태그를 붙인 이미지를 가져옵니다.
Docker **수행하기 : docker/whalesay**
docker image pull docker/whalesay:latest
- docker/whalesay의 최신 이미지를 받아옵니다.
docker image ls
docker container run --name 컨테이너_이름 docker/whalesay:latest cowsay boo
- 컨테이너_이름을 이름으로 갖는 컨테이너를 실행
- {container} run
- [OPTIONS]
- [COMMAND]
- command는 초기 컨테이너 실행 시 수행되는 명령어입니다.
- cowsay : 컨테이너 실행 시 cowsay 명령어를 호출합니다. node를 호출하듯 이용합니다.
- [ARG..]
- boo : COMMAND인 cowsay에 넘겨질 파라미터입니다.
docker container ps -a
- 모든 컨테이너의 리스트를 출력
- {container} ps : 컨테이너의 리스트를 출력
- a : Default 로는 실행되는 컨테이너지만 종료된 컨테이너를 포함하여 모든 컨테이너를 출력
docker container rm 컨테이너_이름
- 컨테이너_이름이라는 이름을 가진 컨테이너를 삭제
- • {container} rm : 컨테이너를 지칭해서 삭제합니다. 컨테이너를 명시할 때는 ps 명령을 통해 확인할 수 있는 NAMES 혹은 CONTAINER ID 를 사용합니다.
docker image ls
docker image rm docker/whalesay
- {container} run : 컨테이너를 실행합니다. 이미지가 없다면 이미지를 받아온 뒤(pull) 실행합니다.
- rm : 컨테이너를 일회성으로 실행합니다. 컨테이너가 중지되거나 종료될 때, 컨테이너와 관련된 리소스를 모두 제거합니다.
docker image rm docker/whalesay
- • image rm : 지정된 도커 이미지를 삭제합니다.
docker container run -it --rm danielkraic/asciiquarium:latest
- it : -i, -t 를 동시에 사용한 옵션입니다. 사용자와 컨테이너 간에 인터렉션(interaction)이 필요하다면 이 옵션을 사용
- 웹 서버는 도커 컨테이너로 실행
- 웹 서버를 구성하는 파일은 직접 만들거나 가져온 파일 구성
- 장점
- 서버에 문제가 생기는 것을 호스트와 별개로 파악할 수 있음
- 문제가 생긴 서버를 끄고, 마치 공장 초기화를 하듯 도커 이미지로 서버를 재구동할 수 있음
- 로컬에 있는 파일과 도커 이미지를 연결하는 방법
- CP(Copy) : 호스트와 컨테이너 사이에 파일을 복사(Copy)
- Volume : 호스트와 컨테이너 사이에 공간을 마운트(Mount)
- 마운트는 저장 공간을 다른 장치에서 접근할 수 있도록 경로를 허용해서, 마치 하나의 저장 공간을 이용하는 것처럼 보이게 하는 작업
**httpd 웹 서버**
- httpd(http daemon)은 Apache HTTP Server를 실행할 수 있는 오픈소스 웹 서버 소프트웨어
- httpd 는
/usr/local/apache2/htdocs/
경로에 웹 서버와 관련된 파일들이 저장되어 있다면, 해당 파일을 기반으로 웹 서버가 실행되도록 합니다.
docker container run --name 컨테이너_이름 -p 818:80 httpd
- •
-p
옵션은 로컬호스트의 포트와 컨테이너의 포트를 연결합니다. 명령어에서 818포트가 로컬호스트의 포트이고, 80번은 컨테이너의 포트입니다.
- httpd 는 일정 시간 연결 기록이 없으면, 서버 가동이 중지됩니다.
-d
옵션 : 컨테이너를 백그라운드에서 실행
docker container cp
//src/main/resources/templates 해당 위치에서 터미널 열어야함
docker container cp ./ 컨테이너_이름:/usr/local/apache2/htdocs/
//src/main/resources/static
docker container cp ./ 컨테이너_이름:/usr/local/apache2/htdocs/
- 해당 경로의 파일을 뒤 경로에 복사합니다.
docker exec -it 컨테이너_이름 bash
Docker 이미지 만들기
- Docker Container를 이미지 파일로 변환
- 이전에 작업했던 내용을 다시 한 번 수행하지 않아도 됨
- 배포 및 관리가 유용
- 구**동한 Docker Container를 이미지로 만드는 방법**
docker container commit 컨테이너_이름 my_pacman:1.0
- 생성된 이미지를 900 포트에서 웹 서버로 구동
docker run --name my_web2 -p 900:80 my_pacman:1.0
- **Docker Image 빌드를 위한 파일인 Dockerfile 로 만드는 방법**
- Dockerfile 을 만들고, Dockerfile 대로 이미지를
build
하는 방법
- 이미지 파일의 설명서
FROM httpd:2.4 # 베이스 이미지를 httpd:2.4 로 사용합니다.
WORKDIR /usr/local/apache2 # (Optional) 컨테이너 내의 작업 디렉토리를 설정합니다.
COPY ./ /usr/local/apache2/htdocs/ # 호스트의 현재 경로(./)에 있는 파일을 생성할 이미지 /usr/local/apache2/htdocs/ 에 복사합니다.
FROM httpd:2.4
COPY {웹 서버 실행에 필요한 파일의 경로 1} /usr/local/apache2/htdocs/ # 띄어쓰기에 유의하여 작성합니다.
COPY {웹 서버 실행에 필요한 파일의 경로 2} /usr/local/apache2/htdocs/
docker build
명령은, Dockerfile로 도커 이미지 파일을 생성합니다.
# --tag 는 name:tag 형식으로 이미지를 생성할 수 있습니다.
# 지정한 경로에 있는 Dockerfile을 찾아서 빌드합니다.
docker build --tag my_pacman:2.0 . # "."을 명령어에 꼭 포함해야 합니다!
docker run --name my_web3 -p 901:80 my_pacman:2.0
• 생성된 이미지를 이용해 901 포트에 웹 서버 구동
`docker exec -it 컨테이너_이름 bash`
컨테이너 안에서 bash shell을 실행
**docker-compose CLI**
docker-compose up # -d 옵션을 함께 사용하면, 컨테이너를 백그라운드로 실행할 수 있습니다.
- docker-compose.yaml에 정의된 이미지를 컨테이너로 실행
docker-compose down
- docker-compose.yaml에 정의된 이미지를 이용해 실행된 컨테이너를 종료
docker-compose up {특정 이미지}
- 하나의 docker-compose에서 관리되는 컨테이너끼리는 동일한 docker network에서 구동됩니다.
- docker -compose.yaml 파일 생성
- 파일을 생성할 때 터미널의 위치는 무관
services:
nginx:
image: sebcontents/client
restart: 'always'
ports:
- "8080:80"
container_name: client
spring:
image: 0xnsky/server-spring
restart: 'always'
ports:
- "4999:3000"
container_name: server-spring
volumes:
- "./volumefolder:/data"
mysql:
image: mysql:latest
restart: 'always'
ports:
- "3307:3306"
container_name: database
environment:
MYSQL_ROOT_PASSWORD: root_계정_비밀번호
MYSQL_DATABASE: 초기_생성_데이터베이스
MYSQL_USER: 유저_이름
MYSQL_PASSWORD: 유저_패스워드
볼륨
(volume) 또는 논리 드라이브
(logical drive)는 하나의 파일 시스템
을 갖춘 하나의 접근 가능한 스토리지 영역으로, 일반적으로(꼭 필수는 아니지만) 하드 디스크
의 단일 파티션
에 상주한다. 볼륨이 물리 디스크 드라이브와 다를 수 있지만, 운영 체제의 논리 인터페이스로 접근할 수 있다.
**컨테이너와 VM의 비교**
- 둘 다 프로세스, 네트워크, 파일 시스템을 격리할 수 있다는 장점을 공유하지만 작동원리는 많이 다릅니다.
- VM을 만들고 실행하는 과정이 많은 컴퓨팅 자원을 필요로 한다
- 도커는 한 호스트 컴퓨터에 여러 개의 컨테이너를 띄워도 크게 컴퓨터에 무리가 가지 않습니다.
- 도커 이미지는 (운영체제 이미지도 존재하지만) 보통 애플리케이션 단위로 만들어져 있음
- VM을 사용하기 위해서는 해당 VM 위에 운영체제(OS, Operating System)를 설치해야 한다.
- VM의 구성 요소에 OS가 존재하는데 비해, 오른쪽의 도커 컨테이너에는 OS를 포함하고 있지 않습니다.
- 도커라는 플랫폼 위에 컨테이너들이 올라가 있고, 그 아래 호스트 OS가 존재
- 각 컨테이너는 호스트 OS의 커널을 공유
- 도커는 애플리케이션을 컨테이너화해서 실행하는 데에 주 목적이 있으므로, 특별히 컨테이너에 OS를 올려서 사용하지 않습니다.
- 호스트 OS의 입장에서 컨테이너 하나는 프로세스 하나에 불과합니다
컨테이너에 OS를 올리지 않는데, Docker Hub에 존재하는 각종 OS 이미지는 무엇인가요?
리눅스 배포판인 우분투, CentOS 등은 결국 동일한 리눅스 커널 위에서 만들어진 것입니다. 각자가 고유의 디렉토리 구조, 패키지 시스템(apt, yum), 쉘(bash, zsh) 등을 사용했을 뿐입니다. OS 이미지는 컨테이너 내 애플리케이션 구성의 편의를 위해 존재하는 이미지입니다. 우분투, CentOS 이미지를 사용한다고 해도 결코 컨테이너에 커널 수준의 OS가 올라가지 않습니다.
- 하이퍼바이저는 VM을 생성하고 구동하는 소프트웨어
윈도우나 macOS용 도커를 살펴보면 컨테이너 안쪽은 리눅스로 작동됩니다. 윈도우나 macOS는 리눅스가 아닌데, 어떻게 컨테이너 안에서 리눅스 기반으로 작동하는 것인가요?
해당 운영체제의 경우 리눅스 커널을 VM의 형태로 실행시키는 하이퍼바이저(Hyper-V, LinuxKit, HyperKit)를 자체적으로 구동합니다. 윈도우용 또는 macOS용 도커는 하이퍼바이저 위의 리눅스 커널을 사용하는 것입니다
윈도우용 도커는 윈도우 커널을 사용한 윈도우 전용 컨테이너를 실행할 수 있는 기능을 제공합니다. 컨테이너는 커널을 공유하므로, 윈도우 커널을 사용하는 컨테이너는 리눅스용 도커에서 사용할 수 없습니다.