'따라하며 배우는 도커와 CI 환경' 책을 읽고 리뷰를 쓸까 하다가 개념을 전체적으로 정리해두면 좋을 것 같아서 남기는 글 🫠
도커란 애플리케이션을 "컨테이너"라는 표준화된 유닛으로 패키징해서 신속하게 구축, 테스트, 배포, 실행할 수 있게 해주는 소프트웨어 플랫폼
→ 컨테이너를 사용해 응용프로그램을 더 쉽게 만들고 배포하고 실행할 수 있도록 설계
이미지를 통해 컨테이너를 만든다!
이미지: 애플리케이션과 그 실행에 필요한 시스템, 라이브러리를 포함하는 읽기 전용 실행 템플릿
컨테이너: 이미지 기반으로 실행한 인스턴스

가상머신(VM)은 하이퍼바이저 기반(물리 하드웨어 위에서 여러 가상 머신을 구동)으로, 전체 운영 체제(OS)를 포함하여 자체 커널, 하드웨어 드라이버, 프로그램 및 애플리케이션 등 더 많은 리소스를 포함하고 있어 무겁다
따라서 단 하나의 애플리케이션만 격리하기 위해 가상 머신을 생성하는 건 비효율적이다
다만 더 강력한 격리와 보안 제공
컨테이너는 여러 개의 컨테이너를 실행해도 동일한 커널을 공유하며, 필요한 애플리케이션과 그 종속성만을 포함하여 가볍고 빠르다
실행 시간이 짧고 리소스 사용도 효율적
각 컨테이너는 사용자 공간에서 격리된 프로세스로 실행
서로 협업하면서 일어날 수 있는 상황을 가정해보자!
개발 환경 불일치
A : 프로젝트 실행하려니까 갑자기 이런 에러가 나면서 안돼요 (java 17)
B : 제 컴퓨터에서는 되는데요? (java 11)
🔎 문법과 라이브러리 의존성이 미묘하게 어긋나면서 개발 환경 불일치로 오류가 일어날 수 있음
✅ 도커를 쓴다면 개발, 테스트, 운영 환경을 일치시켜 환경 차이로 인한 문제를 원천 차단할 수 있다!
복잡한 설치 과정 생략
물론물론 이런 일이 실무에는 없겠지만 개발을 막 배우기 시작한 시점에 팀 프로젝트를 하다가 아직 배포 전이라 프론트엔드 A가 백엔드 API를 연동해서 테스트를 해봐야 하는 상황이라고 하자
A: API 연동 테스트 할 건데 어떻게 해야 하나요?
B: 앗 먼저 Java랑 MySQL 까시구요 스크립트 한 번 돌리시고 앗 그리고 Redis도 포트 열어서 띄워두셔야하는데...
A: (백엔드 DB 세팅까지 해야하는거..?)
🔎 이렇게 API 연결 하나를 위해서 프론트엔드 개발자가 데이터베이스와 백엔드 다 로컬에 직접 구축하게 되면 환경 세팅에만 하루를 쓰게 될 수도 있다
✅ 도커를 쓴다면 프론트엔드는 백엔드 쪽에서 미리 만들어놓은 docker-compose.yml 파일 하나만 받아다가 컨테이너 실행하기만 하면 된다

1. 도커 클라이언트(CLI) 에서 명령(요청)
예) docker run hello-world
2-1. 도커 서버(데몬)
해당 이미지가 로컬에 이미 다운로드 되어있는지 확인 (이미지 캐시 보관 장소)
없으면 아래와 같이 출력되며 docker가 어떤 단계를 따르는지 확인해볼 수 있음
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
d5e71e642bf5: Download complete
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
Status: Downloaded newer image for hello-world:latest
2-2. 도커 허브와 연결하여 이미지 가져와서 로컬에 보관 후 이미지 이용하여 컨테이너 생성하게 된다
이는 명령어 실행 후 나오는 출력 결과에서도 확인 가능
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64)
3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.

