[Network | Docker] Apache, Docker Compose를 이용한 Reverse Proxy 구성

📢 해당 포스트는 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