개발 ON
  • [Network | Docker] Apache, Docker Compose를 이용한 Reverse Proxy 구성
    2024년 07월 17일 18시 04분 55초에 업로드 된 글입니다.
    작성자: 이주여이
    📢 해당 포스트는 Docker Compose를 사용하여 여러 컨테이너들을 하나의 서비스로 묶어 관리하고 호스트 PC에 설치된 httpd(Apache)를 통해 특정 도메인과 도커 컨테이너를 연결하는 과정을 설명합니다.

     

    🛠️ 참고
    Virtualbox - Oracle VM Virtualbox
    Linux OS - Rocky Linux
    HTTPD - Apache

    0. Docker Compose 개념

    docker-compose.yml 파일을 사용해 하나의 가상 서버에서 여러 개의 컨테이너를 하나의 서비스로 정의해 컨테이너를 묶음으로 관리할 수 있다.

     

    만약 Docker Compose를 사용하지 않는다면 컨테이너를 하나 하나씩 run 해야하는 번거러움이 있다. 하지만 Docker Compose를 사용하면 한번의 명령어로 설정 파일 안에 여러 개의 컨테이너들을 관리할 수 있다.(각 컨테이너들의 의존성, 네트워크, 볼륨 등등)

     

    정말 편하긴 하더라.. 이제 docker run 안해도 된다!

    1. Docker Compose 설치

    # 도커 깃허브 저장소에서 Docker Compose 다운로드
    [root@localhost ~]# curl -L https://github.com/docker/compose/releases/download/1.11.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
    100 8052k  100 8052k    0     0  4269k      0  0:00:01  0:00:01 --:--:-- 6290k
    # 권한 부여
    [root@localhost ~]# chmod +x /usr/local/bin/docker-compose
    # 버전 확인
    [root@localhost ~]# docker-compose -v
    docker-compose version 1.11.0, build 6de1806

    2. docker-compose.yml 생성

    💡 하위 항목은 탭(Tab)이 아닌 2개의 공백으로 하위 항목을 구분한다.

     

    version: "3.0"
    services:
      app5221:
        build:
          context: /home/user5221
          dockerfile: Dockerfile
        container_name: app5221
        ports:
          - "5221:80"
        volumes:
          - 5221:/home/download
      app5222:
        build:
          context: /home/user5222
          dockerfile: Dockerfile
        container_name: app5222
        ports:
          - "5222:80"
        volumes:
          - 5222:/home/download
      app5224:
        build:
          context: /home/user5224
          dockerfile: Dockerfile
        container_name: app5224
        ports:
          - "5224:80"
        volumes:
          - 5224:/home/download
    
    volumes:
      '5221':
        external: true
      '5222':
        external: true
      '5224':
        external: true
    • version - Docker Compose 버전을 지정한다. 3.0 버전은 Docker Compose 1.10 및 Docker Engine 1.13.0 이상에서 사용된다.
      • services - 생성될 컨테이너를 묶어놓은 단위로 services 아래에 생성할 컨테이너 서비스를 지정한다.
        • app5221, app5222, app5224 - 생성될 서비스의 이름으로 각각의 서비스는 하나의 컨테이너를 나타낸다.
        • build - build 아래에 하위 항목으로 빌드할 때 사용할 옵션을 지정한다.
          • context
            • Dockerfile이 있는 경로를 지정한다.
            • 이전에 Dockerfile로 빌드 할 때 su - user5221 계정으로 접속해 루트 경로에서 Dockerfile과 app.jar을 두고 진행했었다. 현재 경로에서 dockerfile과 build 파일이 어디 있는지 적어주면 된다.
          • dockerfile - Dockerfile 그대로 적어준다.
        • container_name - 컨테이너 명을 지정한다.
        • ports
          • 해당 컨테이너로 접속할 포트를 지정한다.
          • 5221 포트로 요청 시 컨테이너 내부의 80 포트로 전달한다.
          • FROM openjdk:17-jdk-alpine
            ARG JAR_FILE=*.jar ADD ${JAR_FILE} app.jar
            EXPOSE 80
            WORKDIR /home/user5221
            VOLUME /home/download/
            ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar"]
          • 조금 더 쉽게 이해하기 위해 위의 dockerfile을 보자. dockerfile에 EXPOSE를 80으로 지정했다. 이것은 도커 컨테이너 내부에 포트 번호를 80으로 지정한다는 뜻이다. 그리고 docker-compose.yml에서 지정한 ports 5221은 내가 도메인:5221 로 접근할 경우 5221 포트를 확인하고 도커 컨테이너 내부의 80 포트로 매핑해주는 것이다.
        • volumes - 호스트와 컨테이너 간의 디렉토리 혹은 파일을 공유할 수 있는 볼륨을 지정한다.(볼륨이 없다면 docker volume create --name ${볼륨명 } 으로 만들면 된다) 왼쪽엔 내가 만들어놨던 도커 볼륨을 오른쪽엔 컨테이너 내에 파일이 저장될 경로를 적어주면 된다.
    • volumes
      • 외부 볼륨을 설정한다.
      • 5221 ~ 5224 - 볼륨명(참고로 숫자만 있다면 따옴표(’)로 감싸줘야 한다. 아니면 docker-compose.yml 실행 시 따옴표로 감싸라며 에러가 발생한다)
      • external: true - docker-compose.yml에서 정의한 볼륨이 외부에 이미 존재하며 Docker Compose가 해당 볼륨을 새로 생성하지 않고 기존에 있던 볼륨을 사용할 수 있도록 지정한다.

    3. httpd 수정

    ❓ 앞에 숫자가 있는 것은 vi 편집기에서 `:set number` 명령어로 넘버 라인을 표시했기 때문이다.

     

    47 Listen 80
    
    100 ServerName localhost:80
    
    360 <VirtualHost *:80>
    361   ServerName ljy.r-e.kr
    362   ProxyPreserveHost On
    363   ProxyPass / http://192.168.56.103:5221/
    364   ProxyPassReverse / http://192.168.56.103:5221/
    365 </VirtualHost>
    366
    367 <VirtualHost *:80>
    368   ServerName replay.o-r.kr
    369   ProxyPreserveHost On
    370   ProxyPass / http://192.168.56.103:5222/
    371   ProxyPassReverse / http://192.168.56.103:5222/
    372 </VirtualHost>
    373
    374 <VirtualHost *:80>
    375   ServerName ttoganjip.kro.kr
    376   ProxyPreserveHost On
    377   ProxyPass / http://192.168.56.103:5224/
    378   ProxyPassReverse / http://192.168.56.103:5224/
    379 </VirtualHost>
    
    • Listen 80 - 호스트 PC의 포트 번호는 기본적으로 80이다. 어디서 사용하는 거 아니면 변경할 필요는 없다.
    • ServerName localhost:80 - ServerName에 앞에 #로 주석 처리가 되어있을 경우 'systemctl restart httpd' 했을 때 에러가 발생하므로 주석을 풀어준다.
    • <VirtualHost> - 가상 호스트를 설정하는 시작 태그
      • * - 와일드 카드, 모든 IP에서 접근할 수 있다.
      • 80 - 웹 브라우저에서 접근할 포트
      • ServerName - 발급받은 도메인 주소를 적어주면 된다.
      • ProxyPass
        • 웹 서버가 받은 요청을 다른 서버로 전달한다.
        • 간단하게 설명하면 ljy.r-e.kr 도메인으로 접근할 경우 포트 80은 http의 기본 포트이기 때문에 생략이 가능하다. 그리고 ProxyPass 옆에 / 로 명시했기 때문에 ServerName 자체로 접근이 가능하다. 만약 / 옆에 /app1 과 같이 문자가 있을 경우 http://ljy.r-e.kr/app1 까지 접근해줘야 192.xxx.xxx.xx.xxx:5221 로 매핑된다.
        • / 우측의 192.xxx.xx.xxx 는 호스트 PC(도커 컨테이너가 있는 가상 서버)의 IP 주소이며 5221 은 위에 docker-compose.yml을 실행하며 생성된 도커 컨테이너의 포트 번호이다.
      • ProxyPassReverse - ProxyPassReverse는 ProxyPass로 전달된 요청의 응답을 원래 요청한 URL(http://ljy.r-e.kr)로 반환한다.

    4. docker-compose.yml 실행

    [root@localhost ~]# docker-compose up -d
    Building app5221
    Step 1/7 : FROM openjdk:17-jdk-alpine
    17-jdk-alpine: Pulling from library/openjdk
    Digest: sha256:4b6abae565492dbe9e7a894137c966a7485154238902f2f25e9dbd9784383d81
    Status: Downloaded newer image for openjdk:17-jdk-alpine
     ---> 264c9bdce361
    Step 2/7 : ARG JAR_FILE=*.jar
     ---> Running in d4e39d164dab
     ---> Removed intermediate container d4e39d164dab
     ---> 123f25dbf9ef
    Step 3/7 : ADD ${JAR_FILE} app.jar
     ---> 3c33b3c3ab69
    Step 4/7 : EXPOSE 80
     ---> Running in 2b4b2b2843d1
     ---> Removed intermediate container 2b4b2b2843d1
     ---> a5d5b704de06
    Step 5/7 : WORKDIR /home/user5221
     ---> Running in 2e3190589b51
     ---> Removed intermediate container 2e3190589b51
     ---> de8bdb8b89a9
    Step 6/7 : VOLUME /home/download/
     ---> Running in 8e8f719dee29
     ---> Removed intermediate container 8e8f719dee29
     ---> d1906f0955fd
    Step 7/7 : ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar"]
     ---> Running in 76b283596830
     ---> Removed intermediate container 76b283596830
     ---> 45add8706680
    Successfully built 45add8706680
    Successfully tagged root_app5221:latest
    Step 1/7 : FROM openjdk:17-jdk-alpine
     ---> 264c9bdce361
    Step 2/7 : ARG JAR_FILE=*.jar
     ---> Using cache
     ---> 123f25dbf9ef
    Step 3/7 : ADD ${JAR_FILE} app.jar
     ---> d82f9b2101cf
    Step 4/7 : EXPOSE 80
     ---> Running in 5de73cff26e0
     ---> Removed intermediate container 5de73cff26e0
     ---> e882c553ce93
    Step 5/7 : WORKDIR /home/user5222
     ---> Running in 1e8354ca8a60
     ---> Removed intermediate container 1e8354ca8a60
     ---> 0f4aa1023a3f
    Step 6/7 : VOLUME /home/download/
     ---> Running in e960781f165a
     ---> Removed intermediate container e960781f165a
     ---> 865d83bf6c09
    Step 7/7 : ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar"]
     ---> Running in 2b4961456f2e
     ---> Removed intermediate container 2b4961456f2e
     ---> 05a578f785fc
    Successfully built 05a578f785fc
    Successfully tagged root_app5222:latest
    Step 1/7 : FROM openjdk:17-jdk-alpine
     ---> 264c9bdce361
    Step 2/7 : ARG JAR_FILE=*.jar
     ---> Using cache
     ---> 123f25dbf9ef
    Step 3/7 : ADD ${JAR_FILE} app.jar
     ---> 3320792a1923
    Step 4/7 : EXPOSE 80
     ---> Running in cebb9be1f1f7
     ---> Removed intermediate container cebb9be1f1f7
     ---> d236bab3f5ae
    Step 5/7 : WORKDIR /home/user5224
     ---> Running in b569d6082ae4
     ---> Removed intermediate container b569d6082ae4
     ---> 717ddfe785e0
    Step 6/7 : VOLUME /home/download/
     ---> Running in afac756c4972
     ---> Removed intermediate container afac756c4972
     ---> b8509aceb6a7
    Step 7/7 : ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/app.jar"]
     ---> Running in 85b6a4ae19c8
     ---> Removed intermediate container 85b6a4ae19c8
     ---> 27fa929132f9
    Successfully built 27fa929132f9
    Successfully tagged root_app5224:latest
    Creating app5221
    Creating app5224
    Creating app5222
    Creating apache

    그리고 docker ps 명령어를 통해 컨테이너가 정상적으로 띄워졌는지 확인해보자.

    CONTAINER ID   IMAGE          COMMAND                  CREATED       STATUS       PORTS                                       NAMES
    e4475ce40736   root_app5221   "java -jar -Dspring.…"   3 hours ago   Up 3 hours   0.0.0.0:5221->80/tcp, :::5221->80/tcp       app5221
    f344f94e5267   root_app5222   "java -jar -Dspring.…"   3 hours ago   Up 3 hours   0.0.0.0:5222->80/tcp, :::5222->80/tcp       app5222
    bb9858deaf5f   root_app5224   "java -jar -Dspring.…"   3 hours ago   Up 3 hours   0.0.0.0:5224->80/tcp, :::5224->80/tcp       app5224
    925df5c890d9   mariadb        "docker-entrypoint.s…"   8 days ago    Up 2 days    0.0.0.0:3307->3306/tcp, :::3307->3306/tcp   mariadb

    5. 포트 포워딩 및 방화벽 포트 등록

    1. 공유기 포트 포워딩

    80 포트는 가상 서버의 httpd 기본 포트(변경하지 않았으므로 이 포트를 사용했다) 그리고 5221 ~ 5229까지 되어있는 것은 위에서 5221, 5222, 5224와 같이 도커 컨테이너 접근 시 사용하는 포트 번호를 미리 설정해놓은 것이다.

    2. 가상 머신 포트 포워딩

    내가 포스팅한 네트워크 관련 글에는 죄다 이 캡처가 들어가있는 것 같은데.. 여튼 이렇게 외부에서 들어오는 요청을 받을 수 있게 설정해준다. 외부에서 80 포트로 들어오면 내부의 80 포트(http 기본 포트)로 연결시킨다. 만약 httpd.conf에서 포트를 8080 뭐 이런 식으로 잡았다면 80, 8080으로 설정해야겠지..

    3. 방화벽 포트 등록

    80 포트를 받을 수 있게 firewall을 통해 포트를 등록한다.

    [root@localhost ~]# firewall-cmd --permanent --add-port=80/tcp
    [root@localhost ~]# firewall-cmd --reload
    [root@localhost ~]# firewall-cmd --list-all
    public (active)
      target: default
      icmp-block-inversion: no
      interfaces: enp0s3 enp0s8
      sources:
      services: cockpit dhcpv6-client ssh
      ports: 30000/tcp 80/tcp
      protocols:
      forward: yes
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:

    이렇게 등록되어 있으면 된다.

    6. 도메인 등록

    나는 무료로 도메인을 발급해주는 내도메인.한국을 사용하고 있다.

    궁금하면 아래 이전 포스팅 링크를 통해 발급받는 방법을 확인할 수 있다.

     

    [ETC] 무료 도메인 발급

    포트폴리오, 실습용으로 도메인을 구입하기엔 치킨 한마리 값이라도 뭔가 비싸보였다. 그래서 무료 도메인 발급을 검색하다가 내도메인.한국 이라는 곳을 알게 되었는데 사용법을 검색하지 않

    mytilblog.tistory.com

     

    그리고 IP 연결할 때 뒤에 포트 번호는 붙이지 않는다.

    공인 IP로 해당 도메인에 접근했을 때 위에 httpd.conf에서 지정한 5221 포트로 매핑된다.

    7. 확인

    짠~

    'Network > Docker' 카테고리의 다른 글

    [Network | Docker] jar 배포  (0) 2024.07.07
    [Network | Docker] Dockerfile  (0) 2024.07.05
    [Network | Docker] 이미지  (0) 2024.07.04
    [Network | Docker] 네트워크  (0) 2024.07.03
    [Network | Docker] 데이터베이스 외부 원격 접속  (0) 2024.07.03
    댓글