Inception

hhkim·2022년 8월 22일
1

42cursus

목록 보기
20/20
post-thumbnail

개념

가상 머신 vs 도커

도커 : Docker 와 VM의 차이

가상 머신(Virtual Machine)

하나의 서버를 여러 서버로 전환하는 물리적인 하드웨어의 추상화

  • 물리적인 하드웨어를 논리적으로 분할하여 독립적인 가상 환경을 만들어 놓은 것
  • 하이퍼바이저(예: VirtualBox)를 통해 하나의 호스트 OS에서 여러 개의 OS를 사용하는 방법
    👉 각 가상 머신이 OS, 애플리케이션, 필요한 바이너리와 라이브러리 전체를 포함하기 때문에 상대적으로 무겁고 느림
  • 다른 게스트 OS와 분리되어 독립된 공간과 자원을 할당 받음
    👉 보안성 굿

도커(Docker)

컨테이너 기반의 오픈소스 가상화 플랫폼

  • 컨테이너: 코드와 종속성을 함께 패키징하는 애플리케이션 계층의 추상화
    프로세스 단위의 분리 독립된 환경
  • 하나의 호스트 OS 위에 도커를 설치하고 그 위에 각 애플리케이션 환경을 설치 및 운영
    👉 애플리케이션이 각각 OS를 가지지 않기 때문에 메모리 공간을 적게 차지
  • 도커가 설치된 환경이라면 이미지를 통해 어디서든 동일한 환경 구축 가능
  • 도커 자체가 가상 머신이기 때문에 하이퍼바이저와 게스트 OS를 포함하고 있다고 함

도커 이미지와 도커 컨테이너

도커 이미지(Docker Image)

도커 컨테이너를 생성하는데 사용되는 애플리케이션의 파일들과 설정을 모아둔 것

  • 특정 프로세스를 실행하기 위해 필요한 모든 파일과 설정값(환경)을 지닌 것
    더이상의 의존성이 필요없음
  • VM의 ISO와 비슷한 역할이지만 더 가벼움
  • 상태값을 가지지 않으며 불변(immutable)
  • 이미지만 있으면 도커가 있는 환경에서 컨테이너를 생성 가능
  • DockerHub를 통해 버전 관리 및 배포 가능
  • Dockerfile이라는 파일로 이미지를 만듦
    이미지 생성 과정을 확인할 수 있고 수정도 쉬움
  • 여러 개의 읽기 전용 레이어로 구성되며, 파일이 추가되면 새로운 레이어 생성
    👉 도커는 여러 개의 레이어를 묶어서 하나의 파일 시스템으로 사용할 수 있게 함
  • 기반 이미지(base image): 부모가 없는 이미지 (예: OS들 - ubuntu, alpine, debian)
    자식 이미지(child image): 기반 이미지에 추가적인 기능을 더해 만든 이미지

도커 컨테이너(Docker Container)

실행중인 이미지의 인스턴스
애플리케이션의 종속성과 함께 프로그램 자체를 캡슐화하여 호스트 OS와 격리된 공간에서 프로세스를 동작시키는 기술

  • 종료되어도 메모리에서 삭제되지 않아서 다시 시작 가능
    👉 필요하면 명시적으로 삭제해야 함
    컨테이너를 삭제하면 컨테이너에서 생성한 파일이 사라짐
  • 컨테이너끼리 커널 공간과 호스트의 OS 자원을 고유

데몬(Daemon)

데몬 프로세스에 대한 이해😈
백그라운드에서 실행되면서 여러 작업을 처리하는 프로그램

  • 일반적으로 이름 끝에 d를 붙임
  • 보통 부모 프로세스를 갖지 않기 때문에 PPID가 1
  • 시스템을 시작할 때 데몬을 시작하는 경우가 많음
  • 네트워크 요청, 하드웨어 동작 등의 기능
    예) devfsd(하드웨어 설정), cron(주기적인 작업 실행)
  • 터미널을 가지지 않음
    👉 터미널이 종료되거나 세션이 끊겨도 시스템이 종료되기 까지는 유지됨

도커 데몬과 도커 클라이언트

  • 도커 데몬(Docker Daemon): 호스트의 백그라운드에서 실행되며, 도커 컨테이너의 빌드, 실행, 배포를 관리하는 서비스
  • 도커 클라이언트(Docker Client): 사용자가 도커 데몬과 상호작용할 수 있도록 하는 명령행 도구

