[토이프로젝트][MSA] 감정일기장-9: docker 컨테이너 가상화

onlydev7777·2024년 9월 25일

☀️ 개요

각 마이크로서비스와 관련 소프트웨어(db, kafka, rabbitmq 등)를 docker 컨테이너 가상화 시켜서 어플리케이션 배포에 활용한다.

1️⃣ Dockerfile 작성

Dockerfile은 Docker 이미지를 만들기 위한 스크립트 파일로서, 베이스 이미지 / 애플리케이션 jar 복사 / 패키지 설치 / 환경변수 설정 등의 명령어가 포함

auth-service Dockerfile 스크립트

FROM openjdk:17-ea-slim 
VOLUME /tmp
COPY build/libs/auth-service-0.0.1-SNAPSHOT.jar auth-service.jar
ENTRYPOINT ["java", "-jar", "auth-service.jar"]
  1. openjdk:17-ea-slim 베이스 이미지를 갖고
  2. tmp 경로에 애플리케이션 jar를 마운트 후
  3. java -jar auth-service.jar 명령어를 수행하는 docker 이미지 생성 스크립트

2️⃣ docker image 생성

Dockerfile 을 기반으로 Docker 이미지를 생성하는 명령어

docker build [OPTIONS] [PATH]

[OPTIONS]

  • -t : 생성된 이미지 태그 지정
  • -f : Dockerfile 경로 지정
  • --no-cache : 이미지 build 시 캐시 기능 OFF
  • --build-arg : Dockerfile에 전달할 인수

[PATH] : Dockerfile이 위치한 [로컬 Path || 원격 URL]

  • auth-service docker build 명령어

    docker build -t auth-service:latest .

    현재 디렉터리에 있는 Dockerfile 을 사용해서 auth-service:latest Docker 이미지 생성

3️⃣ docker push

로컬에서 생성한 docker image를 원격 Docker Registry(Docker Hub, AWS ECR 등) 에 업로드 하는 명령어

docker push [OPTIONS] NAME[:TAG]

[OPTIONS]

  • --all-tags: 특정 이미지의 모든 태그를 업로드
  • --disable-content-trust : 원격저장소 푸시될 때 무결성 체크 비활성화 옵션
    • default.: true

NAME[:TAG]

  • NAME : 이미지 이름
  • TAG : 이미지 태그(버전 의미)
    • default : latest

auth-service docker push 명령어

docker push onlydev7777/auth-service:latest

Docker Hub의 onlydev7777 계정에 auth-service:latest 이미지를 Push

4️⃣ docker pull

Docker Registry(Docker Hub, AWS ECR 등) 에서 Docker 이미지를 다운로드하여 로컬 시스템에 저장하는 명령어

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

[OPTIONS]

  • --all-tags: 특정 이미지의 모든 태그를 다운로드
  • --disable-content-trust : 원격저장소 에서 로컬로 다운로드 될 때 무결성 체크 비활성화 옵션
    • default.: true

NAME[:TAG|@DIGEST]

  • NAME : 이미지 이름
  • TAG : 이미지 태그(버전 의미)
  • @DIGEST: 이미지의 고유한 해시 값을 사용하여 특정 버전 지정

auth-service docker pull 명령어

docker pull onlydev7777/auth-service

Docker Hub의 onlydev7777 계정에 auth-service:latest 이미지를 Pull

5️⃣ docker network

docker 컨테이너 간의 네트워크 통신을 가능하게 하는 사용자 정의 네트워크를 생성한다.
기본적으로 docker 컨테이너는 서로 격리된 환경에서 실행하지만, 동일한 네트워크 설정을 통해 컨테이너간의 통신을 허용할 수 있다.

docker network create [OPTIONS] NETWORK_NAME

[OPTIONS]

  • --driver : 네트워크 유형을 지정 기본값은 bridge
    • bridge: 기본 네트워크 유형으로, 단일 호스트 내에서 컨테이너 간의 통신을 허용
    • overlay: 여러 Docker 데몬에 걸쳐 있는 분산 네트워크를 생성, Swarm 모드에서 사용
    • host: 컨테이너가 호스트와 동일한 네트워크를 사용하도록 만듬
  • --subnet
    • 서브넷마스크 IP 지정
  • --gateway
    • 게이트웨이 IP 지정
  • --ip-range
    • 네트워크에 할당할 IP 주소 범위를 지정