도커허브는 도커 레지스트리 (컨테이너 이미지를 저장하고 공유하는 중앙 집중식 위치)
다양한 공개 Docker 이미지가 저장되어 있고, 빌드된 이미지도 저장할 수 있음
docker-compose.yml에서 build 대신 image:<도커아이디>/<도커이미지이름> 으로 도커이미지를 실제로 빌드 하는게 아닌 도커 허브에 빌드된 도커 이미지를 사용
services:
# 로컬 Dockerfile을 빌드해서 사용하는 경우
my-app:
build: .
# 도커 허브에 이미 올라가 있는 이미지를 그대로 가져다 쓰는 경우
my-app:
image: ppnyoong/my-app:latest
도커 이미지를 만들기 위한 설정 파일
이 파일 안에는 이미지를 생성하는 데 필요한 명령어들이 순서대로 기술
→ 도커 컨테이너가 어떻게 행동해야 하는지에 대한 설정을 정의
docker build 명령어를 사용하여 Dockerfile로부터 이미지를 생성할 수 있으며, 이 과정에서 각 명령어가 순차적으로 실행
FROM node:10
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
EXPOSE 8080
CMD ["node","server.js"]
<이미지 이름>:<태그> 형식으로 작성
소스코드 변경만 일어난 경우에는 종속성까지 다시 내려받을 필요가 없다
종속성을 내려받는 단계를 나누어 종속성에 변화가 있을때만 다시 내려받고 없으면 캐시(cache)를 이용해 해당 과정 생략
→ 빌드 결과 출력에서 Using Cache 가 뜨는걸 확인할 수 있다
코드 수정 시 소스 코드를 복사하는 게 아니라 호스트 디렉터리에 있는 파일들을 참조해서 사용
→ COPY 해서 재빌드할 필요를 줄이고 바로바로 작업 내용 확인 가능

-v는 바인드 마운트, 익명 볼륨
앞은 익명 볼륨을 나타내고 뒤는 바인드를 나타낸다 -v 호스트 경로:컨테이너 경로
하나의 파일에서 여러 Docker 컨테이너를 정의하고 한번에 실행하기 위한 도구
docker-compose.yaml 파일로 구성
docker-compose up--build 를 붙이면 이미지 있든 없든 이미지 빌드하고 시작docker-compose stopdocker-compose downversion: '3.8' # 도커 컴포즈의 버전
services: # 이곳에 실행하려는 컨테이너들을 정의
# 공식 이미지를 사용하는 Redis 서비스
redis-server: # 컨테이너 이름
image: redis:alpine # 컨테이너에서 사용하는 이미지
restart: always
# 로컬 Dockerfile을 빌드하여 사용하는 Node.js 앱 서비스
node-app: # 컨테이너 이름
build: . # 현재 디렉터리의 Dockerfile 빌드
ports:
- "8080:8080" # 포트매핑 "로컬:컨테이너 포트"
depends_on:
- redis-server # redis-server가 먼저 시작되도록 설정
environment: # 환경 변수
- REDIS_HOST=redis-server
- REDIS_PORT=6379
restart 옵션 비교always 언제나 다시 시작unless-stopped 멈추지 않았다면 다시 시작no (기본값)on-failure 실패했을 때만 다시 시작Dockerfile은 컨테이너 이미지를 빌드하는 방법에 대한 지침을 제공하고, compose 파일은 실행 중인 컨테이너를 정의 (compose 파일은 특정 서비스에 사용할 이미지를 빌드하기 위해 Dockerfile을 참조하는 경우가 많음)
docker versiondocker run hello-worlddocker run = docker create + docker startdocker run <이미지> lsdocker ps (ps=process status)docker ps -a (a=all) docker inspect <컨테이너명>docker logs <컨테이너명>docker exec -it <컨테이너명> <명령어>docker exec -it <컨테이너명> shdocker stop <컨테이너명>docker kill <컨테이너명>docker rmi <이미지>docker imagesCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:80->80/tcp web-server
--name 옵션으로 이름을 설정하지 않으면 도커 엔진이 임의로 형용사와 명사를 조합해 설정docker rename <원래 이름> <변경할 이름>)Docker docs
따라하며 배우는 도커와 CI 환경
[따라하며 배우는 도커와 CI 환경] Docker 개념
"Docker 없어도 되지 않나요?" — 면접관이 듣고 싶은 진짜 대답
[면접] 기술 면접 - Docker
도커 면접 질문 20선 정리 실무 개발자라면 꼭 알아야 할 핵심 개념