ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 컨테이너와 컨테이너 사이의 통신
    인프라/도커 2024. 1. 3. 21:47

     

     

    지난 글에 이어서 서버와 DB를 함께 다양한 환경에서 사용해보겠습니다.

    아래 순서로 글을 진행해보겠습니다.

     

    - 호스트와 컨테이너 사이의 통신 

    1. DB (호스트) & 서버 (호스트) 실행시키기

    2. DB (호스트) & 서버 (도커) 실행시키기

    3. DB (도커) & 서버 (호스트) 실행시키기

     

    - 컨테이너 사이의 통신

    4. 한 개의 컨테이너에서 DB & 서버 실행시키기

    5. 각각 다른 컨테이너에서 DB & 서버 실행시키기 

    6. 도커 컴포즈로 DB & 서버 관리하기

     

     


     

     

    4. 한 개의 컨테이너에서 DB & 서버 실행시키기

     

    로컬 환경에서 DB와 서버를 한 곳에서 실행시키 듯이 컨테이너에서도 가능은 합니다.

    스프링 서버와 mysql을 실행시킬 수 있는 환경을 컨테이너에 구현합니다.

    # Ubuntu 베이스 이미지 사용
    FROM ubuntu:20.04
    
    # 필요한 도구 설치
    RUN apt-get update \
        && apt-get install -y wget software-properties-common gnupg
    
    # Temurin 저장소 추가 및 Java 17 설치
    RUN wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | apt-key add - \
        && add-apt-repository --yes https://packages.adoptium.net/artifactory/deb/ \
        && apt-get update \
        && apt-get install -y temurin-17-jdk
    
    # MySQL 설치
    RUN apt-get install -y mysql-server
    
    WORKDIR workspace/app
    
    COPY ./settings.gradle /workspace/app/
    COPY ./build.gradle /workspace/app/
    COPY ./gradlew /workspace/app/
    COPY ./gradle /workspace/app/gradle/
    COPY ./src /workspace/app/src/
    
    RUN /workspace/app/gradlew build
    RUN mv /workspace/app/build/libs/myapp-0.0.1-SNAPSHOT.jar /workspace/app/app.jar
    
    # 실행 파일 복사 및 실행 권한 부여
    COPY ./init.sh /init.sh
    RUN chmod +x /init.sh
    
    # 애플리케이션 실행 및 MySQL 설정
    CMD ["/init.sh"]

     

    초기화 스크립트를 작성해서 추가해줍니다.

    #!/bin/bash
    
    # MySQL 서비스 시작
    service mysql start
    
    # MySQL 설정
    mysql -e "CREATE DATABASE sqltest;"
    mysql -e "CREATE USER 'user1' IDENTIFIED BY 'Uuser123!';"
    mysql -e "GRANT ALL PRIVILEGES ON sqltest.* TO 'user1';"
    
    # Java 애플리케이션 실행
    java -jar /workspace/app/app.jar

     

    테스트 요청도 스크립트로 만들어서 스크립트를 호출해 줍니다.

    curl -X POST http://localhost:8090/post -H 'Content-Type: application/json' -d '{"title": "hi title"}';
    curl http://localhost:8090/post/1;

     

    application.yml도 sql의 유저에 맞게 사용해줍니다.

     

    같은 도커 컨테이너 속에 들어있기 때문에 localhost를 사용하여 통신이 가능합니다.

     

     

     

    이것은 좋은 방법일까요?

     

    A container's main running process is the ENTRYPOINT and/or CMD at the end of the Dockerfile. It's best practice to separate areas of concern by using one service per container. 

     

    공식 문서를 찾아보면 도커의 best practice는 한 컨테이너에 한 개의 서비스를 사용할 것을 권하고 있습니다.

     

    몇 가지 이유를 생각해 볼 수 있습니다.

     

    1. 확장성: 단일 서비스를 사용한다면 부담없이 필요에 따라 컨테이너를 추가할 수 있을 것입니다.

    2. 유지보수성: 컨테이너의 문제가 발생했을 때, 문제의 원인을 찾기가 수월합니다.

    3. 격리성: 하나의 서비스에서 생긴 문제가 다른 컨테이너에 영향을 주지 않기 때문에 관리에 용이합니다.

     

     

     

     

     

     

    5.  각각 다른 컨테이너에서 DB & 서버 실행시키기 

    4번은 좋지 않다는 것을 느껴보기 위해 한번 진행해본 예제 입니다.

    실행부터도 이미 기존에 도커를 사용하던 느낌이 아니고 이미지도 한 개당 1.5GB씩 합니다.

    이번에는 다른 2개의 컨테이너에서 실행시켜 보겠습니다.

     

     

    먼저 mysql을 mydb라는 이름으로 컨테이너에 실행시켜보겠습니다.

    $ docker run -d --name=mydb -p 3308:3306 -e MYSQL_ROOT_PASSWORD=12345678 mysql

     

     

    마찬가지로 서버도 컨테이너에 올려보았으나, 디비 연결에 실패합니다.

    $ docker build -t myapp .
    $ docker run -it -p 8090:8080 myapp

     

    localhost를 바라보는 것이 문제겠네요.

    어떻게 해결할 수 있을까요?

     

     

     

    * 해결방법1 - 호스트 ip를 사용한다. ( 권장x )

     

    바로 드는 생각은 이전에 해본 호스트 ip를 사용하는 방법입니다.

    호스트 ip를 확인하고 3308번으로 접속해보겠습니다.

     

    이렇게 실행하니 동작은 합니다만 요청이 상당히 돌아가는 느낌이 듭니다.

    다른 방법을 살펴보겠습니다.

     

     

     

    * 해결방법2 - 사용자 정의의 네트워크 사용

     

    먼저 별도의 네트워크 환경을 생성합니다. 

    # 네트워크 조회
    $ docker network ls
    
    # 네트워크 생성
    $ docker network create mywebapp

     

     

    mywebapp 이라는 네트워크가 생성된 것을 확인할 수 있습니다. 

     

     

    network옵션을 주려면 새로운 컨테이너를 만들어야합니다.

    기존의 컨테이너는 제거하고 새로운 mysql을 위한 컨테이너를 실행하고 database를 생성합니다.

    # 네트워크 옵션으로 실행
    $ docker run -d --network=mywebapp --name mydb -p 3308:3306 -e MYSQL_ROOT_PASSWORD=12345678 mysql
    
    mysql> create database sqltest;

     

     

    이제 실행되고 있는 컨테이너가 할당받은 ip를 확인합니다.

    $ docker inspect mydb
    
    or
    
    $ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mydb

     

     

    많은 정보를 주는데 끝에 보면 IPAddress를 통해서 해당 컨테이너가 실행 중인 Ip가 확인이 가능하다.

    그럼 이 ip를 이용해서 서버를 띄워보자.

     

     

    서버가 잘 실행되는 것을 확인할 수 있습니다.. 감동..

     

     

    또 다른 방법으로는 ip를 사용하는 대신에 컨테이너의 이름을 사용할 수도 있습니다. 

    저는 mysql이 떠있는 컨테이너의 이름을 mydb로 설정하였으니, 다음과 같이 application.yml을 수정해보겠습니다.

     

    컨테이너의 이름을 사용하여도 서버가 잘 실행됩니다.

     

     

     

     

    6. 도커 컴포즈로 DB & 서버 관리하기

    같이 사용하는 2개의 프로그램을 각각 관리하는게 번거롭게 느껴집니다.

    도커 컴포즈를 이용하면 여러 개의 컨테이너 설정을 하나의 파일에서 정의하고 관리할 수 있습니다.

     

     

    docker-compose.yml 파일을 작성해보겠습니다.

    version: '3'
    
    services:
      spring:
          container_name: mywebserver
          build: .
          ports:
            - "8090:8080"
          depends_on:
            mysql:
              condition: service_healthy
          networks:
            - my-network
    
    
      mysql:
        container_name: mydb
        image: mysql
        environment:
          - MYSQL_ROOT_PASSWORD=12345678
          - MYSQL_DATABASE=sqltest
        ports:
          - "3308:3306"
        healthcheck:
          test: ["CMD", "mysqladmin", "ping", "-uroot", "-p12345678", "-h", "localhost"]
          interval: 10s
          timeout: 5s
          retries: 10
        networks:
          - my-network
    #   volumes:
    #     - ./initQuery.sql:/docker-entrypoint-initdb.d/initQuery.sql
    
    networks:
      my-network:

     

    •  services: docker-compose로 실행될 서비스를 적는 프로퍼티입니다. 현재 2개의 서비스를 실행할 예정이기 때문에 spring과 mysql을 적어 주었습니다. 개별 서비스 이름은 사용자가 정할 수 있습니다.
    • build: spring 서비스에서 build를 사용하고 있습니다. build는 Dockerfile의 경로를 적게 되어있습니다. 해당 경로의 Dockerfile을 사용해서 이미지를 만들고 실행시킵니다. 
    • image: docker hub에 있는 이미지를 다운받으려면 image 프로퍼티를 사용합니다.
    • container_name: 컨테이너의 tag 이름입니다.
    • depends_on: 해당 서비스가 다른 서비스에 종속된다는 것을 보여주는 프로퍼티입니다. 의존하고 있는 서비스가 실행된 후에 해당 서비스가 실행됩니다.
    • networks: 도커 컴포즈를 사용하면 기본적으로 동일 네트워크에서 실행이됩니다. 네트워크 이름을 명시적으로 적을 수 있는 프로퍼티입니다.  가장 아래에 위치한 networks와 함께 사용해야합니다.
    • volumes: 호스트가 가지고 있는 파일 시스템의 일부를 컨테이너에 공유하는 프로퍼티입니다. 주석 처리된 내용은 현재 경로에 있는 initQuery.sql 파일을 docker-entrypoint-initdb.d 폴더에 initQuery.sql로 복사하는 내용입니다. mysql은 실행시에 docker-entrypoint-initdb.d 에 있는 모든 sql파일을 실행합니다. 따라서 초기화를 위한 별도의 sql파일을 작성해서 추가할 수 있습니다.

     

    docker-compose 파일을 실행시켜보겠습니다.

    $ docker-compose up -d

     

     

    컨테이너 이름과 함께 로그가 찍히는 것을 확인할 수 있습니다.

     

     

    docker-compose로 묶어서 관리하는 편이 유지 보수에 훨씬 편리함이 느껴집니다.

Designed by Tistory.