도커는 컨테이너 기반의 오픈소스 가상화 플랫폼이다.
우리가 하나의 컴퓨터 안에 여러 개의 환경을 두고 싶을 땐 어떻게 할까? 바로 가상 머신을 사용하면 된다.
윈도우 컴퓨터라도 가상 환경에서 실행을 하게 되면 리눅스 체제를 깔 수도 있다.
가상 환경이란 쉽게 말해서 컴퓨팅 환경을 소프트웨어로 구동한 것이다.
vmware와 같이 가상 환경에서 실행하는 가상 머신의 조건은 아래와 같다.
요건 | 설명 |
등가성 | VMM 상에서 동작하는 프로그램은 실제 머신 상에서 직접 실행한 경우와 본질적으로 같은 행동을 보여야 함 |
자원 관리 | VMM은 가상화된 자원을 완전히 그 관리 하에 두어야 함 |
효율성 | 대부분의 기계 명령을 VMM의 개입없이 실행할 수 있어야 함 |
이런가상 머신의 장점은 높은 수준의 격리, 하드웨어 종속 애플리케이션, 강력한 성능 등이 있으나
별도의 운영체제를 같이 설치해야 해서 용량이 매우 크다는 것이 단점이다.
컨테이너 기술을 사용하는 도커는 이와 다르게 경량화되어있고 오버헤드가 낮다.
자원을 효율적으로 사용할 수 있고 부팅 과정, 종속성 문제, 개발 및 배포 속도 등등의 문제에서 도커는 더 자유롭다.
무거운 guest os 대신 컨테이너 플랫폼인 도커 엔진 위에서 상대적으로 훨씬 가벼운 이미지를 이용할 수가 있다는 것을 위 사진을 보면 알 수 있다.
이 정도까지만 알아두고, 본론인 도커로 들어가보자.
도커를 알기 위해선 컨테이너와 이미지에 대해 알아야 한다.
1. 컨테이너와 이미지
컨테이너는 애플리케이션과 그 의존성을 함께 묶어 독립적으로 실행할 수 있는 가상 환경이다.
애플리케이션 코드, 런타임, 라이브러리, 환경 변수 등을 포함한 모든 필요한 파일을 하나의 패키지로 구성한다.
우리가 깃허브에는 버전 관리와 소스코드 복사 등등을 할 수 있는 것을 알 수 있다.
컨테이너 기술을 사용하면 애플리케이션의 소스 코드뿐만 아니라 실행에 필요한 모든 환경을 포함시킬 수 있다.
애플리케이션의 실행 환경을 일관되게 유지하고, 개발 환경과 운영 환경의 차이를 최소화할 수 있게 해주는 기술이다.
컨테이너에 포함할 수 있는 요소
- 애플리케이션 소스 코드:
- 애플리케이션의 실행 파일이나 스크립트.
- 운영 체제 종속성:
- 애플리케이션이 필요로 하는 특정 운영 체제 라이브러리와 도구.
- 라이브러리 및 패키지:
- 애플리케이션이 필요로 하는 모든 라이브러리와 패키지.
- 예: Python 패키지, Node.js 모듈, Java 라이브러리 등.
- 환경 변수:
- 애플리케이션이 필요로 하는 환경 변수 설정.
- 설정 파일:
- 애플리케이션이 필요로 하는 설정 파일.
- 예: 데이터베이스 설정, API 키, 설정 파일 등.
- 데이터 파일 및 디렉토리:
- 애플리케이션이 필요로 하는 데이터 파일.
- 예: 초기 데이터, 템플릿 파일 등.
- 네트워크 설정:
- 컨테이너의 네트워크 설정.
- 포트 매핑, 네트워크 인터페이스 등.
- 실행 명령어:
- 컨테이너가 시작될 때 실행할 기본 명령어.
이미지는 컨테이너를 실행하기 위한 템플릿이라고 생각하면 된다.
애플리케이션, 필요한 라이브러리, 설정 파일 등을 모두 포함하고 있다.
Dockerfile이라는 스크립트로 이미지를 만들 수 있다.
이미지는 여러 계층으로 구성되고 각 계층은 변경 사항들을 포함한다.
이런 계층 구조를 가지는 이미지는 기존 계층들애 대한 변경 사항만을 새로운 계층으로 추가한다.
그래서 이미지를 재생성할 때 변경된 부분만 새로운 계층으로 추가되고 그 외의 부분은 이전에 생성된 이미지 계층을 그대로 사용한다.
아무리 경량화라고 해도 용량이 수백 MB에서 수 GB정돈 나갈 수 있기에 계층 구조가 중요하다.
이미지를 한 번 만들면, 어디서든 동일한 환경에서 컨테이너를 실행할 수 있다.
그래서 이미지를 사용하면 개발 환경과 배포 환경이 일관되게 유지된다.
도커에 대해 익숙해지면 많은 사람들이 AWS의 ECR,ECS,Fargate를 사용하여 애플리케이션을 장소에 구애받지 않고 어떻게 효율적으로 배포하고 실행하는지 실습도 해보겠다.
각설하고, 이런 컨테이너 기반 가상화 플랫폼 중 가장 유명하고 많이 쓰이는 것이 도커이다.
2. 도커 사용
앱을 도커로 사용하는 기본적인 흐름을 적어보겠다.
Application --> Dockerfile --(빌드)--> Image --(생성)--> Container
1. 앱에 Dockerfile을 작성한다.
도커파일은 도커 이미지를 빌드하는 데 사용되는 텍스트 파일로, 앱의 환경 설정과 실행 방법을 정의한다.
이미지 빌드를 위한 스크립트라고 생각하면 된다.
2. Dockerfile로 앱을 build해서 도커 이미지로 만든다.
3. 이미지를 만들었으면 컨테이너를 만들어서 실행시킨다.
Docker: Accelerated Container Application Development
Docker is a platform designed to help developers build, share, and run container applications. We handle the tedious setup, so you can focus on the code.
www.docker.com
도커 허브
Docker Hub Container Image Library | App Containerization
Increase your reach and adoption on Docker Hub With a Docker Verified Publisher subscription, you'll increase trust, boost discoverability, get exclusive data insights, and much more.
hub.docker.com
도커 허브로 들어가서 원하는 앱을 검색하여 pull 하면 이미지를 받아서 사용할 수 있다.
후에 사용할 AWS에선 Docker Hub 역할을 하는 것이 ECR이다.
도커 명령어
도커 설치부터 커맨드를 정리해보겠다. 우분투 리눅스 환경이라고 가정한다.
설치 이후 도커의 모든 명령어는 'docker'로 시작하고 어떤 대상에게 명령어를 실행할 것인지로 구분하면 보기 쉽다.
docker {대상} {커맨드} {옵션} {인자}
이런 식으로 커맨드가 이루어질 것이다.
- 도커가 기존에 깔려 있다면 버전 삭제
sudo apt-get remove docker docker-engine docker.io containerd runc
- apt-get 업데이트 및 기타 설정
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |
sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
- 도커 설치
sudo apt-get install docker-ce docker-ce-cli containerd.io
- 설치 확인
docker --version
- 도커 실행
sudo systemctl status docker
- 도커 이미지 빌드
docker image bulid -t 이미지명[:태그명] Dockerfile경로
- 도커 이미지 pull
docker image pull 레파지토리명[:태그명]
- docker ps
: 실행중인 컨테이너 목록 확인
- docker ps -a
: 전체 컨테이너 목록 확인
- docker container ls -a
: 전체 컨테이너 목록 확인
- docker start 컨테이너ID
: 컨테이너 시작
- docker attach 컨테이너ID
: 컨테이너 접속
- docker stop 컨테이너ID
: 컨테이너 멈춤
- docker run 컨테이너ID
: 컨테이너 생성 및 시작
- docker run -it 컨테이너ID
: 컨테이너 생성 및 시작 및 접속
- docker rm 컨테이너ID
: 컨테이너 삭제
- docker exec -it 컨테이너ID /bin/bash
: 실행되고 있던 컨테이너 접속
- exit
: 컨테이너 빠져나오기
예시로 톰캣을 검색하여 다운받는 커맨드를 적어보겠다.
# 톰캣 이미지 다운로드
docker pull tomcat:latest
# 톰캣 이미지 다운로드 (특정 버전)
docker pull tomcat:9.0
# 톰캣 이미지 검색
docker search tomcat
# 톰캣 이미지 업로드 (사용자 지정 이미지)
docker push myuser/my_repository/my_tomcat
# 톰캣 이미지 목록 확인
docker images tomcat
# 톰캣 이미지 삭제
docker rmi tomcat:latest
# 톰캣 이미지 강제 삭제
docker rmi -f tomcat:latest
# 특정 이름의 컨테이너 삭제
docker rm container_name
Dockerfile
dockerfile은 단일 애플리케이션 컨테이너 이미지의 설정 및 빌드를 정의하는 파일이다.
내용으로 베이스 이미지 설정, 애플리케이션 코드 복사, 의존성 설치, 실행 명령어 등을 포함할 수 있다.
예시
# 베이스 이미지 설정
FROM python:3.8-slim
# 작업 디렉토리 설정
WORKDIR /app
# 호스트 파일 복사
COPY . /app
# 패키지 설치
RUN pip install -r requirements.txt
# 컨테이너 실행 시 실행될 명령어
CMD ["python", "app.py"]
FROM: 베이스 이미지를 설정한다. 여기서는 python:3.8-slim 이미지를 사용. 이 이미지는 파이썬 3.8 버전과 기본적인 라이브러리가 포함되어 있다.
WORKDIR: 작업 디렉토리를 설정한다. 여기서는 /app 디렉토리를 작업 디렉토리로 설정한다. 이 디렉토리에는 애플리케이션 코드와 의존성 패키지가 위치하게 된다.
COPY: 호스트 파일을 컨테이너로 복사한다. 여기서는 현재 디렉토리(.)의 모든 파일을 /app 디렉토리로 복사한다.
RUN: 컨테이너 내부에서 명령어를 실행한다. 여기서는 pip 명령어를 사용하여 requirements.txt 파일에 명시된 의존성 패키지를 설치한다.
(의존성 패키지를 설치하는 이유는 패키지 버전 관리, 의존성 관리, 배포 용이, 업데이트 용이, 충돌 방지 등의 이유 때문)
CMD: 컨테이너 실행 시 실행될 명령어를 설정한다. 여기서는 python 명령어와 app.py 파일을 실행하도록 설정되어 있다.
하나 더 좀 더 자세한 예시를 들어보자
리눅스 환경에서 디렉토리 생성하는 것부터 해보겠다.
1. 디렉토리 생성하고 디렉토리로 이동
mkdir smDock
cd smDock
2. Dockerfile 생성
touch Dockerfile
3. 테스트 파일1 생성
touch smtest1
vi smtest1
#vi 들어가서 아무 글이나 막 쓰고 :wq로 저장
4. Dockerfile 작성
vi Dockerfile
5. 작성 내용
FROM ubuntu:latest
# 베이스 이미지로 사용할 ubuntu:latest 이미지를 로컬에서 먼저 찾고 없으면 docker hub에서 다운
MAINTAINER hsm
# hsm이라는 이름이 관리자라는 뜻
RUN apt-get install -y
# 컨테이너 생성 시 apt-get install 실행 되게 한다. -y는 전부 yes 한다는 것
ADD smtest1 /smtest2
# smtest1 파일을 컨테이너 생성할 때 /smtest2라는 경로와 이름의 파일로 만들겠다는 뜻.
VOLUME /mountcheck
# 컨테이너 생성할 때 /mountcheck 디렉토리 생성, 이를 HOST OS에 마운트.
# 도커에서 마운트는 host 시스템의 디렉토리나 파일을 컨테이너 내부에 연결하여 공유하는 것을 의미
6. 이미지 빌드
docker build --tag Myimage:1.0
7. docker image ls
로컬에 저장된 도커 이미지 목록 표
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 2a4cca5ac898 2 weeks ago 64.2MB
my_flask_app v1.0 4d2eabf6c962 3 days ago 105MB
redis alpine a3ed95caeb02 4 weeks ago 20MB
보통 이런 식으로 결과값이 나온다.
8. docker run -it Myimage:1.0
동작 과정
- 이미지 확인: Docker는 로컬에서 Myimage:1.0이라는 이름과 태그를 가진 이미지를 찾음.
- 컨테이너 생성: 해당 이미지를 기반으로 새로운 컨테이너 생성.
- 터미널 실행: -it 옵션 덕분에 컨테이너 내에서 터미널 세션이 시작됨. 보통 기본 쉘(/bin/bash 또는 /bin/sh)이 실행.
Docker-compose
Docker Compose 파일은 Docker Compose 도구를 사용하여 다중 컨테이너 애플리케이션을 정의하고 실행하는 데 사용되는 YAML 형식의 설정 파일이다.
이 파일은 여러 Docker 컨테이너를 하나의 애플리케이션으로 정의하고 각 컨테이너의 설정을 지정한다.
Dockerfile과 docker-compose 파일은 함께 사용되는 경우가 많다.
Dockerfile을 사용하여 각각의 컨테이너 이미지를 정의하고, docker-compose 파일을 사용하여 이런 이미지를 기반으로 여러 컨테이너를 조정하고 연결할 수 있는 것이다.
보통 YAML 형식으로 설정한다.
주요 개념
- Services: 각 서비스는 하나의 컨테이너를 나타내며, 애플리케이션의 구성 요소이다.
- Networks: 서비스 간의 네트워크 연결을 정의한다.
- Volumes: 데이터 지속성을 위해 호스트와 컨테이너 간에 데이터를 공유하는 방법을 정의한다.
docker-compose.yaml 파일 예시
services:
db:
image: smin01/postgres
build:
context: ./db
dockerfile: Dockerfile
healthcheck:
test: ["CMD-SHELL", "pg_isready -q -d moviedb -U postgres"]
interval: 10s
timeout: 5s
retries: 3
expose:
- "5432"
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: moviedb
web:
image: smin01/django
build:
context: ./crud
dockerfile: Dockerfile
ports:
- "8000:8000"
command: ["sh", "./start.sh"]
depends_on:
db:
condition: service_healthy
nginx:
image: smin01/nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- "80:80"
depends_on:
- web
이 docker-compose.yml 파일은 세 개의 서비스(db, web, nginx)를 정의하고 있다.
각 서비스의 설정을 분석해보자
db 서비스
image: smin01/postgres는 사용자 정의 PostgreSQL 이미지를 사용하겠다는 것을 의미.
build는 도커 이미지를 빌드할 컨텍스트와 도커파일을 지정한다. 여기서는 ./db 디렉토리와 Dockerfile 사용.
healthcheck는 서비스의 상태를 확인하는 설정. pg_isready 명령을 사용하여 PostgreSQL 서버의 상태를 10초 간격으로 확인하고, 5초 내에 응답이 없거나 3번 연속 실패할 경우 비정상으로 간주.
expose는 컨테이너 내부에서만 접근 가능하게 포트를 공개한다. 외부에는 노출되지 않는다.
ports는 호스트와 컨테이너 간의 포트를 매핑한다. 여기서는 호스트의 5432 포트와 컨테이너의 5432 포트를 연결한다.
environment는 환경 변수 설정. PostgreSQL 사용자, 비밀번호, 데이터베이스 이름을 설정.
web 서비스
# image: smin01/django는 사용자 정의 Django 이미지를 사용.
# build는 ./crud 디렉토리와 Dockerfile을 사용하여 이미지를 빌드.
# ports는 호스트의 8000 포트를 컨테이너의 8000 포트에 연결.
# command는 컨테이너가 시작될 때 실행할 커맨드 지정. 여기서는 start.sh 스크립트 실행.
# depends_on은 db 서비스가 건강한 상태(service_healthy)일 때만 web 서비스가 시작되도록 설정한다.
nginx 서비스
# image: smin01/nginx는 사용자 정의 Nginx 이미지 사용.
# build는 ./nginx 디렉토리와 Dockerfile을 사용하여 이미지 빌드.
# ports는 호스트의 80 포트를 컨테이너의 80 포트에 연결.
# depends_on은 web 서비스에 의존하며, web 서비스가 시작된 후에 nginx 서비스가 시작.
이 설정에 따르면, docker-compose up 명령을 실행할 때, 먼저 db 서비스가 시작되고 건강 상태가 확인된 후에 web 서비스가 시작된다.
그리고 web 서비스가 시작된 후에 nginx 서비스가 시작된다.
nginx는 주로 정적 파일을 서빙하거나 리버스 프록시 역할을 하기 때문에, web 애플리케이션이 구동된 이후에 시작하는 것이 일반적이다.
이 설정을 통해 각 서비스의 시작 순서와 의존성을 관리할 수 있으며, 서비스 간의 연결 및 네트워크 통신을 효과적으로 구성할 수 있다.
조만간 프로젝트로 fastAPI와 Svelte를 이용한 애플리케이션을 도커 이미지화 시키고 ECR에 저장하여 ECS 및 Fargate 설정 및 배포를 해보겠다.
'가상화 > Docker' 카테고리의 다른 글
[docker] dockerfile 자세히 알아보기 (42) | 2024.07.24 |
---|---|
[docker] Volume 옵션으로 폴더 연결하기 (32) | 2024.07.19 |
[docker] exec 명령어 (33) | 2024.07.11 |
[docker] dit 옵션과 attach (27) | 2024.07.09 |
포트포워딩 알아보기 (feat. Docker) (52) | 2024.06.26 |