ediary-service-network 생성 명령어

docker network create --gateway 172.18.0.1 --subnet 172.18.0.0/16 ediary-service-network
  1. 컨테이너 생성 시 해당 네트워크로 설정하면 gateway는 172.18.0.1로 설정
  2. 컨테이너 생성 시 해당 네트워크로 설정하면 subnet 마스크는 172.18.0.0로 설정

6️⃣ docker run

생성된 Docker 이미지를 기반으로 컨테이너를 생성하고 실행하는 명령어

docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]

[OPTIONS]

  • -d : 컨테이너를 백그라운드에서 실행
  • --name : 컨테이너의 이름을 지정
  • -p : 호스트 서버와 컨테이너의 포트를 연결(포트 매핑)
  • -e : 컨테이너 내에서 사용할 환경변수 설정
  • -v : 호스트 서버 경로 to 컨테이너 경로 볼륨 마운트
  • --rm : 컨테이너 종료 후 컨테이너 자동 삭제
  • -it : 컨테이너 터미널 명령 모드로 실행
  • --network : 컨테이너가 연결될 네트워크 지정

IMAGE[:TAG]
실행할 Docker 이미지의 이름과 태그

[COMMAND]
컨테이너 내에서 실행할 명령어

[ARG]
명령어에 전달할 인수(환경변수 아님)

6-1. RabbitMQ docker 컨테이너 실행 명령어

docker run -d --name ediary-rabbitmq --network ediary-service-network \
  -p 15673:15672 -p 5673:5672 -p 15672:15671 -p 4370:4369 \
  -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest \
  ediary-rabbitmq
  1. ediary-rabbitmq 이름으로 컨테이너 생성
  2. ediary-service-network 로 등록된 docker 네트워크 사용
  3. 호스트 서버 포트 - Docker 컨테이너 포트 매핑
    • 15673 - 15672
    • 5673 - 5672
    • 15672 - 15671
    • 4370 - 4369
  4. Docker 컨테이너에 환경변수 전달
    • RABBITMQ_DEFAULT_USER = guest
    • RABBITMQ_DEFAULT_PASS = guest
  5. ediary-rabbitmq 로 등록된 Docker Image로 컨테이너 생성
  6. 생성된 컨테이너를 백그라운드로 실행

6-2. Prometheus docker 컨테이너 실행 명령어

docker run -d --network ediary-service-network --name ediary-prometheus \
  -p 9091:9090 -v ./prometheus.yml:/etc/prometheus/prometheus.yml \
  ediary-prometheus
  1. ediary-prometheus 이름으로 컨테이너 생성
  2. ediary-service-network 로 등록된 docker 네트워크 사용
  3. 호스트 서버 포트 - Docker 컨테이너 포트 매핑
    • 9091 - 9090
  4. 호스트 서버의 ./prometheus.yml 파일을 Docker 컨테이너 /etc/prometheus/prometheus.yml 에 마운트
  5. ediary-prometheus 로 등록된 Docker Image로 컨테이너 생성
  6. 생성된 컨테이너를 백그라운드로 실행

6-3. auth-service docker 컨테이너 실행 명령어

docker run -d --network ediary-service-network \
    --name ediary-auth-service \
    -e "spring.cloud.config.uri=http://config-service:8888" \
    -e "spring.rabbitmq.host=rabbitmq" \
    -e "eureka.client.serviceUrl.defaultZone=http://discovery-service:8761/eureka" \
    -e "logging.file=/api/logs/catalog-ws.log" \
    ediary-auth-service:0.0.1
  1. ediary-auth-service 이름으로 컨테이너 생성
  2. ediary-service-network 로 등록된 docker 네트워크 사용
  3. Docker 컨테이너에 환경변수 전달
  4. ediary-auth-service:0.0.1 로 등록된 Docker Image로 컨테이너 생성
  5. 생성된 컨테이너를 백그라운드로 실행

7️⃣ docker 자주 사용하는 명령어

7-1. docker image

현재 호스트 서버에 빌드되어 있는 Docker Image 리스트 조회

docker images

Docker Image name 변경

