본문 바로가기

웹 프로그래밍/스프링

Docker

가상화

실제 컴퓨터 자원을 좀더 유연하게 사용하기 위해 추상화하는 기술

 

컨테이너

Docker의 가상화 기술

  • 물리적 컴퓨터의 OS와 소통하여 격리된 환경을 만든다.
  • Hypervisor에 비해 가볍고 자원 활용이 용이하다.
  • Container를 실행하는 Engine이 있다면 실행가능하다. 이식성이 높다.
  • 각 Container가 실제로 사용하는 Kernel은 동일하다. 

 

가상머신 vs 도커(컨테이너)

  • OS와는 Docker Engine통해서 소통하여 자원 부담이 적고 더 빠르게 만들고 실행하기가 가능하다.
  • 같은 OS 같은 커널을 사용하기때문에 완전한 격리를 할수는 없다.

도커의 핵심은 image(Class와 비슷)와 image로부터 만든 컨테이너(인스턴스와 비슷)

 

도커 실행 예시

sudo docker run -d --name rabbitmq -p 5672:5672  -p 15672:15672 rabbitmq:3.13-management

(d는 백그라운드 실행 p는 내부포트를 외부포트와 연결) 

docker rm -f

(도커 삭제)

 

docker stop rabbitmq

(일시정지)

 

docker start rabbitmq

(다시 재개)

 

docker ps -a

(실행중인 컨테이너 확인, -a 옵션은 종료된 컨테이너도 다볼수 있음)

 

docker logs -n 10 -f rabbitmq

(컨테이너 로그 출력하기 tail 처럼 새로 생길때마다 보여줌)

 

docker run --rm -p 8080:8080 todo-boot

(--rm 컨테이너 종료시, 컨테이너 삭제, 테스트용도)

 

docker images

(현재 가지고있는 이미지 모두 보기)

 

docker rmi <이미지 ID>

(이미지 삭제하기)

 

 

 

sudo docker run -d --name rabbitmq \

-e RABBITMQ_DEFAULT_USER=user \

-e RABBITMQ_DEFAULT_PASS=password \

-p 5672:5672 -p 15672:15672 \

-v /home/ubuntu/rabbitmq:/var/lib/rabbitmq \

rabbitmq:3.13-management

(-e 환경 변수로 아이디와 비밀번호 전달 가능, -v 외부 스토리지에 볼륨 마운팅 가능)

 

sudo docker exec -it <컨테이너 ID 혹은 네임>

(실행한 컨테이너로 들어가서 마치 우분투 환경처럼 사용가능)

 

도커 파일

Docker는 Container로 애플리케이션을 실행한다.

- Container를 만드는 방법이 작성된게 Image

- Image를 만드는 방법을 명령의 형식으로 나열한 파일이 Dockerfile

도커 파일 만들기

FROM eclipse-temurin:17 (처음에 이 이미지 부터 시작하겠다. -> jdk 설치하는 대신 jdk가 설치돼있는 이미지를 고르기)

WORKDIR /app (작업공간 마련하기, 없을 경우 생성후 이동)

COPY . . (현재 모든 파일들을 복사한다 -> 이미지에 포함시키기)

RUN <<EOF

./gradlew bootJar

