
📌 Docker
`Docker`는 어플리케이션을 쉽게 만들고 테스트하고 배포할 수 있게 도와주는 소프트웨어 플랫폼을 말한다.
어플리케이션을 `컨테이너`라는 가볍고 이식성 있는 `패키지`로 실행할 수 있다.
`Docker 이미지`는 어플리케이션 실행을 위한 모든 것을 포함한다.
Docker의 주요 특징 `컨테이너화` `경량` `이식성` `확장성`
`이미지` 어플리케이션 실행에 필요한 파일을 포함한 읽기 전용 템플릿`컨테이너` 실행중인 이미지 인스턴스`Dockerfile` 이미지를 생성하기 위한 명령어가 담긴 스크립트 파일`볼륨` 컨테이너 데이터를 지속적으로 저장하는 메커니즘`네트워크` 컨테이너 간 통신을 관리하는 방식
정리하자면 로컬에서 `Dockerfile`을 통해 `이미지`를 생성하고 이미지를 실행하면 `컨테이너`가 된다.그리고 이 `컨테이너`들은 `네트워크`를 통해 통신한다.
도커 이미지를 로컬에서 만든 후, 이를 `Docker Hub`에 `push`하여 다른 컴퓨터에서도 동일한 환경에서 작업할 수 있다.이 과정을 통해 애플리케이션의 일관성을 유지하고, 쉽게 배포할 수 있는 것이다 !!
📌 Docker 의 장점과 단점
💡 장점
- 빠른 시작 시간과 낮은 오버헤드
- 높은 이식성과 확장성
- 도커 컨테이너는 한 번 만들면 어디서든 동일하게 실행
💡 단점
- 보안 격리가 가상 머신보다 약함 (동일한 운영 체제 커널을 공유하므로)
- 운영 체제 종속성 존재 (Docker가 리눅스 커널로 작동하므로 리눅스가 가장 호환이 잘됨)
📌 Docker는 언제 사용할까?
- 일관된 개발 환경이 필요할 때
- 애플리케이션을 빠르게 배포하고 싶을 때
- 마이크로서비스 아키텍처를 도입할 때
- CI/CD 파이프라인을 구축할 때
- 애플리케이션 격리가 필요할 때
📌 Docker 명령어
💡 Docker 이미지 관련 명령어
`이미지 빌드`
docker build -t myapp:latest .
현재 디렉토리의 `Dockerfile`을 기반으로 myapp 이미지 생성
-t 옵션으로 이름과 태그 설정
`이미지 목록 보기`
docker images
`이미지 삭제`
docker rmi myapp:latest
이미지를 로컬 저장소에서 삭제
💡 Docker 컨테이너 관련 명령어
- 컨테이너 아이디는 식별 가능한 자릿수까지만 입력해도 된다
`컨테이너 실행`
docker run -d -p 8080:80 myapp:latest
myapp 이미지를 사용하여 컨테이너를 실행
`-d` 백그라운드에서 실행하는 옵션
`-p` 호스트의 8080 포트를 컨테이너의 80 포트에 매핑
`컨테이너 내부 접속`
docker exec -it 컨테이너_아이디 /bin/bash
`컨테이너 중지 / 컨테이너 삭제`
docker stop container_id
docker rm 컨테이너_아이디
컨테이너가 삭제돼도 이미지는 삭제되지 않는다!
📌 Docker Compose
`Docker Compose`는 다중 컨테이너 `Docker` 어플리케이션을 정의하고 실행하기 위한 도구이다.
`docker-compose.yml` 파일 하나로 어플리케이션의 서비스, 네트워크, 볼륨 등을 정의한다.
version: '3'
services:
web:
image: nginx
ports:
- "8080:80"
app:
build: .
ports:
- "8081:8080"
depends_on:
- db
db:
image: postgres
environment:
POSTGRES_PASSWORD: example
이런 식으로 `docker-compose.yml` 파일을 작성하고 명령어를 사용하여 빌드하면 된다.
`파일에 정의된 서비스를 빌드하고 시작`
docker compose up -d
이러한 방식으로 여러 컨테이너로 구성된 어플리케이션을 쉽게 관리하고 배포할 수 있다.
`docker-compose.yml` 파일 하나로 모든 서비스의 설정을 관리할 수 있어 일관된 환경을 제공할 수 있다.
📌 실습
💡 Docker 실습
2개의 스프링 컨테이너를 생성하고 서로의 서비스를 호출해볼 것이다.
우선 FeignClient를 사용하여 서비스 A가 B를 호출하는 형태로 프로젝트를 생성한다.
Docker에서 서로 다른 컨테이너를 사용할 경우, 각 컨테이너가 독립된 네임스페이스 내에서 실행되므로, 동일한 포트 번호를 사용할 수 있다.
이는 각 컨테이너가 격리된 환경에서 실행되기 때문에 가능하며, 같은 호스트 머신에서 서로 다른 컨테이너가 동일한 포트 번호를 사용하더라도 충돌이 발생하지 않는다.
따라서 A, B 서비스 모두 포트번호를 8080으로 설정한다.
spring.application.name=service-a
server.port=8080
service.b.url=http://service-b:8080
서비스 A에서 B를 호출하기 위해 `service.b.url`을 지정하는데 두 서비스 포트가 같은 것을 볼 수 있다.
FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
위와 같이 `Dockerfile`을 작성하여 각 서비스 디렉토리에 넣는다.
도커끼리 컨테이너 이름으로 호출하기 위해서는 기본 브리지 네트워크 대신 사용자 정의 네트워크에서 진행해야 한다.
docker network create my-network
`사용자 정의 네트워크 생성`
./gradlew clean bootJar
서비스 B 프로젝트의 루트 폴더에서 프로젝트를 빌드하고
docker build -t img-service-b .
`이미지를 생성`한 뒤,
(`.`은 `Dockerfile` 위치)
docker run -d --name service-b \
--network my-network \
-p 18081:8080 \
img-service-b
`컨테이너를 생성`한다!
18081 호스트 포트에서 8080 컨테이너 포트를 매핑한다.
`호스트 포트`란 Docker 컨테이너가 실행되는 컴퓨터의 네트워크 포트를 의미한다. 즉, 우리 컴퓨터의 포트 번호인 것!
컨테이너 내부에서는 자체적으로 네트워크 환경이 격리되어 있어, 컨테이너 내부의 애플리케이션이 사용하는 포트는 외부에서 직접 접근할 수 없다.
그래서 Docker에서는 호스트 포트와 컨테이너 포트를 매핑하는 방법으로 외부에서 컨테이너에 접근할 수 있도록 한다.
docker ps
`컨테이너 확인` 명령어를 통해 컨테이너가 실행됐는지 확인한다.
docker run -d --name service-a \
--network my-network \
-p 18080:8080 \
-e SERVICE_B_URL=http://service-b:8080 \
img-service-a
서비스 A도 같은 방식으로 컨테이너로 실행한다.
이렇게 다 실행하고 나면 서비스 A가 서비스 B를 정상적으로 호출하는 것을 볼 수 있다!
💡 Docker Compose 실습
version: '3.8'
services:
service-a:
image: img-service-a
ports:
- "18080:8080"
environment:
- SERVICE_B_URL=http://service-b:8080
depends_on:
- service-b
service-b:
image: img-service-b
ports:
- "18081:8080"
networks:
default:
driver: bridge
서비스 A 프로젝트와 서비스 B 프로젝트의 상위 폴더에서 `docker-compose.yml` 파일을 생성한다.
`environment`는 컨테이너의 환경 변수를 설정한다.
서비스 A에서 B를 호출할때 사용하는 변수를 설정해주었다.
`depends_on`은 먼저 실행되어야 하는 서비스를 설정한다!
docker compose up -d
그리고 도커 컴포즈를 실행하면 위의 실습과 같은 결과를 확인할 수 있다!
* 도커 실습시에는 사용자 정의 네트워크를 따로 생성하였는데 도커 컴포즈에서는 생성 없이 어떻게 된걸까?
💡 Docker Compose를 사용하여 서비스를 실행하면, Docker Compose는 `docker-compose.yml`이 있는 디렉토리의 이름을 기반으로 하여 기본적으로 새 브리지 네트워크를 생성하고 각 서비스 컨테이너를 그 네트워크에 연결한다.
이 네트워크는 docker-compose.yml 파일에 정의된 모든 서비스가 서로 통신할 수 있도록 한다!
드디어 도커 강의를 들었다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
그동안 도커가 너무 막연하게 느껴졌는데 ..
이렇게 강의를 듣고 나서 정리까지 해보니 조금이나마~ 이해가 되는 것 같다!!
더 연습해봐야지
'공부 > DevOps' 카테고리의 다른 글
| [GitLab] AWS ECR, ECS로 SpringBoot 프로젝트에 CI/CD 적용하기 (0) | 2024.08.14 |
|---|