도커가 명령어를 실행하는 원리

$ docker run alpine ls -l
total 48
drwxr-xr-x    2 root     root          4096 Mar  2 16:20 bin
drwxr-xr-x    5 root     root           360 Mar 18 09:47 dev
drwxr-xr-x   13 root     root          4096 Mar 18 09:47 etc
drwxr-xr-x    2 root     root          4096 Mar  2 16:20 home
drwxr-xr-x    5 root     root          4096 Mar  2 16:20 lib
......
......
  1. 도커 클라이언트가 도커 데몬에 신호
  2. 도커 데몬이 로컬에 이미지가 있는지 확인. 없으면 DockerHub에서 다운로드)
  3. 도커 데몬이 컨테이너를 생성하고 그 컨테이너 안에서 명령(위의 경우 ls -l) 실행
  4. 도커 데몬이 결과를 도커 클라이언트에 보냄

👉 가상 머신을 켜고 명령어를 실행하고 다시 종료하는 과정에 비하면 엄청 빠르다!

도커 볼륨(Docker Volume)

컨테이너에서 발생한 데이터들을 저장할 외부 공간

  • 호스트의 경로에 연결하여 컨테이너가 상태를 갖지 않도록 함(스테이트리스, stateless)
  • 컨테이너가 삭제되면 데이터도 사라지기 때문에 데이터를 보존하기 위해 사용
  • 실행 중인 컨테이너끼리 데이터를 공유해야 하는 경우에 사용

Dockerfile

Docker - Dockerfile 작성 / Build (이미지 제작)
Image-building best practices
도커 데몬이 이미지를 생성할 때 호출하는 명령어 목록을 담은 텍스트 파일

  • 베이스 이미지, 프로젝트 코드 위치, 의존성, 시작할 때 필요한 명령어 등을 포함
  • 명령어를 작성할 때 리눅스 명령어를 쓰면 돼서 간편
  • 레이어가 스택처럼 쌓이므로 변경이 빈번한 작업은 나중에 작성하는 것이 좋음

문법

  • FROM 베이스 이미지
  • RUN 빌드 타임에 실행할 명령어
  • ENV 환경변수
  • WORKDIR 작업을 실행할 경로
    • 지정한 경로가 없으면 생성
  • COPY 복사할 파일과 복사할 경로
  • VOLUME 컨테이너에 마운트할 볼륨 경로
  • CMD 컨테이너를 실행하기 위해 필요한 명령어
  • ENTRYPOINT docker run 명령을 실행할 때 같이 인자로 전달되는 명령어 (컨테이너 자체를 executable로 사용할 때 필요)

도커 컴포즈(Docker Compose)

도커 컴포즈 기초 및 문법
Docker Compose와 버전별 특징
여러 개의 컨테이너를 하나로 묶어주는 도구

  • YAML 파일에 서비스를 정의하면 명령어 하나로 모든 서비스를 생성하고 실행할 수 있음
    • 자동으로 서비스(애플리케이션 스택)들 사이에 네트워크 생성
  • 애플리케이션의 생명주기를 관리하는 명령어들이 있음
    • 시작, 중지, 재시작, 상태 확인, 로그 확인, 개별 서비스에 대한 명령어 실행
  • 하나의 호스트에 여러 개의 독립된 환경을 구성할 수 있음
  • 컨테이너가 생성되면 이전 컨테이너의 볼륨 데이터를 복사해서 데이터가 보존됨
  • 변경된 경우에만 컨테이너를 재생성
    👉 변경이 없으면 서비스가 재시작될 때 이미 있던 컨테이너를 재활용하므로 빠름
  • 변수를 설정해서 여러 환경에 맞게 커스터마이징할 수 있음
  • 여러 컴포즈 파일을 extends 키워드로 연결할 수 있음
  1. 어디서든 서비스가 생성될 수 있도록 애플리케이션의 환경을 Dockerfile에 정의
  2. 애플리케이션을 구성할 서비스들을 docker-compose.yml 파일에 정의
  3. docker-compose up으로 실행