docker image tag auth-service:0.0.1 ediary-auth-service:0.0.1

Docker Image 삭제

docker image rm IMAGE

7-2. docker container

현재 호스트 서버에 실행 되고 있는 컨테이너 리스트 조회

docker container ls

현재 호스트 서버에 등록 되어 있는 컨테이너 리스트 전체 조회

docker ps -a

컨테이너 실행/중단/리스타트/강제종료

docker container start CONTAINER
docker container stop CONTAINER
docker container restart CONTAINER
docker container kill CONTAINER

컨테이너 로그 출력

docker container log CONTAINER

컨테이너 삭제

docker container rm CONTAINER

7-3. docker [image|container|volume|network|system] prune

사용하지 않는 이미지 삭제

docker image prune

중단 상태의 컨테이너 삭제

docker container prune

사용하지 않는 볼륨 삭제

docker volume prune

사용하지 않는 네트워크 삭제

docker network prune

사용하지 않는 Docker 시스템 삭제

  • 중단 상태의 컨테이너
  • 사용하지 않는 네트워크
  • dangling 이미지
  • dangling 이미지 빌드 캐시
docker system prune

8️⃣ docker-compose

docker-compose 는 여러 개의 Docker 컨테이너를 정의하고 동시에 관리하는 도구
docker-compose.yml 파일을 사용해서 Docker 컨테이너를 정의하고 단일 명령어로 여러 개의 Docker 컨테이너를 실행할 수 있다.

8-1. docker-compose.yml 파일

zookeeper 와 kafka 컨테이너를 정의한 docker-compose.yml 파일

networks:
  emotion-service-network:
    external: true

services:
  zookeeper:
    image: confluentinc/cp-zookeeper
    container_name: emotion-zookeeper
    environment:
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
    ports:
      - "22181:2181"
    networks:
      - emotion-service-network
  kafka:
    image: confluentinc/cp-kafka
    container_name: emotion-kafka
    hostname: kafka
    ports:
      - "29092:29092"
    networks:
      - emotion-service-network
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
    depends_on:
      - zookeeper

1. networks

networks:
 emotion-service-network:
   external: true
  • 컨테이너의 네트워크는 emotion-service-network 을 사용
  • emotion-service-network 는 이미 docker network create 명령어로 인해 생성 되어 있는 상태

2. zookeeper 서비스

services:
  zookeeper:
    image: confluentinc/cp-zookeeper
    container_name: emotion-zookeeper
    hostname : zookeeper
    environment:
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
      ZOOKEEPER_INIT_LIMIT: 5
      ZOOKEEPER_SYNC_LIMIT: 2
    ports:
      - "22181:2181"
    networks:
      - emotion-service-network
  • image : Confluent의 Kafka 용 Zookeeper 이미지 사용
  • container_name : emotion-zookeeper 이름의 컨테이너로 생성
  • hostname
    • 컨테이너 내에서 사용할 호스트 이름 정의
    • 이는 다른 서비스가 zookeeper 서버에 연결할 때 사용할 수 있는 내부 DNS 이름
  • environment : zookeeper 컨테이너의 환경변수 제공
    • ZOOKEEPER_SERVER_ID
      • zookeeper 서버의 고유 ID
      • 클러스터에 여러개의 zookeeper 서버가 있을 때 구분
    • ZOOKEEPER_CLIENT_PORT
      • zookeeper 서버가 클라이언트 연결을 수신하는 포트
      • kafka 컨테이너는 이 포트를 통해 zookeeper 와 통신
    • ZOOKEEPER_TICK_TIME
      • zookeeper 서버의 기본 시간 ms 단위
      • 세션 유지와 관련된 여러 작업 처리
    • ZOOKEEPER_INIT_LIMIT
      • 팔로워가 초기 연결 시 리더와 동기화 할 수 있는 최대 시간
    • ZOOKEEPER_SYNC_LIMIT
      • 팔로워와 리더 간에 메시지가 교환에 허용되는 최대 지연 시간
  • ports : 호스트 서버와 컨테이너 간의 포트 연결(매핑)
  • networks : emotion-service-network 를 통해 네트워크 통신

3. kafka 서비스