mv build/libs/*.jar app.jar

EOF

(RUN: 이미지를 설정하기 위한 명령, 이미지 내부에서 새로운 명령어를 실행 -> 실행하고 생긴 Layer를 이미지에 포함, 즉 이미지내부에서 환경을 구성하기 위함(ex. Build), 애플리케이션 실행이 아니다)

 

CMD ["java", "-jar", "app.jar"] (이미지를 가지고 만든 컨테이너가 실행할 명령, 애플리케이션 실행)

 

EXPOSE 8080 (마지막으로 컨테이너가 실행 되었을때 요청을 듣고있는 포트를 나열해준다, 실행하는지 안보이기때문)

 

우분투 서버에서 도커파일로 이미지 만들고 컨테이너 만들기

github에서 repository를 가져옴

docker build -t todo-boot:latest . ( todo-boot라는 이름으로 이미지를 만든다, lastest는 태크이고 생략하면 lastest가 디폴트)

 

docker run --rm -p 8080:8080 todo-boot (만든 이미지로 컨테이너 생성)

 

 

멀티 스테이징 빌드

굳이 JRE만 필요한데 JDK을 설치할 필요가 있을까?

굳이 app.jar만 필요한다 모든 파일을 가지고 있을 필요가 있을까? -> 분리시켜서 하나는 이미지를 생성하고 하나는 그 이미지를 사용하게 하면 된다.

 

 

FROM eclipse-temurin:17 as build

WORKDIR /app
COPY . .

RUN <<EOF
./gradlew bootJar
mv build/libs/*.jar app.jar
EOF

# 여기부터 새로운 Stage가 시작된다.
FROM eclipse-temurin:17-jre

WORKDIR /app

# 카피를 하되, build 단계에서 만든 app.jar만 가져온다.
COPY --from=build /app/app.jar .

CMD ["java", "-jar", "app.jar"]
EXPOSE 8080

 

Multi Container Application(멀티 컨테이너 애플리케이션)

요구사항에 따라 데이터베이스, Redis, RabbitMQ 등이 필요하다면?

- 싹다 Container로 만들어서 실행해도 되지 않을까?

 

이미지를 가져올때는 환경변수를 주의깊게 살펴보기

mysql 사용 예시

docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=todo \
-e MYSQL_PASSWORD=password \
-e MYSQL_DATABASE=todos \
-p 3306:3306 \
mysql:8.0

 

yaml 파일 변경(mysql에 접근할수 있게)

spring:
  datasource:
    url: jdbc:mysql://43.203.219.173:3306/todos
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: todo
    password: password
  jpa:
    hibernate:
      ddl-auto: create

 

네트워크 생성

같은 컴퓨터내에서는 격리된 상태이기 때문에 localhost로는 다른 컨테이너를 접근을 못한다.

따라서 서로의 존재를 알게 해줘야 한다.

 

  1. docker network를 만든다
  2. mysql을 네트워크에 연결한다
  3. 애플리케이션도 네트워크에 연결한다.

 

docker network create todo-network

 

docker network connect --alias mysql todo-network mysql 

(원래있던 컨테이너를 사설 네트워크에 연결하는 내용, --alias는 localhost 부분 치환, 연결하려는 네트워크, 네트워크에 연결하는 컨테이너)

docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=todo \
-e MYSQL_PASSWORD=password \
-e MYSQL_DATABASE=todos \
-p 3306:3306 \
mysql:8.0

 

docker run --rm -p 8080:8080 --network todo-network todo-boot:simple

(실행하면서 동시에 사설 네트워크에 연결)

애플리케이션 yaml은 --alias mysql로 호스트 변경

spring:
  datasource:
    url: jdbc:mysql://mysql:3306/todos
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: todo
    password: password
  jpa:
    hibernate:
      ddl-auto: create

 

docker network rm todo-network

(네트워크 삭제)

 

 

 

이렇게 명령어를 연달아 치는것이 번거롭다? ->  yaml 파일을 활용한 docker compose를 사용

services:
  app:
    image: todo-boot
    container_name: todo-compose
    restart: on-failure
  ports:
    - 8080:8080
  depends_on:
    - mysql
  
  mysql:
    image: mysql:8.0
    container_name: todo-mysql-compose
    restart: always
    environment:
      -MYSQL_ROOT_PASSWORD=password
      -MYSQL_USER=todo
      -MYSQL_PASSWORD=password
      -MYSQL_DATABASE=todos
    ports:
      - 3306:3306  # MySQL 의 기본 포트를 호스트의 동일 포트에 연결(외부 연결 가능)

 

docker compose up -d

(이제 컨네이너 한번에 띄우기)

 

docker compose ps

(compose로 띄운 컨테이너들 보기)

 

docker compose logs -f app

(해당 컨테이너의 로그 출력하기)

 

docker compose stop

(compose 내 모든 컨테이너 스탑)

 

docker compose start

(compsoe 내 모든 컨테이너 시작)

 

docker compose rm

(모든 컨테이너 지우기)