문법(Version 3)

  • version 스키마 버전
    • 최신 버전을 쓰는 것을 권장
    • 버전 3 이후에는 버전을 쓰지 않는 것 같은데 잘 모르겠다 (참고)
      예시 튜토리얼 같은 곳에서는 버전 3.9를 명시하고 있음
  • services: 애플리케이션을 구성할 서비스 목록 (컨테이너를 실행할 때 필요한 정보 명시)
    • 서비스 이름 (아래의 목록은 순서가 상관없음)
      • build 빌드할 Dockerfile의 경로
      • image 사용할 이미지
      • command 컨테이너에서 수행할 명령어
      • ports 포트 정의
      • working_dir 작업할 경로
      • container_name 컨테이너 이름
      • volumes 마운트할 볼륨 (상대 경로 사용 가능)
      • environment 환경변수
      • networks 사용할 네트워크 정의
  • volumes: 미리 생성해두고 컨테이너에서 불러와서 사용할 볼륨
    • 볼륨 이름 (볼륨 이름만 명시하면 기본 옵션을 사용)
    • driver
    • driver_opts 드라이버 옵션 설정, 리눅스의 mount 실행과 동일 (참고)
  • networks: 컨테이너 간 네트워크 설정
    • 네트워크 이름

CGI와 fastCGI

What is Common Gateway Interface (CGI)?
CGI와 FastCGI 알아보기
CGI, FastCGI, PHP-FPM 개념
Common Gateway Interface (공용 게이트웨이 인터페이스)

  • 웹서버와 외부 프로그램 사이에 정보를 주고받는 방법이나 규약
  • 클라이언트(브라우저)가 서버에 보낸 요청이 정적인 HTML이 아니라 동적인 PHP 등이라면 서버는 CGI를 요청하고 CGI를 사용하는 CGI 프로그램이 CGI 응답을 보내면 서버는 이걸 HTTP 응답으로 바꿔서 클라이언트로 다시 보냄
  • 표준 입출력을 이용하므로 대부분의 프로그래밍 언어로 구현 가능
  • CGI는 요청이 올 때마다 새 프로세스를 생성하는데, fastCGI는 이전에 생성한 프로세스를 재활용해서 성능 개선
    (php-fpm은 CGI 프로그램!)

구현

VirtualBox 세팅

중간중간 스냅샷 찍어서 백업해두기! (참고)

  1. VirtualBox에 Ubuntu 설치: 메모리는 4기가, 파일 크기는 10기가
  1. 패키지 설치
    su -
    apt-get update
    apt-get install -y curl
    apt-get install -y git
    apt-get install -y vim
    apt-get install -y nscd
  2. Docker 설치 (문제있을 때 참고)
  3. docker-compose 설치

공유폴더 설정

mount -t vboxsf (공유 폴더 이름) /mnt/share

virtualBox에서 실행하니까 나는 오류들...

nginx

MariaDB

WordPress

php-fpm
nginx, php-fpm간 통신

error establishing a database connection

이것 때문에 며칠을 고생했는데 mariadb가 제대로 실행되기 전에 워드프레스가 연결을 시도하면서 그런 거였다. Dockerfile에서 wp core install 명령을 바로 실행하지 않고 따로 쉘 스크립트를 작성한 뒤 컨테이너가 만들어진 후 CMD로 실행하니까 해결됐다.

networks

  • docker-compose.yml에 네트워크를 정의하면 도커 컴포즈 실행 시에 자동으로 네트워크 설정
  • docker-compose run [서비스명] ping [서비스명]으로 ping 날려서 연결이 잘 됐는지 확인
    예) docker-compose run nginx ping mariadb

사용자 정의 네트워크를 사용해야 하는 이유

기본적으로 default 네트워크가 생성되고 bridge 방식으로 연결되긴 함

  • default 네트워크에서는 IP 주소로만 서로에게 접근이 가능하기 때문에 이름을 사용하려면 따로 네트워크를 정의
    (아니면 --link 옵션을 써야 하는데 섭젝에서 금지하기도 했고 레거시)
  • 컨테이너가 추가되면 --network 옵션을 쓰지 않는 이상 기본적으로 default 네트워크에 속하게 되는데, 이는 예기치 않은 문제를 일으킬 수 있으므로 사용자 지정 네트워크를 만드는 것이 안전
  • default 네트워크 설정을 변경하면 호스트의 iptables 자체가 변경되어야 하기 때문에 도커를 재시작해야 하므로 비효율적
  • --link 옵션 없이 도커 볼륨, 도커 컴포즈 변수 등을 통해 환경 변수 공유 가능