services:
  kafka:
    image: confluentinc/cp-kafka
    container_name: emotion-kafka
    hostname: kafka
    ports:
      - "29092:29092"
    networks:
      - emotion-service-network
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
    depends_on:
      - zookeeper
  • image : Confluent의 Kafka 이미지 사용
  • container_name : emotion-kafka 이름의 컨테이너로 생성
  • hostname
    • 컨테이너 내에서 사용할 호스트 이름 정의
    • 이는 다른 서비스가 Kafka 브로커에 연결할 때 사용할 수 있는 내부 DNS 이름
  • ports : 호스트 서버와 컨테이너 간의 포트 연결(매핑)
  • networks : emotion-service-network 를 통해 네트워크 통신
  • environment : kafka 컨테이너의 환경변수 제공
    • KAFKA_BROKER_ID
      • Kafka 브로커 고유 ID
      • 클러스터에 여러 개의 Kafka 브로커가 있을 때 구분
    • KAFKA_ZOOKEEPER_CONNECT
      • zookeeper 서버와 연결하는 URL
      • zookeeper 는 Zookeeper 컨테이너의 호스트명
    • KAFKA_ADVERTISED_LISTENERS
      • Kafka 브로커가 외부 및 내부 클라이언트와 통신할 때 사용할 리스너 주소 정의
      • 형식: <프로토콜>://<호스트명 또는 IP>:<포트>
      • PLAINTEXT://kafka:9092
        • 내부 클라이언트가 Kafka 브로커에 접근할 때 사용하는 리스너
        • 브로커간 통신이나 내부 컨테이너 간 통신에 사용
      • PLAINTEXT_HOST://localhost:29092
        • 외부 클라이언트가 Kafka 브로커에 접근할 때 사용하는 리스너
        • 호스트 서버가 29092 포트를 통해 Kafka 브로커에 통신
    • KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
      • 리스너에서 사용하는 보안 프로토콜 정의
      • 형식 : <리스너 이름>:<보안 프로토콜>
      • PLAINTEXT:PLAINTEXT: PLAINTEXT 리스너는 암호화되지 않은 평문 통신(PLAINTEXT) 사용
      • PLAINTEXT_HOST:PLAINTEXT: PLAINTEXT_HOST 리스너는 암호화되지 않은 평문 통신(PLAINTEXT)을 사용
      • 암호화된 통신을 하려면 SSL:SSL 로 정의해서 SSL 프로토콜 사용
    • KAFKA_INTER_BROKER_LISTENER_NAME
      • 클러스터 내부의 브로커들이 통신할 때 PLAINTEXT 리스너 사용
    • KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
      • Kafka 오프셋 토픽에 대한 복제 수 설정
      • 클러스터의 크기에 따라 조정
      • 현재는 단일 브로커 이기 때문에 1로 설정
    • KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS
      • 새로운 Consumer Group이 생성될 때 리밸런싱에 지연되는 시간
      • 0으로 설정 했기 때문에 리밸런싱 지연 없이 바로 시작
  • depends_on
    • zookeeper 이름의 서비스 컨테이너가 실행 후 kafka 컨테이너 실행

8-2. docker-compose 주요 명령어

docker-compose.yml 파일에 정의된 서비스들을 이미지, 컨테이너 생성 및 백그라운드 실행

docker-compose up -d

docker-compose.yml 파일에 정의된 모든 컨테이너를 중지 하고 제거

docker-compose down

docker-compose.yml 파일에 정의된 모든 컨테이너를 중지

docker-compose stop

docker-compose.yml 파일에 정의된 모든 컨테이너를 리스타트

docker-compose restart

docker-compse.yml 에 정의된 서비스들의 이미지 빌드

docker-compose build

docker-compse.yml 에 정의된 서비스들의 컨테이너 상태 확인

docker-compse ps

이미 실행중인 컨테이너 내에서 명령어 실행

# kafka 서비스에 bash 셸 실행
docker-compose exec kafka bash

★ Github

front-end("front-msa" 브랜치) : https://github.com/onlydev7777/emotion-diary-react
back-end : https://github.com/onlydev7777/emotion-diary-msa
docker-files : https://github.com/onlydev7777/emotion-diary-msa/tree/main/docker-files
inflearn-msa : https://github.com/onlydev7777/springboot-msa-3.0/tree/master

profile
https://github.com/onlydev7777

0개의 댓글