volumes

Makefile

최적화

  • Best practices for writing Dockerfiles
    • RUN, COPY, ADD만 레이어를 생성함
    • 레이어 수 줄이기: 여러 줄의 RUN을 한 줄로
    • COPYADD는 파일의 변경사항까지 비교해서 캐싱하기 때문에 여러 줄로 분리해서 작성
    • 레이어는 스택으로 쌓이기 때문에 변경이 빈번한 레이어를 나중에 작성 (이전 레이어는 캐시에 저장된 것을 사용하도록)
    • 설치하는 패키지는 알파벳 순서로 줄을 분리해서 쓰면 관리가 용이

명령어 정리

docker

# 이미지 목록 확인
docker images

# 컨테이너 생성 및 실행
docker run [이미지 이름]		# 이미지를 가지고 컨테이너를 생성/실행
# 옵션
-it [이미지 이름]				# 인터랙티브 쉘(interactive tty) 실행
-d							# detached 모드로 실행 (현재 터미널에서 분리하여 실행)
--name [컨테이너 이름]			# 컨테이너 이름 설정
-e [환경변수명]="[값]"			# 컨테이너 환경변수 설정
-P							# 컨테이너의 모든 포트를 호스트의 랜덤한 포트로 연결
-p [호스트포트]:[컨테이너포트]	# 포트를 명시적으로 매핑

# 컨테이너 목록 확인
docker ps		# 현재 실행중인 컨테이너 목록 확인
# 옵션
-a	# 현재 실행중 + 실행됐던 컨테이너 목록 확인

# 컨테이너 콘솔 로그 확인
docker logs [컨테이너 id/이름]

# 실행중인 컨테이너 내부에서 명령 실행
docker exec [컨테이너 id/이름] [명령어]

# 컨테이너 실행 중단
docker stop [컨테이너 id/이름]

# 컨테이너 삭제
docker rm [컨테이너 id/이름]
# 옵션
-f	# 실행중인 컨테이너 강제 삭제

# 컨테이너 포트 확인
docker port [컨테이너 id/이름]

# 이미지 빌드
docker build [경로]
# 옵션
-t [이미지 이름]	# 이미지 이름 지정. [이미지 이름]:[태그 이름]을 통해 태그를 지정할 수도 있음

docker-compose

# 도커 컴포즈 실행
docker-compose up	# 현재 디렉토리의 docker-compose.yml 파일을 참고하여 실행
# 옵션
-d		# detached 모드 (백그라운드에서 실행)
--build	# build하고 실행

# 도커 컴포즈 실행 종료
docker-compose down
# 옵션
--volumes	# 데이터 볼륨까지 삭제

# 실행 중인 서비스 목록
docker-compose ps

# 로그 확인
docker-compose logs	# 뒤에 특정 서비스명을 써서 해당 로그만 골라서 볼 수도 있음
# 옵션
-f	# follows (실시간 출력 확인)

# 특정 서비스에서 명령어 실행
docker-compose run [서비스 이름] [명령어]

# 서비스 실행 중단
docker-compose stop

mariaDB

# 데이터베이스 목록 확인
show databases;

# 데이터베이스 선택
use [데이터베이스 이름];

# 테이블 목록 확인
show tables;

# 사용자 목록 확인
select * from mysql.user;

참고

도커 한방에 정리 🐳 (모든 개발자들이 배워보고 싶어 하는 툴!) + 실습
Docker for Beginners
Get started with Docker Compose
Use Docker Compose
How To Install WordPress With Docker Compose

1개의 댓글

comment-user-thumbnail
2025년 1월 23일

Wow, this was exactly what I needed! I’ve been trying to wrap my head around Docker and virtual machines, especially how Docker containers and images work compared to traditional VMs. The clear breakdown of concepts like Docker volumes, Docker Compose, and even Dockerfiles was a game-changer for me. I feel like I finally get the big picture and can start setting up my environment confidently.

For anyone struggling with setting up NGINX on Rocky Linux, I highly recommend this guide: Install Nginx on Rocky Linux 9. It was a lifesaver when I was trying to connect everything together. Thank you so much for sharing this—I absolutely loved it!

답글 달기